Skip to main content
Call Agent Vault from any language for everything except driving the browser.

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 from SELF_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:
Recipe reads need no authentication. Every other endpoint does.

Errors

Every error response is JSON with a stable code and a human-readable error:
Branch on 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.
With neither parameter, returns the index.

Request

Response

A per-URL lookup returns four slots, each a recipe or null:
The index and the full bundle return { "recipes": [...] }. Each entry has these fields: With full=1 each entry also carries the recipe body under recipe.
A per-URL lookup is unauthenticated, and its URL can reach logs before the no-store header applies. Never send a raw hosted-checkout URL: a Stripe cs_... path or a Shopify /checkouts/... path carries a session token. The SDK’s recipesForUrl() strips it for you.

Errors

None specific to this endpoint. A URL that does not parse returns four null 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

Status 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 three POST 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.
Responds 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.
Past either one, the request comes back 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.
The poll never returns a password. 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:
  • passwordPolicy describes 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/password refuses this login with not_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.
Responds 200 with the login’s updated catalog entry under login:
A handle is recorded once. Sending the exact same handle again succeeds with the same envelope. A different handle is refused with 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.
Plus any of the password rule fields above. Responds 200 with the login’s catalog entry under login, the rules the new password was generated under in passwordPolicy, and rotated: true:
This example followed "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.
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.