Overview
Driving the proxied browser uses the proxy’s WebSocket protocol, not this API.
The Playwright SDK and the MCP server are the two
supported clients for it.
Base URL
Your deployment’s API base URL, which the SDK reads fromSELF_AGENT_PAY_API_URL.
Copy it from the dashboard’s framework picker on Overview or API keys.
Authentication
Send an API key from the dashboard as a bearer token:Errors
Every error response is JSON with a stablecode and a human-readable error:
code, never on error, whose wording can change. Every authenticated
response carries Cache-Control: no-store. Full list:
Error codes.
GET /v1/tokens
Returns the mock token catalog this API key may use.
Query parameters
string
Narrows
cards and logins to those registered for this page, and adds
relatedLogins. Cards marked anySite: true are always kept, after the ones
registered for the page. host is accepted as an alias. A value that does not
parse matches no site: every site-scoped card and every login drops out, but
every anySite card is still returned. Identity and addresses are returned
unchanged.Request
Response
200 with the catalog. Every field is described in
Token catalog.
The URL filter is a convenience over data the key can already see. It is not a
security boundary: the proxy’s URL locking is.
Errors
Both windows are fixed, not sliding. The account budget is shared by every key on
the account, so creating more keys does not raise it. A refused request records
nothing, so retrying early is simply refused again. A successful fetch also marks the key as used, which
is how the dashboard shows that your agent has connected.
GET /v1/recipes
Looks up the checkout recipe registry.
Query parameters
string
Returns the recipes that apply to this page. Send only the scheme, host and
path: strip the query, the fragment and any hosted-checkout token first.
string
1 returns every recipe body. Ignored when url is set.Request
Response
A per-URL lookup returns four slots, each a recipe ornull:
{ "recipes": [...] }. Each entry has these
fields:
With
full=1 each entry also carries the recipe body under recipe.
Errors
None specific to this endpoint. A URL that does not parse returns fournull
slots.
POST /v1/recipes
Contributes a recipe. Screening runs after the request returns.
Body
The recipe JSON on its own, or wrapped:object
required
The recipe. See Recipe format.
string
Free text for the maintainer, up to 2,000 characters. For a verification
request, the out-of-band evidence. Published word for word as the recipe’s
evidence if the claim is approved.boolean
Says a real purchase completed (or, for a signup recipe, an account was
created). Requires a non-empty
note. The recipe goes live at the submitted
status and the claim waits for a maintainer, who alone can set verified.$-prefixed field names, such as an editor-only $schema pointer, are removed
on parse.
Request
Response
202. Read the outcome from GET /v1/recipes/submissions/{id}.
Errors
GET /v1/recipes/submissions/{id}
Returns the verdict for a submission made by this account.
Path parameters
string
required
The
id returned by POST /v1/recipes.Request
Response
status is pending, approved, merged, rejected or needs_human.
verdict lists the screening findings in fixed text, and is empty while
pending. See Submission outcomes.
While status is pending, poll again. Do not resubmit.
Errors
Signup and login endpoints
These four endpoints let an agent open and maintain site logins for the account holder. The threePOST endpoints need an API key the owner has granted the
signup permission, which is off by default. See
Agent signup.
Shared by all four:
The three
POST endpoints (/v1/logins/requests, /v1/logins/username and
/v1/logins/password) also share these rules:
The account’s budget of agent credential changes, 25 by default in a 24-hour
window, is not shared the same way. The window starts at the first counted
change and resets 24 hours after it, not at midnight.
POST /v1/logins/username and POST /v1/logins/password
charge it when they write, and answer daily_limit when it is spent.
POST /v1/logins/requests does not charge it when it files an ordinary
pending request. The account holder’s approval charges it later, and if the
budget is spent at that moment, the request stays pending: your poll never
shows daily_limit. A pre-approved signup that completes at once does not
charge it either. It draws on the pre-approved allowance instead, described
under POST /v1/logins/requests below.
GET /v1/logins/requests/{id} only reads. It takes no body and is not counted
against the per-minute limit or the 24-hour budget. It answers only the key that
filed the request.
Password rule fields, accepted by the request and password endpoints. Every field
is optional. A value of the wrong type is ignored, so the vault’s stronger
defaults apply. The generated password is 12 to 64 characters, 24 by default,
and always holds a lowercase letter, an uppercase letter and a digit, plus a
symbol unless noSymbols is set.
number
Shortest password the site accepts. A whole number, at most 64. A higher value
is refused with
invalid_policy, because the vault never generates a password
longer than 64. Such a login has to be added by the account holder.number
Longest password the site accepts. A whole number. Below 12 is refused with
password_too_short.boolean
The site rejects punctuation. Set it only from a stated rule.
string
The exact punctuation the site accepts. It can only narrow the vault’s safe
set,
!@#$*+-_=.?. A value with none of those characters is refused with
invalid_policy.boolean
The site rejects three identical characters in a row.
POST /v1/logins/requests
Files a signup request. Usually the account holder has to approve it, and
nothing is created until they do. If they have put this site and this exact
email on their Pre-approved signups list, the login is created right away
instead.
string
required
The site’s domain, for example
shop.example.com.string
required
The mailbox to sign up with.
string
A handle, only if the site has already accepted it. At least 4 characters.
202 with { "requestId": "...", "status": "pending", "expiresAt": 1789000000000 }.
A pending request expires 24 hours after it is filed.
When the site and email are on the pre-approved list, the same 202 carries
"status": "approved". The login already exists, so poll the requestId right
away: the first answer carries the tokens. A pre-approved signup that cannot
complete falls back to pending and waits for the account holder. Handle both
statuses. Pre-approval completes at once only within two ceilings:
- 2 signups per listed site. The count resets only when the account holder removes the site and adds it again, or saves it with a different email.
- 60 signups per account in a 24-hour window, by default. The window starts with the first pre-approved signup and resets to zero 24 hours later.
pending instead of approved. The
other checks an approval runs, such as the key’s allowed-logins list or a free
label for the site’s name, also send it to pending. See
Limits.
The 500-login ceiling works differently. If the account already holds 500
logins when you file the request, the call is refused at once with 403 and
login_limit, whether or not the site is pre-approved. No request is created
and the account holder is not asked. The ceiling is checked again at approval,
so a request filed below it can still stay pending if the account reaches 500
while it waits.
GET /v1/logins/requests/{id}
Polls one signup request.
login is exactly what GET /v1/tokens will
show for it.
passwordPolicy describes the password the vault generated at approval.
passwordOwnerManaged is true when the account holder has replaced that
password from their dashboard before you polled. Then:
passwordPolicydescribes a password that no longer exists.- The login’s password token resolves to the account holder’s password, so fill it as normal.
POST /v1/logins/passwordrefuses this login withnot_rotatable, for good. If the site rejects the password, tell the account holder instead.
false, or absent on an older deployment, means the generated password is still
in place and the policy describes it.
An approved login the account holder has since removed from this key’s scope
answers scope_denied instead of approved.
POST /v1/logins/username
Records the handle on a login that was opened with only an email.
string
required
The login’s label, for example
shop.string
required
The handle. At least 4 characters, with no control characters.
200 with the login’s updated catalog entry
under login:
username_already_set.
Only the API key that created the login can set its username, and only within
seven days of the login being created. Seven days is the default; a deployment
can set a different window. Any other key, or a later request, gets 404
not_found, the same answer as an unknown label. Re-sending the handle already
stored still succeeds after the seven days.
POST /v1/logins/password
Mints a replacement password for a login an agent created. The mock tokens do not
change, so a token already in use resolves to the new password.
string
required
The login’s label.
200 with the login’s
catalog entry under login, the rules the new password was generated under in
passwordPolicy, and rotated: true:
"noSymbols": true, so passwordPolicy has no
symbolAlphabet. The tokens are the same as before the rotation. Only the API
key that created the login can rotate it, only within seven days of the login
being created, and only while the account holder has not replaced its password.
Seven days is the default; a deployment can set a different window. Every other
case, including an unknown label, gets 409 not_rotatable.
Errors
Some checks run only when the account holder approves a signup, such as the
key’s allowed-logins list being full or the site’s name having no free label. A
failed check is shown to the account holder and never returned to you: the poll
keeps answering
pending. If the account holder says they approved and the
poll still answers pending, the approval was blocked: they have to fix the
cause and approve again. Do not open a second request. See
Signup and login writes.
POST /v1/logins (retired)
Answers 410 Gone with signup_requires_approval. Use
POST /v1/logins/requests instead.
Account holder links
The dashboard’s approval, security code, challenge and signup prompts are backed by single-use links sent to the account holder. Each link’s token is the only credential, it expires on its own, and the agent never sees it. They are not an integration surface for agents.
Deleting an account removes every pending prompt, and a link for a deleted
account reads as not found.
Two further paths serve Agent Vault’s own infrastructure and billing. Neither
accepts an API key.
Worked example
Read the catalog, check the registry and contribute, with no SDK:This fingerprint strips the query and fragment. It does not remove a session
token embedded in the path, such as a Stripe
cs_... checkout or a Shopify
/checkouts/... path. For those hosts, send only the scheme and host.