Skip to main content
createSeller(config) validates its configuration up front and returns a frozen client. Invalid configuration throws a ZCError with code malformed_input at construction, not at request time. Construction enforces two constraints:
  • Exactly one signing-secret source. Provide signingSecrets or resolveSigningSecret: not both, not neither.
  • Both usage directions covered. Allowance checks (guard, checkAllowance) use usageReadKey. Usage reporting (reportUsage) uses usageWriteKey. A single apiKey with both scopes backfills either side. createSeller rejects a config that leaves a direction without a key; context.issues names the missing side.

Options

Usage keys

One API key with both usage scopes covers everything. To separate concerns (a request path that only checks, a worker that only reports), pass scoped keys:
A scoped key can also override one direction while apiKey backfills the other. See keys and secrets for minting scoped keys.

Signing-secret rotation

ZeroClick identifies each signature with a kid: the signing secret’s id, carried in every zc-signature header. Keep every key that may still sign an in-flight request available to the SDK:
If a request’s kid is missing from the record, the SDK denies it with a 401 (reason unknown_kid). Never log or return a signing secret. Revoke an old key only after requests signed by it can no longer be in flight.

Resolving secrets dynamically

For managed secret storage, resolve by kid instead of holding secrets in memory:
The resolver runs on every verification with the kid from the request’s signature header. Return the secret, or null for a kid you do not recognize. The SDK denies that request as unknown_kid. A resolver that throws surfaces as a ZCError with code signing_secret_resolution_failed rather than a deny. An outage in your secret store shows up as an error instead of silently rejecting traffic.

Allowance outage policy

The default policy is fail-open after the 1.5-second check timeout: the SDK allows a verified request with allowance.status === "unavailable", and onAllowanceUnavailable receives the sanitized error. Configure "deny" to return 503 {"error":"allowance_unavailable"} instead, or "throw" to handle the typed error in application code:
The policy applies when the allowance check produces no usable answer: the call failed or timed out (api_transport_error), the API answered with an unsuccessful status (api_status_error), or the response body did not validate (api_response_invalid). It applies only after the signature verifies: the SDK never allows an unverified request because the allowance API is unavailable. A definite allowed: false answer is never subject to the policy; it always denies with the 402.

Per-call cancellation

The bound checkAllowance and reportUsage methods accept an optional { signal }:
The signal combines with the built-in timeout; whichever fires first aborts the call. guard already ties its allowance check to the incoming request’s own AbortSignal, so an agent that disconnects does not leave a check running. Through the client, the allowance check times out after checkTimeoutMs, and reportUsage after the fixed 1,500 ms default. To raise the reporting timeout, call the standalone export with timeoutMs.

Standalone function options

The checkAllowance and reportUsage named exports hold no client state. Each call carries its own options, for middleware layers or workers that never construct a client:
The standalone guard, guardIdentity, and verifyRequest exports take the options a client would otherwise hold; the API reference lists their shapes.