Skip to main content
Everything in @zeroclickai/sellers comes two ways: as bound methods on the client createSeller(config) returns, and as standalone named exports. The standalone exports are for applications that place verification, allowance checking, and response construction in separate middleware layers. All public functions validate their inputs and throw a typed ZCError for malformed input or API failure. Signature failures and business denials are returned decisions, never exceptions.

Client methods

createSeller(config) (see the configuration reference) returns these bound methods:

guard

Verifies the signature first, then checks the allowance under the request’s own zcRequestId and returns a decision. It never consults the allowance API for an unverified request. Each UsageItem names a meterSlug and declares the charge one of three ways: an exact quantity, a maxQuantity ceiling, or neither. A ceiling covers work you cannot size up front; it settles later at actual usage, so it never overcharges. An item with neither defers to the meter’s configured max usage per request. The SDK rejects an item that declares both. It also rejects duplicate meters and an empty usage array: an accidentally empty computed array must fail rather than silently skip the check.
On a business denial, the SDK builds the carried response from your input: the exact 402 payment_required body with the declared usage and, if you passed one, the planSlug. See charge up to a maximum for the ceiling pattern.

guardIdentity

The guard for free, identity-scoped endpoints: calls that cost nothing but serve only the buyer that owns the underlying records, such as polling a job the buyer created. It verifies the signature exactly like guard. When zc-agent-id is present, it allows with allowance: { status: "not_required" }. When it is absent, it denies with reason: "identity_required" and a 402 whose body carries usage: []. ZeroClick answers that with a free identity challenge, and the retry arrives with the buyer’s zc-agent-id attached. guardIdentity makes no allowance call, and no zc-usage belongs on the response: free means free.
Identity alone is not billability: a buyer that has only proven identity has no active access, so reportUsage against it fails with access_not_found. Gate billable work with guard. See free and identity endpoints.

verifyRequest

Verifies the zc-signature header and nothing else: parses t, kid, and v1, enforces the timestamp tolerance, resolves the signing secret by kid, recomputes the HMAC-SHA256 over the canonical string, and compares in constant time. It reads a clone, so the original body stays readable. The result is a decision:
reason is one of missing_signature, malformed_signature, stale_timestamp, missing_request_id, unknown_kid, or invalid_signature; response is the ready-to-return 401 {"error":"invalid_zeroclick_signature"}. Use it when verification and allowance checking live in different layers:
The signature spec specifies the canonical string and header format.

checkAllowance

Calls POST /v1/usage/check with the verified request’s zcRequestId. Checking records nothing and burns no credit: it answers whether the declared usage is covered right now. The SDK rejects an empty or duplicate-metered usage array before calling; the API accepts up to 20 items. Unlike guard, checkAllowance throws on a failed call: no outage policy applies here, so the caller decides.
See check allowances for what each denial reason means.

paymentRequired

Constructs the exact 402 refusal ZeroClick expects from a seller: {"error":"payment_required","serviceSlug":"…","usage":[…]}. For pay-as-you-go pricing, ZeroClick re-prices the refusal an anonymous probe earns into the priced challenge the agent sees. An empty usage array is valid here: it is the refusal for a free, identity-scoped endpoint, and ZeroClick answers it with a $0 identity challenge.

withUsage

Sets the validated zc-usage header for synchronous settlement without consuming the response body: it requires an unread Response and rebuilds it around the same body stream. Every item declares an exact quantity: this is where ceilings settle at actual usage. The header belongs on successful (2xx) responses only, and ZeroClick strips it before the agent sees the response.
See settle usage for choosing between synchronous and asynchronous settlement.

reportUsage

Calls POST /v1/usage for work that finishes after the response is gone. The idempotency key is seller-owned: derive it from stable facts (zcreq_8h2m4x0q9k1f_output_tokens), never random. Reporting is idempotent per service on that key, and reportUsage does not generate keys or retry automatically.
The result is { recorded: true, duplicate: boolean, usageEvent }. duplicate: true replays the stored event: a success, not an error. A business denial at reporting time throws an api_status_error whose context.reason carries the denial reason; see errors.

Result shapes

GuardResult

guard and guardIdentity return the same union:
The allow branch’s context is the verified ZeroClick envelope: allowance.status is "allowed" when the API said yes, "unavailable" when the fail-open outage policy admitted a verified request without an answer, and "not_required" from guardIdentity, which makes no allowance call.

Deny reasons

Standalone exports

The same primitives are named exports for applications that spread the flow across middleware layers. The guards take an options argument in place of client configuration; the API calls take per-call options.
  • guard(request, input, options): options are a signing-secret source (signingSecrets or resolveSigningSecret), a required apiKey, and the guard settings (apiBaseUrl, fetch, clock, toleranceSeconds, allowanceUnavailable, checkTimeoutMs, onAllowanceUnavailable).
  • guardIdentity(request, input, options) and verifyRequest(request, options): options are a signing-secret source plus optional clock and toleranceSeconds.
  • checkAllowance(input, options) and reportUsage(input, options): options are { apiKey, apiBaseUrl?, fetch?, signal?, timeoutMs? }.
  • paymentRequired(input) and withUsage(response, usage): identical to the bound methods.
  • invalidZeroClickSignature() and allowanceUnavailable(): construct the bare 401 and 503 refusal responses.
  • ZCError and isZCError: the typed error and its narrowing helper; see errors.
The package root exports TypeScript types for every input and result: SellerConfig, GuardInput, GuardResult, ZeroClickContext, UsageItem, SyncUsageItem, CheckAllowanceInput, AllowanceDecision, UsageDenialReason, ReportUsageInput, ReportUsageResult, and the rest.

The contracts subpath

@zeroclickai/sellers/contracts exports the seller-facing Zod schemas and their inferred types: guard input, usage items, allowance requests, responses, and denial reasons, the payment_required body, zc-usage items, signature headers, the verified context, report inputs and results, seller configuration, and API call options.
Public SDK methods already validate their inputs, so reach for the schemas only to validate data at an earlier boundary: a queue message that will become a reportUsage call, a stored usage draft, a test fixture.

Encryption

The @zeroclickai/sellers/encryption subpath exports decryptRequest(request, { resolvePrivateKey }) and encryptResponse(response, envelope). Run guard or verifyRequest against the original encrypted request before decryption. The signature then covers the original Compact JWE bytes. The suite is fixed to ECDH-ES+A256KW key management and A256GCM content encryption. decryptRequest selects a private key with the protected kid. Private encryption keys remain seller-owned. The SDK does not generate, upload, persist, or rotate them. See end-to-end body encryption for the complete data path and trust boundary.

The stateful subpath

@zeroclickai/sellers/stateful implements the account routes for sellers whose purchases create accounts and API keys:
  • handleAccessRequest(request, { onWrite, onMint }, options): routes, verifies, and validates both account calls, then hands off to your two handlers. Returns null for anything that is not one of its routes.
  • shouldApply, deriveCreditDelta, periodAdvanced, and parseEntitlement: the dedup and never-regress arithmetic an account write must be applied with.
  • isServiceable: the one request-time gate — true only while the account is active and its period, when it has an end, has not lapsed.
  • parseMoneyUsd and formatMoneyUsd: six-decimal money strings to integer micros and back, so no floating-point math ever touches money.
  • verifyAccessSignature, canonicalAccessString, and signAccessRequest: the purpose-carrying access signature on its own, plus a signer for integration tests.
  • The wire schemas and their types (accessUpsertRequestSchema, mintKeyResponseSchema, and the rest), mirroring the contracts subpath pattern.
Do not route these calls through guard or verifyRequest: account calls carry a different, purpose-separated signature by design. The account and key reference documents every field, status, and retry rule.