API reference

The ZadQ API is plain HTTPS with JSON bodies at https://api.zadq.net. This page is generated at build time from the service's OpenAPI contract, so every operation, parameter and schema below is the contract itself, rendered.

The verification path is free and public: it needs no account and no credential. Every integration keeps working when no verdict is available — the answer is unknown, and what to do with it stays the caller's decision.

Quickstart

Each operation in the reference carries a ready-to-run curl example; the three calls below are the ones most integrations start with. Values in angle brackets are placeholders to replace with your own.

1. Read the substrate status. Public, no credential: whether the identity substrate behind the verdicts is ok, degraded or unknown, and when a standing read last succeeded.

curl -sS "https://api.zadq.net/v0/status" -H "Accept: application/json"

2. Verify a seller endpoint. The free verification path: the current signed verdict for an x402 endpoint, or an explicit no-signal outcome. No account, no credential, never charged.

curl -sS "https://api.zadq.net/v0/verifications?chain=base&payTo=<wallet-address>&resourceUrl=<endpoint-url>" \
  -H "Accept: application/json"

Signatures verify locally against the published keys at https://api.zadq.net/v0/verification-keys.

3. Prove the wallet for a payTo write. The dashboard runs under an account: the responsible person signs in with a passkey at https://zadq.app, and that session carries every read and write of the account. The wallet that controls a payTo address is bound to the account and signs only the writes that touch that address (registering an endpoint on it, acknowledging the terms, rotating to a new wallet). For those, request a challenge for the address, sign it with the wallet and redeem the signature for a short-lived session credential, which rides as a bearer beside the passkey session. On its own it opens nothing: the wallet is never a login.

curl -sS -X POST "https://api.zadq.net/v0/auth/challenge" \
  -H "Content-Type: application/json" \
  -d '{"chain":"base","address":"<wallet-address>"}'

curl -sS -X POST "https://api.zadq.net/v0/auth/session" \
  -H "Content-Type: application/json" \
  -d '{"chain":"base","address":"<wallet-address>","nonce":"<challenge-nonce>","signature":"<wallet-signature>"}'

The exact request and response bodies of every call are in the reference below (AuthChallengeRequest, AuthSessionRequest, Verdict). The reference renders the service's v0 contract. The account's routes are not part of it yet; the calls a runtime makes are listed on the agent operators page.

Overview

FieldValue
ContractSeller-Verification Service API
Version0.1.0
SpecificationOpenAPI 3.0.3

v0 seller-verification API: seller intake, admission state, attestation issuance metadata, and the free verification path.

The free verification path is never charged for, to anyone, ever.

Graceful degradation: consumers must treat an unreachable service or an absent verdict as "no signal", never as a failure of their own flow.

Authentication

Operations name the schemes they accept; an operation marked as public takes no credential at all.

walletSession

HTTP header Authorization: Bearer <credential>.

Session bearer from POST /v0/auth/session (wallet-proven payTo).

Other operations

POST /v0/auth/challenge

Wallet login, step 1 — challenge for a payTo address

Returns a one-time message for the seller's payment wallet to sign (EVM personal_sign or Solana message signing). Proving control of the payTo address is the only credential the dashboard uses — no account, no personal data. Challenges expire after 5 minutes.

Authentication: none — this operation is public.

Request body

application/json — required

Schema: AuthChallengeRequest

PropertyTypeRequiredDescriptionValues
chainChainyes
addressstringyes

Responses

201 — Challenge issued.

Content type application/json.

Schema: AuthChallenge

PropertyTypeRequiredDescriptionValues
noncestringyes
messagestringyesExact text to sign, byte for byte.
expiresAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/auth/challenge" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/auth/session

Wallet login, step 2 — redeem the signed challenge

Verifies the wallet signature over the challenge message and returns a bearer credential bound to {chain, address} (12 h). Send it as Authorization: Bearer <bearer> on the write operations.

Authentication: none — this operation is public.

Request body

application/json — required

Schema: AuthSessionRequest

PropertyTypeRequiredDescriptionValues
chainChainyes
addressstringyes
noncestringyes
signaturestringyesEVM — 0x-hex r||s||v from personal_sign; Solana — base58 (or hex) 64-byte signature.

Responses

201 — Session issued.

Content type application/json.

Schema: AuthSession

PropertyTypeRequiredDescriptionValues
bearerstringyesOpaque session credential for the Authorization header.
expiresAtstring (date-time)yes
chainChainyes
addressstringyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/auth/session" \
  -H "Content-Type: application/json" \
  -d @request-body.json

GET /healthz

Liveness probe

Authentication: none — this operation is public.

Responses

200 — Service is up.

Content type application/json.

Schema: Health

PropertyTypeRequiredDescriptionValues
statusstringyes"ok"
versionstringno

Example

curl -sS "<base-url>/healthz"

GET /v0/status

Substrate status (public)

What an explorer or a seller can check before asking: whether the identity substrate behind the verdicts is ok, degraded or unknown, when a standing read last succeeded, and the cadence promise. Read from the verifier's own status contract when wired (source: verifier); otherwise inferred from the cadence — degraded only after three consecutive cycles in which every attestation was withheld, never from a single unknown (source: cadence). No credentials, no identifiers, nothing personal (ZADQ-70). While the substrate is degraded every integration keeps working: verdicts read no_signal, badges read unknown, nothing blocks.

Authentication: none — this operation is public.

Responses

200 — The substrate's state as this service sees it.

Content type application/json.

Schema: SubstrateStatus

PropertyTypeRequiredDescriptionValues
substratestringyes"ok", "degraded", "unknown"
sourcestringyesWhere the state comes from — the verifier's status read, or this service's cadence accounting."verifier", "cadence"
reasonstringnoWhy the substrate is not ok, in the verifier's standing vocabulary (for example height_stale, root_expired, state_unavailable). Absent when ok.
checkedAtstring (date-time)yes
lastSuccessfulStandingReadstring (date-time)noThe last time a standing read answered with a known status. Absent before the first.
cadenceobjectyes
cadence.recheckEveryHoursintegeryesThe published cadence promise.
cadence.lastCycleAtstring (date-time)no
cadence.checkedintegernoAttestations the last cycle asked the verifier about.
cadence.withheldintegernoOf those, how many came back with an unknown standing.

Example

curl -sS "<base-url>/v0/status"

POST /v0/interest

Register interest (public web form target)

The target of the native HTML form on the public web's register-interest page (ZADQ-103): a vendor or an agent operator says which side of the trust perimeter it is on, optionally the x402 resource URL it sells at or the size band of its fleet, and nothing else. No contact data is accepted or stored here — the person sends their address through the mailbox from the page the browser is sent back to. Submissions are counted by side for the funnel; the optional details are cleared after twelve months, the count stays.

Answers with a redirect to the public web in every case, so a browser without scripts lands on a page: the "received" page (with the side as the fragment) on success, the "not received" page when the input is invalid, when the client is over its rate limit (a few submissions per client per ten minutes, and a global bound), or when storage fails. The page reached always shows the mailbox route, so nothing a person can do depends on this service being up. The field named website is a trap for automated submitters: when it carries a value the submission is dropped and the browser still lands on the "received" page.

Authentication: none — this operation is public.

Request body

application/x-www-form-urlencoded — required

Schema: InterestForm

PropertyTypeRequiredDescriptionValues
sidestringyesWhich side of the trust perimeter the person stands on."vendor", "agent_operator"
resource_urlstring (uri)noThe x402 resource URL a vendor sells at (optional, vendors).
agent_count_bandstringnoThe size band of an operator's fleet (optional, agent operators)."up_to_10", "up_to_100", "more_than_100"
sourcestringnoThe page family the form was reached from (optional; a hidden field rendered at build time, ZADQ-160). An unknown value is dropped, not refused."home", "seller", "agent", "plans", "industries", "trust_about", "docs", "blog", "legal", "metrics"
websitestringnoTrap field for automated submitters; a person leaves it empty.

Responses

303 — The browser is sent back to the public web.

Example

curl -sS -X POST "<base-url>/v0/interest" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d @request-body.json

POST /v0/sellers

Seller intake (onboarding flow 1)

Registers a seller's x402 identifiers and segment declaration and opens a KYC session at the issuer-side KYC boundary. No identity data is accepted here. Requires a wallet session for the intake payTo address (401/403 otherwise): control of the address is proven from the first minute. 409 when the endpoint (chain, payTo, resource URL) is already registered: the problem's instance is the existing record's route (/v0/sellers/{sellerId}), the returning customer's way back. 501 kyb_not_available when the operator type is organisation and the issuer's provider runs no business verification yet: nothing is recorded, the same endpoint can register later (ZADQ-192).

Authentication: walletSession.

Request body

application/json — required

Schema: SellerIntake

PropertyTypeRequiredDescriptionValues
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
segmentSegmentDeclarationyes
kycSandboxHintKycSandboxHintno

Responses

201 — Seller registered; KYC session opened.

Content type application/json.

Schema: Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

GET /v0/sellers/{sellerId}

Seller state (admission, attestation, billing)

Wallet-bound since ZADQ-130: the record (KYC hand-off, billing, credential) is the seller's own, so the read requires the wallet session of this seller's payTo (401 without a session, 403 for another wallet). The free path is the verdict (GET /v0/sellers/{sellerId}/verdict) and GET /v0/verifications.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

200 — Current seller state.

Content type application/json.

Schema: Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/sellers/<sellerId>" \
  -H "Authorization: Bearer <session-credential>"

GET /v0/sellers/{sellerId}/endpoints

The endpoints of this seller's operator

Every endpoint the same accountable operator registered on its approved verification (ZADQ-53). Requires the wallet session of this seller's payTo (401/403): the grouping is never a public read, so an operator's endpoints stay uncorrelatable to third parties.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

200 — The operator's endpoints, oldest first.

Content type application/json.

Schema: OperatorEndpoints

PropertyTypeRequiredDescriptionValues
endpointsarray of EndpointSummaryyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/sellers/<sellerId>/endpoints" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/sellers/{sellerId}/endpoints

Add an endpoint on the operator's approved verification

Registers a further endpoint of the accountable operator behind this admitted seller, reusing its approved session inside the reuse window (ZADQ-53): no new KYC, the new seller reads admitted at once and can be attested. Requires the wallet session of this seller's payTo (401/403). When the new endpoint's payTo differs, proof must carry a signed auth challenge for the new address (POST /v0/auth/challenge for it, sign the message): control of every address is proven. 409 unless admitted with an open window (re-verify first), or when the endpoint already exists.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Request body

application/json — required

Schema: EndpointAddition

PropertyTypeRequiredDescriptionValues
resourceUrlstring (uri)yes
payToPayTono
proofAddressProofno

Responses

201 — The new seller, admitted on the shared verification.

Content type application/json.

Schema: Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/endpoints" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/sellers/{sellerId}/wallet

Rotate the payment wallet behind an attested endpoint

Changes this admitted seller's payTo address inside the approved session's reuse window (ZADQ-53): the attestation bound to the old identifiers is revoked upstream and a new one is issued for the new ones on the same verification — no new KYC. Requires the wallet session of the current payTo (401/403) and proof: a signed auth challenge for the new address. 409 unless admitted with an open window and acknowledged terms, or when the endpoint already exists.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Request body

application/json — required

Schema: WalletRotation

PropertyTypeRequiredDescriptionValues
payToPayToyes
proofAddressProofyes

Responses

200 — The seller on its new address, with the new attestation.

Content type application/json.

Schema: Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/wallet" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/sellers/{sellerId}/billing/checkout

Set up billing on the operator's hosted checkout

Opens the operator's hosted checkout page for this admitted seller, keyed by the seller id and the chosen tier only (ZADQ-54). The person enters legal and billing data there — none of it enters this service, which keeps the billing state, the tier name and an opaque customer reference. Opening the session records nothing (ZADQ-221): the record keeps billing: none and no tier until the provider's signed checkout.session.completed lands on POST /v0/billing/events, which sets active and the tier the session was opened for; a session the person abandons leaves the record as it was. Calling again opens a fresh session (the dashboard's "resume"). Requires the wallet session of the seller's payTo (401/403); 409 unless admitted, or while billing is already active. Manual bank transfer for the first contracts is agreed with us directly, outside the service.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Request body

application/json — required

Schema: BillingCheckout

PropertyTypeRequiredDescriptionValues
tierstringyesThe schedule tier, by name. Amounts are on the checkout page and in the operator agreement."attested_vendor", "regulated_compliance"
cadencestringnoHow the tier's minimum is billed: monthly or annually (ZADQ-230). The cadence rides on the session's metadata like the tier and lands on the record with the provider's completed event. 400 when this deployment has no price for the cadence requested."monthly", "annual"

Responses

201 — The hosted checkout to open, and the seller's billing state.

Content type application/json.

Schema: BillingHandoff

PropertyTypeRequiredDescriptionValues
urlstring (uri)yesThe hosted checkout page — open it as-is.
billingstringyesThe record's billing state as the session opens — none, since opening a session records nothing (ZADQ-221). It moves to active with the provider's signed completed event, never here."none", "active"

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/billing/checkout" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/billing/events

Billing provider event (signed)

Inbound event from the operator's billing provider, signed with the webhook secret (Stripe-Signature: t=<unix>,v1=<hmac-sha256>), applied once per event id. checkout.session.completed moves billing to active; checkout.session.expired and customer.subscription.deleted to none; anything else is acknowledged and ignored. The payload is read for its id, type, seller reference and customer reference only. 401 on a bad or stale signature.

Authentication: none — this operation is public.

Parameters

NameInRequiredTypeDescription
Stripe-Signatureheaderyesstring

Request body

application/json — required

Type: object.

Responses

200 — Acknowledged; whether the event changed a state.

Content type application/json.

Schema: BillingEventReceipt

PropertyTypeRequiredDescriptionValues
appliedbooleanyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/billing/events" \
  -H "Stripe-Signature: <Stripe-Signature>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/sellers/{sellerId}/deposit/kyb

Guarantee deposit — open the holder's hosted verification

Opens the deposit holder's hosted verification of the vendor and returns the URL the person opens; the holder sends the person back to the dashboard afterwards. This service keeps the session id and its state only — no document or identity datum passes through it. By the wallet that owns payTo. 409 until the operator has linked the vendor's account at the holder, once the verification is validated, or while the deposit is being returned; 501 when no deposit holder is configured on this deployment.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

201 — The hosted verification is open.

Content type application/json.

Schema: DepositKybHandoff

PropertyTypeRequiredDescriptionValues
urlstring (uri)yesThe holder's hosted verification page.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/deposit/kyb" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/sellers/{sellerId}/deposit/pay-in

Guarantee deposit — bank-wire instructions for the missing part

Registers a bank-wire pay-in into the vendor's own wallet at the holder for the part of the level still missing, and relays the holder's collection details once: shown to the vendor, never stored. By the wallet that owns payTo. 409 before the verification is validated, while the level is met, or while the deposit is being returned; 501 when no deposit holder is configured.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

201 — The pay-in is registered; wire with these details.

Content type application/json.

Schema: DepositPayInInstructions

PropertyTypeRequiredDescriptionValues
collectionAccountstringyesThe holder's collection account to wire to.
bankNamestringyes
bankCodestringyes
wireReferencestringyesMust travel with the wire so the holder credits the right wallet.
amountMinorinteger (int64)yes
currencystringyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/deposit/pay-in" \
  -H "Authorization: Bearer <session-credential>"

GET /v0/deposit/hooks/{hookToken}

Deposit holder hook (a signal, never a fact)

The holder's notification: an unsigned GET naming an event type and a resource id, guarded by a secret path segment compared in constant time. Answered 200 at once whatever the event; a known event is a prompt to read the resource back from the holder — nothing in the query is trusted or recorded as a fact. Unknown events are acknowledged and ignored; a wrong path segment is 404.

Authentication: none — this operation is public.

Parameters

NameInRequiredTypeDescription
hookTokenpathyesstring
EventTypequerynostring
RessourceIdquerynostring
Datequerynostring

Responses

200 — Acknowledged.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/deposit/hooks/<hookToken>"

POST /v0/sellers/{sellerId}/credential/offer

Hand out the v1 credential offer, once

Creates the v1 credential offer for this admitted seller from its approved verification (ZADQ-83) and hands it out exactly once, over the wallet session of the seller's payTo (401/403). The offer is a one-shot pre-authorized code the seller's own middleware redeems at once with the holder library, in the seller's own infrastructure: this service never stores or logs it, never sees the credential, a key or a proof — the dashboard shows state, never secrets. The code and the credential it yields expire exactly with the verification (no grace); past the window the issuer answers 409 and the seller re-verifies. 409 while a credential is already held or a re-verification is pending; 501 when the substrate offers no v1 credential rail.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

201 — The offer, handed out once, and when it expires.

Content type application/json.

Schema: CredentialOfferHandoff

PropertyTypeRequiredDescriptionValues
offerobjectyesThe credential offer object, as the issuer returned it — opaque, one-shot; redeem it at once.
expiresAtstring (date-time)yesWhen the code and the credential it yields expire — the verification's own expiry at the latest. No grace.
credentialCredentialStateyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/credential/offer" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/sellers/{sellerId}/credential

Report the credential's state from the seller's infrastructure

The seller's middleware reports what it did with the offer: held (optionally with an opaque reference of the seller's choosing, and with the presentationUrl its holder answers this service's challenges at — that URL puts the seller on the v1 verdict path: on the cadence this service forwards its verifier's 10-second challenge there, byte for byte, and the verifier's decision on the holder's envelope governs the positive claim, ZADQ-84) or self_revoked (the holder revoked its own credential through the network's privacy relay; it stops presenting it at once and, within the network's published bound — 245 s from the moment the revocation is recorded — the credential presents nowhere, including any copy taken before; revoked is accepted as the older spelling of the same report; the presentation URL is cleared). Without a presentation URL the seller keeps the v0 standing path. Wallet session of the seller's payTo required (401/403). Nothing secret travels here; the reference is never a key, a code or a proof. presentationUrl must be an absolute https URL (http only to a loopback host, local development).

A self_revoked report is recorded as the state change on the seller's own record and nothing else: no event, no time, no log line, no notification — the reference, the hand-out time and the presentation URL are cleared. The consequence lands at the next verdict cadence, never at this moment: the v0 attestation is retired (statusReason: self_revoked) and the public verdict reads revoked from then on. The way back is a new verification (re-verify), which yields a fresh offer; another offer on the same verification answers 409.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Request body

application/json — required

Schema: CredentialReport

PropertyTypeRequiredDescriptionValues
statestringyesheld, or self_revoked (revoked is the older spelling of the same report)."held", "self_revoked", "revoked"
credentialRefstringnoAn opaque reference of the seller's choosing for the credential it holds. Never a key.
presentationUrlstring (uri)noWhere the seller's holder answers this service's challenges (ZADQ-84): POST of the issued challenge as the verifier returned it ({request, signature_hex}), 200 with the envelope ({proof_hex, issuer_id, status_root, claimed_predicates}); any other status means the holder cannot present this time. Only with held; kept when omitted on a later report.

Responses

200 — The seller with the reported credential state.

Content type application/json.

Schema: Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/credential" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/sellers/{sellerId}/kyc/sessions

Start the identity verification again, or re-verify before the reuse window ends

Opens a new KYC session at the boundary. From kyc_expired: start again (the seller reads pending_kyc with the new handoff). From admitted: a re-verification that renews the approved session (ZADQ-91) — the seller stays admitted, its attestation keeps its standing, and the pending renewal is returned in renewal; once approved, the renewal is bound upstream to the attestation, which keeps its reference, and a rekyc_overdue suspension is lifted at the next root. 409 from any other state or while a renewal is pending. Requires the wallet session of the seller's payTo address (401/403 otherwise).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

201 — New session opened; the seller reads pending_kyc again.

Content type application/json.

Schema: Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/kyc/sessions" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/sellers/{sellerId}/consent/withdraw

Withdraw consent to the service (terminal)

The accountable party withdraws its consent to the service (ZADQ-91). The boundary records it on the approved session; every attestation it backs is revoked upstream with reason consent_withdrawn — an issuer revocation, effective everywhere within the network's published bound, 185 s from the root that drops it —, the verdict reads revoked, and the seller is withdrawn — terminal (a new intake is a new session). Consent given to the identity provider itself is withdrawn at the provider and has no status effect here. Requires the wallet session of the seller's payTo address (401/403); 409 unless admitted; 501 when the substrate cannot record it (raised with the operator; nothing changes).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

200 — Consent withdrawn; the seller is terminal.

Content type application/json.

Schema: Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/consent/withdraw" \
  -H "Authorization: Bearer <session-credential>"

GET /v0/terms

The terms-acknowledgement document in force (free path)

The versioned document a seller signs with its payment wallet before the first issuance (ZADQ-55): the version, its SHA-256, where the full Terms of Service are published, and the text itself — which carries the related-party disclosure at contract time. Public and cacheable, so anyone can check what an attested seller acknowledged.

Authentication: none — this operation is public.

Responses

200 — The current document.

Content type application/json.

Schema: TermsDocument

PropertyTypeRequiredDescriptionValues
versionstringyesVersion name of the acknowledgement document.
sha256stringyesHex SHA-256 of text.
urlstring (uri)yesWhere the full Terms of Service are published.
textstringyesThe acknowledgement text the wallet signs for.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/terms"

GET /v0/sellers/{sellerId}/terms

Terms acknowledgement state of a seller, and the message to sign

Whether the seller's wallet has acknowledged the current terms version, and — if not — the exact message to sign, with the signing time the service will verify it against (messageSignedAt; submit it back unchanged within fifteen minutes). Requires the wallet session of the seller's payTo address (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

200 — Acknowledgement state.

Content type application/json.

Schema: SellerTerms

PropertyTypeRequiredDescriptionValues
currentTermsDocumentyes
acknowledgedbooleanyesWhether the current version is acknowledged by this seller.
acknowledgedVersionstringno
signedAtstring (date-time)noWhen the current version was signed, if it was.
messagestringyesThe exact text to sign for the current version.
messageSignedAtstring (date-time)yesThe signing time embedded in message; submit it back as signedAt.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/sellers/<sellerId>/terms" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/sellers/{sellerId}/terms

Acknowledge the current terms with the seller's wallet

Records the wallet signature over the acknowledgement message for the current version (same challenge mechanism as the login, a different message). Stored against the seller: version, SHA-256, signature, signing time — no mailbox, no account, no identity data. Issuance requires an acknowledgement of the current version (409 terms not acknowledged otherwise). 401 on a signature that does not verify for the seller's payTo; 409 when the version or hash is not the current one; 400 when the signing time is outside the accepted window. A second acknowledgement of the same version changes nothing.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Request body

application/json — required

Schema: TermsAcknowledgement

PropertyTypeRequiredDescriptionValues
versionstringyes
sha256stringyes
signedAtstring (date-time)yes
signaturestringyesWallet signature over the message (hex for EVM, base58 or hex for Solana).

Responses

201 — Acknowledged.

Content type application/json.

Schema: SellerTerms

PropertyTypeRequiredDescriptionValues
currentTermsDocumentyes
acknowledgedbooleanyesWhether the current version is acknowledged by this seller.
acknowledgedVersionstringno
signedAtstring (date-time)noWhen the current version was signed, if it was.
messagestringyesThe exact text to sign for the current version.
messageSignedAtstring (date-time)yesThe signing time embedded in message; submit it back as signedAt.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/terms" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

GET /v0/sellers/{sellerId}/webhooks

The seller's own receivers (secrets never shown again)

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

200 — The seller's receivers.

Content type application/json.

Schema: SellerWebhooks

PropertyTypeRequiredDescriptionValues
webhooksarray of Webhookyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/sellers/<sellerId>/webhooks" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/sellers/{sellerId}/webhooks

Register a receiver for the seller's own events

Owner-bound (ZADQ-51): the wallet session must prove the seller's payTo (401/403). The per-subscription secret is returned once; https is required except for loopback receivers (local development). Events and signing: see the webhooks note at the top of this document. 409 receiver already registered when the URL is already registered for this seller (remove it first; a new secret is shown once).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Request body

application/json — required

Schema: WebhookRegistration

PropertyTypeRequiredDescriptionValues
urlstring (uri)yes

Responses

201 — Receiver registered; secret shown once.

Content type application/json.

Schema: Webhook

PropertyTypeRequiredDescriptionValues
idstringyes
urlstring (uri)yes
secretstringnoHex signing secret for X-Signature. Returned once at registration.
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/webhooks" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

DELETE /v0/sellers/{sellerId}/webhooks/{webhookId}

Remove one of the seller's receivers

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring
webhookIdpathyesstring

Responses

204 — Receiver removed.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X DELETE "<base-url>/v0/sellers/<sellerId>/webhooks/<webhookId>" \
  -H "Authorization: Bearer <session-credential>"

GET /v0/sellers/{sellerId}/events

What changed — the seller's recent events, newest first

The append-only event stream of the seller (intake, KYC outcomes and expiry, issuance, status changes, consent withdrawal), for the dashboard's "what changed" list (ZADQ-51). Wallet-bound; metadata only, never identity data.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring
limitquerynointeger

Responses

200 — Recent events.

Content type application/json.

Schema: SellerEvents

PropertyTypeRequiredDescriptionValues
eventsarray of SellerEventyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/sellers/<sellerId>/events" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/sellers/{sellerId}/kyc/result

KYC outcome callback (issuer-side boundary → this service)

Callback endpoint for the KYC boundary. Carries outcome metadata only — never identity data. HMAC-authenticated: X-Signature: sha256=<hex> over the raw body with the shared callback secret and X-Signature-Key (first 8 bytes of the secret's SHA-256, hex); 401 otherwise. Local fake mode without a secret leaves it open for the smoke.

Authentication: none — this operation is public.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Request body

application/json — required

Schema: KycResult

PropertyTypeRequiredDescriptionValues
sessionIdstringyes
outcomestringyes"approved", "rejected"
assuranceLevelstringnoAssurance grade met by the proofing process (e.g. "G").

Responses

200 — Admission state updated.

Content type application/json.

Schema: Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/kyc/result" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/sellers/{sellerId}/attestations

Issue the seller-side attestation (flow 2)

Orchestrates issuance for an admitted seller via the issuer path and records attestation metadata. Fails for non-admitted sellers. Requires a wallet session for the seller's payTo address.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

201 — Attestation issued.

Content type application/json.

Schema: Attestation

PropertyTypeRequiredDescriptionValues
idstringyes
sellerIdstringyes
assuranceLevelstringyes
statusstringyes"active", "suspended", "revoked"
statusReasonstringnoWhy a non-active status was set — never silent. rekyc_overdue: the reuse window ended; restored under the same reference by a bound re-verification. consent_withdrawn: terminal. self_revoked: the holder revoked its own credential and the attestation was retired at the next verdict cadence — terminal for this attestation; a new verification yields a new one. Absent for operator changes and while active."rekyc_overdue", "consent_withdrawn", "self_revoked"
freshnessBandstringnoFreshness band of the backing session, as the issuer reports it."F4", "F3", "F2", "F1"
issuedAtstring (date-time)yes
updatedAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/attestations" \
  -H "Authorization: Bearer <session-credential>"

GET /v0/sellers/{sellerId}/attestations/{attestationId}/receipt

The issuer's signed receipt of the attestation (for X-PAYMENT-IDENTITY)

The issuer-signed receipt of the issuance, byte-shaped as the attestation-ref/v0 payload of the payment-identity companion header (ZADQ-92): the seller's middleware puts it on X-PAYMENT-IDENTITY beside X-PAYMENT, and a receiver may verify the issuer's Ed25519 signature locally against the issuer's registered status key. It is proof of issuance, never of standing: standing is the verdict's (GET /v0/verifications). Requires the wallet session of the seller's payTo address (401/403). 404 when no receipt is stored (local fakes, attestations recorded before receipts were kept).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring
attestationIdpathyesstring

Responses

200 — The receipt.

Content type application/json.

Schema: AttestationReceipt

PropertyTypeRequiredDescriptionValues
attestation_refstringyes32-byte opaque reference, hex.
issuer_idstringyes
chainstringyes
pay_tostringyes
resource_urlstringyes
assurance_gradeintegeryes
issued_at_unixintegeryes
signaturestringyesEd25519 by the issuer's registered status signing key, hex (64 bytes).

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/sellers/<sellerId>/attestations/<attestationId>/receipt" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/attestations/{attestationId}/status

Status-mirror update (network status cycle → this service)

Applies a status change originating in the standard network status machinery. The service never revokes by its own say-so (seed §3.1 flow 4); this endpoint mirrors upstream state. HMAC-authenticated like the KYC callback (X-Signature, X-Signature-Key).

Authentication: none — this operation is public.

Parameters

NameInRequiredTypeDescription
attestationIdpathyesstring

Request body

application/json — required

Schema: AttestationStatusUpdate

PropertyTypeRequiredDescriptionValues
statusstringyes"active", "suspended", "revoked"

Responses

200 — Mirrored status applied.

Content type application/json.

Schema: Attestation

PropertyTypeRequiredDescriptionValues
idstringyes
sellerIdstringyes
assuranceLevelstringyes
statusstringyes"active", "suspended", "revoked"
statusReasonstringnoWhy a non-active status was set — never silent. rekyc_overdue: the reuse window ended; restored under the same reference by a bound re-verification. consent_withdrawn: terminal. self_revoked: the holder revoked its own credential and the attestation was retired at the next verdict cadence — terminal for this attestation; a new verification yields a new one. Absent for operator changes and while active."rekyc_overdue", "consent_withdrawn", "self_revoked"
freshnessBandstringnoFreshness band of the backing session, as the issuer reports it."F4", "F3", "F2", "F1"
issuedAtstring (date-time)yes
updatedAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/attestations/<attestationId>/status" \
  -H "Content-Type: application/json" \
  -d @request-body.json

GET /v0/verification-keys

Verdict-verification public keys (free path)

The Ed25519 public keys verdict signatures are checked against. Free, unauthenticated, cacheable. keyId matches Verdict.keyId (first 8 bytes of the key's SHA-256, hex). Consumers without the key keep working: a signature they cannot check is "unverifiable", never an error.

Authentication: none — this operation is public.

Responses

200 — Current verification keys.

Content type application/json.

Schema: VerificationKeys

PropertyTypeRequiredDescriptionValues
keysarray of VerificationKeyyes

Example

curl -sS "<base-url>/v0/verification-keys"

GET /v0/metrics

Published metrics (free path)

The published metric series (ZADQ-106): sellers attested, 90-day retention, verifications served, independent registered verifiers, anchor-service revenue — computed from this service's own records, counts only, monthly, complete months only. Free, unauthenticated, cacheable. Every series carries relatedParty: true and its period: the operator runs a related-party pilot and nothing measured on it counts as independent adoption. A series the records hold no source for says so (available: false) rather than carrying a figure. Registry-based or aggregate throughout — no per-verification record exists — and nothing personal, no identifier of any kind.

Authentication: none — this operation is public.

Responses

200 — The current report.

Content type application/json.

Schema: MetricsReport

PropertyTypeRequiredDescriptionValues
schemastringyesThe wire shape's name (published-metrics/v1).
computedAtstring (date-time)yes
asOfstring (date)yesThe cut-off — the last day of the last complete month (UTC). Partial months are never published.
periodMetricsPeriodno
cadenceobjectyes
cadence.publicationstringyesmonthly.
cadence.snapshotstringyesquarterly, aligned to the two-consecutive-quarters clock.
relatedPartybooleanyesAlways true — the operator's position is a property of the dataset.
operatorMetricsOperatoryes
seriesarray of MetricsSeriesyes
contextNotestringyes

Example

curl -sS "<base-url>/v0/metrics"

GET /v0/verifications

Free verification path (explorers, buyers)

Returns the current signed verdict for an x402 endpoint, or a no-signal outcome. Free of charge, no authentication, ever.

Authentication: none — this operation is public.

Parameters

NameInRequiredTypeDescription
chainqueryyesChain
payToqueryyesstring
resourceUrlqueryyesstring

Responses

200 — Verdict (or explicit no-signal outcome).

Content type application/json.

Schema: Verdict

PropertyTypeRequiredDescriptionValues
outcomestringyes"human_backed", "revoked", "stale", "no_signal"
subjectobjectyes
subject.chainChainyes
subject.payTostringyes
subject.resourceUrlstringyes
assuranceLevelstringno
verifiedAtstring (date-time)no
recheckEveryHoursintegeryes
signaturestringnoEd25519 over the canonical verdict payload, base64.
keyIdstringno
reasonstringnoWhy the outcome is not human_backed: the standing read's reason code (closed vocabulary), or suspended when the witnessed status is suspended. Absent on human_backed; absent on revoked too. The policy reason of a suspension (rekyc_overdue) is the seller's own record, never part of the public verdict. On the v1 path (ZADQ-84) a verifier-side condition of the presentation decision is carried with the same code (issuer_not_active, status_root_stale, height_stale) or as state_unavailable; a presentation the verifier refused on the holder's side withholds the positive claim with no reason — the decision's exact code is the seller's own record (credential.lastPresentation). The freshness half of "human-backed" (grade ≥ 2 and freshness ≥ F1) is the issuer's state on both rails (ZADQ-182): the issuer computes the band and suspends rekyc_overdue when the reuse window ends; ZadQ mirrors that state and never asks a presentation about recency (a presentation proves the grade threshold, expiry and non-revocation only). The verdict carries neither the band nor a date; the band is the seller's own record (freshnessBand)."state_unavailable", "issuer_unknown", "issuer_not_active", "status_root_stale", "height_stale", "witness_unavailable", "witness_malformed", "witness_invalid", "witness_root_mismatch", "bond_insufficient", "suspended"
extensionsVerdictExtensionsno

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/verifications?chain=<chain>&payTo=<payTo>&resourceUrl=<resourceUrl>"

POST /v0/webhooks

Register an explorer receiver for verdict.updated

Free and unauthenticated — the payload is the public verdict. The per-subscription secret is returned once; https is required except for loopback receivers (local development).

Authentication: none — this operation is public.

Request body

application/json — required

Schema: WebhookRegistration

PropertyTypeRequiredDescriptionValues
urlstring (uri)yes

Responses

201 — Subscription created; secret shown once.

Content type application/json.

Schema: Webhook

PropertyTypeRequiredDescriptionValues
idstringyes
urlstring (uri)yes
secretstringnoHex signing secret for X-Signature. Returned once at registration.
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/webhooks" \
  -H "Content-Type: application/json" \
  -d @request-body.json

DELETE /v0/webhooks/{webhookId}

Remove a receiver

Authentication: none — this operation is public.

Parameters

NameInRequiredTypeDescription
webhookIdpathyesstring

Responses

204 — Subscription removed.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X DELETE "<base-url>/v0/webhooks/<webhookId>"

GET /v0/sellers/{sellerId}/verdict

Latest verdict for a seller (dashboard view)

Authentication: none — this operation is public.

Parameters

NameInRequiredTypeDescription
sellerIdpathyesstring

Responses

200 — Latest verdict.

Content type application/json.

Schema: Verdict

PropertyTypeRequiredDescriptionValues
outcomestringyes"human_backed", "revoked", "stale", "no_signal"
subjectobjectyes
subject.chainChainyes
subject.payTostringyes
subject.resourceUrlstringyes
assuranceLevelstringno
verifiedAtstring (date-time)no
recheckEveryHoursintegeryes
signaturestringnoEd25519 over the canonical verdict payload, base64.
keyIdstringno
reasonstringnoWhy the outcome is not human_backed: the standing read's reason code (closed vocabulary), or suspended when the witnessed status is suspended. Absent on human_backed; absent on revoked too. The policy reason of a suspension (rekyc_overdue) is the seller's own record, never part of the public verdict. On the v1 path (ZADQ-84) a verifier-side condition of the presentation decision is carried with the same code (issuer_not_active, status_root_stale, height_stale) or as state_unavailable; a presentation the verifier refused on the holder's side withholds the positive claim with no reason — the decision's exact code is the seller's own record (credential.lastPresentation). The freshness half of "human-backed" (grade ≥ 2 and freshness ≥ F1) is the issuer's state on both rails (ZADQ-182): the issuer computes the band and suspends rekyc_overdue when the reuse window ends; ZadQ mirrors that state and never asks a presentation about recency (a presentation proves the grade threshold, expiry and non-revocation only). The verdict carries neither the band nor a date; the band is the seller's own record (freshnessBand)."state_unavailable", "issuer_unknown", "issuer_not_active", "status_root_stale", "height_stale", "witness_unavailable", "witness_malformed", "witness_invalid", "witness_root_mismatch", "bond_insufficient", "suspended"
extensionsVerdictExtensionsno

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/sellers/<sellerId>/verdict"

POST /v0/agent-operators

Agent-operator enrolment — the human or organisation behind an agent

Enrols the accountable party behind an agent: the wallet the operator's agent pays from, and the operator type (person → identity verification, organisation → business verification). Opens a KYC session at the issuer-side KYC boundary and returns the operator in pending_kyc with the identity provider's hosted page in kyc.handoffUrl. No identity data is accepted here. Requires the wallet session of that wallet (401/403 otherwise): control of the wallet is proven from the first minute. 409 when the wallet is already enrolled: the problem's instance is the existing record's route (/v0/agent-operators/{agentOperatorRef}). 501 kyb_not_available for an organisation where the issuer's provider runs no business verification yet: nothing is recorded (ZADQ-192). An agent operator is not an x402 endpoint: it carries no resource URL and no attestation, and a wallet that is also a vendor's payTo is not linked to that vendor by this service.

Authentication: walletSession.

Request body

application/json — required

Schema: AgentOperatorEnrolment

PropertyTypeRequiredDescriptionValues
walletall of PayToyesThe wallet the operator's agent pays from — the one the wallet session proves.
operatorTypestringyesperson is verified by identity verification, organisation by business verification; the boundary learns this and nothing else."person", "organisation"
kycSandboxHintKycSandboxHintno

Responses

201 — Operator enrolled; KYC session opened.

Content type application/json.

Schema: AgentOperator

PropertyTypeRequiredDescriptionValues
idstringyesThe operator's opaque reference (aop_…).
walletall of PayToyesThe wallet the operator's agent pays from.
operatorTypestringyes"person", "organisation"
statestringyespending_kyc → approved → credential_held (the principal's credential is held in the operator's infrastructure) → active (its first agent is minted). kyc_expired: the proofing deadline passed, or the approved verification's reuse window closed — the principal's credential expired with it; verify again (POST …/kyc/sessions). rejected and withdrawn are terminal."pending_kyc", "kyc_expired", "approved", "rejected", "credential_held", "active", "withdrawn"
billingstringyesThe one-off entry fee at the operator's billing provider: none until the provider's signed checkout.session.completed lands, active once it is recorded. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
agentsAgentCountsno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

GET /v0/agent-operators/{agentOperatorRef}

Agent-operator state (verification, entry fee, the principal's credential)

The operator's state as the dashboard shows it — state, never keys. The read brings it up to date first: a pending session's outcome is read from the KYC boundary, a session past its deadline reads kyc_expired, and an approved verification whose reuse window closed reads kyc_expired too (the principal's credential expired with it, exactly — no grace). Wallet session of the operator's wallet required (401/403): an operator's record is never a public read.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).

Responses

200 — Current agent-operator state.

Content type application/json.

Schema: AgentOperator

PropertyTypeRequiredDescriptionValues
idstringyesThe operator's opaque reference (aop_…).
walletall of PayToyesThe wallet the operator's agent pays from.
operatorTypestringyes"person", "organisation"
statestringyespending_kyc → approved → credential_held (the principal's credential is held in the operator's infrastructure) → active (its first agent is minted). kyc_expired: the proofing deadline passed, or the approved verification's reuse window closed — the principal's credential expired with it; verify again (POST …/kyc/sessions). rejected and withdrawn are terminal."pending_kyc", "kyc_expired", "approved", "rejected", "credential_held", "active", "withdrawn"
billingstringyesThe one-off entry fee at the operator's billing provider: none until the provider's signed checkout.session.completed lands, active once it is recorded. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
agentsAgentCountsno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/agent-operators/<agentOperatorRef>" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/agent-operators/{agentOperatorRef}/kyc/sessions

Start the verification again

Opens a new KYC session at the boundary: from kyc_expired (the proofing deadline passed, or the approved verification's reuse window closed), or after the holder revoked the principal's credential — the way back is a new verification, which yields a fresh credential that carries nothing of the old one. The operator reads pending_kyc with the new handoff. 409 from any other state. Wallet session of the operator's wallet required (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).

Responses

201 — New session opened; the operator reads pending_kyc again.

Content type application/json.

Schema: AgentOperator

PropertyTypeRequiredDescriptionValues
idstringyesThe operator's opaque reference (aop_…).
walletall of PayToyesThe wallet the operator's agent pays from.
operatorTypestringyes"person", "organisation"
statestringyespending_kyc → approved → credential_held (the principal's credential is held in the operator's infrastructure) → active (its first agent is minted). kyc_expired: the proofing deadline passed, or the approved verification's reuse window closed — the principal's credential expired with it; verify again (POST …/kyc/sessions). rejected and withdrawn are terminal."pending_kyc", "kyc_expired", "approved", "rejected", "credential_held", "active", "withdrawn"
billingstringyesThe one-off entry fee at the operator's billing provider: none until the provider's signed checkout.session.completed lands, active once it is recorded. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
agentsAgentCountsno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/kyc/sessions" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/agent-operators/{agentOperatorRef}/kyc/result

KYC outcome callback for an agent operator (issuer-side boundary → this service)

Callback endpoint for the KYC boundary, the same contract as the sellers' one. Carries outcome metadata only — never identity data. HMAC-authenticated: X-Signature: sha256=<hex> over the raw body with the shared callback secret and X-Signature-Key (first 8 bytes of the secret's SHA-256, hex); 401 otherwise. Local fake mode without a secret leaves it open for the smoke.

Authentication: none — this operation is public.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).

Request body

application/json — required

Schema: KycResult

PropertyTypeRequiredDescriptionValues
sessionIdstringyes
outcomestringyes"approved", "rejected"
assuranceLevelstringnoAssurance grade met by the proofing process (e.g. "G").

Responses

200 — Verification state updated.

Content type application/json.

Schema: AgentOperator

PropertyTypeRequiredDescriptionValues
idstringyesThe operator's opaque reference (aop_…).
walletall of PayToyesThe wallet the operator's agent pays from.
operatorTypestringyes"person", "organisation"
statestringyespending_kyc → approved → credential_held (the principal's credential is held in the operator's infrastructure) → active (its first agent is minted). kyc_expired: the proofing deadline passed, or the approved verification's reuse window closed — the principal's credential expired with it; verify again (POST …/kyc/sessions). rejected and withdrawn are terminal."pending_kyc", "kyc_expired", "approved", "rejected", "credential_held", "active", "withdrawn"
billingstringyesThe one-off entry fee at the operator's billing provider: none until the provider's signed checkout.session.completed lands, active once it is recorded. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
agentsAgentCountsno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/kyc/result" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/agent-operators/{agentOperatorRef}/billing/checkout

Pay the entry fee on the operator's hosted checkout

Opens the hosted checkout of the one-off entry fee, keyed by the operator's reference and the tier of its operator type only (person or organisation; the amount is on the checkout page). The person enters legal and billing data there — none of it enters this service, which keeps the billing state and an opaque customer reference. Opening the session records nothing (ZADQ-221): billing stays none until the provider's signed checkout.session.completed lands on POST /v0/billing/events, active afterwards; a session the person abandons leaves the record as it was, and calling again opens a fresh session. The principal's credential is offered once the fee is recorded. Wallet session of the operator's wallet required (401/403); 409 for a rejected operator or once the fee is recorded.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).

Responses

201 — The hosted checkout to open, and the operator's billing state.

Content type application/json.

Schema: BillingHandoff

PropertyTypeRequiredDescriptionValues
urlstring (uri)yesThe hosted checkout page — open it as-is.
billingstringyesThe record's billing state as the session opens — none, since opening a session records nothing (ZADQ-221). It moves to active with the provider's signed completed event, never here."none", "active"

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/billing/checkout" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/agent-operators/{agentOperatorRef}/credential/offer

Hand out the offer of the principal's identity credential, once

Creates the offer of the operator's own identity credential — the principal its agents are minted from — from its approved verification, on the same issuer route as sellers' credentials, and hands it out exactly once over the wallet session of the operator's wallet (401/403). The offer is a one-shot pre-authorized code the operator's own infrastructure redeems at once with the holder library; the credential and its keys stay there — this service never stores or logs the offer and never sees the credential, a key or a proof. The operator's holder answers the issuer's mint challenge with it when an agent is minted. The code and the credential expire exactly with the verification (no grace). 409 until the entry fee is recorded, unless approved, while a credential is held, after the holder revoked it on this verification (verify again), or past the reuse window; 501 when the substrate offers no credential rail.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).

Responses

201 — The offer, handed out once, and when it expires.

Content type application/json.

Schema: CredentialOfferHandoff

PropertyTypeRequiredDescriptionValues
offerobjectyesThe credential offer object, as the issuer returned it — opaque, one-shot; redeem it at once.
expiresAtstring (date-time)yesWhen the code and the credential it yields expire — the verification's own expiry at the latest. No grace.
credentialCredentialStateyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/credential/offer" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/agent-operators/{agentOperatorRef}/credential

Report the principal's credential state from the operator's infrastructure

The operator's infrastructure reports what it did with the offer: held (optionally with an opaque reference of its choosing; the operator reads credential_held and can have agents minted) or self_revoked (the holder revoked the principal's credential through the network's privacy relay; it stops presenting it at once and, within the network's published bound — 245 s from the moment the revocation is recorded — it presents nowhere; the agents minted on it are revoked with it, everywhere within 395 s of the root that carries the trigger; revoked is accepted as the older spelling of the same report). Nothing secret travels here; the reference is never a key, a code or a proof. Wallet session of the operator's wallet required (401/403).

A self_revoked report is recorded as the state change on the operator's own record and nothing else: no event, no time, no log line — the reference and the hand-out time are cleared. The way back is a new verification (POST …/kyc/sessions), which yields a fresh offer; another offer on the same verification answers 409.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).

Request body

application/json — required

Schema: AgentOperatorCredentialReport

PropertyTypeRequiredDescriptionValues
statestringyesheld, or self_revoked (revoked is the older spelling of the same report)."held", "self_revoked", "revoked"
credentialRefstringnoAn opaque reference of the operator's choosing for the credential it holds. Never a key.

Responses

200 — The operator with the reported credential state.

Content type application/json.

Schema: AgentOperator

PropertyTypeRequiredDescriptionValues
idstringyesThe operator's opaque reference (aop_…).
walletall of PayToyesThe wallet the operator's agent pays from.
operatorTypestringyes"person", "organisation"
statestringyespending_kyc → approved → credential_held (the principal's credential is held in the operator's infrastructure) → active (its first agent is minted). kyc_expired: the proofing deadline passed, or the approved verification's reuse window closed — the principal's credential expired with it; verify again (POST …/kyc/sessions). rejected and withdrawn are terminal."pending_kyc", "kyc_expired", "approved", "rejected", "credential_held", "active", "withdrawn"
billingstringyesThe one-off entry fee at the operator's billing provider: none until the provider's signed checkout.session.completed lands, active once it is recorded. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
agentsAgentCountsno
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/credential" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

GET /v0/agent-scopes

The delegation vocabulary an agent is minted with

The scope vocabulary v2 (mintid.scope-vocabulary.v2) an agent's delegation draws from — the content carried on chain, read under its pinned content hash (contentSha256: SHA-256 over the RFC 8785 canonical JSON of the content), never hard-coded. Only values whose status is active are served: scopes lists the enumerated ones (actions, mintid: categories); axes gives, per axis (action, counterparty, category, geo), the enumerated values and the forms or namespaces with their canonical patterns — a value is valid only in its canonical form. A gated value (agent.delegate) is never served, and an offer naming it is refused (400, code scope_value_gated). units are the value units of the per-transaction limit with their minor-unit exponent. The dashboard builds the "Mint an agent" form from it. 503 when the content does not match its pin (fail closed: no offer is validated against it); 501 when the substrate supplies no vocabulary. Wallet session required (401).

Authentication: walletSession.

Responses

200 — The vocabulary and the hash it was read under.

Content type application/json.

Schema: ScopeVocabulary

PropertyTypeRequiredDescriptionValues
contentSha256stringyesSHA-256 (hex) of the RFC 8785 canonical JSON of the vocabulary content it was read under.
versionstringno
scopesarray of stringyesThe enumerated active values as an offer writes them (actions, mintid: categories).
axesarray of ScopeAxisno
unitsarray of ScopeValueUnitno
custodyClassesarray of stringyesKey-custody class codes, lowest rank first.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/agent-scopes" \
  -H "Authorization: Bearer <session-credential>"

GET /v0/agent-bundles

The bundle catalogue ZadQ mints bounded agents from

ZadQ's bounded-agent bundle catalogue (ZADQ-173): the named, bounded scopes an operator mints agent credentials from — for each bundle the actions every agent of it is granted, the categories and regions the operator may choose from at mint (and the defaults), the counterparty forms, the per-transaction caps by unit in minor units, the lease bounds and the minimum backing grade; always private-only and software-custodied. The catalogue is ZadQ's own content in the format the network's issuer validates; digest is the SHA-256 of its canonical form and is what the issuer serves beside the catalogue once configured with it. price is ZadQ's price line for the bundle (the issuer echoes it in offers; it never reaches a policy). The dashboard builds the "Mint an agent" form from this read. servedByIssuer says whether the network's issuer serves this catalogue (servedCatalogue names the one it serves, when read): when it does, an agent sold under a bundle is minted in the issuer's bundle form; when it does not, ZadQ mints the same agent on raw-scope terms derived from the bundle's definition and records its price line itself — either way the operator chooses a ZadQ bundle and never sees the issuer's catalogue codes. Wallet session required (401).

Authentication: walletSession.

Responses

200 — The catalogue, its digest and ZadQ's price per bundle.

Content type application/json.

Schema: AgentBundleCatalogue

PropertyTypeRequiredDescriptionValues
versionstringyes<namespace>.agent-bundles[.<name>].v<N>; ZadQ's namespace is zadq.
vocabularystringyes
digeststringyesLowercase hex SHA-256 of the catalogue's canonical form.
bundlesarray of AgentBundleyes
servedByIssuerbooleanyesWhether the network's issuer serves this catalogue (same id and digest). False also when its catalogue could not be read.
servedCataloguestringnoThe id of the catalogue the issuer serves, when read.

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/agent-bundles" \
  -H "Authorization: Bearer <session-credential>"

GET /v0/agent-operators/{agentOperatorRef}/agents

The operator's agents (pseudonymous handles, state, lease)

The agents minted for the operator, newest first: ZadQ's pseudonymous handle (agt_…), the delegation summary, the lease and the state — never a chain identifier, a key or the offer. Wallet session of the operator's wallet required (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).

Responses

200 — The operator's agents.

Content type application/json.

Schema: Agents

PropertyTypeRequiredDescriptionValues
itemsarray of Agentyes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/agent-operators/<agentOperatorRef>/agents" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/agent-operators/{agentOperatorRef}/agents

Mint an agent — hand out the agent offer, once

The operator declares the agent in one of two exclusive forms (both is 400, code bundle_and_scope_exclusive):

  • raw terms: scope values from GET /v0/agent-scopes (at least

one action), a per-transaction limit and its value unit, a lease of 1..90 days, and optionally a key-custody class;

  • a ZadQ bundle from GET /v0/agent-bundles and the operator's

choices inside it (counterparties, regions, categories, limit, custody class, lease); what is left out takes the bundle's defaults, and a choice outside the bundle is refused with the issuer's bundle code.

The key-custody class the agent is minted with is the issuer's: it appraises it from attestation evidence for the agent's key, and an offer without evidence — every offer ZadQ makes — is minted software. A declared custodyClass is only a hint that can lower the issuer's class, never raise it. The agent's record carries the issuer's class as keyCustody once the issuer's answer names it. A bundle whose custody minimum is above software is refused by the issuer with bundle_custody_not_attested (ZadQ's bundles have software as their minimum).

ZadQ records that it collected its fee (the fee declaration) and creates the agent offer on the issuer's operator route; the offer and its mint challenge are handed out exactly once over the wallet session of the operator's wallet (401/403) and never stored or logged. The operator's agent client redeems the offer at once: the principal answers the mint challenge with a mint presentation of its identity credential within 10 seconds, at the issuer, in the operator's own infrastructure; the agent credential and its keys stay there, and the link between the principal and the agent stays sealed with the issuer — this service never sees it. expiresAt is when the offer stops being redeemable; the agent itself ends at the end of its lease or with the principal's verification, whichever is first.

The issuer's limits: a lease of at most 90 days; at most 10 active agents per person and 5 mints per hour, renewals included. The two caps are answered at the mint step, not here: the operator's agent client reports the answer (POST …/credential, mint_refused) and the agent reads refused with the issuer's reason. ZadQ shows the answers; it does not re-count.

Refused here, before the issuer is asked: 400 for terms outside the vocabulary, the lease bounds or the bundle (the problem's code is the issuer's closed code); 409 until the entry fee is recorded, unless the principal's credential is held, or once the verification's window is closed. The issuer's own refusals are terminal and never retried: 400 with its terms code, 409 with its conflict code (for instance grade_exceeds_principal, session_reuse_expired); the problem's title names the reason. 501 when the substrate offers no agent route.

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).

Request body

application/json — required

Schema: AgentOfferRequest

PropertyTypeRequiredDescriptionValues
scopearray of stringnoRaw terms — scope values of the vocabulary in canonical form, each once, at least one action.
limitAgentLimitno
custodyClassstringnoOptional — a lowering hint, never raising: the issuer appraises the agent key's custody class from attestation evidence (ZadQ sends none, so its agents are minted software); absent, the issuer's appraisal stands. Forwarded to the issuer only when given. When given, a class of the vocabulary; with a bundle, not below the bundle's minimum (absent with a bundle: the bundle's minimum is sent, as before).
leaseDaysintegernoThe lease in days. With a bundle — optional (the bundle's default), within the bundle's maximum.
bundleAgentBundleChoiceno

Responses

201 — The agent offer, handed out once, and the agent's record.

Content type application/json.

Schema: AgentOfferHandoff

PropertyTypeRequiredDescriptionValues
offerobjectyesThe credential offer as the issuer returned it (the operator's price-line echo removed) — opaque, one-shot; the operator's agent client redeems it at once.
mintChallengeobjectnoThe issuer's mint challenge — the principal answers it with a mint presentation of its identity credential within 10 seconds, when redeeming the offer.
scopearray of AgentScopeEntrynoThe scope the issuer signs into the agent, with the issuer's id of each value.
expiresAtstring (date-time)yesWhen the offer stops being redeemable.
agentAgentyes

400 — An agent request refused — by ZadQ before the issuer is asked, or by the issuer. RFC 9457 problem details whose code is the issuer's closed, value-free code (ZadQ's local refusals use the same names). Terminal: shown as such, never retried.

Content type application/problem+json.

Schema: AgentProblem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

409 — An agent request refused — by ZadQ before the issuer is asked, or by the issuer. RFC 9457 problem details whose code is the issuer's closed, value-free code (ZadQ's local refusals use the same names). Terminal: shown as such, never retried.

Content type application/problem+json.

Schema: AgentProblem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/agents" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

GET /v0/agent-operators/{agentOperatorRef}/agents/{agentId}

One agent (state, reason, delegation, lease)

One agent of the operator. Another operator's agent reads 404. Wallet session of the operator's wallet required (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).
agentIdpathyesstringThe agent's pseudonymous handle (agt_…).

Responses

200 — The agent.

Content type application/json.

Schema: Agent

PropertyTypeRequiredDescriptionValues
idstringyesThe agent's pseudonymous handle (agt_…), assigned by ZadQ.
statestringyes"offered", "held", "revoked", "expired", "refused"
reasonstringno"operator_revoked", "issuer_revoked", "principal_revoked", "self_revoked", "lease_expired", "active_agent_cap", "mint_rate_limited", "lease_too_long", "fee_not_declared", "bundle_required", "mint_policy_unconfigured", "session_reuse_expired", "principal_not_active", "principal_mismatch", "grade_exceeds_principal", "agent_revoked", "session_not_approved", "invalid_grant"
delegationAgentDelegationyes
keyCustodyAgentKeyCustodyno
saleAgentSaleno
leaseUntilstring (date-time)yesThe lease's end as the issuer set it.
generationintegeryes1 at the mint, one more per renewal (replacement).
credentialRefstringnoThe reference reported with the held credential — the issuer's 64-hex credential handle when the operator's client reports it. Never a key.
feeDeclaredbooleanyesWhether ZadQ's fee declaration for the current generation is recorded.
offeredAtstring (date-time)yes
createdAtstring (date-time)yes

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/agent-operators/<agentOperatorRef>/agents/<agentId>" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/agent-operators/{agentOperatorRef}/agents/{agentId}/credential

Report the agent credential's state from the operator's infrastructure

The operator's agent client reports what it did with the offer: held (optionally with a reference; the operator's first agent held makes it active), self_revoked (the agent's holder revoked it through the network's privacy relay) or mint_refused (the issuer's mint step refused the principal's answer for good). With held, credentialRef should be the 64-hex credential_id the holder received at issuance: ZadQ renews and revokes the agent at the issuer by it (until it is reported, renewal is refused and a revocation lets the unredeemed offer lapse). With mint_refused, refusal carries the issuer's answer as received — 403 mint_not_authorized with its errorDescription (active_agent_cap, mint_rate_limited, lease_too_long, fee_not_declared, bundle_required, mint_policy_unconfigured), a terminal 409 (session_reuse_expired, principal_not_active, principal_mismatch, grade_exceeds_principal, agent_revoked, session_not_approved) or 400 invalid_grant; a first mint then reads refused with that reason, a refused renewal leaves the agent held on its current credential. An answer that came with a fresh mint challenge is not a refusal (400, code mint_retryable): the principal answers it again. A self_revoked report is recorded as the state and the reason and nothing else — no event, no time, no log line. Nothing secret travels here. Wallet session of the operator's wallet required (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).
agentIdpathyesstringThe agent's pseudonymous handle (agt_…).

Request body

application/json — required

Schema: AgentCredentialReport

PropertyTypeRequiredDescriptionValues
statestringyes"held", "self_revoked", "mint_refused"
credentialRefstringnoWith held — the issuer's 64-hex credential handle the holder received at issuance (or another reference of the operator's choosing, which leaves renewal unavailable). Never a key.
refusalAgentMintRefusalno

Responses

200 — The agent with the reported state.

Content type application/json.

Schema: Agent

PropertyTypeRequiredDescriptionValues
idstringyesThe agent's pseudonymous handle (agt_…), assigned by ZadQ.
statestringyes"offered", "held", "revoked", "expired", "refused"
reasonstringno"operator_revoked", "issuer_revoked", "principal_revoked", "self_revoked", "lease_expired", "active_agent_cap", "mint_rate_limited", "lease_too_long", "fee_not_declared", "bundle_required", "mint_policy_unconfigured", "session_reuse_expired", "principal_not_active", "principal_mismatch", "grade_exceeds_principal", "agent_revoked", "session_not_approved", "invalid_grant"
delegationAgentDelegationyes
keyCustodyAgentKeyCustodyno
saleAgentSaleno
leaseUntilstring (date-time)yesThe lease's end as the issuer set it.
generationintegeryes1 at the mint, one more per renewal (replacement).
credentialRefstringnoThe reference reported with the held credential — the issuer's 64-hex credential handle when the operator's client reports it. Never a key.
feeDeclaredbooleanyesWhether ZadQ's fee declaration for the current generation is recorded.
offeredAtstring (date-time)yes
createdAtstring (date-time)yes

400 — An agent request refused — by ZadQ before the issuer is asked, or by the issuer. RFC 9457 problem details whose code is the issuer's closed, value-free code (ZadQ's local refusals use the same names). Terminal: shown as such, never retried.

Content type application/problem+json.

Schema: AgentProblem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

409 — An agent request refused — by ZadQ before the issuer is asked, or by the issuer. RFC 9457 problem details whose code is the issuer's closed, value-free code (ZadQ's local refusals use the same names). Terminal: shown as such, never retried.

Content type application/problem+json.

Schema: AgentProblem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/agents/<agentId>/credential" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

POST /v0/agent-operators/{agentOperatorRef}/agents/{agentId}/renew

Renew an agent — replacement, with a new offer handed out once

Renewal is replacement: a new credential with the same terms and a new lease, the old one revoked when the new one is issued. ZadQ records the renewal's fee declaration first, then asks the issuer (under the same ZadQ bundle when the issuer serves ZadQ's catalogue); the new offer and its mint challenge are handed out once, like a mint, and the agent reads offered (generation + 1) until the new credential is reported held. A renewal counts against the issuer's mint rate. A revoked or expired agent is not renewable (409): mint a new one. Renewal needs the agent's credential handle reported (409 otherwise). The issuer's refusals are terminal, with its code. Wallet session of the operator's wallet required (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).
agentIdpathyesstringThe agent's pseudonymous handle (agt_…).

Responses

201 — The renewal offer, handed out once, and the agent's record.

Content type application/json.

Schema: AgentOfferHandoff

PropertyTypeRequiredDescriptionValues
offerobjectyesThe credential offer as the issuer returned it (the operator's price-line echo removed) — opaque, one-shot; the operator's agent client redeems it at once.
mintChallengeobjectnoThe issuer's mint challenge — the principal answers it with a mint presentation of its identity credential within 10 seconds, when redeeming the offer.
scopearray of AgentScopeEntrynoThe scope the issuer signs into the agent, with the issuer's id of each value.
expiresAtstring (date-time)yesWhen the offer stops being redeemable.
agentAgentyes

400 — An agent request refused — by ZadQ before the issuer is asked, or by the issuer. RFC 9457 problem details whose code is the issuer's closed, value-free code (ZadQ's local refusals use the same names). Terminal: shown as such, never retried.

Content type application/problem+json.

Schema: AgentProblem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

409 — An agent request refused — by ZadQ before the issuer is asked, or by the issuer. RFC 9457 problem details whose code is the issuer's closed, value-free code (ZadQ's local refusals use the same names). Terminal: shown as such, never retried.

Content type application/problem+json.

Schema: AgentProblem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/agents/<agentId>/renew" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/agent-operators/{agentOperatorRef}/agents/{agentId}/revoke

Revoke an agent (the operator's decision)

The operator revokes the agent: the issuer's status change, then the agent reads revoked with reason operator_revoked; an issuer revocation is effective everywhere within the network's published bound, 185 s from the root that drops the credential. 409 for an agent already revoked or expired. Wallet session of the operator's wallet required (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).
agentIdpathyesstringThe agent's pseudonymous handle (agt_…).

Responses

200 — The revoked agent.

Content type application/json.

Schema: Agent

PropertyTypeRequiredDescriptionValues
idstringyesThe agent's pseudonymous handle (agt_…), assigned by ZadQ.
statestringyes"offered", "held", "revoked", "expired", "refused"
reasonstringno"operator_revoked", "issuer_revoked", "principal_revoked", "self_revoked", "lease_expired", "active_agent_cap", "mint_rate_limited", "lease_too_long", "fee_not_declared", "bundle_required", "mint_policy_unconfigured", "session_reuse_expired", "principal_not_active", "principal_mismatch", "grade_exceeds_principal", "agent_revoked", "session_not_approved", "invalid_grant"
delegationAgentDelegationyes
keyCustodyAgentKeyCustodyno
saleAgentSaleno
leaseUntilstring (date-time)yesThe lease's end as the issuer set it.
generationintegeryes1 at the mint, one more per renewal (replacement).
credentialRefstringnoThe reference reported with the held credential — the issuer's 64-hex credential handle when the operator's client reports it. Never a key.
feeDeclaredbooleanyesWhether ZadQ's fee declaration for the current generation is recorded.
offeredAtstring (date-time)yes
createdAtstring (date-time)yes

400 — An agent request refused — by ZadQ before the issuer is asked, or by the issuer. RFC 9457 problem details whose code is the issuer's closed, value-free code (ZadQ's local refusals use the same names). Terminal: shown as such, never retried.

Content type application/problem+json.

Schema: AgentProblem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

409 — An agent request refused — by ZadQ before the issuer is asked, or by the issuer. RFC 9457 problem details whose code is the issuer's closed, value-free code (ZadQ's local refusals use the same names). Terminal: shown as such, never retried.

Content type application/problem+json.

Schema: AgentProblem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/agents/<agentId>/revoke" \
  -H "Authorization: Bearer <session-credential>"

GET /v0/agent-operators/{agentOperatorRef}/agents/{agentId}/kill

The agent kill switch's state, read from the chain on demand

The kill's record, settled first by one issuer-scoped chain read when it is still open (requested, submitted, pending). 404 when the agent has no kill. Wallet session of the operator's wallet required (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).
agentIdpathyesstringThe agent's pseudonymous handle (agt_…).

Responses

200 — The kill's state.

Content type application/json.

Schema: AgentKill

PropertyTypeRequiredDescriptionValues
agentIdstringyes
statestringyes"requested", "submitted", "pending", "folded", "refused"
boundSecondsintegeryesThe published effect bound of the kill switch, G + A + K = 245 s from N recorded.
recordedAtstring (date-time)noWhile pending — when this service's chain read first saw N recorded (at or after the chain recorded it).
deadlinestring (date-time)noWhile pending — recordedAt + boundSeconds; the kill is effective everywhere by then.
refusalAgentKillRefusalno
retryAfterSecondsintegernoWhen requested after a busy relay — wait this long, then post the same message again.
revocationReasonstringnoThe agent record's reason once it reads revoked (self_revoked after the fold)."operator_revoked", "principal_revoked", "self_revoked", "lease_expired"

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS "<base-url>/v0/agent-operators/<agentOperatorRef>/agents/<agentId>/kill" \
  -H "Authorization: Bearer <session-credential>"

POST /v0/agent-operators/{agentOperatorRef}/agents/{agentId}/kill

The agent kill switch — submit the holder's self-revocation and follow it to the fold

The kill switch for an agent credential (ZADQ-198). It runs where the key is: the agent's holder builds the self-revocation; this route takes the holder's message, submits it to the network's privacy relay and follows it on the chain. The call sequence:

  1. On the operator's side, the holder refreshes its witness

(GET {issuer}/v1/credentials/{id}/witness): the answer carries self_revoke_context — the issuer's public anchoring material for the served root, null unless the witness is usable and anchored on that root.

  1. The holder runs self_revoke with

{"chain_id": <the network's chain id>, "status_root": self_revoke_context.status_root, "anchoring": self_revoke_context without status_root} and keeps the nullifier and ciphertext it returns. From then on it refuses to present with that credential.

  1. The console posts the holder's result.message here, unchanged

(five fields).

  1. This service submits it to the relay (MINTID_RELAY_URL) with no

header beyond the content type, and answers the kill's state: submitted (the relay took it — its answer is never the receipt), refused (a closed relay code: unknown_root means rebuild the message against the current root and post again, once), or requested with retryAfterSeconds (the relay asked to wait — post the same message again after it; the Retry-After header carries it too).

  1. The state then comes from the issuer-scoped chain read

(RecordedNullifiers, which names the issuer only), on every read of this route and at the verdict cadence: pending once the chain holds N, folded once the issuer's root folded it; the agent then reads revoked with reason self_revoked.

Effect bounds (SPEC-1 §9.1; the same on the anchor and the testnet, with H = 30 s root period, A = 180 s acceptance window, K = 5 s future skew, G = 60 s fold grace). The bound is the guarantee; a measured figure is quoted only next to its bound and the release it ran on.

PathBoundValueCounted from
Emergency rootone blockone blockthe emergency root's transaction
Issuer revocationA + K185 sthe root that drops the credential
Holder self-revocation / agent kill switchG + A + K245 sN recorded on the chain
Principal cascade7·H + A + K395 sthe root that carries the trigger

While pending, the record carries recordedAt (when this service's read first saw N recorded — at or after the chain recorded it) and deadline = recordedAt + 245 s, never earlier than the guarantee.

What this service keeps: the state and the closed code; the issuer id and N only while the state is open, cleared at folded or refused; the first sighting only in memory. No log line, no event and no time column next to a kill. It cannot tell which credential a message belongs to (that is the point of the proof): the record is the operator's own. 400 for a message outside the relay contract's shape, 409 for an agent already revoked or expired or a kill already recorded on the chain, 501 when no relay is configured on this deployment. Wallet session of the operator's wallet required (401/403).

Authentication: walletSession.

Parameters

NameInRequiredTypeDescription
agentOperatorRefpathyesstringThe agent operator's opaque reference (aop_…).
agentIdpathyesstringThe agent's pseudonymous handle (agt_…).

Request body

application/json — required

Schema: AgentKillRequest

PropertyTypeRequiredDescriptionValues
messageSelfRevocationMessageyes

Responses

200 — The kill's state after the relay's answer and one chain read.

Content type application/json.

Schema: AgentKill

PropertyTypeRequiredDescriptionValues
agentIdstringyes
statestringyes"requested", "submitted", "pending", "folded", "refused"
boundSecondsintegeryesThe published effect bound of the kill switch, G + A + K = 245 s from N recorded.
recordedAtstring (date-time)noWhile pending — when this service's chain read first saw N recorded (at or after the chain recorded it).
deadlinestring (date-time)noWhile pending — recordedAt + boundSeconds; the kill is effective everywhere by then.
refusalAgentKillRefusalno
retryAfterSecondsintegernoWhen requested after a busy relay — wait this long, then post the same message again.
revocationReasonstringnoThe agent record's reason once it reads revoked (self_revoked after the fold)."operator_revoked", "principal_revoked", "self_revoked", "lease_expired"

default — RFC 9457 problem details.

Content type application/problem+json.

Schema: Problem

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

Example

curl -sS -X POST "<base-url>/v0/agent-operators/<agentOperatorRef>/agents/<agentId>/kill" \
  -H "Authorization: Bearer <session-credential>" \
  -H "Content-Type: application/json" \
  -d @request-body.json

Schemas

TermsDocument

PropertyTypeRequiredDescriptionValues
versionstringyesVersion name of the acknowledgement document.
sha256stringyesHex SHA-256 of text.
urlstring (uri)yesWhere the full Terms of Service are published.
textstringyesThe acknowledgement text the wallet signs for.

SellerTerms

PropertyTypeRequiredDescriptionValues
currentTermsDocumentyes
acknowledgedbooleanyesWhether the current version is acknowledged by this seller.
acknowledgedVersionstringno
signedAtstring (date-time)noWhen the current version was signed, if it was.
messagestringyesThe exact text to sign for the current version.
messageSignedAtstring (date-time)yesThe signing time embedded in message; submit it back as signedAt.

TermsAcknowledgement

PropertyTypeRequiredDescriptionValues
versionstringyes
sha256stringyes
signedAtstring (date-time)yes
signaturestringyesWallet signature over the message (hex for EVM, base58 or hex for Solana).

SellerWebhooks

PropertyTypeRequiredDescriptionValues
webhooksarray of Webhookyes

SellerEvent

PropertyTypeRequiredDescriptionValues
typestringyesEvent name of the seller stream (e.g. intake, kyc_approved, attested, status_suspended, consent_withdrawn).
occurredAtstring (date-time)yes

SellerEvents

PropertyTypeRequiredDescriptionValues
eventsarray of SellerEventyes

Chain

The payment rail of a payTo address (Platform Decision 14, ZADQ-66): USDC on Base (base, an EVM address, stored and compared lowercase) or on Solana (solana, case-sensitive). Any other value is refused with a 400 problem; other EVM chains are not declared until a seller needs one.

Type: string, one of "base", "solana".

AuthChallengeRequest

PropertyTypeRequiredDescriptionValues
chainChainyes
addressstringyes

AuthChallenge

PropertyTypeRequiredDescriptionValues
noncestringyes
messagestringyesExact text to sign, byte for byte.
expiresAtstring (date-time)yes

AuthSessionRequest

PropertyTypeRequiredDescriptionValues
chainChainyes
addressstringyes
noncestringyes
signaturestringyesEVM — 0x-hex r||s||v from personal_sign; Solana — base58 (or hex) 64-byte signature.

AuthSession

PropertyTypeRequiredDescriptionValues
bearerstringyesOpaque session credential for the Authorization header.
expiresAtstring (date-time)yes
chainChainyes
addressstringyes

Health

PropertyTypeRequiredDescriptionValues
statusstringyes"ok"
versionstringno

CredentialOfferHandoff

PropertyTypeRequiredDescriptionValues
offerobjectyesThe credential offer object, as the issuer returned it — opaque, one-shot; redeem it at once.
expiresAtstring (date-time)yesWhen the code and the credential it yields expire — the verification's own expiry at the latest. No grace.
credentialCredentialStateyes

CredentialReport

PropertyTypeRequiredDescriptionValues
statestringyesheld, or self_revoked (revoked is the older spelling of the same report)."held", "self_revoked", "revoked"
credentialRefstringnoAn opaque reference of the seller's choosing for the credential it holds. Never a key.
presentationUrlstring (uri)noWhere the seller's holder answers this service's challenges (ZADQ-84): POST of the issued challenge as the verifier returned it ({request, signature_hex}), 200 with the envelope ({proof_hex, issuer_id, status_root, claimed_predicates}); any other status means the holder cannot present this time. Only with held; kept when omitted on a later report.

CredentialState

The v1 credential the seller holds in its own infrastructure, as this service knows it (ZADQ-83): state only. expired is derived — an offered or held credential past the verification's expiry — since a credential lasts exactly what the verification lasts. revoked: revoked by the issuer's policy (consent withdrawn). self_revoked (ZADQ-89): revoked by its holder through the network's privacy relay; terminal on this verification, with nothing recorded next to it — the way back is a new verification.

PropertyTypeRequiredDescriptionValues
statestringyes"none", "offered", "held", "expired", "revoked", "self_revoked"
offeredAtstring (date-time)no
expiresAtstring (date-time)noThe verification's expiry, which is the credential's.
credentialRefstringno
presentationUrlstring (uri)noThe holder's presentation endpoint registered with held (ZADQ-84); absent on the v0 path.
lastPresentationPresentationOutcomeno

PresentationOutcome

The outcome of the last cadence presentation of the held credential (ZADQ-84), as the verifier's own decision record keeps it: never the challenge, the envelope or a proof. stage says where it ended — challenge (no challenge issued: the verifier's proven state was unavailable), transport (the holder did not present: holder_unreachable, holder_refused, envelope_malformed) or decision (the verifier decided; reason is its code — accepted, or one of its closed vocabulary such as proof_invalid, predicate_missing, deadline_exceeded, status_root_stale, request_not_ours). A refused decision withholds the positive claim on the public verdict; the public reason stays in the standing vocabulary, so the exact code lives here and on the seller's channel.

PropertyTypeRequiredDescriptionValues
stagestringyes"challenge", "transport", "decision"
acceptedbooleanyes
reasonstringyes
sessionIdstringnoThe verifier's session id of the decision record.
decidedAtstring (date-time)yes

SubstrateStatus

PropertyTypeRequiredDescriptionValues
substratestringyes"ok", "degraded", "unknown"
sourcestringyesWhere the state comes from — the verifier's status read, or this service's cadence accounting."verifier", "cadence"
reasonstringnoWhy the substrate is not ok, in the verifier's standing vocabulary (for example height_stale, root_expired, state_unavailable). Absent when ok.
checkedAtstring (date-time)yes
lastSuccessfulStandingReadstring (date-time)noThe last time a standing read answered with a known status. Absent before the first.
cadenceobjectyes
cadence.recheckEveryHoursintegeryesThe published cadence promise.
cadence.lastCycleAtstring (date-time)no
cadence.checkedintegernoAttestations the last cycle asked the verifier about.
cadence.withheldintegernoOf those, how many came back with an unknown standing.

BillingCheckout

PropertyTypeRequiredDescriptionValues
tierstringyesThe schedule tier, by name. Amounts are on the checkout page and in the operator agreement."attested_vendor", "regulated_compliance"
cadencestringnoHow the tier's minimum is billed: monthly or annually (ZADQ-230). The cadence rides on the session's metadata like the tier and lands on the record with the provider's completed event. 400 when this deployment has no price for the cadence requested."monthly", "annual"

BillingHandoff

PropertyTypeRequiredDescriptionValues
urlstring (uri)yesThe hosted checkout page — open it as-is.
billingstringyesThe record's billing state as the session opens — none, since opening a session records nothing (ZADQ-221). It moves to active with the provider's signed completed event, never here."none", "active"

BillingEventReceipt

PropertyTypeRequiredDescriptionValues
appliedbooleanyes

AddressProof

Proof of control of a payment address: the nonce of an auth challenge issued for it and the wallet's signature over the challenge message. Consumed on use, valid or not, like a login.

PropertyTypeRequiredDescriptionValues
noncestringyes
signaturestringyes

EndpointAddition

PropertyTypeRequiredDescriptionValues
resourceUrlstring (uri)yes
payToPayTono
proofAddressProofno

WalletRotation

PropertyTypeRequiredDescriptionValues
payToPayToyes
proofAddressProofyes

OperatorEndpoints

PropertyTypeRequiredDescriptionValues
endpointsarray of EndpointSummaryyes

EndpointSummary

PropertyTypeRequiredDescriptionValues
sellerIdstringyes
payToPayToyes
resourceUrlstringyes
statestringyes"pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
attestationStatusstringno"active", "suspended", "revoked"

InterestForm

The register-interest form's fields; contact data is not among them.

PropertyTypeRequiredDescriptionValues
sidestringyesWhich side of the trust perimeter the person stands on."vendor", "agent_operator"
resource_urlstring (uri)noThe x402 resource URL a vendor sells at (optional, vendors).
agent_count_bandstringnoThe size band of an operator's fleet (optional, agent operators)."up_to_10", "up_to_100", "more_than_100"
sourcestringnoThe page family the form was reached from (optional; a hidden field rendered at build time, ZADQ-160). An unknown value is dropped, not refused."home", "seller", "agent", "plans", "industries", "trust_about", "docs", "blog", "legal", "metrics"
websitestringnoTrap field for automated submitters; a person leaves it empty.

SellerIntake

PropertyTypeRequiredDescriptionValues
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
segmentSegmentDeclarationyes
kycSandboxHintKycSandboxHintno

KycSandboxHint

Staging only (ZADQ-196). The outcome a tester picks for the KYC session on an issuer whose KYC provider is MintID's sandbox driver (MintID's public testnet), in the sandbox grammar sandbox:<outcome>[:g1..g4][:F1..F4][:window=<s>][:review=<s>][:ttl=<s>] (ops/runbook-staging.md; the grammar's identity-data option is refused here: this service carries no identity data, not even synthetic). Accepted only when the issuer's build-info reported kyc_provider sandbox at start-up and this instance is not the production service; otherwise 400 sandbox_hint_not_available (a malformed value is 400 invalid_sandbox_hint). When accepted it replaces this service's opaque handle as the session's seller_ref at the issuer — on sandbox issuers only — and is kept nowhere else and never logged. Without it the sandbox approves at grade 2.

Type: string.

PayTo

Chain-qualified x402 payment address.

PropertyTypeRequiredDescriptionValues
chainChainyes
addressstringyesThe address that receives the payment; on base stored and compared lowercase.

SegmentDeclaration

PARAM-29 declaration. Recorded, not enforced in v0.

PropertyTypeRequiredDescriptionValues
annualVolumeUsdAtLeast300booleanyes
regulatedB2bCounterpartiesbooleanyes

Seller

PropertyTypeRequiredDescriptionValues
idstringyes
payToPayToyes
resourceUrlstring (uri)yes
operatorTypestringyes"person", "organisation"
statestringyeskyc_expired: the proofing session ran past its deadline without an outcome; a new session can be opened (POST …/kyc/sessions). withdrawn: consent to the service withdrawn — terminal."pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn"
billingstringyesBilling state at the operator's billing provider (ZADQ-54): none until the provider's signed checkout.session.completed lands, active afterwards; back to none on customer.subscription.deleted. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
billingTierstringnoThe schedule tier, by name, as the provider's completed event carried it from the session's metadata. Absent until billing is active (ZADQ-221)."attested_vendor", "regulated_compliance"
billingCadencestringnoHow the minimum is billed, as the provider's completed event carried it from the session's metadata (ZADQ-230). Absent until billing is active; a record active before cadences existed reads annual."monthly", "annual"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
depositDepositno
renewalall of KycHandoffnoThe pending re-verification session, while one is open (ZADQ-91): the person completes it on handoffUrl; the approved session in kyc keeps backing the attestation meanwhile.
attestationAttestationno
createdAtstring (date-time)yes

Deposit

The seller's guarantee deposit state as mirrored by this service (ZADQ-151): the state, its dashboard label, the holder's verification state, the level owed, the balance as last read from the holder and when, and the claims pending. Never a bank or card detail: this service mirrors states and amounts and holds nothing.

PropertyTypeRequiredDescriptionValues
statestringyes"required", "awaiting_funds", "held", "below_level", "returning", "returned"
dashboardStatestringyesOne of the eight labels shown as state only."Deposit required", "Awaiting funds", "Held (≥ level)", "Below level (top-up)", "Claim pending", "Released (partial)", "Returning", "Returned"
kybstringyesThe holder's verification of the vendor, as reported."none", "pending", "review", "validated", "refused", "expired", "out_of_date"
requiredMinorinteger (int64)yesThe level owed, in minor units of currency.
currencystringyes
balanceMinorinteger (int64)yesThe wallet balance as last read from the holder.
syncedAtstring (date-time)no
openClaimsintegeryes
returnDueAtstring (date-time)noWhen the return falls due after termination.

DepositKybHandoff

PropertyTypeRequiredDescriptionValues
urlstring (uri)yesThe holder's hosted verification page.

DepositPayInInstructions

The holder's collection details for one bank wire, relayed once and never stored by this service.

PropertyTypeRequiredDescriptionValues
collectionAccountstringyesThe holder's collection account to wire to.
bankNamestringyes
bankCodestringyes
wireReferencestringyesMust travel with the wire so the holder credits the right wallet.
amountMinorinteger (int64)yes
currencystringyes

KycHandoff

The person's side of the KYC session (ZADQ-52). handoffUrl is the identity provider's hosted page where the proofing is completed — open it as-is; it is present only while the session is pending. Nothing here is identity data.

PropertyTypeRequiredDescriptionValues
statestringyes"pending", "approved", "rejected", "expired", "withdrawn"
handoffUrlstring (uri)no
expiresAtstring (date-time)noProofing deadline of the current session.
reusableUntilstring (date-time)noEnd of the approved session's reuse window (approval + the grade's validity — 12 months at grades 1–2, 6 at grade 3, 3 at grade 4). No grace and no extension: the attestation is suspended rekyc_overdue at the first root after it unless a re-verification was bound before. Re-verify ahead of it (POST …/kyc/sessions).
freshnessBandstringnoAge of the last successful proofing as a band (F4 < 30 days, F3 < 90, F2 < 180, F1 < 365) — never a date. "Human-backed at G" means grade ≥ 2 and freshness ≥ F1; the issuer enforces it."F4", "F3", "F2", "F1"
reverificationDueAtstring (date-time)noWhen "re-verification due" starts: reusableUntil minus the service's lead (ZADQ-79). Present while approved and no re-verification is pending. The issuer extends nothing; this is the whole of the notice.
reverificationDuebooleannoTrue from reverificationDueAt until the window ends: re-verify now (POST …/kyc/sessions) so the attestation keeps its standing and its reference. Past the window the issuer refuses every step with 409 session_reuse_expired — terminal: the seller reads kyc_expired and starts a new verification.

KycResult

Outcome metadata only — the contract carries no identity data.

PropertyTypeRequiredDescriptionValues
sessionIdstringyes
outcomestringyes"approved", "rejected"
assuranceLevelstringnoAssurance grade met by the proofing process (e.g. "G").

Attestation

PropertyTypeRequiredDescriptionValues
idstringyes
sellerIdstringyes
assuranceLevelstringyes
statusstringyes"active", "suspended", "revoked"
statusReasonstringnoWhy a non-active status was set — never silent. rekyc_overdue: the reuse window ended; restored under the same reference by a bound re-verification. consent_withdrawn: terminal. self_revoked: the holder revoked its own credential and the attestation was retired at the next verdict cadence — terminal for this attestation; a new verification yields a new one. Absent for operator changes and while active."rekyc_overdue", "consent_withdrawn", "self_revoked"
freshnessBandstringnoFreshness band of the backing session, as the issuer reports it."F4", "F3", "F2", "F1"
issuedAtstring (date-time)yes
updatedAtstring (date-time)yes

AttestationReceipt

The attestation-ref/v0 payload, field for field (snake_case as the issuer signs it): Ed25519 over `"mintid/seller-attestation/v0" || 0x00

|| SHA-256(canonical JSON of the seven fields but signature)`. Only opaque handles and public endpoint identifiers.

PropertyTypeRequiredDescriptionValues
attestation_refstringyes32-byte opaque reference, hex.
issuer_idstringyes
chainstringyes
pay_tostringyes
resource_urlstringyes
assurance_gradeintegeryes
issued_at_unixintegeryes
signaturestringyesEd25519 by the issuer's registered status signing key, hex (64 bytes).

AttestationStatusUpdate

PropertyTypeRequiredDescriptionValues
statusstringyes"active", "suspended", "revoked"

Verdict

The explorer-consumable signed verdict: "human-backed at assurance ≥ G, verified at T, re-checked every N hours." Staleness is policy-driven. Funded-recourse policy: the positive claim is published only while the issuer's bond on the network meets the published minimum; otherwise the outcome is no_signal with reason: bond_insufficient. Every non-positive outcome carries reason from the closed vocabulary (ZADQ-78); human_backed never does.

PropertyTypeRequiredDescriptionValues
outcomestringyes"human_backed", "revoked", "stale", "no_signal"
subjectobjectyes
subject.chainChainyes
subject.payTostringyes
subject.resourceUrlstringyes
assuranceLevelstringno
verifiedAtstring (date-time)no
recheckEveryHoursintegeryes
signaturestringnoEd25519 over the canonical verdict payload, base64.
keyIdstringno
reasonstringnoWhy the outcome is not human_backed: the standing read's reason code (closed vocabulary), or suspended when the witnessed status is suspended. Absent on human_backed; absent on revoked too. The policy reason of a suspension (rekyc_overdue) is the seller's own record, never part of the public verdict. On the v1 path (ZADQ-84) a verifier-side condition of the presentation decision is carried with the same code (issuer_not_active, status_root_stale, height_stale) or as state_unavailable; a presentation the verifier refused on the holder's side withholds the positive claim with no reason — the decision's exact code is the seller's own record (credential.lastPresentation). The freshness half of "human-backed" (grade ≥ 2 and freshness ≥ F1) is the issuer's state on both rails (ZADQ-182): the issuer computes the band and suspends rekyc_overdue when the reuse window ends; ZadQ mirrors that state and never asks a presentation about recency (a presentation proves the grade threshold, expiry and non-revocation only). The verdict carries neither the band nor a date; the band is the seller's own record (freshnessBand)."state_unavailable", "issuer_unknown", "issuer_not_active", "status_root_stale", "height_stale", "witness_unavailable", "witness_malformed", "witness_invalid", "witness_root_mismatch", "bond_insufficient", "suspended"
extensionsVerdictExtensionsno

VerdictExtensions

Declarations of the verifying party, beside the verdict and outside it (ZADQ-240). The verdict's own fields above are the identity network's vocabulary and are closed; what ZadQ states on its own account travels under its own key, zadq, labelled as ZadQ's claim and not as a statement of the identity network. A reader that does not know the key ignores it and loses nothing. The signature covers the verdict's canonical payload only, not this object. Absent when ZadQ has nothing of its own to declare.

PropertyTypeRequiredDescriptionValues
zadqZadqVerdictExtensionno

ZadqVerdictExtension

ZadQ's own declarations about the seller, under ZadQ's Terms.

PropertyTypeRequiredDescriptionValues
depositDepositDeclarationno

DepositDeclaration

ZadQ's statement about the seller's guarantee deposit under ZadQ's Terms (Platform Decision 18); not a statement of the identity network, which carries no fact about this deposit. A state and a level band, read from ZadQ's mirrored record at verifiedAt — the record moves on every event of the deposit holder, so the read is the re-check. Never a balance, never an amount, never a holder reference. Present only while the deposit rail is on and the seller owes a deposit on the record. The gate on the positive claim (a positive standing whose deposit is not held reads no_signal) is ZadQ's verdict policy and is stated as such; this field is the reading behind it.

PropertyTypeRequiredDescriptionValues
statestringyesThe deposit's public state, one code per label of the seller's deposit.dashboardState."required", "awaiting_funds", "held", "below_level", "claim_pending", "released_partial", "returning", "returned"
levelstringyesThe band of the deposit, named by the tier of the schedule it belongs to; the level's amount is published on the plans page, never here."attested_vendor", "regulated_compliance"
verifiedAtstring (date-time)yesWhen ZadQ read its mirrored record for this answer.

WebhookRegistration

PropertyTypeRequiredDescriptionValues
urlstring (uri)yes

Webhook

PropertyTypeRequiredDescriptionValues
idstringyes
urlstring (uri)yes
secretstringnoHex signing secret for X-Signature. Returned once at registration.
createdAtstring (date-time)yes

VerificationKeys

PropertyTypeRequiredDescriptionValues
keysarray of VerificationKeyyes

VerificationKey

PropertyTypeRequiredDescriptionValues
keyIdstringyesFirst 8 bytes of the public key's SHA-256, hex.
algorithmstringyes"Ed25519"
publicKeystringyesRaw 32-byte Ed25519 public key, base64.
statusstringnocurrent signs new verdicts; previous is a key a rotation retired, kept published for at least the re-check window so verdicts signed before the rotation keep verifying (select the key by keyId, never by position)."current", "previous"

AgentOperatorEnrolment

PropertyTypeRequiredDescriptionValues
walletall of PayToyesThe wallet the operator's agent pays from — the one the wallet session proves.
operatorTypestringyesperson is verified by identity verification, organisation by business verification; the boundary learns this and nothing else."person", "organisation"
kycSandboxHintKycSandboxHintno

AgentOperator

The accountable party behind an agent, as this service keeps it (ZADQ-85): the wallet the operator's agent pays from, the operator type, the verification, the entry fee and the principal's identity credential — state only; the dashboard shows state, never keys. Agents present proof that an accountable operator stands behind them; they never disclose who.

PropertyTypeRequiredDescriptionValues
idstringyesThe operator's opaque reference (aop_…).
walletall of PayToyesThe wallet the operator's agent pays from.
operatorTypestringyes"person", "organisation"
statestringyespending_kyc → approved → credential_held (the principal's credential is held in the operator's infrastructure) → active (its first agent is minted). kyc_expired: the proofing deadline passed, or the approved verification's reuse window closed — the principal's credential expired with it; verify again (POST …/kyc/sessions). rejected and withdrawn are terminal."pending_kyc", "kyc_expired", "approved", "rejected", "credential_held", "active", "withdrawn"
billingstringyesThe one-off entry fee at the operator's billing provider: none until the provider's signed checkout.session.completed lands, active once it is recorded. Opening a checkout session records nothing (ZADQ-221). The service holds no legal or payment data."none", "active"
kycSessionIdstringnoOpaque session handle at the KYC boundary. Not identity data.
kycKycHandoffno
credentialCredentialStateno
agentsAgentCountsno
createdAtstring (date-time)yes

AgentOperatorCredentialReport

PropertyTypeRequiredDescriptionValues
statestringyesheld, or self_revoked (revoked is the older spelling of the same report)."held", "self_revoked", "revoked"
credentialRefstringnoAn opaque reference of the operator's choosing for the credential it holds. Never a key.

ScopeVocabulary

The delegation vocabulary carried on chain (mintid.scope-vocabulary.v2), as read under its pinned content hash: the active scope values, the forms and canonical patterns per axis, the value units and the key-custody classes an agent offer may name. Gated values are not served.

PropertyTypeRequiredDescriptionValues
contentSha256stringyesSHA-256 (hex) of the RFC 8785 canonical JSON of the vocabulary content it was read under.
versionstringno
scopesarray of stringyesThe enumerated active values as an offer writes them (actions, mintid: categories).
axesarray of ScopeAxisno
unitsarray of ScopeValueUnitno
custodyClassesarray of stringyesKey-custody class codes, lowest rank first.

ScopeAxis

One axis of the vocabulary as an offer may write it.

PropertyTypeRequiredDescriptionValues
axisstringyes"action", "counterparty", "category", "geo"
valuesarray of stringyesThe enumerated active values of the axis (canonical form).
formsarray of ScopeFormyesThe forms (counterparty) or namespaces (category, geo) and their canonical patterns.

ScopeForm

PropertyTypeRequiredDescriptionValues
formstringyes
patternstringyesThe canonical pattern a value of this form matches.

ScopeValueUnit

PropertyTypeRequiredDescriptionValues
codestringyes
minorExponentintegeryes

AgentBundleCatalogue

ZadQ's bundle catalogue as served to the dashboard: identifier and version, the vocabulary it is written against, the content digest (SHA-256 of the RFC 8785 canonical form, hex) and the bundles with ZadQ's price line.

PropertyTypeRequiredDescriptionValues
versionstringyes<namespace>.agent-bundles[.<name>].v<N>; ZadQ's namespace is zadq.
vocabularystringyes
digeststringyesLowercase hex SHA-256 of the catalogue's canonical form.
bundlesarray of AgentBundleyes
servedByIssuerbooleanyesWhether the network's issuer serves this catalogue (same id and digest). False also when its catalogue could not be read.
servedCataloguestringnoThe id of the catalogue the issuer serves, when read.

AgentBundle

One named, bounded scope an agent credential is minted from.

PropertyTypeRequiredDescriptionValues
bundleIdstringyes
descriptionstringyes
assuranceGradeMinintegeryesThe lowest backing grade (the principal's KYC grade) an agent of this bundle may be minted at.
keyCustodyMinstringyes
leaseSecondsAgentBundleRangeyes
actionsarray of stringyesThe actions every agent of the bundle is granted (never agent.delegate).
categoriesAgentBundleCategoriesyes
regionsAgentBundleRegionsyes
counterpartyAgentBundleCounterpartyyes
limitsobjectyesPer value unit (EUR, USD, USDC, EURC), the per-transaction limit in minor units — the default when the offer names none and the highest it may ask for.
defaultUnitstringyes
priceAgentBundlePriceno

AgentBundleRange

PropertyTypeRequiredDescriptionValues
defaultinteger (int64)yes
maxinteger (int64)yes

AgentBundleCategories

Categories the operator may choose from at mint (mcc:NNNN or mintid:<code>), the ones used when it chooses none, and how many one agent may carry.

PropertyTypeRequiredDescriptionValues
allowedarray of stringyes
defaultarray of stringyes
maxintegeryes

AgentBundleRegions

Regions the operator may choose from at mint (iso3166-1:XX or iso3166-2:XX-YYY; at least one is required) and how many one agent may carry.

PropertyTypeRequiredDescriptionValues
allowedarray of stringyes
maxintegeryes

AgentBundleCounterparty

The named counterparty forms the operator may list at mint and how many one agent may carry; the counterparties themselves are chosen per mint.

PropertyTypeRequiredDescriptionValues
formsarray of stringyesbIP-0004 named counterparty forms: merchant, url, caip10, verifier.
maxintegeryes

AgentBundlePrice

ZadQ's price line for the bundle, in minor units of its unit; absent when the bundle is unpriced.

PropertyTypeRequiredDescriptionValues
amountMinorinteger (int64)yes
unitstringyes

AgentLimit

The per-transaction limit the issuer signs into the agent's delegation.

PropertyTypeRequiredDescriptionValues
amountstringyesA positive decimal amount (up to 8 decimals), as a string.
unitstringyesThe limit's unit — a value unit of the vocabulary (EUR, USD, USDC, EURC).

AgentDelegation

What the agent is allowed to do, as the operator declares it and the issuer signs it. custodyClass is the operator's declared hint and is absent when none was declared; the class the agent is minted with is the issuer's, on the agent as keyCustody.

PropertyTypeRequiredDescriptionValues
scopearray of stringyesScope values of the vocabulary (GET /v0/agent-scopes), each once.
limitAgentLimityes
custodyClassstringnoThe key-custody class the operator declared, from the vocabulary — a lowering hint, never raising: the issuer appraises the class from attestation evidence and, absent a hint, its appraisal stands. Absent when no hint was declared (raw terms). With a bundle and no hint, the bundle's minimum is sent and shown here.
leaseDaysintegeryesThe lease in days; the issuer allows at most 90.

AgentOfferRequest

An agent offer in one of two exclusive forms: raw terms (scope, limit, leaseDays and optionally custodyClass, as in AgentDelegation) or a ZadQ bundle (bundle, with the choices inside it). Naming both is 400 bundle_and_scope_exclusive.

PropertyTypeRequiredDescriptionValues
scopearray of stringnoRaw terms — scope values of the vocabulary in canonical form, each once, at least one action.
limitAgentLimitno
custodyClassstringnoOptional — a lowering hint, never raising: the issuer appraises the agent key's custody class from attestation evidence (ZadQ sends none, so its agents are minted software); absent, the issuer's appraisal stands. Forwarded to the issuer only when given. When given, a class of the vocabulary; with a bundle, not below the bundle's minimum (absent with a bundle: the bundle's minimum is sent, as before).
leaseDaysintegernoThe lease in days. With a bundle — optional (the bundle's default), within the bundle's maximum.
bundleAgentBundleChoiceno

AgentBundleChoice

A ZadQ bundle and the operator's choices inside it; what is left out takes the bundle's defaults. Counterparties (in the bundle's forms) and regions are required. With a bundle, limit in the request is optional (the bundle's default cap) and may not exceed the bundle's cap for the unit (bundle_cap_exceeded).

PropertyTypeRequiredDescriptionValues
bundleIdstringyes
counterpartiesarray of stringyesCounterparty values in canonical form (url, caip10, merchant:…, verifier:…).
regionsarray of stringyes
categoriesarray of stringno

AgentSale

The ZadQ bundle the agent was sold under and ZadQ's price line for it, recorded by ZadQ; issuerForm says whether the issuer minted it under the bundle (bundle) or on the raw terms ZadQ derived from it while the issuer served another catalogue (raw).

PropertyTypeRequiredDescriptionValues
bundleIdstringyes
cataloguestringyes
priceAgentBundlePriceno
issuerFormstringyes"bundle", "raw"

AgentProblem

RFC 9457 problem details of an agent refusal, with the issuer's closed code.

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
codestringnoThe closed, value-free code (for instance scope_value_gated, bundle_cap_exceeded, bundle_custody_not_attested, grade_exceeds_principal).

Agent

An agent minted for the operator, as this service keeps it: ZadQ's pseudonymous handle — never a chain identifier —, the delegation summary, the lease and the state; never a key, the offer or a link to a person. States: offered (handed out, not yet reported held; again after a renewal) → held; revoked, expired and refused are terminal, with the reason: operator_revoked (the operator revoked it), issuer_revoked (revoked at the issuer outside ZadQ's route), principal_revoked (the principal stopped backing its agents — self-revoked, verification window closed or consent withdrawn — whatever triggered it), self_revoked (the agent's holder revoked it) or lease_expired (past its lease); refused (the issuer's mint step refused the offer, so no credential exists) carries the issuer's reason: active_agent_cap (10 active agents per person), mint_rate_limited (5 mints per hour, renewals included), lease_too_long, fee_not_declared, bundle_required, mint_policy_unconfigured, or a terminal conflict (session_reuse_expired, principal_not_active, principal_mismatch, grade_exceeds_principal, agent_revoked, session_not_approved, invalid_grant).

PropertyTypeRequiredDescriptionValues
idstringyesThe agent's pseudonymous handle (agt_…), assigned by ZadQ.
statestringyes"offered", "held", "revoked", "expired", "refused"
reasonstringno"operator_revoked", "issuer_revoked", "principal_revoked", "self_revoked", "lease_expired", "active_agent_cap", "mint_rate_limited", "lease_too_long", "fee_not_declared", "bundle_required", "mint_policy_unconfigured", "session_reuse_expired", "principal_not_active", "principal_mismatch", "grade_exceeds_principal", "agent_revoked", "session_not_approved", "invalid_grant"
delegationAgentDelegationyes
keyCustodyAgentKeyCustodyno
saleAgentSaleno
leaseUntilstring (date-time)yesThe lease's end as the issuer set it.
generationintegeryes1 at the mint, one more per renewal (replacement).
credentialRefstringnoThe reference reported with the held credential — the issuer's 64-hex credential handle when the operator's client reports it. Never a key.
feeDeclaredbooleanyesWhether ZadQ's fee declaration for the current generation is recorded.
offeredAtstring (date-time)yes
createdAtstring (date-time)yes

AgentKeyCustody

The key-custody class of the agent's key as the issuer appraised it and minted it, from the issuer's answer to the offer. Present only when that answer carried it: agents offered before the issuer's appraisal release have none, and a renewal keeps the class sealed at mint. Two closed codes — nothing about a key, a device or the evidence.

PropertyTypeRequiredDescriptionValues
classstringyesA key-custody class of the vocabulary (software for every offer without attestation evidence).
appraisedFromstringyesThe attestation format the class was appraised from; none when the offer carried no evidence (ZadQ sends none).

Agents

PropertyTypeRequiredDescriptionValues
itemsarray of Agentyes

AgentOfferHandoff

PropertyTypeRequiredDescriptionValues
offerobjectyesThe credential offer as the issuer returned it (the operator's price-line echo removed) — opaque, one-shot; the operator's agent client redeems it at once.
mintChallengeobjectnoThe issuer's mint challenge — the principal answers it with a mint presentation of its identity credential within 10 seconds, when redeeming the offer.
scopearray of AgentScopeEntrynoThe scope the issuer signs into the agent, with the issuer's id of each value.
expiresAtstring (date-time)yesWhen the offer stops being redeemable.
agentAgentyes

AgentScopeEntry

PropertyTypeRequiredDescriptionValues
axisstringyes
valuestringyes
valueIdstringno

AgentCredentialReport

PropertyTypeRequiredDescriptionValues
statestringyes"held", "self_revoked", "mint_refused"
credentialRefstringnoWith held — the issuer's 64-hex credential handle the holder received at issuance (or another reference of the operator's choosing, which leaves renewal unavailable). Never a key.
refusalAgentMintRefusalno

AgentMintRefusal

The issuer's answer at the mint step, as the operator's agent client received it (mint_refused only).

PropertyTypeRequiredDescriptionValues
statusintegeryes
errorstringyes
errorDescriptionstringno

AgentCounts

The operator's live agents (offered or held), for display. The issuer enforces at most 10 active agents per person and 5 mints per sliding hour, renewals included; ZadQ shows the answer, it does not re-count.

PropertyTypeRequiredDescriptionValues
activeintegeryes

MetricsReport

PropertyTypeRequiredDescriptionValues
schemastringyesThe wire shape's name (published-metrics/v1).
computedAtstring (date-time)yes
asOfstring (date)yesThe cut-off — the last day of the last complete month (UTC). Partial months are never published.
periodMetricsPeriodno
cadenceobjectyes
cadence.publicationstringyesmonthly.
cadence.snapshotstringyesquarterly, aligned to the two-consecutive-quarters clock.
relatedPartybooleanyesAlways true — the operator's position is a property of the dataset.
operatorMetricsOperatoryes
seriesarray of MetricsSeriesyes
contextNotestringyes

MetricsPeriod

Inclusive month range, YYYY-MM at both ends. Absent while no complete month holds a record.

PropertyTypeRequiredDescriptionValues
fromstringyes
tostringyes

MetricsOperator

PropertyTypeRequiredDescriptionValues
servicestringyes
operatorstringyes
relatedPartybooleanyes
positionstringyes
disclosurestringyesThe canonical metrics disclosure, embedded in every report.

MetricsSeries

PropertyTypeRequiredDescriptionValues
idstringyes"sellers_attested", "retention_r90", "verifications_free_path", "independent_verifiers", "anchor_service_revenue"
titlestringyes
disciplinestringyes"registry-based", "aggregate", "context"
definitionstringyes
relatedPartybooleanyesAlways true, on every series.
periodMetricsPeriodno
availablebooleanyesFalse when the records hold no source for the series; unavailableReason says why and points is empty.
unavailableReasonstringno
pointsarray of MetricsPointyes

MetricsPoint

One month-end observation. Which fields carry a value depends on the series: cumulative, active, independent (sellers_attested); cohort, retained, r (retention_r90; r absent while the cohort is empty); count, registrations (independent_verifiers); count (verifications_free_path: reads served on the free path in the month, summed from the per-minute counters — never one read at a time).

PropertyTypeRequiredDescriptionValues
periodstringyesYYYY-MM.
cumulativeintegerno
activeintegerno
independentintegerno
cohortintegerno
retainedintegerno
rnumbernoRatio, two decimals.
countintegerno
registrationsintegerno

Problem

RFC 9457 problem details.

PropertyTypeRequiredDescriptionValues
typestringno
titlestringno
statusintegerno
detailstringno
instancestringno

SelfRevocationMessage

The holder's self_revoke output (result.message), unchanged — the relay's body (MintID self-revocation relay v0, provisional 0.1.0). It names neither the holder nor the credential.

PropertyTypeRequiredDescriptionValues
issuer_idstringyesThe issuer's 32-byte identifier, lowercase hex.
nullifierstringyesN, 32 bytes, lowercase hex, not zero.
status_epochinteger (uint64)yesAn epoch of the issuer's anchored ring.
zk_authorization_proofstringyesThe authorisation proof, lowercase hex, at most 4 608 bytes.
proof_system_versionstringyes"01"

AgentKillRequest

PropertyTypeRequiredDescriptionValues
messageSelfRevocationMessageyes

AgentKill

The agent kill switch's record: requested → submitted → pending → folded, or refused with a closed relay code. Never the message, N, the proof or the issuer id.

PropertyTypeRequiredDescriptionValues
agentIdstringyes
statestringyes"requested", "submitted", "pending", "folded", "refused"
boundSecondsintegeryesThe published effect bound of the kill switch, G + A + K = 245 s from N recorded.
recordedAtstring (date-time)noWhile pending — when this service's chain read first saw N recorded (at or after the chain recorded it).
deadlinestring (date-time)noWhile pending — recordedAt + boundSeconds; the kill is effective everywhere by then.
refusalAgentKillRefusalno
retryAfterSecondsintegernoWhen requested after a busy relay — wait this long, then post the same message again.
revocationReasonstringnoThe agent record's reason once it reads revoked (self_revoked after the fold)."operator_revoked", "principal_revoked", "self_revoked", "lease_expired"

AgentKillRefusal

The relay's closed reason code and stage (or relay_unreachable / relay_unrecognised_answer when the relay could not be heard or answered outside its contract — those two are this service's own).

PropertyTypeRequiredDescriptionValues
codestringyes
stagestringno"relay", "precheck", "chain"