Credentials API
Credentials are envelope-encrypted at rest. The plaintext is never returned from any API call — list endpoints expose metadata only.
POST /credentials
curl -s -X POST "$API_URL/credentials" \ -H "Authorization: Bearer $SYNTHUSERS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "label": "Vercel staging signup", "target_host": "vercel.com", "username": "agent+vercel@example.com", "password": "<plaintext>" }'Response
{ "id": "cred_01H...", "label": "Vercel staging signup", "target_host": "vercel.com" }target_host is the SSRF allowlist key. A run that references this
credential must have a target_url whose host equals target_host.
GET /credentials
{ "items": [ { "id": "cred_01H...", "label": "Vercel staging signup", "target_host": "vercel.com", "username": "agent+vercel@example.com", "created_at": "2026-05-15T18:00:00Z" } ]}No password, no encrypted blobs.
DELETE /credentials/:id
Hard-delete. Subsequent runs referencing this id return 404 credential_not_found.
Encryption model
- Master key: 32 random bytes in Workers Secrets (
MASTER_ENCRYPTION_KEY). - Per-customer DEK: random 32 bytes per customer, wrapped with the master.
- Credential blob: AES-GCM over the password with the customer’s DEK.
- In-transit: TLS 1.3 only.
- At rest in D1: only
encrypted_password+encrypted_dekbytes; never plaintext. - In the agent: decrypted once inside the SessionDO, passed to the browser action that needs it, then dropped.
The master key can be rotated with zero downtime by re-wrapping each customer’s data key.