@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
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.
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
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.
reportUsage against it fails with access_not_found. Gate billable work with guard. See free and identity endpoints.
verifyRequest
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:
checkAllowance
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.
paymentRequired
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
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.
reportUsage
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.
{ 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:
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 (signingSecretsorresolveSigningSecret), a requiredapiKey, and the guard settings (apiBaseUrl,fetch,clock,toleranceSeconds,allowanceUnavailable,checkTimeoutMs,onAllowanceUnavailable).guardIdentity(request, input, options)andverifyRequest(request, options): options are a signing-secret source plus optionalclockandtoleranceSeconds.checkAllowance(input, options)andreportUsage(input, options): options are{ apiKey, apiBaseUrl?, fetch?, signal?, timeoutMs? }.paymentRequired(input)andwithUsage(response, usage): identical to the bound methods.invalidZeroClickSignature()andallowanceUnavailable(): construct the bare401and503refusal responses.ZCErrorandisZCError: the typed error and its narrowing helper; see errors.
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.
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. Returnsnullfor anything that is not one of its routes.shouldApply,deriveCreditDelta,periodAdvanced, andparseEntitlement: the dedup and never-regress arithmetic an account write must be applied with.isServiceable: the one request-time gate —trueonly while the account isactiveand its period, when it has anend, has not lapsed.parseMoneyUsdandformatMoneyUsd: six-decimal money strings to integer micros and back, so no floating-point math ever touches money.verifyAccessSignature,canonicalAccessString, andsignAccessRequest: 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.
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.