Endpoints
Signup and accounts
Self-serve signup for buyers and sellers, and the email/password console login. Signup, sign-in and password recovery work without an API key.
Signup
/v1/signupNo auth. Claims an address and sends a confirmation email. Creates nothing yet.
| Field | Type | Required | Notes |
|---|---|---|---|
role | "buyer" | "seller" | yes | |
email | string | yes | |
organizationName | string | yes | |
website | string | no | helps seller verification |
dailyBudgetMicros | string | no | buyers only: the workspace's daily cap in micro-dollars |
password | string | no | enables console sign-in once the email is confirmed |
withCode | boolean | no | also email a 6-digit code, so the person can confirm through an AI agent instead of a browser. The link still works |
ref | string | no | where the signup came from: up to 64 letters, digits, _ or -. Recorded for Zanora's own attribution and never returned. The console sends the ref from a ?ref= link |
// 202
{ "signupId": "sgn_…", "status": "pending", "expiresAt": "…", "emailSent": true }There's one pending signup per email and role. Asking again resends the email for the same signup. The response is identical whether or not the address is already known.
Asking again doesn't change a signup's ref.
Asking again with withCode: true adds a code to a signup that didn't have one. A resend of a signup that has a code always sends a new code.
/v1/signup/verifyNo auth. Confirms the email and creates the tenant. Send either the link's token, or the signupId with the emailed code.
| Field | Type | Required | Notes |
|---|---|---|---|
token | string, from the email link | one of the two proofs | |
signupId | string | with code | from the POST /v1/signup response |
code | string of 6 digits | with signupId | from the email. A JSON number is refused |
agent | { name, publicKeyPem } | no, code only | buyers only. Creates an agent wallet with this ed25519 public key, and an agent key. name is the wallet's owner id, shown on receipts and approvals |
defaultRules | boolean | no, code only | registers the console's suggested rules: purchases over $2.00, and any from an unverified seller, need a person's approval |
// 201
{
"signupId": "sgn_…", "role": "seller", "status": "completed",
"tenant": { "kind": "provider", "id": "prv_…", "name": "Acme OCR", "walletId": "wal_…" },
"credential": { "keyId": "akey_…", "token": "zk.akey_….…", "label": "…", "scopes": ["…"] }
}credential.token is shown once. walletId (sellers only) is the settlement wallet. The token can be used only once and expires after 24 hours. If two requests use it at the same moment, only one tenant is created.
With agent, the response carries the agent's wallet and key instead of credential:
// 201
{
"signupId": "sgn_…", "role": "buyer", "status": "completed",
"tenant": { "kind": "workspace", "id": "wsp_…", "name": "Northwind" },
"agent": {
"walletId": "wal_…", "name": "claude-code",
"credential": { "keyId": "akey_…", "token": "zk.akey_….…", "label": "claude-code agent", "scopes": ["discovery:read", "…"] }
}
}The agent key can search, buy, read balances and receipts, rate sellers and read approvals. It can't approve a held purchase or create keys. The workspace's root key is created but never returned to the agent, and no console session is returned either. The person signs in to the console with the password from the signup request. A signup without one is sent a "Set your console password" email as soon as it's confirmed (by link or code). The link works once for 24 hours, and is redeemed like a reset (POST /v1/accounts/password/reset). After that, Forgot password does the same.
The code's limits. It works once, expires 30 minutes after it was sent (never later than the link), and allows 5 attempts. After that, request a new one with POST /v1/signup/resend, which also invalidates the old code. A malformed code or agent key doesn't use up an attempt. A private key sent as publicKeyPem is refused: generate a new keypair, because that key has left the machine.
/v1/signup/resendNo auth. Body { role, email }. Always returns 202. Invalidates the previous link, and the previous code if the signup has one.
/v1/signup/:idNo auth. The status of a signup by its signupId: pending, completed or expired. Returns no email address and no token.
Console accounts
A console session is an ordinary API key of kind session, limited to your tenant.
/v1/accounts/loginNo auth. Body { email, password }. Returns { sessionToken, expiresAt?, scopes, account }. Failed attempts count toward a lockout.
/v1/accounts/logoutRevokes the session presenting it. It refuses an ordinary API key, so an agent's key can't be revoked from a sign-out button by mistake.
/v1/accounts/meThe account behind the current session, plus its standing: { status: "active" }, or { status: "frozen", frozenAt, reason } while Zanora has frozen it. Returns 404 for an ordinary API key.
/v1/accounts/password/forgotNo auth. Body { email }. Always returns 202 with the same body.
/v1/accounts/password/resetNo auth. Body { token, password }. Revokes every console session and no API keys, so your agents keep running.
/v1/accounts/passwordChanges the password while signed in. Body { currentPassword, newPassword }.
/v1/accounts/closeCloses your account. Console session only: an ordinary API key gets 403, so an agent can never close the account it runs on. Body { confirm, password?, reason? }, where confirm is the email address on the account and password is required if the login has one.
Returns { status: "closed", closedAt, purgeAfter }. Every API key and session is revoked at once, sign-in stops working, and a seller's listings are removed from discovery. Your account details are deleted by purgeAfter. See Closing your account for what happens to money left in your wallets. A frozen account can't be closed this way; email support.