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

Helpers for encrypted request and response bodies are opt-in through the @zeroclickai/sellers/encryption subpath: decryptRequest(request, { resolvePrivateKey }) and encryptResponse(response, envelope). Always run guard or verifyRequest against the original encrypted request before decrypting it, so the signature covers the Compact JWE bytes. The suite is fixed: ECDH-ES+A256KW key management with A256GCM content encryption. decryptRequest resolves the private key by the protected header’s kid, which supports rotation. Private encryption keys remain seller-owned: the SDK does not generate, upload, persist, or rotate them.