Skip to main content
Every detail behind sell accounts and API keys. Read that guide first — this page is for looking things up once you are building.

Configuring the endpoint

ZeroClick derives the endpoint from the origin of your upstream base URL plus /zeroclick/access. Any path on the base URL is dropped: https://api.example.com/v1 gives https://api.example.com/zeroclick/access. To host it elsewhere, set an override:
GET the same path returns the current accessEndpointUrl, plus salesEnabled (can buyers make new purchases) and servicingEnabled (can existing customers still recover and rotate keys). Changing those two is not self-serve — email help@zeroclick.ai. The mint route is always the write route plus /{accessId}/keys.

Request headers

Both calls arrive as POST with:

The account write

POST /zeroclick/access
Every money field is a string with exactly six decimal places. parseMoneyUsd converts one to an integer count of millionths of a dollar (“micros”) so you never do floating-point math on money; formatMoneyUsd converts back.

Why the write is a complete picture

The write describes how the account should look, not what changed. Replay it, receive it twice, or receive an old one late: applying the newest version you have seen always leaves the account correct. That is why creditGrantedUsd and creditReversedUsd are running totals rather than deltas. deriveCreditDelta nets the two totals into one purse movement, and returns one of four outcomes:

The key mint

POST /zeroclick/access/zacc_8h2m4x0q9k1f/keys
A successful response returns the key once. maxKeys tells ZeroClick how many live keys this account may hold (the SDK sends 1 automatically when remintPolicy is "rotating"), and keyExpiresAt lets ZeroClick tell the buyer when to come back for a new one. Both are optional.
200
ZeroClick passes the key straight to the buyer and never stores it. If the buyer needs it again, they ask for a new one and you mint again under your remintPolicy.

What your handlers receive

WriteInput, passed to onWrite: MintInput, passed to onMint, is the same minus entitlement, with dedupeKey of mint:{requestId}. Its accessId comes from the URL path rather than a body.

What your handlers can return

onWrite: onMint: Before either handler runs, the SDK answers 401 on a missing, stale, or invalid signature, and 400 if the body is malformed or its agent does not match the signed zc-agent-id.

Retries, timeouts, and failures

Account writes are at-least-once. Expect duplicates, and expect a retry after a network timeout that happened after you committed. When a delivery permanently fails, the buyer is made whole automatically: a reserved payment is released, a captured one is refunded. You never owe a refund for an account you did not create. If the refund itself fails, ZeroClick flags the account internally and follows up — there is nothing for you to do. Because ZeroClick considers the write applied when you answer 200 with lifecycle: "active", do not start anything irreversible after that point.

Buyer-facing routes on your pay URL

Your customer’s agent uses these to manage a purchase, all on your pay URL (https://acme.pay.zeroclick.io) and all authenticated with the agent’s own bearer token. You do not implement them — ZeroClick does — but you may want to point agents at them.

Free plans

A $0 subscription or subscription_usage plan can create an account, but only for a buyer who has verified their email address — that is what stops one person minting unlimited free accounts. A buyer without a verified email cannot claim a live free plan. Once created, the free account is durable and recoverable across that verified buyer’s agents, just like a paid account.

Signature, for stacks without an SDK

The stateful helpers ship in the TypeScript SDK today. On any other stack, implement the two routes and verify the signature yourself. It is HMAC-SHA256 over these seven lines joined by \n — the ordinary canonical string plus a trailing purpose:
Select the purpose from the route you matched, never from anything in the request. That is what stops a signature captured from ordinary proxied traffic from authorizing an account write. Compare against the v1= value in constant time, and reject a t= more than 5 minutes old or in the future.