Everything in cdn.zeroclick.io/sdks/sellers-go, importable as:
The Client is safe for concurrent use: build it once with New and share it. Every decision flows through the framework-neutral Request and Response types, so the SDK works outside net/http too. FromHTTP is only the net/http adapter, and the Meter and Identify middleware are packaged versions of the same calls.
Guards return decisions, not errors: an unsigned or unpayable request is an expected event on a public endpoint, so it comes back as a result carrying the exact Response to return. The SDK reserves errors for your own misconfiguration and for ZeroClick API failures. See Go SDK errors.
Client methods
Guard
The one call a billable endpoint needs: it verifies the signature, then checks that the buyer’s allowance covers usage, before any work happens. Verification always runs first: a request that fails it never reaches the allowance API. planSlug may be empty.
body must be the raw request bytes, read in full before the call. The middleware bounds that read for you. When you call Guard directly, bound the read yourself (for example with http.MaxBytesReader).
Declaring an exact Quantity lets ZeroClick offer the exact x402 payment scheme. A MaxQuantity forces upto, which fewer clients can pay. Prefer a fixed per-request charge, and report variable work afterwards with ReportUsage. See charge up to a maximum.
Guard deliberately severs the caller’s cancellation for the allowance check: it wraps ctx with context.WithoutCancel and applies its own CheckTimeout. Inheriting cancellation meant a client disconnect, or any proxy-side timeout, short-circuited the check before it was even sent. Under the allow policy the request was served anyway: a buyer who would have been denied got served, and the API was never asked. The check’s own timeout still bounds it. CheckAllowance keeps the caller’s context, because it surfaces the error instead of applying a policy to it.
The SDK still honors a denial with a reason it does not recognize: allowed is legible on its own, and the unfamiliar reason passes through in GuardResult.Reason for you to log. Rejecting the whole response on an unfamiliar reason would turn a denial into an allow the day ZeroClick adds a new one. An additive server change must stay additive.
GuardIdentity
Guards a free endpoint that must still know which buyer is calling, such as a limits or account route. It makes no network call.
A signed request with no zc-agent-id is an anonymous probe: valid, but it has not established a buyer. GuardIdentity answers it with a 402 carrying an empty usage list (Reason is identity_required). That makes ZeroClick issue a $0 identity challenge and retry the request with the identity attached. A signed request that does carry a buyer passes with Outcome set to OutcomeNotRequired. See free and identity endpoints.
Verify
Verifies the request’s signature using the client’s secrets, tolerance, and clock; it does nothing else. Use it directly only for endpoints that bill nothing. Anything billable should go through Guard, which also checks that the buyer can pay. The package-level Verify does the same without a Client.
CheckAllowance
Asks the allowance API directly, without verifying a request and without applying the outage policy. Errors surface for you to handle, classified with IsAllowanceUnavailable. It keeps the caller’s context, bounded by CheckTimeout. Checking records nothing and burns no credit. Guard is what an endpoint should use; this is for sellers driving the check themselves.
ReportUsage
Records usage out of band, after the response has gone out. This is how a seller bills for work whose amount is only known once it is done (pages extracted, tokens produced). The seller still declares a fixed per-request charge to the guard, so the exact scheme stays available. CheckTimeout bounds the call, and the write-scoped key authenticates it.
Reports are idempotent on IdempotencyKey: a retried report replays the stored event with Duplicate: true, which is a success, not a failure. Derive the key from the request id and the meter: a random key double-bills on retry. A failure here means work was delivered and not billed. Log it with the reason; do not fail the request the buyer already received.
Meter
Middleware that guards a billable endpoint: it verifies the signature, checks that the buyer can pay, and, if the handler responds 2xx, settles the declared usage via the zc-usage response header. It takes fixed quantities only. If handed an UpTo item or a non-positive quantity, it panics at wire-up. Covered in depth in Go SDK middleware.
Identify
Middleware form of GuardIdentity, for free identity-scoped endpoints. Also covered in Go SDK middleware.
Request helpers
FromHTTP
Builds a Request from a server-side *http.Request and an already-read body. It reads r.RequestURI, which is the raw percent-encoded request target exactly as it arrived. r.URL.Path is decoded and would break verification for any target containing an encoded character. On a hand-built request (where RequestURI is unset), it falls back to the escaped path plus raw query, which is exact unless the path held an encoded slash.
FromContext
Returns what a guarded request proved about its caller; ok is false on an unguarded route.
BackgroundContext
Returns a context for work that outlives the response, such as reporting usage after the buyer has their result. It is context.WithoutCancel(r.Context()): context values survive, cancellation does not. Deriving from r.Context() would not work: the server cancels that context the moment the handler returns. The report would be dropped, and the work would go unbilled with nothing in the logs to say so.
Usage constructors
PerRequest and UpTo
PerRequest declares a fixed charge, which is what lets ZeroClick offer the exact x402 scheme. UpTo declares a ceiling for work whose cost is unknown until it is done. It settles at the amount actually reported, so a ceiling never overcharges. But it forces the upto scheme, which fewer clients can pay, and Meter rejects it because a ceiling has no settled quantity. Prefer PerRequest plus ReportUsage for the variable part.
Signing secret helpers
SecretsFromEnv and ParseSigningSecrets
SecretsFromEnv parses the ZEROCLICK_SIGNING_SECRETS environment variable (the constant SigningSecretsEnv), which holds <kid>:<secret> pairs, comma-separated. Listing more than one is how a rotation survives. ParseSigningSecrets parses the same format from any source, such as a secret manager. Entries split on the first colon only, so secrets containing colons are safe, and parse errors never echo the value. See configuration for the format and rotation examples.
SigningSecrets
Adapts a static map to the ResolveSigningSecret resolver signature, for use with the package-level Verify. Config.SigningSecrets applies this adapter for you.
ok == false means the key id is unknown (a refusal); a non-nil error means the lookup itself failed, such as a vault being unreachable (a fault).
Response builders
Guard and the middleware build these responses for you; use them directly when you drive the flow yourself.
PaymentRequired
The 402 that tells ZeroClick what this request would cost: {"error":"payment_required","serviceSlug":…,"usage":[…]}, with planSlug included when non-empty. ZeroClick reads the usage list, prices it, and issues the buyer an x402 or MPP challenge; the buyer never sees this body. Return it before doing the work: a 402 after the fact means the work is done and unpaid. An empty usage list is meaningful, not a mistake: it is the free identity-scoped refusal, answered with a $0 identity challenge.
MustPaymentRequired
PaymentRequired for a usage list built from constants, where a validation failure is a bug rather than a runtime condition. It panics instead of returning an error.
InvalidSignature
The 401 {"error":"invalid_zeroclick_signature"} for a request that did not prove it came from ZeroClick. The body says nothing about why, deliberately. Your logs carry the FailureReason.
AllowanceUnavailable
The 503 {"error":"allowance_unavailable"} for “we could not reach the allowance API”, as distinct from “the allowance API said no”. The SDK returns it only under PolicyDeny.
WithUsage and UsageHeader
UsageHeader renders the zc-usage header value: what this response actually consumed, settled against whatever was authorized. WithUsage attaches it to a response. Set it only on a response that delivered: a 4xx for input you rejected must not carry it, because that bills the buyer for a refusal. The Meter middleware does this for you on 2xx responses.
JSON
Builds a JSON Response with the content-type header set. It panics only on a payload that cannot be marshalled, which is a programming error rather than a runtime condition.
Verification primitives
Verify (package function)
Verifies a ZeroClick signature over an already-read body, without a Client; no API key is needed. The body must be the raw bytes as received: re-serialized JSON will not match, because the digest covers bytes, not meaning. The verifier parses the signature header additively: it ignores unknown members (ZeroClick appends fields such as the sandbox marker over time) and rejects duplicate members. The returned error is non-nil only for a resolver fault (wrapped in ErrSecretResolution) or a missing resolver; every authentication failure is a VerifyResult decision instead.
CanonicalString
Builds the exact bytes that get signed, as six newline-joined fields: the timestamp, the uppercased method, the raw percent-encoded path and query, the lowercase hex SHA-256 of the body bytes, the zc-request-id value, and the zc-agent-id value or empty string. Useful for debugging a verification mismatch or building your own verifier; the full wire format is in the signature spec.
Error helpers
IsAllowanceUnavailable
Reports whether an error means “the allowance API did not give us an answer”, as opposed to “the API said no” or “we are misconfigured”. Only that condition is subject to the configured outage policy. The full classification is on the errors page.
Types
Request
The framework-neutral view of an inbound request. PathAndQuery must be the raw percent-encoded target: the signature covers those bytes, and the decoded path most frameworks hand you hashes differently. FromHTTP takes care of this for net/http. Header looks up the first value for a name, case-insensitively, whether Headers is an http.Header or a plain map.
Response
The framework-neutral response you return to ZeroClick. WriteTo writes it to a net/http response writer; outside net/http, map the three fields onto your framework’s response type.
Context
AnonymousID repeats AgentID under the name that will eventually replace zc-agent-id. BuyerID is the buyer that agent belongs to; unlike the fields above it is not covered by the signature. See agents and access.
What a verified request proved. AgentID is empty for a signed anonymous probe, which is valid: ZeroClick uses probes to price pay-as-you-go 402s. Test it with == "", never against a sentinel: an absent header and a present-but-empty one both mean “no buyer identity” and both sign identically.
GuardResult and GuardOutcome
The guard’s decision. Read OK first; when it is false, return Response verbatim and do no work. Reason is the denial code: a verification FailureReason, an allowance denial such as usage_exhausted, identity_required from GuardIdentity, or allowance_unavailable under PolicyDeny. Watch for Outcome == OutcomeUnavailable in logs and metrics: it means work is being done that may not be billed.
VerifyResult
A decision, not an error. The errors page lists the FailureReason values and explains why they are values rather than errors.
UsageItem
What a request will be charged for. Set exactly one of Quantity or MaxQuantity, or neither to defer to the meter’s configured per-request ceiling. A usage list must name at least one meter and may not repeat one. See usage and allowances for how the three forms are priced.
SyncUsageItem
Actual usage reported alongside a successful response, in the zc-usage header.
AllowanceDecision
ZeroClick’s answer to an allowance check. The SDK exports the denial codes as constants:
A reason outside this set passes through unchanged, and the decision still stands.
Input and outcome of ReportUsage.
Encrypted request bodies
ZeroClick can encrypt a buyer’s request body to your public key. Support lives in a separate subpackage, so a seller who does not use it never pulls in a JOSE library. The core package imports only the standard library, and Go’s module graph pruning keeps go-jose out of your go.sum and your binary unless you import this:
Verify the signature before decrypting: the signature covers the ciphertext as it arrived on the wire, not the plaintext. The cipher suite is pinned (ECDH-ES+A256KW key management, A256GCM content encryption), so a sender cannot negotiate something weaker. The errors page lists the subpackage’s error codes.
Known limitation: jwe.DecryptRequest returns decryption_failed for an encrypted request whose plaintext is empty; every non-empty body works. This is a limitation of Go’s JOSE libraries, not of the platform: ZeroClick permits empty-plaintext encrypted requests, and the TypeScript and Python SDKs decrypt them. If your endpoint accepts encrypted requests and a zero-length body is meaningful to it, handle that case before decrypting.