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
| Field | Value |
|---|---|
| Contract | Seller-Verification Service API |
| Version | 0.1.0 |
| Specification | OpenAPI 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.
MintID unreachable at start-up (ZADQ-407): a deployment whose MintID ids are discovered at start-up (never production, where they are configuration) serves while MintID does not answer. /healthz stays 200 and names mintid: discovering; the free path and every route that reads this service's own records are served; the routes that reach MintID synchronously — the issuer's KYC sessions (POST /v0/sellers, the kyc/sessions, kyc/result and consent-withdrawal routes of /v0 and /v1), the attestations and credential offers it issues, the agent mints, renewals and revocations (/v0 agent routes, POST /v1/enrolments/{id}/offer and /mint, POST /v1/agents/{id}/renewals and /stop) — answer 503 mintid_unavailable with Retry-After: 60 (the /v1 envelope's error, the /v0 problem's title), nothing recorded. Discovery is retried in the background; mintid: ready once it succeeds, and the same routes answer as usual.
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). Since ZADQ-287 the wallet is no longer a login: a wallet session alone may register the account's first passkey and nothing else (403 passkey required); inside a passkey session it is the signature every write touching that payTo re-signs with (ADR-0015).
passkeySession
API key in the cookie __Host-passkey_session.
The passkey session (ZADQ-287; platform API v1 §4): set after a WebAuthn registration or sign-in, same site, HttpOnly, Secure, short lived (30 minutes idle) and renewed on use, at most 12 hours. On a development host (localhost) the cookie is named passkey_session and is not Secure.
runtimeCredential
HTTP header Authorization: Bearer <credential>.
The runtime credential (the contract's runtime_token; ZADQ-289, issued at claim by ZADQ-288): Authorization: Bearer <runtime_token>, scoped to one enrolment and, once registered, to that agent's runtime for its present approvals; random, hashed at rest, revocable. 401 runtime_token_invalid when unknown, revoked or expired.
Other operations
POST /v0/auth/challenge
Wallet signature, step 1 — challenge for a payTo address
Returns a one-time message for the payment wallet to sign (EVM personal_sign or Solana message signing). Since ZADQ-287 the wallet signature is the binding of a payTo (ADR-0015), not a login: the dashboard's session is the passkey (/v1/auth/passkeys). No personal data. Challenges expire after 5 minutes.
Authentication: none — this operation is public.
Request body
application/json — required
Schema: AuthChallengeRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
chain | Chain | yes | ||
address | string | yes |
Responses
201 — Challenge issued.
Content type application/json.
Schema: AuthChallenge
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
nonce | string | yes | ||
message | string | yes | Exact text to sign, byte for byte. | |
expiresAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
Example
curl -sS -X POST "<base-url>/v0/auth/challenge" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v0/auth/session
Wallet signature, step 2 — redeem the signed challenge for the payTo's bearer
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 operations that write a payTo (ADR-0015): the wallet proves control of the address, it is not the dashboard's login and carries no account or personal data — the session is the passkey (/v1/auth/passkeys, platform API v1 §4). The challenge and this redemption are served by the service on every host that reaches it (the API host; the app host's /v0/* once its path behaviour is on), and the bearer is a header, so a payTo write under the passkey session sends both the cookie and the bearer (platform API v1.3 §5.9). With the passkey release switch on (ZADQ-287): a wallet whose account has no passkey yet gets the migration bearer, which may register the account's first passkey and nothing else; a wallet whose account has a passkey gets a bearer only inside that account's passkey session (the re-signature of a payTo write) — without it, 403 "wallet login retired".
Authentication: none — this operation is public.
Request body
application/json — required
Schema: AuthSessionRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
chain | Chain | yes | ||
address | string | yes | ||
nonce | string | yes | ||
signature | string | yes | EVM — 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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
bearer | string | yes | Opaque session credential for the Authorization header. | |
expiresAt | string (date-time) | yes | ||
chain | Chain | yes | ||
address | string | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
Example
curl -sS -X POST "<base-url>/v0/auth/session" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /healthz
Liveness probe
200 whenever the process serves, MintID reachable or not (the load balancer's health check); mintid says whether the MintID ids are known (ZADQ-407).
Authentication: none — this operation is public.
Responses
200 — Service is up.
Content type application/json.
Schema: Health
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
status | string | yes | "ok" | |
version | string | no | ||
mintid | string | no | The readiness of this deployment's MintID ids (ZADQ-407): discovering while MintID was unreachable at start-up and the ids are retried in the background (the MintID-dependent routes answer 503 mintid_unavailable), ready otherwise. The probe answers 200 either way. | "discovering", "ready" |
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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
substrate | string | yes | "ok", "degraded", "unknown" | |
source | string | yes | Where the state comes from — the verifier's status read, or this service's cadence accounting. | "verifier", "cadence" |
reason | string | no | Why the substrate is not ok, in the verifier's standing vocabulary (for example height_stale, root_expired, state_unavailable). Absent when ok. | |
checkedAt | string (date-time) | yes | ||
lastSuccessfulStandingRead | string (date-time) | no | The last time a standing read answered with a known status. Absent before the first. | |
cadence | object | yes | ||
cadence.recheckEveryHours | integer | yes | The published cadence promise. | |
cadence.lastCycleAt | string (date-time) | no | ||
cadence.checked | integer | no | Attestations the last cycle asked the verifier about. | |
cadence.withheld | integer | no | Of 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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
side | string | yes | Which side of the trust perimeter the person stands on. | "vendor", "agent_operator" |
resource_url | string (uri) | no | The x402 resource URL a vendor sells at (optional, vendors). | |
agent_count_band | string | no | The size band of an operator's fleet (optional, agent operators). | "up_to_10", "up_to_100", "more_than_100" |
source | string | no | The 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" |
website | string | no | Trap 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: there is no business verification (KYB) in this phase — an organisation is declared by its responsible person, not verified, and the issuer answers 501 on this deployment; nothing is recorded, the same endpoint can register later (ZADQ-192). A person acting for a company registers as person and declares the company (PUT /v1/organisation). biometric_consent: {version} is required (ZADQ-331): the consent to the face comparison the person gave on ZadQ's page before the verification link opens — 409 biometric_consent_required when absent, 409 biometric_consent_version_stale (the current label in the detail) when it is not the deployment's label; refused, nothing is registered and nothing reaches the issuer. Accepted, the consent is recorded with the session the intake opened.
Authentication: walletSession.
Request body
application/json — required
Schema: SellerIntake
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
segment | SegmentDeclaration | yes | ||
kycSandboxHint | KycSandboxHint | no | ||
biometric_consent | BiometricConsentGiven | no |
Responses
201 — Seller registered; KYC session opened.
Content type application/json.
Schema: Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
200 — Current seller state.
Content type application/json.
Schema: Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
Example
curl -sS "<base-url>/v0/sellers/<sellerId>" \
-H "Authorization: Bearer <session-credential>"
GET /v0/sellers/{sellerId}/billing
The vendor's billing lines and usage statement (ZADQ-470)
Platform API v1.3.31 (ZADQ-470; Platform Decision 10's vendor lines, built on Marc's decision of 2026-11-07). What the operator group of this seller record is billed beside its tier, for the seller dashboard's billing screen: the tier and cadence of the group's billing; the entry fee — paid once per operator group at the tier's checkout (Attested Vendor €400, Regulated / Compliance €1,500, net, not credited), and what a checkout of each tier would charge now (a higher tier charges the difference — confirmed by Marc on 2026-11-08, v1.3.32; a lower one nothing); the endpoints — the group's admitted endpoint records against the tier's included ones (3 / 10) and the additional-endpoint item on the subscription (its quantity and one endpoint's price for the period); and the usage fee's monthly statements — the meter's closes (0.75 % of each covered settlement received, capped at USD 0.40, converted at the ECB rule, credited against the minimum), shown whether or not the fee is invoiced (usage_fee.invoicing: off until the counsel items of Platform Decision 15, Marc's gate; v1.3.32: on, each billable month is invoiced at the close on a monthly invoice of its own, every cadence, its id the statement's invoice_ref). Amounts in minor units, net (the provider adds the VAT). Requires the wallet session of this seller's payTo (401/403), as the operator's endpoints read.
Authentication: walletSession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
200 — The vendor's billing lines.
Content type application/json.
Schema: VendorBilling
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
seller_id | string | yes | The seller record asked about. | |
billing_seller_id | string, nullable | no | The operator group's seller record whose billing is active (the oldest); null when none. | |
billing | string | yes | The group's billing state. | "none", "active" |
tier | string, nullable | no | "attested_vendor", "regulated_compliance" | |
cadence | string, nullable | no | "monthly", "annual" | |
entry_fee | VendorEntryFee | yes | ||
endpoints | VendorEndpoints | yes | ||
usage_fee | VendorUsageFee | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
Example
curl -sS "<base-url>/v0/sellers/<sellerId>/billing" \
-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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
200 — The operator's endpoints, oldest first.
Content type application/json.
Schema: OperatorEndpoints
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
endpoints | array of EndpointSummary | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json — required
Schema: EndpointAddition
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
resourceUrl | string (uri) | yes | ||
payTo | PayTo | no | ||
proof | AddressProof | no |
Responses
201 — The new seller, admitted on the shared verification.
Content type application/json.
Schema: Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json — required
Schema: WalletRotation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
payTo | PayTo | yes | ||
proof | AddressProof | yes |
Responses
200 — The seller on its new address, with the new attestation.
Content type application/json.
Schema: Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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.
v1.3.31 (ZADQ-470), where the deployment prices the vendor lines: the one session carries the tier's subscription, the entry fee due as a one-off line (once per operator group; a higher tier's checkout charges the difference) and, when the operator group holds more admitted endpoint records than the tier includes (3 / 10), the additional endpoints as a recurring line, quantity the endpoints above the quota. 409 while the operator's billing is active on another of its endpoint records (one billing per operator); 400 when endpoints above the quota have no price for the cadence chosen.
Authentication: walletSession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json — required
Schema: BillingCheckout
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
tier | string | yes | The schedule tier, by name. Amounts are on the checkout page and in the operator agreement. | "attested_vendor", "regulated_compliance" |
cadence | string | no | How 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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
url | string (uri) | yes | The hosted checkout page — open it as-is. | |
billing | string | yes | The 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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
Stripe-Signature | header | yes | string |
Request body
application/json — required
Type: object.
Responses
200 — Acknowledged; whether the event changed a state.
Content type application/json.
Schema: BillingEventReceipt
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
applied | boolean | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
201 — The hosted verification is open.
Content type application/json.
Schema: DepositKybHandoff
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
url | string (uri) | yes | The holder's hosted verification page. |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
201 — The pay-in is registered; wire with these details.
Content type application/json.
Schema: DepositPayInInstructions
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
collectionAccount | string | yes | The holder's collection account to wire to. | |
bankName | string | yes | ||
bankCode | string | yes | ||
wireReference | string | yes | Must travel with the wire so the holder credits the right wallet. | |
amountMinor | integer (int64) | yes | ||
currency | string | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
hookToken | path | yes | string | |
EventType | query | no | string | |
RessourceId | query | no | string | |
Date | query | no | string |
Responses
200 — Acknowledged.
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
201 — The offer, handed out once, and when it expires.
Content type application/json.
Schema: CredentialOfferHandoff
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
offer | object | yes | The credential offer object, as the issuer returned it — opaque, one-shot; redeem it at once. | |
expiresAt | string (date-time) | yes | When the code and the credential it yields expire — the verification's own expiry at the latest. No grace. | |
credential | CredentialState | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json — required
Schema: CredentialReport
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | held, or self_revoked (revoked is the older spelling of the same report). | "held", "self_revoked", "revoked" |
credentialRef | string | no | An opaque reference of the seller's choosing for the credential it holds. Never a key. | |
presentationUrl | string (uri) | no | Where 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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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). Either way a new verification session opens, so the body carries the consent to the face comparison, {biometric_consent: {version}} (ZADQ-331): 409 biometric_consent_required without it, 409 biometric_consent_version_stale with another label than the deployment's — checked after the wallet and before the state, and nothing reaches the issuer when refused; accepted, the consent is recorded with the session opened.
Authentication: walletSession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json
Schema: KycSessionRestart
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
biometric_consent | BiometricConsentGiven | no |
Responses
201 — New session opened; the seller reads pending_kyc again.
Content type application/json.
Schema: Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
Example
curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/kyc/sessions" \
-H "Authorization: Bearer <session-credential>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v0/sellers/{sellerId}/biometric-consent
Record the consent to the face comparison on the seller's pending session (ZADQ-331)
For a seller whose pending session (or pending re-verification) has no consent recorded: the consent to the face comparison, {version} the label of the text shown. 409 biometric_consent_required / biometric_consent_version_stale (checked after the wallet, before anything else; nothing reaches the issuer); 409 "invalid state" unless a session or a renewal is pending. Accepted, the consent is recorded for that session and the seller is returned with its link. Wallet session of the seller's payTo (401/403).
Authentication: walletSession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json — required
Schema: BiometricConsentGiven
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | The consent text's version label (e.g. 2026-10.2). |
Responses
200 — The seller, with its link.
Content type application/json.
Schema: Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
Example
curl -sS -X POST "<base-url>/v0/sellers/<sellerId>/biometric-consent" \
-H "Authorization: Bearer <session-credential>" \
-H "Content-Type: application/json" \
-d @request-body.json
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
200 — Consent withdrawn; the seller is terminal.
Content type application/json.
Schema: Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | Version name of the acknowledgement document. | |
sha256 | string | yes | Hex SHA-256 of text. | |
url | string (uri) | yes | Where the full Terms of Service are published. | |
text | string | yes | The acknowledgement text the wallet signs for. |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
200 — Acknowledgement state.
Content type application/json.
Schema: SellerTerms
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
current | TermsDocument | yes | ||
acknowledged | boolean | yes | Whether the current version is acknowledged by this seller. | |
acknowledgedVersion | string | no | ||
signedAt | string (date-time) | no | When the current version was signed, if it was. | |
message | string | yes | The exact text to sign for the current version. | |
messageSignedAt | string (date-time) | yes | The signing time embedded in message; submit it back as signedAt. |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json — required
Schema: TermsAcknowledgement
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes | ||
signedAt | string (date-time) | yes | ||
signature | string | yes | Wallet signature over the message (hex for EVM, base58 or hex for Solana). |
Responses
201 — Acknowledged.
Content type application/json.
Schema: SellerTerms
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
current | TermsDocument | yes | ||
acknowledged | boolean | yes | Whether the current version is acknowledged by this seller. | |
acknowledgedVersion | string | no | ||
signedAt | string (date-time) | no | When the current version was signed, if it was. | |
message | string | yes | The exact text to sign for the current version. | |
messageSignedAt | string (date-time) | yes | The signing time embedded in message; submit it back as signedAt. |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
200 — The seller's receivers.
Content type application/json.
Schema: SellerWebhooks
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
webhooks | array of Webhook | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json — required
Schema: WebhookRegistration
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
url | string (uri) | yes |
Responses
201 — Receiver registered; secret shown once.
Content type application/json.
Schema: Webhook
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
url | string (uri) | yes | ||
secret | string | no | Hex signing secret for X-Signature. Returned once at registration. | |
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string | |
webhookId | path | yes | string |
Responses
204 — Receiver removed.
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string | |
limit | query | no | integer |
Responses
200 — Recent events.
Content type application/json.
Schema: SellerEvents
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
events | array of SellerEvent | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Request body
application/json — required
Schema: KycResult
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
sessionId | string | yes | ||
outcome | string | yes | "approved", "rejected" | |
assuranceLevel | string | no | Assurance grade met by the proofing process (e.g. "G"). |
Responses
200 — Admission state updated.
Content type application/json.
Schema: Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
201 — Attestation issued.
Content type application/json.
Schema: Attestation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
sellerId | string | yes | ||
assuranceLevel | string | yes | ||
status | string | yes | "active", "suspended", "revoked" | |
statusReason | string | no | Why 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" |
freshnessBand | string | no | Freshness band of the backing session, as the issuer reports it. | "F4", "F3", "F2", "F1" |
issuedAt | string (date-time) | yes | ||
updatedAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string | |
attestationId | path | yes | string |
Responses
200 — The receipt.
Content type application/json.
Schema: AttestationReceipt
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
attestation_ref | string | yes | 32-byte opaque reference, hex. | |
issuer_id | string | yes | ||
chain | string | yes | ||
pay_to | string | yes | ||
resource_url | string | yes | ||
assurance_grade | integer | yes | ||
issued_at_unix | integer | yes | ||
signature | string | yes | Ed25519 by the issuer's registered status signing key, hex (64 bytes). |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
attestationId | path | yes | string |
Request body
application/json — required
Schema: AttestationStatusUpdate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
status | string | yes | "active", "suspended", "revoked" |
Responses
200 — Mirrored status applied.
Content type application/json.
Schema: Attestation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
sellerId | string | yes | ||
assuranceLevel | string | yes | ||
status | string | yes | "active", "suspended", "revoked" | |
statusReason | string | no | Why 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" |
freshnessBand | string | no | Freshness band of the backing session, as the issuer reports it. | "F4", "F3", "F2", "F1" |
issuedAt | string (date-time) | yes | ||
updatedAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
keys | array of VerificationKey | yes |
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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
schema | string | yes | The wire shape's name (published-metrics/v1). | |
computedAt | string (date-time) | yes | ||
asOf | string (date) | yes | The cut-off — the last day of the last complete month (UTC). Partial months are never published. | |
period | MetricsPeriod | no | ||
cadence | object | yes | ||
cadence.publication | string | yes | monthly. | |
cadence.snapshot | string | yes | quarterly, aligned to the two-consecutive-quarters clock. | |
relatedParty | boolean | yes | Always true — the operator's position is a property of the dataset. | |
operator | MetricsOperator | yes | ||
series | array of MetricsSeries | yes | ||
contextNote | string | yes |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
chain | query | yes | Chain | |
payTo | query | yes | string | |
resourceUrl | query | yes | string |
Responses
200 — Verdict (or explicit no-signal outcome).
Content type application/json.
Schema: Verdict
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
outcome | string | yes | "human_backed", "revoked", "stale", "no_signal" | |
subject | object | yes | ||
subject.chain | Chain | yes | ||
subject.payTo | string | yes | ||
subject.resourceUrl | string | yes | ||
assuranceLevel | string | no | ||
verifiedAt | string (date-time) | no | ||
recheckEveryHours | integer | yes | ||
signature | string | no | Ed25519 over the canonical verdict payload, base64. | |
keyId | string | no | ||
reason | string | no | Why 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" |
extensions | VerdictExtensions | no |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
url | string (uri) | yes |
Responses
201 — Subscription created; secret shown once.
Content type application/json.
Schema: Webhook
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
url | string (uri) | yes | ||
secret | string | no | Hex signing secret for X-Signature. Returned once at registration. | |
createdAt | string (date-time) | yes |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
webhookId | path | yes | string |
Responses
204 — Subscription removed.
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sellerId | path | yes | string |
Responses
200 — Latest verdict.
Content type application/json.
Schema: Verdict
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
outcome | string | yes | "human_backed", "revoked", "stale", "no_signal" | |
subject | object | yes | ||
subject.chain | Chain | yes | ||
subject.payTo | string | yes | ||
subject.resourceUrl | string | yes | ||
assuranceLevel | string | no | ||
verifiedAt | string (date-time) | no | ||
recheckEveryHours | integer | yes | ||
signature | string | no | Ed25519 over the canonical verdict payload, base64. | |
keyId | string | no | ||
reason | string | no | Why 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" |
extensions | VerdictExtensions | no |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
Example
curl -sS "<base-url>/v0/sellers/<sellerId>/verdict"
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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
contentSha256 | string | yes | SHA-256 (hex) of the RFC 8785 canonical JSON of the vocabulary content it was read under. | |
version | string | no | ||
scopes | array of string | yes | The enumerated active values as an offer writes them (actions, mintid: categories). | |
axes | array of ScopeAxis | no | ||
units | array of ScopeValueUnit | no | ||
custodyClasses | array of string | yes | Key-custody class codes, lowest rank first. |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | <namespace>.agent-bundles[.<name>].v<N>; ZadQ's namespace is zadq. | |
vocabulary | string | yes | ||
digest | string | yes | Lowercase hex SHA-256 of the catalogue's canonical form. | |
bundles | array of AgentBundle | yes | ||
servedByIssuer | boolean | yes | Whether the network's issuer serves this catalogue (same id and digest). False also when its catalogue could not be read. | |
servedCatalogue | string | no | The id of the catalogue the issuer serves, when read. |
default — RFC 9457 problem details.
Content type application/problem+json.
Schema: Problem
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
Example
curl -sS "<base-url>/v0/agent-bundles" \
-H "Authorization: Bearer <session-credential>"
POST /v1/auth/passkeys/register/options
Passkey registration, step 1 — creation options
WebAuthn creation options for a discoverable passkey with user verification required; the PRF extension is requested and its support recorded on registration. Three callers: with a passkey session, the person adds a passkey; with the wallet session's bearer alone (POST /v0/auth/session), the migration step — the wallet account's first passkey, the one thing a wallet-only session may do (only the account's first-enrolled wallet may do it; 403 passkey_required names that); with no session and new_account, a new account and its owner person are created when the registration finishes. 401 session_required with neither (or a wallet whose account already has a passkey: the wallet is no longer a login).
Authentication: none or passkeySession or walletSession.
Request body
application/json
Schema: PasskeyRegisterOptionsRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
new_account | object | no | With no session, the account the registration creates. kind (default organisation, so a v1.2 front still works) and country seed the customer record (ZADQ-307 §2.2); the kind may change until the first payment. | |
new_account.name | string | yes | The organisation's label in the dashboard. | |
new_account.kind | NewAccountKind | no | ||
new_account.country | string | no | ISO 3166-1 alpha-2, the country of registration. | |
new_account.referral | all of ReferralParams | no | v1.3.14 (§5.16): the door the sign-up came through — the landing URL's parameters. Checked here (404 referral_unknown, 409 referral_closed; 501 not_available while the door is off) and recorded in the account's transaction at the finish (account_referred). | |
consents | all of ConsentsUpdate | no | The consents given at Create your account (ZADQ-307 §2.3), recorded in the account's own transaction when the registration finishes. Checked here: 409 terms_changed for a stale Terms version or hash, 400 business_use_required for business_use: false. Only with new_account. | |
label | string | no | The passkey's label (e.g. the device). |
Responses
200 — Creation options, as navigator.credentials.create takes them.
Content type application/json.
Schema: PasskeyCeremonyOptions
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
publicKey | object | yes | WebAuthn PublicKeyCredentialCreationOptions or RequestOptions (JSON, base64url binaries). |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/auth/passkeys/register/options" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/auth/passkeys/register
Passkey registration, step 2 — the authenticator's answer
Verifies the registration answer against the ceremony the same caller began (the same passkey session, the same wallet session, or none) and stores the passkey. A registration signs the person in: the passkey session cookie is set and its expiry returned. 400 attestation_invalid when the answer does not verify; 409 ceremony_invalid when it names no live ceremony of this caller.
Authentication: none or passkeySession or walletSession.
Request body
application/json — required
Schema: PasskeyRegisterRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
attestation | object | yes | The PublicKeyCredential the browser answered (toJSON form). |
Responses
201 — Passkey stored; session cookie set.
Content type application/json.
Schema: PasskeyRegistered
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
passkey_id | string | yes | ||
prf_supported | boolean | yes | ||
session_expires_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/auth/passkeys/register" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/auth/passkeys/login/options
Passkey sign-in, step 1 — request options
WebAuthn request options for a discoverable sign-in (no account is named), user verification required. The same options serve a fresh assertion where a decision asks for one (an approval).
Authentication: none — this operation is public.
Responses
200 — Request options, as navigator.credentials.get takes them.
Content type application/json.
Schema: PasskeyCeremonyOptions
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
publicKey | object | yes | WebAuthn PublicKeyCredentialCreationOptions or RequestOptions (JSON, base64url binaries). |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/auth/passkeys/login/options"
POST /v1/auth/passkeys/login
Passkey sign-in, step 2 — the assertion
Verifies the assertion and opens the passkey session: a cookie, same site, HttpOnly, short lived and renewed on use. 401 assertion_invalid when it does not verify.
Authentication: none — this operation is public.
Request body
application/json — required
Schema: PasskeyLoginRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
assertion | object | yes | The PublicKeyCredential the browser answered (toJSON form). |
Responses
200 — Signed in; session cookie set.
Content type application/json.
Schema: PasskeySessionOpened
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_expires_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/auth/passkeys/login" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/auth/logout
Sign out — the passkey session ends
Authentication: none — this operation is public.
Responses
204 — Session ended (or none was open); cookie cleared.
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/auth/logout"
GET /v1/me
The account, its owner person, passkeys, payTo bindings and products
The signed-in person's account. person.kyc holds the issuer's session handle and the facts the issuer's operator API returns for it (state, grade, reuse window) — never KYC data. Products: the vendor's state is read from the account's vendor records; the agent-operator product's from its activation once it exists (ZADQ-290: plan, seats.plan = the plan's seats capped by the issuer's 10 per person), else from the agent-operator records with null plans. seats.used counts the live agents plus the enrolments holding a seat (created, claimed, or approved and waiting on their price line); the hourly counter the agent credentials offered in the last hour against ZadQ's allowance of 4. biometric_consent (ZADQ-331): the consent text's label the deployment requires now and the last consent given, so the page never shows an outdated text. 401 session_required; 403 passkey_required with a wallet session alone.
Authentication: passkeySession.
Responses
200 — The account.
Content type application/json.
Schema: Me
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
account | MeAccount | yes | ||
person | MePerson | yes | ||
passkeys | array of MePasskey | yes | ||
payto_bindings | array of MePaytoBinding | yes | ||
products | MeProducts | yes | ||
biometric_consent | MeBiometricConsent | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/me" \
--cookie "__Host-passkey_session=<api-key>"
PATCH /v1/me/person
Set the person's operational e-mail
The operational e-mail is the one contact field ZadQ keeps: the address it writes to about the account. Optional at migration, required before a product is activated. Never KYC data; null clears it. 400 email_operational_invalid.
Authentication: passkeySession.
Request body
application/json — required
Schema: MePersonUpdate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
given_name | string, nullable | no | ||
family_name | string, nullable | no | ||
email_operational | string, nullable | no | ||
preferred_language | string | no |
Responses
200 — The person.
Content type application/json.
Schema: MePerson
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
given_name | string, nullable | yes | ||
family_name | string, nullable | yes | ||
email_operational | string, nullable | yes | The operational contact address; never KYC data. | |
preferred_language | string | yes | ISO 639-1, from the service's supported set (en, es, ca, et, de, fr, it, pt, nl); en by default. | |
kyc | MeKyc | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X PATCH "<base-url>/v1/me/person" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
DELETE /v1/me/passkeys/{passkeyId}
Remove a passkey (never the last one)
Removes one of the person's passkeys and ends the sessions it opened. 409 last_passkey for the last one: an account never falls back to the wallet as a login. 404 not_found for a passkey that is not the person's. 409 last_wrap for the passkey that carries the last wrap of a live browser credential (§5.8; revoke the credential first). A wrap the passkey carries that is not the last goes in the same step (ZADQ-293, v1.3.2): one custody_version step, rotation_due set, custody_wrap_removed written.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
passkeyId | path | yes | string |
Responses
204 — Removed.
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X DELETE "<base-url>/v1/me/passkeys/<passkeyId>" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/organisation
The account's organisation (or the sole trader's trade), as declared
The customer record the responsible person DECLARES (Marc, 2026-10-18): the legal name, trade name, legal form, business-register number, country, EU VAT number, national tax number, registered address and invoicing e-mail of the organisation or sole trader the verified person contracts for. No documented KYB: no register check, no power-to-represent check, no beneficial owners — VIES on the VAT number is the one check performed. complete and missing are computed: the fields a payment still needs (409 profile_incomplete on the checkout routes until then). Before the first PUT the answer is the skeleton: the account's kind and country, the legal name prefilled from the account's name, no address, complete: false. 401 session_required. 409 account_blocked once the account is blocked by an erasure request or the contract's end (ZADQ-311): the record is kept for the retention periods only and is not served — the same on PUT, on /v1/me/consents, on PATCH /v1/me/person, on the export and at the payment gate (where 409 profile_incomplete answers).
Authentication: passkeySession.
Responses
200 — The declared record.
Content type application/json.
Schema: Organisation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | AccountKind | yes | ||
legal_name | string, nullable | yes | Required to save; for a sole trader the trading name or the person's own name, as on their tax registration. | |
trade_name | string, nullable | yes | ||
legal_form | string, nullable | yes | ||
registration_number | string, nullable | yes | The national business-register number as declared (EE registry code, ES Registro Mercantil entry, DE HRB, FR SIREN…). | |
country | string, nullable | yes | ISO 3166-1 alpha-2, the country of registration. | |
vat_id | all of OrganisationVatId | yes | ||
tax_id | all of OrganisationTaxId | yes | ||
registered_address | all of OrganisationAddress | yes | ||
invoice_email | string, nullable | yes | The invoicing address; the operational e-mail is used when absent. | |
complete | boolean | yes | ||
missing | array of string | yes | The field paths a payment still needs, e.g. registered_address.line1, tax_id. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/organisation" \
--cookie "__Host-passkey_session=<api-key>"
PUT /v1/organisation
Declare (or replace) the organisation record
The full object minus the computed fields. Strings are trimmed; unknown fields answer 400 body_invalid. legal_name and country identify the record; the rest may arrive over several saves (what a payment still needs is missing). vat_id is checked against VIES on write with the operating entity's number as the requester, the consultation kept as evidence: valid | invalid (refused, 400 profile_invalid with fields.vat_id = vat_id_invalid) | unchecked (a prefix outside VIES) | unavailable (no answer; stored and retried every VIES_RETRY_EVERY). tax_id with scheme es_nif is checked for format and control character (checksum). kind may change until the first payment: 409 kind_locked after. 400 profile_invalid with fields: {<path>: required | too_long | invalid | checksum | vat_id_invalid} — paths, never values.
Authentication: passkeySession.
Request body
application/json — required
Schema: OrganisationUpdate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | AccountKind | no | ||
legal_name | string | yes | ||
trade_name | string, nullable | no | ||
legal_form | string, nullable | no | ||
registration_number | string, nullable | no | ||
country | string | yes | ||
vat_id | string, nullable | no | The EU VAT number with its ISO prefix; checked against VIES on write. On PUT the record's own shape {value, status?, checked_at?} is accepted too — the contract's "object minus the computed fields" (zadq.app sends it); the computed fields are ignored. | |
tax_id | all of OrganisationTaxId | no | ||
registered_address | all of OrganisationAddress | no | ||
invoice_email | string, nullable | no |
Responses
200 — The record as saved, with complete and missing.
Content type application/json.
Schema: Organisation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | AccountKind | yes | ||
legal_name | string, nullable | yes | Required to save; for a sole trader the trading name or the person's own name, as on their tax registration. | |
trade_name | string, nullable | yes | ||
legal_form | string, nullable | yes | ||
registration_number | string, nullable | yes | The national business-register number as declared (EE registry code, ES Registro Mercantil entry, DE HRB, FR SIREN…). | |
country | string, nullable | yes | ISO 3166-1 alpha-2, the country of registration. | |
vat_id | all of OrganisationVatId | yes | ||
tax_id | all of OrganisationTaxId | yes | ||
registered_address | all of OrganisationAddress | yes | ||
invoice_email | string, nullable | yes | The invoicing address; the operational e-mail is used when absent. | |
complete | boolean | yes | ||
missing | array of string | yes | The field paths a payment still needs, e.g. registered_address.line1, tax_id. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X PUT "<base-url>/v1/organisation" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/me/consents
The consents record — the current view of the append-only log
The Terms version accepted (version, SHA-256, time), the Privacy Policy version shown (information, never a consent), the business-use declaration's time, the marketing choice. Each is the latest entry of the account's append-only consents log — the evidence of the electronic acceptance (who, what, version, hash, time), never edited. Absent items read null.
Authentication: passkeySession.
Responses
200 — The current view.
Content type application/json.
Schema: Consents
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | object, nullable | yes | ||
terms.version | string | yes | ||
terms.sha256 | string | yes | ||
terms.accepted_at | string (date-time) | yes | ||
privacy_notice | object, nullable | yes | The Privacy Policy version shown — information, never a consent. | |
privacy_notice.version | string | yes | ||
privacy_notice.shown_at | string (date-time) | yes | ||
business_use | object, nullable | yes | ||
business_use.at | string (date-time) | yes | ||
marketing | object | yes | ||
marketing.opt_in | boolean | yes | ||
marketing.at | string (date-time), nullable | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/me/consents" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/me/consents
Accept a Terms version, record the Privacy Policy shown, declare business use, set the marketing choice
Any of terms {version, sha256}, privacy_notice {version}, business_use: true, marketing: <bool>; each appends to the log. No fresh passkey assertion is required. 409 terms_changed when the Terms version or hash is not the published one (re-read /v1/legal/current and ask again); 400 business_use_required for business_use: false; 400 body_invalid for an unpublished Privacy Policy version or an empty body.
Authentication: passkeySession.
Request body
application/json — required
Schema: ConsentsUpdate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | object | no | ||
terms.version | string | yes | ||
terms.sha256 | string | yes | ||
privacy_notice | object | no | ||
privacy_notice.version | string | yes | ||
business_use | boolean | no | The declaration "I act for my business or profession"; false is refused (400 business_use_required). | |
marketing | boolean | no |
Responses
200 — The current view after the append.
Content type application/json.
Schema: Consents
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | object, nullable | yes | ||
terms.version | string | yes | ||
terms.sha256 | string | yes | ||
terms.accepted_at | string (date-time) | yes | ||
privacy_notice | object, nullable | yes | The Privacy Policy version shown — information, never a consent. | |
privacy_notice.version | string | yes | ||
privacy_notice.shown_at | string (date-time) | yes | ||
business_use | object, nullable | yes | ||
business_use.at | string (date-time) | yes | ||
marketing | object | yes | ||
marketing.opt_in | boolean | yes | ||
marketing.at | string (date-time), nullable | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/me/consents" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/legal/current
The Terms and the Privacy Policy versions in force (no session)
What Create your account shows and sends back: the current Terms version with its SHA-256 and url, the current Privacy Policy version with its url. The versions are published by the operator (the console); 404 not_found while none is. The version in force is the latest whose effective_at has passed — computed on read against the clock (ZADQ-313): a published version that applies later is on /v1/legal/upcoming until then.
Authentication: none — this operation is public.
Responses
200 — The versions in force.
Content type application/json.
Schema: LegalCurrent
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | object | yes | ||
terms.version | string | yes | ||
terms.sha256 | string | yes | ||
terms.url | string | yes | ||
terms.effective_at | string (date-time) | yes | ||
privacy | object | yes | ||
privacy.version | string | yes | ||
privacy.url | string | yes | ||
privacy.effective_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/legal/current"
GET /v1/legal/upcoming
The Terms and Privacy Policy versions published and not yet in force (no session)
Every version published with a later effective_at, the soonest first (empty lists when none). A Terms change applies at least 30 calendar days after its publication (Terms clause 20) unless the change is required by law (reason: required_by_law); a Privacy Policy change announced ahead applies at the date given. At effective_at the version becomes the one /v1/legal/current answers, by the clock — no job. A Terms version can be accepted before it applies (POST /v1/me/consents with its version and SHA-256).
Authentication: none — this operation is public.
Responses
200 — The versions to come.
Content type application/json.
Schema: LegalUpcoming
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | array of LegalUpcomingTerms | yes | ||
privacy | array of LegalUpcomingPrivacy | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/legal/upcoming"
GET /v1/me/notices
The change notices of the account — the Terms or Privacy Policy versions it is told about (ZADQ-313)
One notice per account per version, opened when the operator publishes a version that changes a previous one (for the Privacy Policy: one announced before it applies), and e-mailed to the Responsible Person's operational e-mail. A Terms notice carries the version's SHA-256 and whether the account has accepted it (this version or a later one); it clears on the acceptance (POST /v1/me/consents with terms {version, sha256}). A Privacy Policy notice clears when dismissed (POST /v1/me/notices/{id}/seen). state=open (default) lists the notices still asking for something; state=all lists every one. At effective_at the Terms version applies whether or not the account accepted it; clause 20 gives the account the right to terminate without penalty within the notice period.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
state | query | no | string | Values: "open", "all". |
Responses
200 — The notices, the soonest effective first.
Content type application/json.
Schema: ChangeNotices
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
notices | array of ChangeNotice | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/me/notices" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/me/notices/{id}/seen
Dismiss a Privacy Policy change notice (ZADQ-313)
Records the notice as seen (the first dismissal's time is kept; a repeat answers the same). 409 invalid_state for a Terms notice — it clears on the acceptance of the version; 404 not_found for an unknown notice or another account's.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | yes | string |
Responses
200 — The notice, dismissed.
Content type application/json.
Schema: ChangeNotice
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
kind | string | yes | "terms", "privacy" | |
version | string | yes | ||
url | string | yes | ||
effective_at | string (date-time) | yes | ||
in_force | boolean | yes | The version applies already. | |
open | boolean | yes | The notice still asks for something — the acceptance, or reading it. | |
sha256 | string, nullable | yes | The Terms version's SHA-256, to accept it with (null for the Privacy Policy). | |
required_by_law | boolean | yes | ||
accepted | boolean, nullable | yes | ||
seen_at | string (date-time), nullable | yes | ||
mailed_at | string (date-time), nullable | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/me/notices/<id>/seen" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/legal/terms/{version}
The exact text of a published Terms version (the accepted version, for download)
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
version | path | yes | string |
Responses
200 — The version, its SHA-256 and its text.
Content type application/json.
Schema: LegalTermsText
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes | ||
text | string | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/legal/terms/<version>" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/me/export
The account's data export (Art. 15, Art. 20) — JSON
The account, the person, the declared organisation, the consents (current view and log, and biometric_consents: every consent to the face comparison — version, time, the KYC session it opened, the record; kept after a withdrawal, ZADQ-331), the passkeys (ids, labels, dates), the payTo bindings, the product records, the price lines (the invoice facts: kind, amount, state, time — no provider reference), the VIES evidence, the activity log, the erasure state, and the controller's identity. Requires a passkey sign-in within the reauth window (5 minutes by default): 403 reauth_required otherwise — the session stays valid; sign in again with the passkey and retry. The export is recorded as an activity event (data_exported). 409 account_blocked after an erasure request (ZADQ-311): download before asking for the erasure; afterwards the request goes by e-mail.
Authentication: passkeySession.
Responses
200 — The export (application/json; Content-Disposition attachment).
Content type application/json.
Type: object.
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/me/export" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/me/erasure-request
Request the erasure of the account's data
Records the data-subject's request (once; a repeat answers the first), blocks the record for the retention jobs (ZADQ-311: the account closes at the end of the current billing period, what accounting and tax law require is kept blocked for those purposes only, the rest is erased per period), and withdraws now what the existing cascades can: every admitted vendor record (its attestations revoked, consent withdrawn), every live agent-operator record's consent at the issuer (its agents brought along). The person is answered by e-mail (ZADQ-313). Requires a passkey sign-in within the reauth window: 403 reauth_required otherwise. As built by ZADQ-311: the retention job sets every live subscription of the account's billing Customers to end at its current period's end and closes the account at the latest of those ends (at once when nothing is billed periodically); /v1/me reads account.blocked_at and account.closes_at. At the close the sessions end and the passkeys are deleted.
Authentication: passkeySession.
Responses
202 — The request is recorded.
Content type application/json.
Schema: ErasureState
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "requested" | |
at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/me/erasure-request" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/sellers
The account's seller records (the vendor product), under the passkey session
The sellers bound to the account through its payto_bindings (ZADQ-287), oldest first, as the v0 seller routes already serve them (platform API v1.3 §5.9, ZADQ-324): the endpoint, its admission state, whether the current terms version is acknowledged, the billing state and tier, the attestation, the v1 credential's state (with the last cadence presentation's outcome) and the dashboard verdict. No new data: the record's detail, its KYC hand-off, deposit and events stay on GET /v0/sellers/{sellerId} and its sub-routes, which the passkey session also reads (on the app host once its /v0/* path behaviour is on; infra/web). Writes touching a payTo keep the wallet bearer (ADR-0015). A pending seller's admission state is refreshed from the KYC boundary on the read, as GET /v0/sellers/{id} does. 401 session_required.
Authentication: passkeySession.
Responses
200 — The account's sellers.
Content type application/json.
Schema: PlatformSellerList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
sellers | array of PlatformSeller | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/sellers" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/approvals
The approvals inbox
The account's approval requests, newest first (at most 200), in one state with ?state=. Kinds: delegate (an enrolment a runtime claimed), present (a verifier's declaration a runtime brings) and renew (an agent's renewal). A pending request past its expiry reads expired. 401 session_required.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
state | query | no | string | Values: "pending", "approved", "declined", "expired", "failed". |
Responses
200 — The inbox.
Content type application/json.
Schema: ApprovalList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
approvals | array of ApprovalSummary | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/approvals" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/approvals
A runtime asks the person to prove something (kind present only)
Under the runtime credential (Authorization: Bearer <runtime_token>). The request carries the verifier's declaration — profile, origin, challenge endpoint, claim policy, issuer policy — never a challenge (an unknown field is refused). The challenge endpoint is https (http on loopback only) on the verifier origin's host or a subdomain of it. from is the credential's enrolment or agent and its runtime. expires_in_s defaults to 600 (30 to 3600). 400 declaration_invalid · body_invalid; 401 runtime_token_invalid; 429 rate_limited past 20 pending requests of one runtime credential. principal_mode (ZADQ-294): runtime (the operator's runtime holds the person's credential and posts the result) or browser (the person's browser does); absent, the mode of the runtime credential's enrolment. Browser-mode present approvals are closed on every deployment (BROWSER_PRESENT=off) until MintID publishes @mintid-net/holder 0.1.1 — the proof does not fit the ten-second window on slow devices yet: 409 mode_not_available.
Authentication: runtimeCredential.
Request body
application/json — required
Schema: PresentApprovalRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | string | yes | "present" | |
purpose | string | yes | ||
declaration | PresentDeclaration | yes | ||
expires_in_s | integer | no | ||
principal_mode | PrincipalMode | no |
Responses
202 — Pending in the person's inbox.
Content type application/json.
Schema: PresentApprovalCreated
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
state | ApprovalState | yes | ||
expires_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/approvals" \
-H "Authorization: Bearer <session-credential>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/approvals/{approvalId}
One approval (the dashboard) or the runtime's long-poll
Under the passkey session: the approval with what it carries (delegate, present or renew), decided_at once closed, failure for failed, and for a present approval result_taken once its result was delivered.
Under the runtime credential (Authorization: Bearer <runtime_token>), within its scope: the long-poll. ?wait= (0 to 30 seconds; about 1 while a person is deciding) holds the answer until the state changes, or, for an approved present approval, until the holder's result arrives: 200 {state, failure?, result?} with the result {session_id, request, envelope} delivered once and deleted; 204 on every poll after delivery. A declined or expired approval answers its state and nothing else.
Authentication: passkeySession or runtimeCredential.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
approvalId | path | yes | string | The approval's handle (apr_…). |
wait | query | no | integer | Long-poll seconds (runtime credential only), 0 to 30. |
Responses
200 — The approval (dashboard) or the poll's answer (runtime).
Content type application/json.
One of:
204 — Runtime only — the result was delivered; nothing more.
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/approvals/<approvalId>" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/approvals/{approvalId}/approve
Approve — the passkey session plus a fresh WebAuthn assertion
The body carries a fresh assertion of the session's own person, answered to the request options of POST /v1/auth/passkeys/login/options (taken once; it opens no session). Approving a delegate records the decision and hands it to the enrolment's next step (the offer); if that step is refused the approval reads failed and the route answers 422 offer_refused:<issuer code>. For a browser-mode delegate or renew (principal_mode: browser, ZADQ-294) whose price line settles at once, the answer carries the issuer's agent offer once — the operator's price line stripped, Cache-Control: no-store, never stored or logged — for the browser's credential step inside a fresh issuer challenge; the approval reads approved and the enrolment waits for the browser's material (POST /v1/enrolments/{id}/mint). A browser-mode present approval is closed while BROWSER_PRESENT is off (409 mode_not_available, until @mintid-net/holder 0.1.1). 400 body_invalid without an assertion; 401 assertion_invalid; 409 ceremony_invalid · approval_not_pending; 404 not_found.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
approvalId | path | yes | string | The approval's handle (apr_…). |
Request body
application/json — required
Schema: ApproveRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
assertion | object | yes | The PublicKeyCredential the browser answered to the login options (toJSON form). |
Responses
200 — Approved.
Content type application/json.
Schema: ApprovalDecided
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | ApprovalState | yes | ||
offer | object | no | Browser-mode delegate or renew only (ZADQ-294), once: the issuer's agent offer for the browser's credential step — {credential_offer, mint_challenge, expires_at, scope, bundle}, the operator's price line stripped. Never stored or logged. | |
offer_expires_at | string (date-time) | no |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/approvals/<approvalId>/approve" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/approvals/{approvalId}/decline
Decline — nothing is delivered
Closes a pending approval as declined. A declined present request delivers nothing to the runtime. 409 approval_not_pending; 404 not_found.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
approvalId | path | yes | string | The approval's handle (apr_…). |
Request body
application/json
Type: object.
Responses
200 — Declined.
Content type application/json.
Schema: ApprovalDecided
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | ApprovalState | yes | ||
offer | object | no | Browser-mode delegate or renew only (ZADQ-294), once: the issuer's agent offer for the browser's credential step — {credential_offer, mint_challenge, expires_at, scope, bundle}, the operator's price line stripped. Never stored or logged. | |
offer_expires_at | string (date-time) | no |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/approvals/<approvalId>/decline" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/approvals/{approvalId}/result
The holder's runtime posts a present result, once
After the person approved a present request, the holder fetches the challenge from the declared endpoint, presents at once and posts {session_id, request, envelope} here — in stage 1 the operator's runtime under its runtime credential; in stage 2 the browser under the passkey session. Accepted once (202), held encrypted until the operator's poll takes it, deleted on delivery. A result not taken within two minutes is deleted and the approval reads failed(result_not_taken). Instead of a result the holder may post {failure: <code>} (ZADQ-294; closed: window_lapsed, challenge_unreachable, the holder's refusal codes challenge_unsigned, challenge_key_unknown, challenge_origin_mismatch, challenge_profile_mismatch, challenge_expired, challenge_replayed, policy_unsatisfiable, credential_revoked, module_trapped, and person_cancelled): the approval reads failed(<code>). 202 {state}: approved (the result held) or failed. The poster must be the side that holds the person's holder for the approval (principal_mode): a browser on a runtime-mode approval, or a runtime on a browser-mode one, answers 409 mode_not_available, as does every browser post while BROWSER_PRESENT is off. 400 request_invalid · reason_invalid · body_invalid (not a present approval); 409 approval_not_pending · result_already_taken.
Authentication: runtimeCredential or passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
approvalId | path | yes | string | The approval's handle (apr_…). |
Request body
application/json — required
One of:
Responses
202 — Held until the operator's poll takes it, or failed.
Content type application/json.
Schema: ApprovalDecided
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | ApprovalState | yes | ||
offer | object | no | Browser-mode delegate or renew only (ZADQ-294), once: the issuer's agent offer for the browser's credential step — {credential_offer, mint_challenge, expires_at, scope, bundle}, the operator's price line stripped. Never stored or logged. | |
offer_expires_at | string (date-time) | no |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/approvals/<approvalId>/result" \
-H "Authorization: Bearer <session-credential>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/activity
The activity log — reason codes, never a value
The account's events, newest first, 50 a page; next_cursor while more remain. Each event: the time, the kind, the state and reason code where they apply, at most one reference (an enrolment, an agent or an approval) and the actor. Never a value: no seller id, limit, credential id, envelope, pseudonym or decision record. 400 cursor_invalid.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
cursor | query | no | string |
Responses
200 — A page of events.
Content type application/json.
Schema: ActivityPage
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
events | array of ActivityEvent | yes | ||
next_cursor | string | no |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/activity" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/enrolments
The account's enrolments (dashboard) or a runtime's own (runtime credential)
Under the passkey session: the account's enrolments, newest first (at most 200), kind enrol and the renewals (renewal) the person asked for. Under the runtime credential: the enrolments it covers — its own and the renewals of its agent (how a runtime learns that a renewal was asked: it then polls that enrolment as a first mint). Due enrolments are closed before the read.
Authentication: passkeySession or runtimeCredential.
Responses
200 — The enrolments.
Content type application/json.
Schema: EnrolmentList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
enrolments | array of EnrolmentSummary | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/enrolments" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/enrolments
Create an enrolment — a one-time code for the agent's runtime
The bundle and its params are checked against the catalogue the issuer serves (read and cached), before anything is stored; the lease defaults to the bundle's (ZadQ's catalogue) or 30 days, at most 90. principal_mode: browser (ZADQ-294) is accepted only while the account's identity credential is held in a browser (the custody store, GET /v1/custody/browser state: held), else 409 mode_not_available. The code (8 characters, Crockford base32) is shown once and kept as a keyed hash; claimable for 24 hours, once. The Idempotency-Key header is required: the same key and body answer the same enrolment (with a fresh code while it is unclaimed), 409 idempotency_conflict with another body, 409 enrolment_not_claimable once claimed. 400 bundle_unknown · bundle_params_invalid · body_invalid; 409 kyc_required · kyc_grade_below_bundle (ZADQ-321: the served catalogue's assurance_grade_min of the bundle is above the person's grade — refused here, before any line opens, with both grades in the detail; a record without a grade goes through) · product_inactive (no activation, or the product pending or suspended) · credential_not_held (ZADQ-424, runtime mode: the person is verified and the fee recorded, but the identity credential is not held yet — the detail names the two ways to hold it, keep it in this browser or in the operator's runtime) · entry_fee_due · seats_exhausted · person_cap_reached; 503 catalogue_unavailable.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
Idempotency-Key | header | no | string |
Request body
application/json — required
Schema: EnrolmentRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
name | string | yes | The agent's name in the runtime, e.g. trip-planner/concierge_agent. | |
bundle | string | no | A bundle of the issuer's served catalogue (GET /v1/catalogue); required unless referral_id presets it. | |
referral_id | string | no | v1.3.14 (§5.16) — the first bounded agent preset from one of the account's referrals: the bundle (when left out; else it must be the referral's) and the refusing service's origin as a counterparty (added when left out). 404 referral_unknown; 409 referral_closed; 400 bundle_params_invalid for another bundle. | |
bundle_params | EnrolmentBundleParams | yes | ||
lease_seconds | integer | no | ||
principal_mode | string | yes | "runtime", "browser" |
Responses
201 — The enrolment and its code (shown once).
Content type application/json.
Schema: EnrolmentCreated
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
code | string | yes | The one-time code (8 characters), shown once. | |
claim_url | string | yes | The app's origin with the code in the fragment (<origin>/claim#<code>), for the QR code. | |
expires_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/enrolments" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/enrolments/claim
The runtime claims a code (no session; throttled per IP)
The runtime posts the code and its descriptor; it receives the runtime credential (shown once) scoped to the enrolment, and a delegate approval lands in the person's inbox. expires_at is when that approval expires. The same code again from the same runtime (kind and instance_ref) answers the same enrolment with a new runtime credential (the earlier one revoked); after failed(token_expired) it starts a new approval. key_attestation is accepted and not used (ZadQ sends the issuer no attestation evidence). 409 enrolment_not_claimable (unknown, expired or spent code, or another runtime); 400 body_invalid; 429 rate_limited.
Authentication: none — this operation is public.
Request body
application/json — required
Schema: EnrolmentClaimRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
code | string | yes | ||
runtime | EnrolmentRuntime | yes | ||
key_attestation | object | no | Accepted, not used, not kept (ZadQ sends the issuer no attestation evidence). |
Responses
200 — Claimed.
Content type application/json.
Schema: EnrolmentClaimed
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
enrolment_id | string | yes | ||
runtime_token | string | yes | The runtime credential (rt1_…), shown once; sent as Authorization: Bearer on the runtime routes. | |
expires_at | string (date-time) | yes | When the delegate approval expires (keep polling until then). |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/enrolments/claim" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/enrolments/{enrolmentId}
One enrolment (dashboard) or the runtime's long-poll
Under the passkey session: the enrolment. Under the runtime credential, within its scope: the long-poll. ?wait= (0 to 30 seconds) holds the answer while the enrolment is created or claimed; 200 {state, failure?, agent_id?, mint?} with the mint material delivered once (the enrolment then reads minting) and deleted; 204 on every poll after delivery. In runtime mode the material is the issuer's agent offer itself — credential_offer, mint_challenge, expires_at, scope, bundle — with the operator's price line stripped; the runtime redeems it with the published agent client and the person's holder it runs. In browser mode (ZADQ-294) the material is the split mint's MintMaterial the person's browser posted (MintID's stage-2 interface v1.1 §1, to_json()), and the runtime completes it with AgentClient.complete_issuance; the poll waits while the offer is with the browser. Material not taken before its expiry (the offer's in runtime mode, the material's expires_at in browser mode) ends in failed(token_expired). Under the passkey session offer_ready says a browser-mode offer waits to be collected (POST …/offer).
Authentication: passkeySession or runtimeCredential.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
enrolmentId | path | yes | string | |
wait | query | no | integer | Long-poll seconds (runtime credential only), 0 to 30. |
Responses
200 — The enrolment (dashboard) or the poll's answer (runtime).
Content type application/json.
One of:
204 — Runtime only — the material was delivered; nothing more.
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/enrolments/<enrolmentId>" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/enrolments/{enrolmentId}/cancel
Cancel an enrolment (created, claimed, or approved before the material is taken)
The pending approval reads failed(enrolment_cancelled), the price line void (open) or credited (recorded), the runtime credential is revoked. 409 enrolment_not_pending from minting on.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
enrolmentId | path | yes | string |
Responses
200 — Cancelled.
Content type application/json.
Schema: EnrolmentStateAnswer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/enrolments/<enrolmentId>/cancel" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/enrolments/{enrolmentId}/registered
The runtime reports the credential born in it
Under the runtime credential, on a minting enrolment: the credential id the holder received (the issuer never returns it to the operator), its expiry, optionally the scope endpoint, the control hook {url, secret_ref} (the shared secret ZadQ signs a kill with, kept sealed; https on a public address) and usable: true once the agent's scope is anchored (also on a later call). The agent reads registered (or usable), the runtime credential extends to it. Idempotent on (enrolment, credential id); another credential id is 409 enrolment_not_pending. A renewal's report moves the same agent to its new credential.
Authentication: runtimeCredential.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
enrolmentId | path | yes | string |
Request body
application/json — required
Schema: EnrolmentRegisteredRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
credential_id | string | yes | The issuer's handle of the credential (64 hex), as the holder received it. | |
expires_at | string (date-time) | yes | ||
scope_endpoint | string | no | ||
control_hook | EnrolmentControlHook | no | ||
usable | boolean | no | The agent's scope is anchored (it can present its delegation); also on a later call. |
Responses
200 — Registered.
Content type application/json.
Schema: EnrolmentRegistered
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
agent_id | string | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/enrolments/<enrolmentId>/registered" \
-H "Authorization: Bearer <session-credential>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/enrolments/{enrolmentId}/failed
The runtime reports that the mint did not happen
From claimed, approved or minting: failed(reason_code) — a reason code (lowercase words, an optional :-qualified issuer code; anything else reads unspecified). The approval fails, the price line is credited. 409 enrolment_not_pending.
Authentication: runtimeCredential.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
enrolmentId | path | yes | string |
Request body
application/json — required
Schema: EnrolmentFailedRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
reason_code | string | yes |
Responses
200 — Failed.
Content type application/json.
Schema: EnrolmentStateAnswer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/enrolments/<enrolmentId>/failed" \
-H "Authorization: Bearer <session-credential>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/enrolments/{enrolmentId}/offer
The person's browser collects a browser-mode offer, once
Browser mode (ZADQ-294). When the enrolment's price line settled after the approval (the console's mark, a hosted checkout), the issuer's agent offer was asked for then and is held sealed for the person's browser: this answers it once (Cache-Control: no-store), the operator's price line stripped, and deletes it; the enrolment then waits for the browser's material (POST …/mint). When the line settled at the approval, the approve answer carried the offer and nothing is held here. 409 enrolment_not_pending (no offer waits: runtime mode, already collected, or past its expiry); 404 not_found.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
enrolmentId | path | yes | string |
Responses
200 — The offer, once.
Content type application/json.
Schema: BrowserOffer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
offer | object | yes | The issuer's agent offer, the operator's price line stripped (the runtime-mode material shape). | |
expires_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/enrolments/<enrolmentId>/offer" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/enrolments/{enrolmentId}/mint
The person's browser posts the credential step's material, once
Browser mode (ZADQ-294), under the passkey session, on the account's own enrolment once its offer reached the browser: {mint: MintMaterial} — MintMaterial.to_json() of mintToken(offer, holder), MintID's stage-2 interface v1.1 §1 — or {failure: <code>} instead. The material is checked (unknown fields refused; v 1; credential_configuration_id mintid_agent_v1 or mintid_agent_v2; c_nonce 64 hex; expires_at in the future and within ten minutes; issuer_url the configured issuer; bundle_id, when present, the enrolment's bundle; renews_credential_id only on a renewal), held sealed until the runtime's poll takes it once ({state: "minting", mint}), deleted on delivery, never logged; past its expires_at untaken the enrolment fails token_expired and its price line is credited. A failure code (window_lapsed, token_refused, issuer_unavailable, credential_revoked, credential_expired, custody_unavailable, module_trapped, person_cancelled) fails the enrolment the same way. 202 {state}: approved (held) or failed. 400 material_invalid · reason_invalid · body_invalid; 409 enrolment_not_pending (runtime mode, not approved, the offer not handed yet, or a material already posted); 404 not_found.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
enrolmentId | path | yes | string |
Request body
application/json — required
Schema: EnrolmentMintRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
mint | MintMaterial | no | ||
failure | string | no | A code of the closed vocabulary instead of a material. |
Responses
202 — Held for the runtime's poll, or failed.
Content type application/json.
Schema: EnrolmentStateAnswer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/enrolments/<enrolmentId>/mint" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/agents
The account's agents enrolled through the platform
The agents the runtimes reported registered, newest first. State: registered; usable once the runtime reported the scope anchored; expiring within the lease-reminder lead (14 days by default) of the lease end; revoked; expired. Agents minted from the earlier mint form stay on the v0 agents view. Beside ZadQ's state, the issuer's own as the reconciliation last read it (issuer_state, issuer_reason, reconciled_at; ZADQ-296) — an agent whose registered report was lost appears here once the reconciliation recovered it.
Authentication: passkeySession.
Responses
200 — The agents.
Content type application/json.
Schema: PlatformAgentList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
agents | array of PlatformAgent | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/agents" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/agents/{agentId}/stop
Stop — the issuer's revocation through ZadQ
No custody needed. The agent reads revoked; its runtime credentials end; an open renewal is cancelled. A revoked agent answers as it is; 409 agent_not_live for an expired one.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
agentId | path | yes | string |
Responses
200 — Revoked.
Content type application/json.
Schema: EnrolmentStateAnswer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/agents/<agentId>/stop" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/agents/{agentId}/renewals
Renew — a renew approval, then the same machine
Opens a renewal (an enrolment of kind renewal for the agent's runtime) and a renew approval in the inbox; an open renewal answers its approval again. On approval the issuer's renew offer becomes the material; the runtime completes it as in §5.4 and reports the new credential. 409 agent_not_live · kyc_required · product_inactive · credential_not_held (ZADQ-424) · entry_fee_due.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
agentId | path | yes | string |
Responses
202 — The renew approval is pending.
Content type application/json.
Schema: AgentRenewalRequested
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
approval_id | string | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/agents/<agentId>/renewals" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/agents/{agentId}/kill
Kill — only through the runtime's registered control hook
A signed POST to the control hook the runtime registered (the agent's self-revocation needs the agent's custody, which is the runtime's): 202 once the runtime accepted it. 409 control_hook_missing without one (Stop is the way then); 502 control_hook_failed when the hook does not answer 2xx; 409 agent_not_live.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
agentId | path | yes | string |
Responses
202 — The runtime accepted the kill.
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/agents/<agentId>/kill" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/catalogue
The bundles the issuer serves (prices stripped) and ZadQ's plans (no amounts)
The issuer's served bundle catalogue, read through ZadQ (cached ten minutes), each bundle with the keys the enrolment form needs — never its price — and the agent-operator product's plans: id, seats, label. Amounts are never here: they live on the billing provider's checkout page. 503 catalogue_unavailable when the issuer's catalogue was never read. v1.3.30 (ZADQ-472): the plans are the principal plans the deployment offers (kind: principal) and enterprise (kind: contact, its seats the most an Enterprise contract holds today — the issuer's cap per person): sold by contact, activated by ZadQ once agreed, never an amount and never self-serve. No earlier plan and no periods remain.
Authentication: passkeySession.
Responses
200 — The catalogue and the plans.
Content type application/json.
Schema: PlatformCatalogue
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
bundles | array of CatalogueBundle | yes | ||
plans | array of CataloguePlan | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/catalogue" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/products/agent-operator/activate
Activate the agent-operator product with a principal plan
v1.3.30 (ZADQ-472) — the plans an account chooses itself are the principal plans, personal and premium (§5.16; period month or year, yearly when left out): the activation opens in pending_payment with its plan_line, paid before the identity check (POST /v1/price-lines/{id}/pay), then pending_kyc until the responsible person is verified at the plan's grade, then active (product_activated). enterprise is sold by contact and activated by ZadQ from the operator console once agreed (§5.20): 409 plan_by_contact. Any other id: 400 plan_unknown. An account that runs an Enterprise contract, or an earlier plan with a collected fee or seats, answers 409 plan_not_switchable; an earlier plan's activation with nothing collected moves to the principal plan chosen. entry_fee reads null (no entry fee is sold).
v1.3.17 (ZADQ-387, §5.16): Personal → Premium once paid is the switch on either settlement — on the provider, paying the switch line opens a new subscription of Premium's whole price with the credit of the unused period as a one-off credit on the checkout, and the old subscription is cancelled when the new one's checkout completes. A plan closed after its identity check ended refused or withdrawn is chosen again once its refund is paid back (a new period, paid before a new identity check); while the refund is still being paid back, 409 plan_closed.
Authentication: passkeySession.
Request body
application/json — required
Schema: ActivateAgentOperator
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
plan | string | yes | A principal plan's id (personal, premium — v1.3.16; plus is retired). v1.3.30 — enterprise answers 409 plan_by_contact (the console activates it, §5.20). | |
period | string | no | v1.3.14 (§5.16) — the principal plan's billing period, in advance (default year; on a switch, the current one). | "month", "year" |
Responses
200 — The activation.
Content type application/json.
Schema: AgentOperatorActivation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "pending_payment", "pending_kyc", "pending_entry_fee", "active", "suspended", "closed" | |
period | string, nullable | no | v1.3.14 — the principal plan's period. | "month", "year" |
plan_line | all of PriceLine | no | v1.3.14 — the principal plan's seat line for the period (pay it with POST /v1/price-lines/{id}/pay). | |
plan | string | yes | ||
settlement | string | no | "console", "stripe" | |
entry_fee | all of PriceLine | yes | v1.3.30 (ZADQ-472) — always null; no entry fee is sold (kept in the shape for the client app). | |
plan_switch | all of PlanSwitch | no | v1.3.16 — the switch Personal → Premium waiting on its line; null otherwise. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/products/agent-operator/activate" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/products/agent-operator/steps
Open a plan step (§5.16, v1.3.16; no step is offered since v1.3.25)
v1.3.16 (ZADQ-382): the route that opens a plan step (kind agent_extra or grade_a3_option; period month or year, the plan's when left out) for one period, in advance, paid as every line (POST /v1/price-lines/{id}/pay). v1.3.25 (ZADQ-451; Marc, 2026-11-06): a step the deployment's price table does not price is not offered, and no deployment prices one — this route answers 409 line_not_offered on every plan (Personal, Premium, an Enterprise contract), and GET /v1/plans lists no step. Both plans include A3 when a relying party requires it (grade_included: 3). v1.3.27 (ZADQ-451; Marc, 2026-11-07 — the caps as decided): Personal includes 1 bounded agent (seats_max: 1) and the 2nd answers 409 plan_cap_reached on POST /v1/enrolments (the switch to Premium the way on); Premium includes 5 and the 6th answers 409 seats_exhausted (beyond Premium, Enterprise by contact — v1.3.30, §5.20).
Authentication: passkeySession.
Request body
application/json — required
Schema: PlanStepOpen
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | string | yes | "agent_extra", "grade_a3_option" | |
period | string | no | Billed in advance; the plan's period when left out. | "month", "year" |
Responses
200 — The step's line already standing, as it is.
Content type application/json.
Schema: PriceLine
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
period | string, nullable | no | v1.3.14 (§5.16) — the period a principal plan's seat line pays; its amount is the plan's whole price for it. v1.3.15 (§5.17) — the period a managed environment's line pays, in advance. | "month", "year" |
environment | string, nullable | no | v1.3.15 (§5.17) — a managed environment's environment; null on every other line. | "production", "test" |
kind | PriceLineKind | yes | ||
amount_minor | integer (int64), nullable | yes | v1.3.18 (ZADQ-389) — negative on a principal_enrolled line opened since (the month's rebate set off on the invoice; not payable). | |
unit | string, nullable | yes | ||
state | PriceLineState | yes | ||
ref | PriceLineRef | yes | ||
settlement | string | yes | "console", "stripe" | |
channel | string | yes | How the line is collected (ZADQ-324, derived at read time, never stored): invoice on the console settlement (a manual invoice) and for a provider customer whose subscription collects by invoice; card otherwise (the hosted checkout). The dashboard shows "Pay" for card, "on your invoice" for invoice. | "card", "invoice" |
quantity | integer, nullable | no | Seats (seat), lease days (lease_year); v1.3.16 — the month's count of principals enrolled (principal_enrolled); v1.3.18 — on a rebate credit, the rebates settled in the month. | |
bundle | string, nullable | no | ||
vat_treatment | string, nullable | no | v1.3.16 (ZADQ-382) — how the amount stands to VAT, on the lines opened since (null on the lines before). v1.3.29 (ZADQ-469) — every amount is net, ex-VAT: a line opens exclusive (the billing provider adds the VAT at checkout and on the invoice) or reverse_charge (the same net, no VAT, for a business whose customer record holds a valid VAT number of another member state). included is a legacy value: it is never opened now and stays only on lines opened before v1.3.29. | "included", "reverse_charge", "exclusive" |
covers_until | string (date-time), nullable | no | v1.3.16 — the end of the period a step's line (agent_extra, grade_a3_option) pays, from its settlement; null until settled and on every other line. No step is offered since v1.3.25. | |
credit_minor | integer (int64), nullable | no | v1.3.16 — on a switch's seat line (Personal → Premium), the credit of the unused period; amount_minor is the new period's price less it. | |
free_quantity | integer, nullable | no | v1.3.16 — on a principal_enrolled line, the free volume applied to the month's count; null on a rebate credit (v1.3.18). | |
billing_month | string (date), nullable | no | v1.3.16 — on a principal_enrolled line, the month counted (its first day); v1.3.18 — the rebate statement's month. | |
retained_minor | integer (int64), nullable | no | v1.3.17 (ZADQ-387) — on a plan_refund line, the cost of the identity check performed at the person's request, retained; amount_minor is what is paid back. v1.3.29 (ZADQ-469) — net, ex-VAT, on a line exclusive or reverse_charge: the provider's refund pays back amount_minor plus its share of the VAT the payment collected (a legacy included line keeps the amounts it was opened with). | |
refund_reason | string, nullable | no | v1.3.17 — on a plan_refund line, why the plan closed (ZadQ's own code; nothing of the issuer's reason); v1.3.34 (ZADQ-472) — enterprise_replaces_paid_plan, the paid plan replaced by an Enterprise contract (its unused period paid back by hand). | "identity_check_refused", "identity_check_withdrawn", "enterprise_replaces_paid_plan" |
created_at | string (date-time) | yes |
201 — The step's line opened.
Content type application/json.
Schema: PriceLine
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
period | string, nullable | no | v1.3.14 (§5.16) — the period a principal plan's seat line pays; its amount is the plan's whole price for it. v1.3.15 (§5.17) — the period a managed environment's line pays, in advance. | "month", "year" |
environment | string, nullable | no | v1.3.15 (§5.17) — a managed environment's environment; null on every other line. | "production", "test" |
kind | PriceLineKind | yes | ||
amount_minor | integer (int64), nullable | yes | v1.3.18 (ZADQ-389) — negative on a principal_enrolled line opened since (the month's rebate set off on the invoice; not payable). | |
unit | string, nullable | yes | ||
state | PriceLineState | yes | ||
ref | PriceLineRef | yes | ||
settlement | string | yes | "console", "stripe" | |
channel | string | yes | How the line is collected (ZADQ-324, derived at read time, never stored): invoice on the console settlement (a manual invoice) and for a provider customer whose subscription collects by invoice; card otherwise (the hosted checkout). The dashboard shows "Pay" for card, "on your invoice" for invoice. | "card", "invoice" |
quantity | integer, nullable | no | Seats (seat), lease days (lease_year); v1.3.16 — the month's count of principals enrolled (principal_enrolled); v1.3.18 — on a rebate credit, the rebates settled in the month. | |
bundle | string, nullable | no | ||
vat_treatment | string, nullable | no | v1.3.16 (ZADQ-382) — how the amount stands to VAT, on the lines opened since (null on the lines before). v1.3.29 (ZADQ-469) — every amount is net, ex-VAT: a line opens exclusive (the billing provider adds the VAT at checkout and on the invoice) or reverse_charge (the same net, no VAT, for a business whose customer record holds a valid VAT number of another member state). included is a legacy value: it is never opened now and stays only on lines opened before v1.3.29. | "included", "reverse_charge", "exclusive" |
covers_until | string (date-time), nullable | no | v1.3.16 — the end of the period a step's line (agent_extra, grade_a3_option) pays, from its settlement; null until settled and on every other line. No step is offered since v1.3.25. | |
credit_minor | integer (int64), nullable | no | v1.3.16 — on a switch's seat line (Personal → Premium), the credit of the unused period; amount_minor is the new period's price less it. | |
free_quantity | integer, nullable | no | v1.3.16 — on a principal_enrolled line, the free volume applied to the month's count; null on a rebate credit (v1.3.18). | |
billing_month | string (date), nullable | no | v1.3.16 — on a principal_enrolled line, the month counted (its first day); v1.3.18 — the rebate statement's month. | |
retained_minor | integer (int64), nullable | no | v1.3.17 (ZADQ-387) — on a plan_refund line, the cost of the identity check performed at the person's request, retained; amount_minor is what is paid back. v1.3.29 (ZADQ-469) — net, ex-VAT, on a line exclusive or reverse_charge: the provider's refund pays back amount_minor plus its share of the VAT the payment collected (a legacy included line keeps the amounts it was opened with). | |
refund_reason | string, nullable | no | v1.3.17 — on a plan_refund line, why the plan closed (ZadQ's own code; nothing of the issuer's reason); v1.3.34 (ZADQ-472) — enterprise_replaces_paid_plan, the paid plan replaced by an Enterprise contract (its unused period paid back by hand). | "identity_check_refused", "identity_check_withdrawn", "enterprise_replaces_paid_plan" |
created_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/products/agent-operator/steps" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/price-lines
The account's price lines, newest first
Kinds entry | seat | bundle_mint | lease_year | usage; states open | authorised | captured | invoiced | failed | credited | void (failed: the billing provider refused an authorisation — payable again). ref names what the line belongs to (an enrolment or an agent), as the activity log does; the provider's own reference is never shown. amount_minor and unit are the amount the line carries (the bundle's price, the lease priced at settlement), or null when it lives on the provider's price (the entry fee, the seats).
Authentication: passkeySession.
Responses
200 — The lines.
Content type application/json.
Schema: PriceLineList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
lines | array of PriceLine | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/price-lines" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/price-lines/{priceLineId}/pay
Pay a price line — a hosted checkout URL, or the line's state
The entry fee or the seats while the subscription does not exist: the billing provider's hosted checkout (the plan's seats as a licensed quantity and the entry fee when due). A bundle or lease line whose approval waits on it: a card customer's hosted checkout (authorised on completion, captured when the agent is registered, released if the enrolment fails); an invoiced customer's line goes on the open invoice ({state: "invoiced"}). On the console path the answer is the line's state (open until the operator console marks it invoiced). The body names the dashboard's account page the hosted checkout comes back to (return_to, default agent-operator): the way back is <app>/#/account/<page>?billing=done|cancelled (ZADQ-319). The account's customer record must be complete first (ZADQ-307): 409 profile_incomplete with missing otherwise; the hosted page is opened for the account's provider Customer made from the record and asks for neither the address nor the tax id. 400 body_invalid (an unknown page); 404 price_line_not_found; 409 price_line_not_payable (the line is not open or failed: already authorised, captured, invoiced, credited or void — ZADQ-324) · price_line_not_due (an open line not payable yet: its approval has not come, the subscription already carries it, the usage fee) · kyc_required · profile_incomplete; 502 billing_provider_failed. v1.3.17 (ZADQ-387): a plan_refund line is paid back to the person, never paid — 409 price_line_not_payable; a switch's seat line on the provider opens the switch's hosted checkout (Premium's whole price, the credit as a one-off credit on the checkout).
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
priceLineId | path | yes | string |
Request body
application/json
Schema: PriceLinePay
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
return_to | string | no | The dashboard's account page the hosted checkout returns to (account, verification, agent-operator (default), enrolments, approvals, agents, billing, activity). | "account", "verification", "agent-operator", "enrolments", "approvals", "agents", "billing", "activity" |
Responses
200 — A checkout URL or the state.
Content type application/json.
Schema: PriceLinePayment
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
checkout_url | string | no | The billing provider's hosted checkout page. | |
state | PriceLineState | no |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/price-lines/<priceLineId>/pay" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/kyc/sessions
Open the responsible person's KYC session (platform API v1 §5.2)
The responsible person's verification at the issuer, operator type person, on the agent-operator machinery: the account's own record — no wallet, owned by the account from creation — opens a session at the KYC boundary. 201 {session_id, state: "pending", handoff_url, expires_at}. When the account already has a record: a pending session is returned as it is (200); an approved one with its window open answers 409 kyc_current; an expired one, or one whose principal credential its holder revoked, opens a new session on the same record (201); after a rejection or a withdrawal a new record is opened (201).
sandbox (<outcome>[:<option>…], e.g. approved:g2) picks the session's outcome on a staging instance whose issuer runs MintID's sandbox KYC driver, and nowhere else: 400 sandbox_hint_not_available elsewhere, 400 invalid_sandbox_hint when malformed or naming an identity option (this service carries no identity data, not even synthetic). ZadQ keeps the session handle and the window — never identity data.
biometric_consent: {version} is required (ZADQ-331; GDPR Art. 9(2)(a)): the person's explicit consent to the face comparison, given on ZadQ's page by the button whose label is the consent, before the verification link is opened; version is the label of the text shown. Absent (an empty body included): 409 biometric_consent_required; another label than the deployment's (GET /v1/me → biometric_consent.version_required): 409 biometric_consent_version_stale, the current label in the detail. Checked after the body's own 400s and before anything else — when refused nothing reaches the issuer and nothing is recorded. Accepted, the consent is recorded (version, time, the session handed out) and the activity log gains biometric_consent_given, whenever a session is handed out to be opened — a new one (201) or the pending one returned as it is (200); not on 409 kyc_current. "Not now" on the page is the absence of this call.
Authentication: passkeySession.
Request body
application/json
Schema: KycSessionCreate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
sandbox | string | no | Staging only: the sandbox KYC driver's outcome grammar without its sandbox: prefix (<outcome>[:<option>…], e.g. approved:g2, rejected, expired). Identity options are refused. | |
biometric_consent | BiometricConsentGiven | no |
Responses
200 — The account's pending session, as it is.
Content type application/json.
Schema: KycSession
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | The issuer's KYC session handle (opaque). | |
state | string | yes | "pending", "approved", "rejected", "expired", "withdrawn" | |
handoff_url | string, nullable | no | Where the person completes the verification at the issuer's provider; while pending, and only once a consent to the face comparison is recorded for this session (ZADQ-331) — absent (null) otherwise, with biometric_consent_required: true. | |
biometric_consent_required | boolean | no | While pending (ZADQ-331): true when no consent to the face comparison is recorded for this session (one opened before the rule) — the link is withheld until POST /v1/kyc/sessions/{id}/biometric-consent records one. | |
expires_at | string (date-time) | no | The proofing deadline of a pending session. | |
grade | integer, nullable | yes | The issuer's assurance grade the approval was recorded at (ZADQ-321); null while not approved or where the boundary named none. | |
reusable_until | string (date-time), nullable | yes | The end of an approved session's reuse window; the principal credential expires exactly with it. | |
credential | KycCredential | yes |
201 — A new session, pending.
Content type application/json.
Schema: KycSession
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | The issuer's KYC session handle (opaque). | |
state | string | yes | "pending", "approved", "rejected", "expired", "withdrawn" | |
handoff_url | string, nullable | no | Where the person completes the verification at the issuer's provider; while pending, and only once a consent to the face comparison is recorded for this session (ZADQ-331) — absent (null) otherwise, with biometric_consent_required: true. | |
biometric_consent_required | boolean | no | While pending (ZADQ-331): true when no consent to the face comparison is recorded for this session (one opened before the rule) — the link is withheld until POST /v1/kyc/sessions/{id}/biometric-consent records one. | |
expires_at | string (date-time) | no | The proofing deadline of a pending session. | |
grade | integer, nullable | yes | The issuer's assurance grade the approval was recorded at (ZADQ-321); null while not approved or where the boundary named none. | |
reusable_until | string (date-time), nullable | yes | The end of an approved session's reuse window; the principal credential expires exactly with it. | |
credential | KycCredential | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/kyc/sessions" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/kyc/sessions/{kycSessionId}
The responsible person's KYC session, brought up to date
The session's state after the boundary is read: pending (with handoff_url and expires_at), approved (with reusable_until, the end of the reuse window — the principal credential expires exactly with it), rejected, expired (the proofing deadline passed or the window closed: verify again with POST /v1/kyc/sessions) or withdrawn. credential is the principal credential's state in the operator's runtime. grade is the issuer's assurance grade the approval was recorded at (1..4; ZADQ-321), null while not approved or where the boundary named none. 404 not_found unless the session is the current session of one of the account's records.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
kycSessionId | path | yes | string | The issuer's KYC session handle (opaque), as session_id names it. |
Responses
200 — The session.
Content type application/json.
Schema: KycSession
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | The issuer's KYC session handle (opaque). | |
state | string | yes | "pending", "approved", "rejected", "expired", "withdrawn" | |
handoff_url | string, nullable | no | Where the person completes the verification at the issuer's provider; while pending, and only once a consent to the face comparison is recorded for this session (ZADQ-331) — absent (null) otherwise, with biometric_consent_required: true. | |
biometric_consent_required | boolean | no | While pending (ZADQ-331): true when no consent to the face comparison is recorded for this session (one opened before the rule) — the link is withheld until POST /v1/kyc/sessions/{id}/biometric-consent records one. | |
expires_at | string (date-time) | no | The proofing deadline of a pending session. | |
grade | integer, nullable | yes | The issuer's assurance grade the approval was recorded at (ZADQ-321); null while not approved or where the boundary named none. | |
reusable_until | string (date-time), nullable | yes | The end of an approved session's reuse window; the principal credential expires exactly with it. | |
credential | KycCredential | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/kyc/sessions/<kycSessionId>" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/kyc/sessions/{kycSessionId}/withdraw
Withdraw the responsible person's consent on the session
The withdrawal is recorded at the boundary on the session (terminal there; everything it backs is revoked upstream with reason consent_withdrawn), the record reads withdrawn, an offered or held principal credential reads revoked, and the agents minted on it are brought along. Terminal: the next verification is a new session on a new record. 409 invalid_state once rejected or withdrawn; 501 not_available when the substrate records no withdrawal.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
kycSessionId | path | yes | string | The issuer's KYC session handle (opaque), as session_id names it. |
Responses
200 — The session, withdrawn.
Content type application/json.
Schema: KycSession
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | The issuer's KYC session handle (opaque). | |
state | string | yes | "pending", "approved", "rejected", "expired", "withdrawn" | |
handoff_url | string, nullable | no | Where the person completes the verification at the issuer's provider; while pending, and only once a consent to the face comparison is recorded for this session (ZADQ-331) — absent (null) otherwise, with biometric_consent_required: true. | |
biometric_consent_required | boolean | no | While pending (ZADQ-331): true when no consent to the face comparison is recorded for this session (one opened before the rule) — the link is withheld until POST /v1/kyc/sessions/{id}/biometric-consent records one. | |
expires_at | string (date-time) | no | The proofing deadline of a pending session. | |
grade | integer, nullable | yes | The issuer's assurance grade the approval was recorded at (ZADQ-321); null while not approved or where the boundary named none. | |
reusable_until | string (date-time), nullable | yes | The end of an approved session's reuse window; the principal credential expires exactly with it. | |
credential | KycCredential | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/kyc/sessions/<kycSessionId>/withdraw" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/kyc/sessions/{kycSessionId}/biometric-consent
Record the consent to the face comparison on a pending session (ZADQ-331)
For a pending session that has no consent recorded (opened before the rule, or its consent not written): the person's consent to the face comparison, given on ZadQ's page, {version} the label of the text shown. 409 biometric_consent_required without a version, 409 biometric_consent_version_stale (the current label in the detail) with another label — checked before the session is read at the boundary: nothing reaches the issuer when refused. Then 409 invalid_state unless the session is pending. Accepted, the consent is recorded (version, time, this session; activity biometric_consent_given) and the session is returned with its handoff_url. A repeat records the consent again (each press of the button is a consent given).
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
kycSessionId | path | yes | string | The issuer's KYC session handle (opaque), as session_id names it. |
Request body
application/json — required
Schema: BiometricConsentGiven
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | The consent text's version label (e.g. 2026-10.2). |
Responses
200 — The session, with its link.
Content type application/json.
Schema: KycSession
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | The issuer's KYC session handle (opaque). | |
state | string | yes | "pending", "approved", "rejected", "expired", "withdrawn" | |
handoff_url | string, nullable | no | Where the person completes the verification at the issuer's provider; while pending, and only once a consent to the face comparison is recorded for this session (ZADQ-331) — absent (null) otherwise, with biometric_consent_required: true. | |
biometric_consent_required | boolean | no | While pending (ZADQ-331): true when no consent to the face comparison is recorded for this session (one opened before the rule) — the link is withheld until POST /v1/kyc/sessions/{id}/biometric-consent records one. | |
expires_at | string (date-time) | no | The proofing deadline of a pending session. | |
grade | integer, nullable | yes | The issuer's assurance grade the approval was recorded at (ZADQ-321); null while not approved or where the boundary named none. | |
reusable_until | string (date-time), nullable | yes | The end of an approved session's reuse window; the principal credential expires exactly with it. | |
credential | KycCredential | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/kyc/sessions/<kycSessionId>/biometric-consent" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/kyc/sessions/{kycSessionId}/credential/offer
Hand out the offer of the person's identity credential to the runtime, once (erratum E3)
Platform API v1.2.1, erratum E3: the hand-off of the responsible person's identity credential — the principal the account's agents are minted from — to the holder in the operator's runtime (stage 1, principal_mode: runtime), under the passkey session (the v0 wallet path's offer is retired since v1.3.33): the offer is created from the approved session on the issuer's route and returned exactly once (Cache-Control: no-store); the operator's runtime redeems it at once with the holder library, and 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 code and the credential expire exactly with the verification. 409 entry_fee_due until the entry fee is recorded, kyc_required unless approved with the window open, reverification_required after the holder revoked the credential on this verification, invalid_state while one is held; 501 not_available when the substrate offers no credential rail.
location (ZADQ-293, §5.8; MintID ADR-0027: one identity credential per custody location, all from the same KYC session) picks the place the credential is offered for: server (the default, the behaviour above) or browser — a second identity credential offer from the same approved session for the person's browser holder, judged on the browser location's own state: 409 invalid_state while a browser credential is held (revoke it first; custody bytes never move between places), reverification_required after the holder revoked the browser credential on this verification. The answer's credential block is the state of the location offered for.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
kycSessionId | path | yes | string | The issuer's KYC session handle (opaque), as session_id names it. |
Request body
application/json
Schema: KycCredentialOfferRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
location | CustodyLocation | no |
Responses
201 — The offer, handed out once, and when it expires.
Content type application/json.
Schema: KycCredentialOffer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
location | CustodyLocation | no | ||
offer | object | yes | The credential offer object, as the issuer returned it — opaque, one-shot; redeem it at once. | |
expires_at | string (date-time) | yes | When the code and the credential it yields expire — the verification's own window end at the latest. No grace. | |
credential | KycCredential | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/kyc/sessions/<kycSessionId>/credential/offer" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/kyc/sessions/{kycSessionId}/credential
Report the person's credential state from the operator's runtime (erratum E3)
Platform API v1.2.1, erratum E3: what the operator's runtime did with the offer — held (optionally with an opaque reference of its choosing; the record reads credential held and the account's enrolments can be backed by it) or self_revoked (the holder revoked the credential through the network's privacy relay; revoked is the older spelling of the same report). A self_revoked report is recorded as the state change and nothing else — no event, no time, no log line; the way back is a new verification (POST /v1/kyc/sessions). 409 invalid_state when no offer was handed out on this verification.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
kycSessionId | path | yes | string | The issuer's KYC session handle (opaque), as session_id names it. |
Request body
application/json — required
Schema: KycCredentialReport
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | held, or self_revoked (revoked is the older spelling of the same report). | "held", "self_revoked", "revoked" |
credential_ref | string | no | An opaque reference of the runtime's choosing for the credential it holds. Never a key. |
Responses
200 — The session with the reported credential state.
Content type application/json.
Schema: KycSession
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | The issuer's KYC session handle (opaque). | |
state | string | yes | "pending", "approved", "rejected", "expired", "withdrawn" | |
handoff_url | string, nullable | no | Where the person completes the verification at the issuer's provider; while pending, and only once a consent to the face comparison is recorded for this session (ZADQ-331) — absent (null) otherwise, with biometric_consent_required: true. | |
biometric_consent_required | boolean | no | While pending (ZADQ-331): true when no consent to the face comparison is recorded for this session (one opened before the rule) — the link is withheld until POST /v1/kyc/sessions/{id}/biometric-consent records one. | |
expires_at | string (date-time) | no | The proofing deadline of a pending session. | |
grade | integer, nullable | yes | The issuer's assurance grade the approval was recorded at (ZADQ-321); null while not approved or where the boundary named none. | |
reusable_until | string (date-time), nullable | yes | The end of an approved session's reuse window; the principal credential expires exactly with it. | |
credential | KycCredential | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/kyc/sessions/<kycSessionId>/credential" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/custody
The person's identity credential at each custody location
Platform API v1.2.1 §5.8 (MintID ADR-0027, accepted 2026-10-18): one identity credential per custody location, server (the holder in the operator's runtime, stage 1 — the agent-operator record's credential block, read here, never duplicated) and browser (the person's browser holder, stage 2 — the ciphertext store of /v1/custody/browser), all backed by the account's one KYC session: both expire with it, the session's withdrawal revokes both. State only; never a byte of custody.
Authentication: passkeySession.
Responses
200 — The two locations.
Content type application/json.
Schema: CustodyLocations
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
credentials | array of CustodyLocationState | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/custody" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/custody/browser
Read the browser credential's ciphertext and wraps
The account's browser-location credential as last written: the state, the version, the ciphertext (base64; absent once revoked or before the first upload) and the wraps — per passkey, the PRF input and HKDF salt the browser drew and the wrapped data key. The browser evaluates the PRF on its passkey, derives the key-encryption key, unwraps the data key and decrypts in page memory; this service holds no key and performs no step of it: a ciphertext the service cannot open is not custody. rotation_due (v1.3.2): a wrap went without a rotation of the data key — the browser rotates on its next opening of the credential (PUT with rotation: true). Cache-Control: no-store. 404 not_found before any browser offer was handed out.
Authentication: passkeySession.
Responses
200 — The credential with its ciphertext and wraps.
Content type application/json.
Schema: BrowserCustody
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
location | CustodyLocation | yes | ||
state | string | yes | "offered", "held", "expired", "revoked", "self_revoked" | |
kyc_session_id | string | no | The session handle the credential was offered on. | |
scheme | string | yes | The browser's name for the wrap and AEAD construction (default prf-hkdf-aead-v1). Never interpreted here. | |
custody_version | integer (int64) | yes | ||
rotation_due | boolean | yes | v1.3.2: true once a wrap went without a rotation of the data key (a wrap removed, or a passkey removed with its wrap); cleared by the next rotation (PUT with rotation: true). | |
ciphertext | string (byte) | no | Base64 of the ciphertext, as uploaded. | |
issuer_credential_handle | string | no | The issuer's opaque credential handle, when the browser reported it. | |
offered_at | string (date-time) | no | ||
issued_at | string (date-time) | no | ||
expires_at | string (date-time) | no | ||
wraps | array of CustodyWrap | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/custody/browser" \
--cookie "__Host-passkey_session=<api-key>"
PUT /v1/custody/browser
Upload the browser credential's ciphertext with its version
The browser's upload after issuance, and after every witness refresh: the holder's storage bytes encrypted under the data key, the version it read (custody_version: 0 on the first upload), optionally the scheme name, the issuer's opaque credential handle, the issuance time and the wraps. The first upload (201) turns the offered credential into held and must carry at least one wrap; later uploads (200) must carry the stored version and advance it by one — 409 custody_version_conflict otherwise, with the stored version in custody_version (another browser of the person uploaded meanwhile: read and retry on its bytes). After the first upload a plain upload keeps the stored wraps and carries none (400 body_invalid with wraps and without rotation).
The rotation (v1.3.2, ZADQ-293; MintID's binding scheme): with rotation: true the browser drew a new data key, sealed the storage bytes under it and lists the wrap of every passkey that stays. In one write: the ciphertext replaced, one version step, each listed wrap replaced (created_at now), every wrap not listed removed (one custody_wrap_removed each; several may go, never all), rotation_due cleared; 200. Refusals change nothing: 409 custody_version_conflict; 400 wraps_required (no list, a wrap missing a field, a passkey twice, or a passkey that holds no wrap now — a rotation never adds one); 409 last_wrap (an empty list); 409 invalid_state before the first upload.
409 passkey_not_on_account for a passkey that is not one of the account's, invalid_state without a live browser offer, 400 body_invalid. Activity (§5.7): custody_uploaded on the first upload only.
Authentication: passkeySession.
Request body
application/json — required
Schema: BrowserCustodyUpload
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
ciphertext | string (byte) | yes | Base64 of the encrypted holder record (1 to 262144 bytes decoded). | |
custody_version | integer (int64) | yes | The version the browser read; 0 on the first upload. The stored version advances by one. | |
scheme | string | no | ||
issuer_credential_handle | string | no | The issuer's opaque credential handle. Never a key, a code or a proof. | |
issued_at | string (date-time) | no | ||
wraps | array of CustodyWrapInput | no | Required on the first upload (at least one); on a rotation the wrap of every passkey that stays, under the new data key (empty: 409 last_wrap); refused on a later plain upload. | |
rotation | boolean | no | v1.3.2: this upload rotates the data key — the ciphertext and every wrap replaced in one write, wraps not listed removed, rotation_due cleared. |
Responses
200 — Re-uploaded; the version advanced.
Content type application/json.
Schema: BrowserCustody
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
location | CustodyLocation | yes | ||
state | string | yes | "offered", "held", "expired", "revoked", "self_revoked" | |
kyc_session_id | string | no | The session handle the credential was offered on. | |
scheme | string | yes | The browser's name for the wrap and AEAD construction (default prf-hkdf-aead-v1). Never interpreted here. | |
custody_version | integer (int64) | yes | ||
rotation_due | boolean | yes | v1.3.2: true once a wrap went without a rotation of the data key (a wrap removed, or a passkey removed with its wrap); cleared by the next rotation (PUT with rotation: true). | |
ciphertext | string (byte) | no | Base64 of the ciphertext, as uploaded. | |
issuer_credential_handle | string | no | The issuer's opaque credential handle, when the browser reported it. | |
offered_at | string (date-time) | no | ||
issued_at | string (date-time) | no | ||
expires_at | string (date-time) | no | ||
wraps | array of CustodyWrap | yes |
201 — The first upload; the credential reads held.
Content type application/json.
Schema: BrowserCustody
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
location | CustodyLocation | yes | ||
state | string | yes | "offered", "held", "expired", "revoked", "self_revoked" | |
kyc_session_id | string | no | The session handle the credential was offered on. | |
scheme | string | yes | The browser's name for the wrap and AEAD construction (default prf-hkdf-aead-v1). Never interpreted here. | |
custody_version | integer (int64) | yes | ||
rotation_due | boolean | yes | v1.3.2: true once a wrap went without a rotation of the data key (a wrap removed, or a passkey removed with its wrap); cleared by the next rotation (PUT with rotation: true). | |
ciphertext | string (byte) | no | Base64 of the ciphertext, as uploaded. | |
issuer_credential_handle | string | no | The issuer's opaque credential handle, when the browser reported it. | |
offered_at | string (date-time) | no | ||
issued_at | string (date-time) | no | ||
expires_at | string (date-time) | no | ||
wraps | array of CustodyWrap | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X PUT "<base-url>/v1/custody/browser" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/custody/browser/wraps
Add the data key wrapped under one more of the account's passkeys
Multi-wrap: the data key wrapped under another passkey of the account, so losing one passkey is not losing the credential. A wrap for a passkey that already has one is replaced. The body carries the custody_version the browser read (v1.3.2): a wrap of a data key another page rotated away would open nothing, so another version is 409 custody_version_conflict (the stored version in custody_version) and nothing changes; the addition is one version step and the answer carries the new one. 409 passkey_not_on_account for a passkey of another account or none; invalid_state before the first upload. The answer carries the wraps and no ciphertext. Activity: custody_wrap_added.
Authentication: passkeySession.
Request body
application/json — required
Schema: CustodyWrapAdd
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
passkey_id | string | yes | One of the account's passkeys. | |
prf_salt | string (byte) | yes | ||
wrapped_dek | string (byte) | yes | ||
custody_version | integer (int64) | yes | The version the browser read; the addition advances it by one. |
Responses
201 — The credential's wraps after the addition.
Content type application/json.
Schema: BrowserCustody
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
location | CustodyLocation | yes | ||
state | string | yes | "offered", "held", "expired", "revoked", "self_revoked" | |
kyc_session_id | string | no | The session handle the credential was offered on. | |
scheme | string | yes | The browser's name for the wrap and AEAD construction (default prf-hkdf-aead-v1). Never interpreted here. | |
custody_version | integer (int64) | yes | ||
rotation_due | boolean | yes | v1.3.2: true once a wrap went without a rotation of the data key (a wrap removed, or a passkey removed with its wrap); cleared by the next rotation (PUT with rotation: true). | |
ciphertext | string (byte) | no | Base64 of the ciphertext, as uploaded. | |
issuer_credential_handle | string | no | The issuer's opaque credential handle, when the browser reported it. | |
offered_at | string (date-time) | no | ||
issued_at | string (date-time) | no | ||
expires_at | string (date-time) | no | ||
wraps | array of CustodyWrap | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/custody/browser/wraps" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
DELETE /v1/custody/browser/wraps/{passkeyId}
Remove one passkey's wrap (never the last one)
Removes the wrap without a rotation (v1.3.2): one version step and rotation_due set — the stored ciphertext stays under the data key that passkey once read until the browser rotates it (PUT with rotation: true); the dashboard calls this route only when a passkey that stays cannot answer. 200 the credential without ciphertext (204 before v1.3.2). 409 last_wrap for the last one: a held credential nobody could open is not a state — revoke the credential instead (POST /v1/custody/browser/report). 404 not_found when the passkey carries no wrap. The same rule guards DELETE /v1/me/passkeys/{id}: the passkey that carries the last wrap of a live browser credential is not removed (409 last_wrap); another passkey's wrap goes with it the same way. Activity: custody_wrap_removed, written with the removal.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
passkeyId | path | yes | string |
Responses
200 — The credential's wraps after the removal, its new version, rotation_due set.
Content type application/json.
Schema: BrowserCustody
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
location | CustodyLocation | yes | ||
state | string | yes | "offered", "held", "expired", "revoked", "self_revoked" | |
kyc_session_id | string | no | The session handle the credential was offered on. | |
scheme | string | yes | The browser's name for the wrap and AEAD construction (default prf-hkdf-aead-v1). Never interpreted here. | |
custody_version | integer (int64) | yes | ||
rotation_due | boolean | yes | v1.3.2: true once a wrap went without a rotation of the data key (a wrap removed, or a passkey removed with its wrap); cleared by the next rotation (PUT with rotation: true). | |
ciphertext | string (byte) | no | Base64 of the ciphertext, as uploaded. | |
issuer_credential_handle | string | no | The issuer's opaque credential handle, when the browser reported it. | |
offered_at | string (date-time) | no | ||
issued_at | string (date-time) | no | ||
expires_at | string (date-time) | no | ||
wraps | array of CustodyWrap | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X DELETE "<base-url>/v1/custody/browser/wraps/<passkeyId>" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/custody/browser/report
Report that the browser credential ended
What the browser learnt about its credential: revoked (the issuer's policy, as the holder's witness refresh reported it) or self_revoked (the holder revoked it through the network's privacy relay). Per-place revocation (ADR-0027): the server location is untouched. The ciphertext is cleared and the wraps deleted: nothing of a credential that is gone stays here. A self_revoked report is recorded as the state change and nothing else — no event, no log line (MintID R11); revoked writes custody_revoked to the activity. The way back after a self-revocation is a new verification (POST /v1/kyc/sessions). 409 invalid_state without a live browser credential.
Authentication: passkeySession.
Request body
application/json — required
Schema: BrowserCustodyReport
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "revoked", "self_revoked" |
Responses
200 — The credential, ended.
Content type application/json.
Schema: BrowserCustody
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
location | CustodyLocation | yes | ||
state | string | yes | "offered", "held", "expired", "revoked", "self_revoked" | |
kyc_session_id | string | no | The session handle the credential was offered on. | |
scheme | string | yes | The browser's name for the wrap and AEAD construction (default prf-hkdf-aead-v1). Never interpreted here. | |
custody_version | integer (int64) | yes | ||
rotation_due | boolean | yes | v1.3.2: true once a wrap went without a rotation of the data key (a wrap removed, or a passkey removed with its wrap); cleared by the next rotation (PUT with rotation: true). | |
ciphertext | string (byte) | no | Base64 of the ciphertext, as uploaded. | |
issuer_credential_handle | string | no | The issuer's opaque credential handle, when the browser reported it. | |
offered_at | string (date-time) | no | ||
issued_at | string (date-time) | no | ||
expires_at | string (date-time) | no | ||
wraps | array of CustodyWrap | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/custody/browser/report" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/verifier-keys
The verifier records ZadQ pins for the browser holder (staticVerifierKeys)
The records the browser holder passes to staticVerifierKeys (MintID's @mintid-net/holder 0.1.0, whose VerifierKeys shape each record is: verifier_id, the record's state and its request_signing_keys, hex bytes and proto enum numbers). A browser has no light client, so the verifier keys it accepts challenges from are pinned server-side: this deployment serves the set its configuration pins (VERIFIER_KEY_RECORDS), recorded by the operator from a proven read of the chain — every value ics23-proven against the anchor's app hash with the published verifier SDK's chain client; this service runs no MintID chain reader of its own. A key rotation reaches the holder only when the set is recorded again. 501 not_available when the deployment pins none: the holder then refuses every challenge (challenge_key_unknown), the fail-closed answer. Cache-Control: private, max-age=300.
Authentication: passkeySession.
Responses
200 — The pinned records.
Content type application/json.
Schema: PinnedVerifierKeys
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
records | array of PinnedVerifierKeyRecord | yes | ||
pinned_at | string (date-time) | no | When the operator recorded the set from its proven read, when the configuration says. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/verifier-keys" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/holder/network
The network the browser holder talks to (and the browser path's capability read)
What the browser holder needs to reach the network on its own: the issuer's base URL (the six holder routes, CORS-enabled for the app's origin by the issuer), the chain id, the self-revocation relay and, when configured, a chain RPC for the holder's own read of a self-revocation (submitSelfRevocation's chain). The dashboard offers the browser path only when this answers 200 (zadq-public ZADQ-295's proposal 8); 501 not_available on a deployment without the network configured (fake mode). Public facts of the network, no account data. Cache-Control: private, max-age=300.
Authentication: passkeySession.
Responses
200 — The network.
Content type application/json.
Schema: HolderNetwork
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
issuer_url | string | yes | ||
chain_id | string | yes | ||
relay_url | string | yes | ||
chain_rpc_url | string, nullable | no |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/holder/network" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/verifiers
The account's verifier records, oldest first (platform API v1 §5.15)
The business as verifier of record under its own exact origin and request-signing key: each record with its current key, the keys it replaced, the evidence summary, the issuer's commitment handle and the admission request. ZadQ's own record — no proof, pseudonym, envelope or decision of the issuer, no private key.
Authentication: passkeySession.
Responses
200 — The records.
Content type application/json.
Schema: VerifierList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
verifiers | array of VerifierRecord | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/verifiers" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/verifiers
Open a verifier record — the exact origin and the request-signing key as the kit generated them (§5.15)
201 the record, requested. origin is exactly https://<host>[:<port>]: a lowercase DNS host of at least two labels, no IP literal, an optional port other than 443, no path (not even /), query, fragment or user-info — not normalised (400 origin_invalid, the detail names the rule). request_signing_key is the public half: key_id 64 lowercase hex, algorithm ed25519 (32-byte public key) or ecdsa_p256 (the SEC1 point, 33 or 65 bytes), hex (400 key_invalid). ZadQ never receives the private key: a member named like one (private_key, secret, seed, d, …) or a key of the private form's length answers 400 private_key_refused before anything else is read, and nothing of the body is kept or logged. 409 origin_in_use when another live record holds the origin (its holder is never named); 409 account_blocked.
Authentication: passkeySession.
Request body
application/json — required
Schema: VerifierCreate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
origin | string | yes | The exact origin, https://<host>[:<port>], not normalised. | |
request_signing_key | VerifierKeyInput | yes |
Responses
201 — Created.
Content type application/json.
Schema: VerifierRecord
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
origin | string | yes | ||
state | VerifierState | yes | ||
active | boolean | yes | ||
managed | boolean | yes | ||
evidence_format | string | yes | The evidence's format: bip-0005/1 (v1.3.22, ZADQ-431), the format a record without an upload expects too. A record that holds an upload made before v1.3.22 reads pending-MINT-599 until the business uploads the v1 document. | |
operator_account | string, nullable | yes | The bech32 account the bIP-0005 v1 evidence names — the account that signs the registration on the chain (v1.3.22, ZADQ-431); public. Null without a v1 upload. | |
request_signing_key | VerifierKey | yes | ||
previous_keys | array of VerifierPreviousKey | yes | ||
evidence | all of VerifierEvidenceSummary | yes | ||
commitment_handle | string, nullable | yes | The recorded commitment's commitment_hex (MINT-600; v1.3.24), null before one; kept after its reuse window ends. | |
commitment | VerifierRecordCommitment | yes | ||
admission | all of VerifierAdmission | yes | ||
created_at | string (date-time) | yes | ||
updated_at | string (date-time) | yes | ||
withdrawn_at | string (date-time), nullable | yes | ||
evidence_renewed_at | string (date-time), nullable | yes | v1.3.23 (ZADQ-436): when the current evidence document was uploaded as a renewal on the admitted record; null while it is the one the record was admitted with. | |
renewal_reminder_at | string (date-time), nullable | yes | v1.3.23: the revalidation's reminder date — the last renewal, or the admission's decision before one, plus the reminder (150 days by default; configuration). Null unless admitted. | |
renewal_due_at | string (date-time), nullable | yes | v1.3.23: the revalidation's due date — the same start plus the chain's revalidation window (180 days by default; configuration, never read from the chain). Null unless admitted. | |
renewal_due | boolean | yes | v1.3.23 — the due date is past and no renewal was uploaded since; false unless admitted. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/verifiers" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/verifiers/{verifierId}
One verifier record (§5.15)
404 not_found for another account's record.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Responses
200 — The record.
Content type application/json.
Schema: VerifierRecord
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
origin | string | yes | ||
state | VerifierState | yes | ||
active | boolean | yes | ||
managed | boolean | yes | ||
evidence_format | string | yes | The evidence's format: bip-0005/1 (v1.3.22, ZADQ-431), the format a record without an upload expects too. A record that holds an upload made before v1.3.22 reads pending-MINT-599 until the business uploads the v1 document. | |
operator_account | string, nullable | yes | The bech32 account the bIP-0005 v1 evidence names — the account that signs the registration on the chain (v1.3.22, ZADQ-431); public. Null without a v1 upload. | |
request_signing_key | VerifierKey | yes | ||
previous_keys | array of VerifierPreviousKey | yes | ||
evidence | all of VerifierEvidenceSummary | yes | ||
commitment_handle | string, nullable | yes | The recorded commitment's commitment_hex (MINT-600; v1.3.24), null before one; kept after its reuse window ends. | |
commitment | VerifierRecordCommitment | yes | ||
admission | all of VerifierAdmission | yes | ||
created_at | string (date-time) | yes | ||
updated_at | string (date-time) | yes | ||
withdrawn_at | string (date-time), nullable | yes | ||
evidence_renewed_at | string (date-time), nullable | yes | v1.3.23 (ZADQ-436): when the current evidence document was uploaded as a renewal on the admitted record; null while it is the one the record was admitted with. | |
renewal_reminder_at | string (date-time), nullable | yes | v1.3.23: the revalidation's reminder date — the last renewal, or the admission's decision before one, plus the reminder (150 days by default; configuration). Null unless admitted. | |
renewal_due_at | string (date-time), nullable | yes | v1.3.23: the revalidation's due date — the same start plus the chain's revalidation window (180 days by default; configuration, never read from the chain). Null unless admitted. | |
renewal_due | boolean | yes | v1.3.23 — the due date is past and no renewal was uploaded since; false unless admitted. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/verifiers/<verifierId>" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/verifiers/{verifierId}/evidence
The domain-control evidence file to publish at the origin, and its digest (§5.15; bIP-0005 v1)
The file as uploaded (content_base64), its digest (lowercase hex), the format and its digest rule, the operator account the document names, and where to publish it (publish_path, publish_url). format: bip-0005/1 (v1.3.22, ZADQ-431): the digest is SHA-256 over the RFC 8785 canonical form (digest_rule: sha256-rfc8785). A record that holds an upload made before v1.3.22 keeps it and reads format: pending-MINT-599 with digest_rule: sha256 (over the exact bytes) until the business uploads the v1 document. v1.3.23 (ZADQ-436): renewed_at and renewal_check when the file is a renewal on the admitted record (the console's served-file check of it), and history, the documents it replaced, the newest first. 404 not_found before the upload.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Responses
200 — The evidence.
Content type application/json.
Schema: VerifierEvidence
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
format | string | yes | bip-0005/1 (v1.3.22, ZADQ-431); pending-MINT-599 on a record that holds an upload made before v1.3.22. | |
digest | string | yes | ||
digest_rule | string | yes | sha256-rfc8785 for bip-0005/1: SHA-256 over the RFC 8785 canonical form (equal to the SHA-256 of the served bytes when the served file is canonical). sha256 for pending-MINT-599: over the exact bytes. | "sha256", "sha256-rfc8785" |
operator_account | string, nullable | yes | The bech32 account the v1 document names; null for pending-MINT-599. | |
size_bytes | integer | yes | ||
content_base64 | string | yes | ||
publish_path | string | yes | ||
publish_url | string | yes | ||
uploaded_at | string (date-time) | yes | ||
renewed_at | string (date-time), nullable | yes | v1.3.23 (ZADQ-436) — set when this document came as a renewal on the admitted record. | |
renewal_check | all of VerifierRenewalCheck | yes | v1.3.23 — the console's served-file check of this renewed document; null before it, or without a renewal. | |
history | array of VerifierEvidencePrevious | yes | v1.3.23 — the documents renewals replaced, the newest first; empty before a renewal. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/verifiers/<verifierId>/evidence" \
--cookie "__Host-passkey_session=<api-key>"
PUT /v1/verifiers/{verifierId}/evidence
Upload the bIP-0005 v1 evidence document the kit produced (§5.15)
Exactly the bytes the kit produced, standard base64, 1 byte to 16 KiB (400 body_invalid otherwise). The file is a bIP-0005 v1 document (v1.3.22, ZADQ-431): one JSON object with exactly the six members v (the integer 1), origin, verifier_id_hex ("derived" or 64 lowercase hex), request_key_pub_hex (64 lowercase hex), operator_account (bech32, prefix mintid, valid checksum) and issued_at_unix (a non-negative integer); a member missing, unknown, repeated or of the wrong type or shape answers 400 evidence_invalid, the detail naming the member (the pending-MINT-599 format is refused so). origin other than the record's origin, or request_key_pub_hex other than the public key of the record's active request-signing key, answers 409 evidence_mismatch, the detail naming the member. The digest is SHA-256 over the RFC 8785 canonical form; the bytes are kept as uploaded. The record moves to evidence_pending and keeps operator_account. Uploading again replaces the file and its digest (the same canonical document: 200, nothing changes) while no admission request is made.
Renewal (v1.3.23, ZADQ-436). On an admitted record the upload is a renewal: the chain revalidates the origin every 180 days with a fresh document, and a wrong digest is corrected the same way. The same checks apply (bIP-0005 v1 only; origin and active key). The record stays admitted, the admission request is untouched, the document it replaces goes to history, evidence_renewed_at is set and the revalidation clock restarts from it. A record that holds a pending-MINT-599 upload moves to bip-0005/1 (digest_rule: sha256-rfc8785) the same way. The same canonical document again: 200, nothing changes. While the request is submitted or filed (the console is deciding on that file), and on a refused or withdrawn record: 409 invalid_state.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Request body
application/json — required
Schema: VerifierEvidenceUpload
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
content_base64 | string | yes | The exact bytes of the file the kit produced, standard base64; 1 byte to 16 KiB decoded. |
Responses
200 — The evidence as recorded.
Content type application/json.
Schema: VerifierEvidence
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
format | string | yes | bip-0005/1 (v1.3.22, ZADQ-431); pending-MINT-599 on a record that holds an upload made before v1.3.22. | |
digest | string | yes | ||
digest_rule | string | yes | sha256-rfc8785 for bip-0005/1: SHA-256 over the RFC 8785 canonical form (equal to the SHA-256 of the served bytes when the served file is canonical). sha256 for pending-MINT-599: over the exact bytes. | "sha256", "sha256-rfc8785" |
operator_account | string, nullable | yes | The bech32 account the v1 document names; null for pending-MINT-599. | |
size_bytes | integer | yes | ||
content_base64 | string | yes | ||
publish_path | string | yes | ||
publish_url | string | yes | ||
uploaded_at | string (date-time) | yes | ||
renewed_at | string (date-time), nullable | yes | v1.3.23 (ZADQ-436) — set when this document came as a renewal on the admitted record. | |
renewal_check | all of VerifierRenewalCheck | yes | v1.3.23 — the console's served-file check of this renewed document; null before it, or without a renewal. | |
history | array of VerifierEvidencePrevious | yes | v1.3.23 — the documents renewals replaced, the newest first; empty before a renewal. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X PUT "<base-url>/v1/verifiers/<verifierId>/evidence" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/verifiers/{verifierId}/commitment
The issuer's verifier identity commitment for the record's origin (§5.15; MINT-600, v1.3.24)
The issuer's verifier identity commitment (MINT-600) for the record's exact origin, from the responsible person's approved KYC session — one check serves the seller, agent-operator and verifier roles of the same business. available while the record holds a commitment whose reuse window is open, with its members and status_key_check; not_available on a deployment that does not ask an issuer; kyc_required while the person is not verified with the reuse window open; pending_issuer when the issuer did not answer the last request (nothing failed; ask again); refused with refusal_reason when the issuer refused the request or its answer failed ZadQ's check. When no commitment serves and no request for the person's current session was refused, the read asks the issuer first (as POST does); a refusal for that session is answered as recorded.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Responses
200 — The commitment's state.
Content type application/json.
Schema: VerifierCommitment
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "not_available", "kyc_required", "pending_issuer", "refused", "available" | |
handle | string, nullable | yes | The commitment's commitment_hex, 64 lowercase hex. | |
kyc_session_id | string, nullable | yes | ||
obtained_at | string (date-time), nullable | yes | ||
issuer_id | string, nullable | yes | ||
assurance_grade | integer, nullable | yes | ||
approved_at | string (date-time), nullable | yes | ||
reusable_until | string (date-time), nullable | yes | ||
signature | string, nullable | yes | ||
status_key_check | all of VerifierStatusKeyCheck | yes | ||
refusal_reason | all of VerifierCommitmentRefusalReason | yes | ||
checked_at | string (date-time), nullable | yes | When the last request was made. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/verifiers/<verifierId>/commitment" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/verifiers/{verifierId}/commitment
Ask the issuer for the record's commitment now (§5.15; v1.3.24, ZADQ-433)
Asks the issuer (POST <issuer>/v0/verifier-identity-commitments with the account's approved session and the record's exact origin) unless a commitment whose reuse window is open is recorded, checks the answer — the issuer is the deployment's, the signature verifies under the issuer's status key when the deployment holds it (else status_key_check: unverified), the origin is the record's, the grade is A2 or above, the reuse window is open — and records it. 200 with the state after the request, the same shape as GET: an issuer that does not answer reads pending_issuer and nothing fails. 409 invalid_state on a refused or withdrawn record.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Responses
200 — The commitment's state after the request.
Content type application/json.
Schema: VerifierCommitment
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "not_available", "kyc_required", "pending_issuer", "refused", "available" | |
handle | string, nullable | yes | The commitment's commitment_hex, 64 lowercase hex. | |
kyc_session_id | string, nullable | yes | ||
obtained_at | string (date-time), nullable | yes | ||
issuer_id | string, nullable | yes | ||
assurance_grade | integer, nullable | yes | ||
approved_at | string (date-time), nullable | yes | ||
reusable_until | string (date-time), nullable | yes | ||
signature | string, nullable | yes | ||
status_key_check | all of VerifierStatusKeyCheck | yes | ||
refusal_reason | all of VerifierCommitmentRefusalReason | yes | ||
checked_at | string (date-time), nullable | yes | When the last request was made. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/verifiers/<verifierId>/commitment" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/verifiers/{verifierId}/admission
The admission request and what became of it (§5.15; MINT-601)
404 not_found before the request.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Responses
200 — The request.
Content type application/json.
Schema: VerifierAdmission
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "submitted", "filed", "admitted", "refused", "withdrawn" | |
origin | string | yes | ||
evidence_digest | string | yes | ||
commitment | VerifierAdmissionCommitment | yes | ||
obligations | VerifierObligationsAccepted | yes | ||
submitted_at | string (date-time) | yes | ||
evidence_checked_at | string (date-time), nullable | yes | ||
filed_at | string (date-time), nullable | yes | ||
decided_at | string (date-time), nullable | yes | ||
refused_reason | all of VerifierRefusedReason | yes | ||
turnaround | VerifierTurnaround | yes | ||
admissions_log_ref | string, nullable | yes | The public admissions log entry's reference, once recorded. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/verifiers/<verifierId>/admission" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/verifiers/{verifierId}/admission
Ask ZadQ to file the admission request with the chain's operator, accepting the verifier obligations (§5.15)
Checked in this order: the record is live (409 invalid_state after a refusal or a withdrawal); a request already made answers 200 as it is; the evidence is uploaded (409 evidence_required); the body (400 body_invalid); the account is not blocked (409 account_blocked); the responsible person is verified with the window open (409 kyc_required); verifier obligations are published (409 obligations_not_published) and the {version, sha256} sent are the ones in force (409 obligations_changed). 201 the request, submitted: the record stays evidence_pending while ZadQ checks the file at the origin, then the console files it. The request asks the issuer for the commitment first (v1.3.24, as POST …/commitment) and carries it when one serves; an issuer that does not answer or refuses never fails the request (commitment.state pending_issuer or refused), and a commitment recorded before the filing joins the request. The acceptance is appended to the consents log. No price line: verification is free, and the chain's fee is the chain's.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Request body
application/json — required
Schema: VerifierAdmissionRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
obligations | VerifierObligationsAcceptance | yes |
Responses
200 — The request already made, as it is.
Content type application/json.
Schema: VerifierAdmission
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "submitted", "filed", "admitted", "refused", "withdrawn" | |
origin | string | yes | ||
evidence_digest | string | yes | ||
commitment | VerifierAdmissionCommitment | yes | ||
obligations | VerifierObligationsAccepted | yes | ||
submitted_at | string (date-time) | yes | ||
evidence_checked_at | string (date-time), nullable | yes | ||
filed_at | string (date-time), nullable | yes | ||
decided_at | string (date-time), nullable | yes | ||
refused_reason | all of VerifierRefusedReason | yes | ||
turnaround | VerifierTurnaround | yes | ||
admissions_log_ref | string, nullable | yes | The public admissions log entry's reference, once recorded. |
201 — Requested.
Content type application/json.
Schema: VerifierAdmission
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "submitted", "filed", "admitted", "refused", "withdrawn" | |
origin | string | yes | ||
evidence_digest | string | yes | ||
commitment | VerifierAdmissionCommitment | yes | ||
obligations | VerifierObligationsAccepted | yes | ||
submitted_at | string (date-time) | yes | ||
evidence_checked_at | string (date-time), nullable | yes | ||
filed_at | string (date-time), nullable | yes | ||
decided_at | string (date-time), nullable | yes | ||
refused_reason | all of VerifierRefusedReason | yes | ||
turnaround | VerifierTurnaround | yes | ||
admissions_log_ref | string, nullable | yes | The public admissions log entry's reference, once recorded. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/verifiers/<verifierId>/admission" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/verifiers/{verifierId}/key-rotation
Declare a new request-signing key (§5.15; MINT-604's managed line needs it)
The body is the key's own shape, checked as on create (400 key_invalid, private_key_refused). The current key is replaced and listed in previous_keys; the same key id again: 200 unchanged; a key id the record held before: 409 key_reused; while the admission request is filed, or on a refused or withdrawn record: 409 invalid_state. The rotation on the chain is the business's own transaction; ZadQ records the declaration.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Request body
application/json — required
Schema: VerifierKeyInput
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
key_id | string | yes | 64 lowercase hex, as the kit wrote it. | |
algorithm | VerifierAlgorithm | yes | ||
public_key | string | yes | Lowercase hex — 32 bytes (ed25519) or the SEC1 point, 33 or 65 bytes (ecdsa_p256). |
Responses
200 — The record with its new key.
Content type application/json.
Schema: VerifierRecord
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
origin | string | yes | ||
state | VerifierState | yes | ||
active | boolean | yes | ||
managed | boolean | yes | ||
evidence_format | string | yes | The evidence's format: bip-0005/1 (v1.3.22, ZADQ-431), the format a record without an upload expects too. A record that holds an upload made before v1.3.22 reads pending-MINT-599 until the business uploads the v1 document. | |
operator_account | string, nullable | yes | The bech32 account the bIP-0005 v1 evidence names — the account that signs the registration on the chain (v1.3.22, ZADQ-431); public. Null without a v1 upload. | |
request_signing_key | VerifierKey | yes | ||
previous_keys | array of VerifierPreviousKey | yes | ||
evidence | all of VerifierEvidenceSummary | yes | ||
commitment_handle | string, nullable | yes | The recorded commitment's commitment_hex (MINT-600; v1.3.24), null before one; kept after its reuse window ends. | |
commitment | VerifierRecordCommitment | yes | ||
admission | all of VerifierAdmission | yes | ||
created_at | string (date-time) | yes | ||
updated_at | string (date-time) | yes | ||
withdrawn_at | string (date-time), nullable | yes | ||
evidence_renewed_at | string (date-time), nullable | yes | v1.3.23 (ZADQ-436): when the current evidence document was uploaded as a renewal on the admitted record; null while it is the one the record was admitted with. | |
renewal_reminder_at | string (date-time), nullable | yes | v1.3.23: the revalidation's reminder date — the last renewal, or the admission's decision before one, plus the reminder (150 days by default; configuration). Null unless admitted. | |
renewal_due_at | string (date-time), nullable | yes | v1.3.23: the revalidation's due date — the same start plus the chain's revalidation window (180 days by default; configuration, never read from the chain). Null unless admitted. | |
renewal_due | boolean | yes | v1.3.23 — the due date is past and no renewal was uploaded since; false unless admitted. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/verifiers/<verifierId>/key-rotation" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
POST /v1/verifiers/{verifierId}/withdraw
Withdraw the verifier record and its open admission request (§5.15)
Terminal; frees the origin. Again: 200 as it is. 409 invalid_state after a refusal.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Responses
200 — Withdrawn.
Content type application/json.
Schema: VerifierRecord
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
origin | string | yes | ||
state | VerifierState | yes | ||
active | boolean | yes | ||
managed | boolean | yes | ||
evidence_format | string | yes | The evidence's format: bip-0005/1 (v1.3.22, ZADQ-431), the format a record without an upload expects too. A record that holds an upload made before v1.3.22 reads pending-MINT-599 until the business uploads the v1 document. | |
operator_account | string, nullable | yes | The bech32 account the bIP-0005 v1 evidence names — the account that signs the registration on the chain (v1.3.22, ZADQ-431); public. Null without a v1 upload. | |
request_signing_key | VerifierKey | yes | ||
previous_keys | array of VerifierPreviousKey | yes | ||
evidence | all of VerifierEvidenceSummary | yes | ||
commitment_handle | string, nullable | yes | The recorded commitment's commitment_hex (MINT-600; v1.3.24), null before one; kept after its reuse window ends. | |
commitment | VerifierRecordCommitment | yes | ||
admission | all of VerifierAdmission | yes | ||
created_at | string (date-time) | yes | ||
updated_at | string (date-time) | yes | ||
withdrawn_at | string (date-time), nullable | yes | ||
evidence_renewed_at | string (date-time), nullable | yes | v1.3.23 (ZADQ-436): when the current evidence document was uploaded as a renewal on the admitted record; null while it is the one the record was admitted with. | |
renewal_reminder_at | string (date-time), nullable | yes | v1.3.23: the revalidation's reminder date — the last renewal, or the admission's decision before one, plus the reminder (150 days by default; configuration). Null unless admitted. | |
renewal_due_at | string (date-time), nullable | yes | v1.3.23: the revalidation's due date — the same start plus the chain's revalidation window (180 days by default; configuration, never read from the chain). Null unless admitted. | |
renewal_due | boolean | yes | v1.3.23 — the due date is past and no renewal was uploaded since; false unless admitted. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/verifiers/<verifierId>/withdraw" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/verifiers/{verifierId}/door
The record's door — the market and the bundles its refusal sends principals to ZadQ for (§5.16)
The business's declaration on its verifier record (ZADQ-365): the market its refusal sentence is chosen by (1, 2, 3 or null) and the bundles of the served catalogue it accepts, with the landing URL to configure in the refusal for each bundle. 404 not_found before a declaration and for another account's record. The business never reads who arrived through its door.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Responses
200 — The door.
Content type application/json.
Schema: VerifierDoor
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
verifier_id | string | yes | ||
market | integer, nullable | yes | ||
bundles | array of string | yes | ||
declared_at | string (date-time) | yes | ||
urls | array of VerifierDoorUrl | yes | The landing URL to configure in the refusal, one per bundle. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/verifiers/<verifierId>/door" \
--cookie "__Host-passkey_session=<api-key>"
PUT /v1/verifiers/{verifierId}/door
Declare (or replace) the record's door (§5.16)
market 1, 2, 3 or null; bundles 1 to 8 distinct bundle ids of the issuer's served catalogue (400 bundle_unknown; 400 body_invalid otherwise). 409 invalid_state once the record is refused or withdrawn; 503 catalogue_unavailable. A referral reads valid only while the record is admitted and its door names the bundle.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Request body
application/json — required
Schema: VerifierDoorDeclare
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
market | integer, nullable | yes | The market the refusal sentence is chosen by (1 paid APIs and metered data, 2 reference and community content, 3 developer and orchestration platforms); null for the generic sentence. | |
bundles | array of string | yes |
Responses
200 — The door as recorded.
Content type application/json.
Schema: VerifierDoor
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
verifier_id | string | yes | ||
market | integer, nullable | yes | ||
bundles | array of string | yes | ||
declared_at | string (date-time) | yes | ||
urls | array of VerifierDoorUrl | yes | The landing URL to configure in the refusal, one per bundle. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X PUT "<base-url>/v1/verifiers/<verifierId>/door" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/products/verifier/prices
The verifier product's business lines and their prices on this deployment (§5.17)
ZadQ's own price table of the business-side lines of the verifier product (ZADQ-373; VERIFIER_PRODUCT_PRICES): the verifier kit set-up (once per business, opened with the first verifier record), the onboarding of the responsible person at cost (opened with it only when the account has paid no entry of any product), the managed deployment's set-up and each managed environment and period (billed in advance; opened only for a managed record). A line the table does not price reads on_sale: false with the amount null. managed_kit_setup: withdrawn since v1.3.16 (ZADQ-382, P-13: the kit set-up line is no longer opened, for a managed business or any other). Never a verification line: the protocol charges nothing to verify; operators price their own services. Under the passkey session: the figures stay in the operator agreement, not on a public page.
Authentication: passkeySession.
Responses
200 — The business lines and their prices.
Content type application/json.
Schema: BusinessLinePriceTable
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
lines | array of BusinessLinePrice | yes | ||
managed_kit_setup | string | yes | v1.3.15 — whether a managed business pays the kit set-up too; v1.3.16 (ZADQ-382, P-13) — always withdrawn, the kit set-up line is no longer opened. | "charged", "waived", "withdrawn" |
relying_party | RelyingPartyPrices | no | ||
onboarding_rule | string | yes | The onboarding at cost opens only where no entry of a product is paid; the re-check at the grade's renewal opens no line. | "at_cost_unless_entry_paid" |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/products/verifier/prices" \
--cookie "__Host-passkey_session=<api-key>"
GET /v1/products/verifier/relying-party
The relying-party rebate on the business's account — the discovery fee ZadQ pays per principal its door sends (§5.18, v1.3.18)
ZADQ-389 (Platform Decision 24). R1 changed sign: ZadQ pays the business a one-off rebate per principal who arrives through its door (the principal's first referral from one of its verifier records) and keeps a paid plan — once per person, the amount of the plan held when it is earned (GET /v1/products/verifier/prices). A rebate is pending from the plan's payment and earned once the holding days are past, the identity check approved and nothing refunded; each month is closed after it ends: up to the cap (the rest held for review), set off against the business's invoice of the month (a principal_enrolled line with a negative amount) or paid out once the balance reaches the threshold; a refund or a chargeback reverses it, deducted from the next statement once settled. Counts and amounts only, never who; never keyed to a presentation or a verification decision. Reading this route moves the business's rebates and closes the months due. v1.3.16's R1 charge and R2 are withdrawn (the meter route is removed).
Authentication: passkeySession.
Responses
200 — The business's rebates.
Content type application/json.
Schema: RelyingPartyStatus
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
month | string (date) | yes | The current month (its first day, UTC). | |
offered | boolean | yes | Whether the deployment offers the rebate. | |
unit | string, nullable | yes | ||
pending | integer | yes | Rebates whose guards are not all met yet (the holding days, the identity check). | |
earned | integer | yes | Rebates earned and not settled yet (settled at their month's close). | |
earned_minor | integer (int64) | yes | ||
held | integer | yes | Rebates held beyond the cap of their month, for the operator's review. | |
held_minor | integer (int64) | yes | ||
balance_minor | integer (int64) | yes | The balance carried out of the last statement (below the payout threshold, or negative after reversals). | |
statements | array of RebateStatement | yes | The closed months, newest first. |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/products/verifier/relying-party" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/verifiers/{verifierId}/managed/setup
Open the managed deployment's set-up line for a managed record (§5.17)
Once per business: 201 with the line opened, 200 with the line already due or settled. 409 managed_not_offered unless the record is a managed one (no record is managed in this version: the managed deployment, ZADQ-364, is not built); 409 invalid_state for a refused or withdrawn record; 409 account_blocked; 503 billing_unavailable when ZadQ's price table does not price it (nothing opened). Where the deployment waives a managed business's kit set-up, its unpaid kit set-up is voided.
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Responses
200 — The line already due or settled, as it is.
Content type application/json.
Schema: PriceLine
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
period | string, nullable | no | v1.3.14 (§5.16) — the period a principal plan's seat line pays; its amount is the plan's whole price for it. v1.3.15 (§5.17) — the period a managed environment's line pays, in advance. | "month", "year" |
environment | string, nullable | no | v1.3.15 (§5.17) — a managed environment's environment; null on every other line. | "production", "test" |
kind | PriceLineKind | yes | ||
amount_minor | integer (int64), nullable | yes | v1.3.18 (ZADQ-389) — negative on a principal_enrolled line opened since (the month's rebate set off on the invoice; not payable). | |
unit | string, nullable | yes | ||
state | PriceLineState | yes | ||
ref | PriceLineRef | yes | ||
settlement | string | yes | "console", "stripe" | |
channel | string | yes | How the line is collected (ZADQ-324, derived at read time, never stored): invoice on the console settlement (a manual invoice) and for a provider customer whose subscription collects by invoice; card otherwise (the hosted checkout). The dashboard shows "Pay" for card, "on your invoice" for invoice. | "card", "invoice" |
quantity | integer, nullable | no | Seats (seat), lease days (lease_year); v1.3.16 — the month's count of principals enrolled (principal_enrolled); v1.3.18 — on a rebate credit, the rebates settled in the month. | |
bundle | string, nullable | no | ||
vat_treatment | string, nullable | no | v1.3.16 (ZADQ-382) — how the amount stands to VAT, on the lines opened since (null on the lines before). v1.3.29 (ZADQ-469) — every amount is net, ex-VAT: a line opens exclusive (the billing provider adds the VAT at checkout and on the invoice) or reverse_charge (the same net, no VAT, for a business whose customer record holds a valid VAT number of another member state). included is a legacy value: it is never opened now and stays only on lines opened before v1.3.29. | "included", "reverse_charge", "exclusive" |
covers_until | string (date-time), nullable | no | v1.3.16 — the end of the period a step's line (agent_extra, grade_a3_option) pays, from its settlement; null until settled and on every other line. No step is offered since v1.3.25. | |
credit_minor | integer (int64), nullable | no | v1.3.16 — on a switch's seat line (Personal → Premium), the credit of the unused period; amount_minor is the new period's price less it. | |
free_quantity | integer, nullable | no | v1.3.16 — on a principal_enrolled line, the free volume applied to the month's count; null on a rebate credit (v1.3.18). | |
billing_month | string (date), nullable | no | v1.3.16 — on a principal_enrolled line, the month counted (its first day); v1.3.18 — the rebate statement's month. | |
retained_minor | integer (int64), nullable | no | v1.3.17 (ZADQ-387) — on a plan_refund line, the cost of the identity check performed at the person's request, retained; amount_minor is what is paid back. v1.3.29 (ZADQ-469) — net, ex-VAT, on a line exclusive or reverse_charge: the provider's refund pays back amount_minor plus its share of the VAT the payment collected (a legacy included line keeps the amounts it was opened with). | |
refund_reason | string, nullable | no | v1.3.17 — on a plan_refund line, why the plan closed (ZadQ's own code; nothing of the issuer's reason); v1.3.34 (ZADQ-472) — enterprise_replaces_paid_plan, the paid plan replaced by an Enterprise contract (its unused period paid back by hand). | "identity_check_refused", "identity_check_withdrawn", "enterprise_replaces_paid_plan" |
created_at | string (date-time) | yes |
201 — The line opened.
Content type application/json.
Schema: PriceLine
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
period | string, nullable | no | v1.3.14 (§5.16) — the period a principal plan's seat line pays; its amount is the plan's whole price for it. v1.3.15 (§5.17) — the period a managed environment's line pays, in advance. | "month", "year" |
environment | string, nullable | no | v1.3.15 (§5.17) — a managed environment's environment; null on every other line. | "production", "test" |
kind | PriceLineKind | yes | ||
amount_minor | integer (int64), nullable | yes | v1.3.18 (ZADQ-389) — negative on a principal_enrolled line opened since (the month's rebate set off on the invoice; not payable). | |
unit | string, nullable | yes | ||
state | PriceLineState | yes | ||
ref | PriceLineRef | yes | ||
settlement | string | yes | "console", "stripe" | |
channel | string | yes | How the line is collected (ZADQ-324, derived at read time, never stored): invoice on the console settlement (a manual invoice) and for a provider customer whose subscription collects by invoice; card otherwise (the hosted checkout). The dashboard shows "Pay" for card, "on your invoice" for invoice. | "card", "invoice" |
quantity | integer, nullable | no | Seats (seat), lease days (lease_year); v1.3.16 — the month's count of principals enrolled (principal_enrolled); v1.3.18 — on a rebate credit, the rebates settled in the month. | |
bundle | string, nullable | no | ||
vat_treatment | string, nullable | no | v1.3.16 (ZADQ-382) — how the amount stands to VAT, on the lines opened since (null on the lines before). v1.3.29 (ZADQ-469) — every amount is net, ex-VAT: a line opens exclusive (the billing provider adds the VAT at checkout and on the invoice) or reverse_charge (the same net, no VAT, for a business whose customer record holds a valid VAT number of another member state). included is a legacy value: it is never opened now and stays only on lines opened before v1.3.29. | "included", "reverse_charge", "exclusive" |
covers_until | string (date-time), nullable | no | v1.3.16 — the end of the period a step's line (agent_extra, grade_a3_option) pays, from its settlement; null until settled and on every other line. No step is offered since v1.3.25. | |
credit_minor | integer (int64), nullable | no | v1.3.16 — on a switch's seat line (Personal → Premium), the credit of the unused period; amount_minor is the new period's price less it. | |
free_quantity | integer, nullable | no | v1.3.16 — on a principal_enrolled line, the free volume applied to the month's count; null on a rebate credit (v1.3.18). | |
billing_month | string (date), nullable | no | v1.3.16 — on a principal_enrolled line, the month counted (its first day); v1.3.18 — the rebate statement's month. | |
retained_minor | integer (int64), nullable | no | v1.3.17 (ZADQ-387) — on a plan_refund line, the cost of the identity check performed at the person's request, retained; amount_minor is what is paid back. v1.3.29 (ZADQ-469) — net, ex-VAT, on a line exclusive or reverse_charge: the provider's refund pays back amount_minor plus its share of the VAT the payment collected (a legacy included line keeps the amounts it was opened with). | |
refund_reason | string, nullable | no | v1.3.17 — on a plan_refund line, why the plan closed (ZadQ's own code; nothing of the issuer's reason); v1.3.34 (ZADQ-472) — enterprise_replaces_paid_plan, the paid plan replaced by an Enterprise contract (its unused period paid back by hand). | "identity_check_refused", "identity_check_withdrawn", "enterprise_replaces_paid_plan" |
created_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/verifiers/<verifierId>/managed/setup" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/verifiers/{verifierId}/managed/environments
Open a managed environment's line for one period, in advance (§5.17)
environment production or test, period month (default) or year; billed in advance, one line per period. One unpaid line per environment of the record: the same period again answers it (200), another period replaces it (the old one void). 400 body_invalid; 409 managed_not_offered unless the record is a managed one; 409 invalid_state for a refused or withdrawn record; 409 account_blocked; 503 billing_unavailable when ZadQ's price table does not price the environment and period (nothing opened).
Authentication: passkeySession.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifierId | path | yes | string | The verifier record's id (vrf_…). |
Request body
application/json — required
Schema: ManagedEnvironmentOpen
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
environment | string | yes | "production", "test" | |
period | string | no | Billed in advance; month when left out. | "month", "year" |
Responses
200 — The unpaid line of the same period, as it is.
Content type application/json.
Schema: PriceLine
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
period | string, nullable | no | v1.3.14 (§5.16) — the period a principal plan's seat line pays; its amount is the plan's whole price for it. v1.3.15 (§5.17) — the period a managed environment's line pays, in advance. | "month", "year" |
environment | string, nullable | no | v1.3.15 (§5.17) — a managed environment's environment; null on every other line. | "production", "test" |
kind | PriceLineKind | yes | ||
amount_minor | integer (int64), nullable | yes | v1.3.18 (ZADQ-389) — negative on a principal_enrolled line opened since (the month's rebate set off on the invoice; not payable). | |
unit | string, nullable | yes | ||
state | PriceLineState | yes | ||
ref | PriceLineRef | yes | ||
settlement | string | yes | "console", "stripe" | |
channel | string | yes | How the line is collected (ZADQ-324, derived at read time, never stored): invoice on the console settlement (a manual invoice) and for a provider customer whose subscription collects by invoice; card otherwise (the hosted checkout). The dashboard shows "Pay" for card, "on your invoice" for invoice. | "card", "invoice" |
quantity | integer, nullable | no | Seats (seat), lease days (lease_year); v1.3.16 — the month's count of principals enrolled (principal_enrolled); v1.3.18 — on a rebate credit, the rebates settled in the month. | |
bundle | string, nullable | no | ||
vat_treatment | string, nullable | no | v1.3.16 (ZADQ-382) — how the amount stands to VAT, on the lines opened since (null on the lines before). v1.3.29 (ZADQ-469) — every amount is net, ex-VAT: a line opens exclusive (the billing provider adds the VAT at checkout and on the invoice) or reverse_charge (the same net, no VAT, for a business whose customer record holds a valid VAT number of another member state). included is a legacy value: it is never opened now and stays only on lines opened before v1.3.29. | "included", "reverse_charge", "exclusive" |
covers_until | string (date-time), nullable | no | v1.3.16 — the end of the period a step's line (agent_extra, grade_a3_option) pays, from its settlement; null until settled and on every other line. No step is offered since v1.3.25. | |
credit_minor | integer (int64), nullable | no | v1.3.16 — on a switch's seat line (Personal → Premium), the credit of the unused period; amount_minor is the new period's price less it. | |
free_quantity | integer, nullable | no | v1.3.16 — on a principal_enrolled line, the free volume applied to the month's count; null on a rebate credit (v1.3.18). | |
billing_month | string (date), nullable | no | v1.3.16 — on a principal_enrolled line, the month counted (its first day); v1.3.18 — the rebate statement's month. | |
retained_minor | integer (int64), nullable | no | v1.3.17 (ZADQ-387) — on a plan_refund line, the cost of the identity check performed at the person's request, retained; amount_minor is what is paid back. v1.3.29 (ZADQ-469) — net, ex-VAT, on a line exclusive or reverse_charge: the provider's refund pays back amount_minor plus its share of the VAT the payment collected (a legacy included line keeps the amounts it was opened with). | |
refund_reason | string, nullable | no | v1.3.17 — on a plan_refund line, why the plan closed (ZadQ's own code; nothing of the issuer's reason); v1.3.34 (ZADQ-472) — enterprise_replaces_paid_plan, the paid plan replaced by an Enterprise contract (its unused period paid back by hand). | "identity_check_refused", "identity_check_withdrawn", "enterprise_replaces_paid_plan" |
created_at | string (date-time) | yes |
201 — The line opened.
Content type application/json.
Schema: PriceLine
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
period | string, nullable | no | v1.3.14 (§5.16) — the period a principal plan's seat line pays; its amount is the plan's whole price for it. v1.3.15 (§5.17) — the period a managed environment's line pays, in advance. | "month", "year" |
environment | string, nullable | no | v1.3.15 (§5.17) — a managed environment's environment; null on every other line. | "production", "test" |
kind | PriceLineKind | yes | ||
amount_minor | integer (int64), nullable | yes | v1.3.18 (ZADQ-389) — negative on a principal_enrolled line opened since (the month's rebate set off on the invoice; not payable). | |
unit | string, nullable | yes | ||
state | PriceLineState | yes | ||
ref | PriceLineRef | yes | ||
settlement | string | yes | "console", "stripe" | |
channel | string | yes | How the line is collected (ZADQ-324, derived at read time, never stored): invoice on the console settlement (a manual invoice) and for a provider customer whose subscription collects by invoice; card otherwise (the hosted checkout). The dashboard shows "Pay" for card, "on your invoice" for invoice. | "card", "invoice" |
quantity | integer, nullable | no | Seats (seat), lease days (lease_year); v1.3.16 — the month's count of principals enrolled (principal_enrolled); v1.3.18 — on a rebate credit, the rebates settled in the month. | |
bundle | string, nullable | no | ||
vat_treatment | string, nullable | no | v1.3.16 (ZADQ-382) — how the amount stands to VAT, on the lines opened since (null on the lines before). v1.3.29 (ZADQ-469) — every amount is net, ex-VAT: a line opens exclusive (the billing provider adds the VAT at checkout and on the invoice) or reverse_charge (the same net, no VAT, for a business whose customer record holds a valid VAT number of another member state). included is a legacy value: it is never opened now and stays only on lines opened before v1.3.29. | "included", "reverse_charge", "exclusive" |
covers_until | string (date-time), nullable | no | v1.3.16 — the end of the period a step's line (agent_extra, grade_a3_option) pays, from its settlement; null until settled and on every other line. No step is offered since v1.3.25. | |
credit_minor | integer (int64), nullable | no | v1.3.16 — on a switch's seat line (Personal → Premium), the credit of the unused period; amount_minor is the new period's price less it. | |
free_quantity | integer, nullable | no | v1.3.16 — on a principal_enrolled line, the free volume applied to the month's count; null on a rebate credit (v1.3.18). | |
billing_month | string (date), nullable | no | v1.3.16 — on a principal_enrolled line, the month counted (its first day); v1.3.18 — the rebate statement's month. | |
retained_minor | integer (int64), nullable | no | v1.3.17 (ZADQ-387) — on a plan_refund line, the cost of the identity check performed at the person's request, retained; amount_minor is what is paid back. v1.3.29 (ZADQ-469) — net, ex-VAT, on a line exclusive or reverse_charge: the provider's refund pays back amount_minor plus its share of the VAT the payment collected (a legacy included line keeps the amounts it was opened with). | |
refund_reason | string, nullable | no | v1.3.17 — on a plan_refund line, why the plan closed (ZadQ's own code; nothing of the issuer's reason); v1.3.34 (ZADQ-472) — enterprise_replaces_paid_plan, the paid plan replaced by an Enterprise contract (its unused period paid back by hand). | "identity_check_refused", "identity_check_withdrawn", "enterprise_replaces_paid_plan" |
created_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/verifiers/<verifierId>/managed/environments" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/referrals
The referral read — what the refusing service accepts and why (no session; §5.16)
The landing's read (ZADQ-365), with the parameters of the URL the business configures in its refusal: verifier (the verifier record's id) and bundle (a bundle of the served catalogue). valid while the record is admitted, its door names the bundle and a plan of this wave reaches the bundle's grade — then the service's host, the bundle's description and grade floor, the market for the sentence, the plans' fit and the first bounded agent's preset; closed otherwise, with a closed reason and nothing of the service. 404 referral_unknown for a malformed parameter, no such record, or a bundle the catalogue does not carry (the landing's generic form); 503 catalogue_unavailable. Never the business's customer data.
Authentication: none — this operation is public.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
verifier | query | no | string | The refusing service's verifier record id; absent or malformed answers 404 referral_unknown. |
bundle | query | no | string | A bundle id of the served catalogue; absent answers 404 referral_unknown. |
Responses
200 — The referral.
Content type application/json.
Schema: Referral
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "valid", "closed" | |
closed_reason | string, nullable | yes | "verifier_not_admitted", "door_not_declared", "bundle_not_accepted", "grade_not_offered" | |
verifier | string | yes | ||
bundle | ReferralBundle | yes | ||
service | all of ReferralService | yes | ||
market | integer, nullable | yes | 1, 2 or 3 — the refusal sentence's market as the business declared it; null for the generic sentence. | |
plans | array of ReferralPlanFit | yes | ||
preset | all of ReferralPreset | yes | ||
url | string | no | The landing URL of this referral (valid only). |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/referrals"
GET /v1/me/referrals
The account's referrals, the arrival first (§5.16)
Authentication: passkeySession.
Responses
200 — The referrals.
Content type application/json.
Schema: AccountReferralList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
referrals | array of AccountReferral | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/me/referrals" \
--cookie "__Host-passkey_session=<api-key>"
POST /v1/me/referrals
Record a referral on a signed-in account (a person who already has one, §5.16)
201 the referral (200: the same referral, as recorded). 404 referral_unknown; 409 referral_closed (the reason in the detail).
Authentication: passkeySession.
Request body
application/json — required
Schema: ReferralParams
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
verifier | string | yes | The refusing service's verifier record id. | |
bundle | string | yes | The bundle id of the served catalogue the refusal names. |
Responses
200 — Already recorded.
Content type application/json.
Schema: AccountReferral
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | The referral's reference (rfl_…). | |
verifier | string | yes | ||
bundle | string | yes | ||
market | integer, nullable | yes | ||
at_signup | boolean | yes | ||
recorded_at | string (date-time) | yes |
201 — Recorded.
Content type application/json.
Schema: AccountReferral
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | The referral's reference (rfl_…). | |
verifier | string | yes | ||
bundle | string | yes | ||
market | integer, nullable | yes | ||
at_signup | boolean | yes | ||
recorded_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS -X POST "<base-url>/v1/me/referrals" \
--cookie "__Host-passkey_session=<api-key>" \
-H "Content-Type: application/json" \
-d @request-body.json
GET /v1/plans
The principal plans — Personal and Plus — with their prices on this deployment (no session; §5.16)
Each plan's seats (minimum = cap), the grade its verification is at, the renewal by grade (no grace) and, per period (month, year; year by default), the plan's whole price as one amount from ZadQ's own price table — on_sale: false and the amount null when the table does not price it (choosing it answers 503 billing_unavailable). Billed in advance, before the identity check. Who may subscribe: organisations and sole traders; the consumer path is refused until counsel answers. Whether a public page shows these figures is a publication act (Marc's).
Authentication: none — this operation is public.
Responses
200 — The plans.
Content type application/json.
Schema: PrincipalPlanList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
plans | array of PrincipalPlan | yes | ||
contact | object | yes | v1.3.30 (ZADQ-472, §5.20) — beyond Premium, Enterprise — the agent-operator product by contract, agreed by contact and activated by ZadQ; never an amount. | |
contact.id | string | yes | "enterprise" | |
contact.label | string | yes | ||
contact.seats_from | integer | yes | The fewest bounded agents an Enterprise contract carries (6, beyond Premium's 5). | |
contact.by_contact | boolean | yes | true | |
default_period | string | yes | "month", "year" | |
eligibility | object | yes | ||
eligibility.account_kinds | array of AccountKind | yes | ||
eligibility.consumer | string | yes | "not_offered" |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/plans"
GET /v1/legal/verifier-obligations
The verifier obligations in force — the exact text and its SHA-256 (§5.15, as §5.11's legal versions)
The latest published version (no session). 404 not_found until the operator console publishes one (the text is the legal layer's, ZADQ-361). url is where the public web shows it, null when it is served here only.
Authentication: none — this operation is public.
Responses
200 — The version in force.
Content type application/json.
Schema: VerifierObligations
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes | ||
url | string, nullable | yes | ||
text | string | yes | ||
published_at | string (date-time) | yes |
default — A /v1 refusal — {"error", "detail"} (platform API v1 §5).
Content type application/json.
Schema: V1Error
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
Example
curl -sS "<base-url>/v1/legal/verifier-obligations"
Schemas
TermsDocument
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | Version name of the acknowledgement document. | |
sha256 | string | yes | Hex SHA-256 of text. | |
url | string (uri) | yes | Where the full Terms of Service are published. | |
text | string | yes | The acknowledgement text the wallet signs for. |
SellerTerms
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
current | TermsDocument | yes | ||
acknowledged | boolean | yes | Whether the current version is acknowledged by this seller. | |
acknowledgedVersion | string | no | ||
signedAt | string (date-time) | no | When the current version was signed, if it was. | |
message | string | yes | The exact text to sign for the current version. | |
messageSignedAt | string (date-time) | yes | The signing time embedded in message; submit it back as signedAt. |
TermsAcknowledgement
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes | ||
signedAt | string (date-time) | yes | ||
signature | string | yes | Wallet signature over the message (hex for EVM, base58 or hex for Solana). |
SellerWebhooks
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
webhooks | array of Webhook | yes |
SellerEvent
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | yes | Event name of the seller stream (e.g. intake, kyc_approved, attested, status_suspended, consent_withdrawn). | |
occurredAt | string (date-time) | yes |
SellerEvents
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
events | array of SellerEvent | yes |
Chain
The chain a payTo address is paid on (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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
chain | Chain | yes | ||
address | string | yes |
AuthChallenge
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
nonce | string | yes | ||
message | string | yes | Exact text to sign, byte for byte. | |
expiresAt | string (date-time) | yes |
AuthSessionRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
chain | Chain | yes | ||
address | string | yes | ||
nonce | string | yes | ||
signature | string | yes | EVM — 0x-hex r||s||v from personal_sign; Solana — base58 (or hex) 64-byte signature. |
AuthSession
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
bearer | string | yes | Opaque session credential for the Authorization header. | |
expiresAt | string (date-time) | yes | ||
chain | Chain | yes | ||
address | string | yes |
Health
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
status | string | yes | "ok" | |
version | string | no | ||
mintid | string | no | The readiness of this deployment's MintID ids (ZADQ-407): discovering while MintID was unreachable at start-up and the ids are retried in the background (the MintID-dependent routes answer 503 mintid_unavailable), ready otherwise. The probe answers 200 either way. | "discovering", "ready" |
CredentialOfferHandoff
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
offer | object | yes | The credential offer object, as the issuer returned it — opaque, one-shot; redeem it at once. | |
expiresAt | string (date-time) | yes | When the code and the credential it yields expire — the verification's own expiry at the latest. No grace. | |
credential | CredentialState | yes |
CredentialReport
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | held, or self_revoked (revoked is the older spelling of the same report). | "held", "self_revoked", "revoked" |
credentialRef | string | no | An opaque reference of the seller's choosing for the credential it holds. Never a key. | |
presentationUrl | string (uri) | no | Where 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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "none", "offered", "held", "expired", "revoked", "self_revoked" | |
offeredAt | string (date-time) | no | ||
expiresAt | string (date-time) | no | The verification's expiry, which is the credential's. | |
credentialRef | string | no | ||
presentationUrl | string (uri) | no | The holder's presentation endpoint registered with held (ZADQ-84); absent on the v0 path. | |
lastPresentation | PresentationOutcome | no |
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. Since the verifier contract 1.8.0 the vocabulary also holds dispute_retention_unavailable, produced for agent requests only (an identity presentation, which this outcome records, never meets it): it names the verifier's own fault, never the holder's, and would read state_unavailable on the public verdict.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
stage | string | yes | "challenge", "transport", "decision" | |
accepted | boolean | yes | ||
reason | string | yes | ||
sessionId | string | no | The verifier's session id of the decision record. | |
decidedAt | string (date-time) | yes |
SubstrateStatus
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
substrate | string | yes | "ok", "degraded", "unknown" | |
source | string | yes | Where the state comes from — the verifier's status read, or this service's cadence accounting. | "verifier", "cadence" |
reason | string | no | Why the substrate is not ok, in the verifier's standing vocabulary (for example height_stale, root_expired, state_unavailable). Absent when ok. | |
checkedAt | string (date-time) | yes | ||
lastSuccessfulStandingRead | string (date-time) | no | The last time a standing read answered with a known status. Absent before the first. | |
cadence | object | yes | ||
cadence.recheckEveryHours | integer | yes | The published cadence promise. | |
cadence.lastCycleAt | string (date-time) | no | ||
cadence.checked | integer | no | Attestations the last cycle asked the verifier about. | |
cadence.withheld | integer | no | Of those, how many came back with an unknown standing. |
BillingCheckout
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
tier | string | yes | The schedule tier, by name. Amounts are on the checkout page and in the operator agreement. | "attested_vendor", "regulated_compliance" |
cadence | string | no | How 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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
url | string (uri) | yes | The hosted checkout page — open it as-is. | |
billing | string | yes | The 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
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
applied | boolean | yes |
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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
nonce | string | yes | ||
signature | string | yes |
EndpointAddition
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
resourceUrl | string (uri) | yes | ||
payTo | PayTo | no | ||
proof | AddressProof | no |
WalletRotation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
payTo | PayTo | yes | ||
proof | AddressProof | yes |
VendorBilling
v1.3.31 (ZADQ-470) — the vendor lines of an operator group, amounts net in minor units.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
seller_id | string | yes | The seller record asked about. | |
billing_seller_id | string, nullable | no | The operator group's seller record whose billing is active (the oldest); null when none. | |
billing | string | yes | The group's billing state. | "none", "active" |
tier | string, nullable | no | "attested_vendor", "regulated_compliance" | |
cadence | string, nullable | no | "monthly", "annual" | |
entry_fee | VendorEntryFee | yes | ||
endpoints | VendorEndpoints | yes | ||
usage_fee | VendorUsageFee | yes |
VendorEntryFee
The entry fee — one-off, not credited (it pays the onboarding's support and integration; the tier pays the infrastructure).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
paid_tier | string, nullable | no | The highest tier whose entry fee the group paid; null when none. | "attested_vendor", "regulated_compliance" |
paid_minor | integer (int64) | yes | The net paid in total by the group. | |
unit | string, nullable | no | ||
due | array of VendorEntryDue | yes | What a checkout of each tier would charge now (0 once paid; a higher tier the difference). Empty where the deployment prices no entry fee. |
VendorEntryDue
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
tier | string | yes | "attested_vendor", "regulated_compliance" | |
amount_minor | integer (int64) | yes | ||
unit | string | yes |
VendorEndpoints
The group's admitted endpoint records against the tier's included ones, and the additional-endpoint item.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
live | integer | yes | Admitted endpoint records of the operator group. | |
included | integer | yes | Included by the tier (3 Attested Vendor, 10 Regulated / Compliance; Attested's without a tier). | |
additional | integer | yes | Endpoints above the quota (what the item should carry). | |
billed | integer | yes | The quantity last set on the provider's additional-endpoint item (0 without one). An increase is charged at once, prorated; a decrease credits nothing and counts from the next period. | |
price | object, nullable | no | One additional endpoint for one period of the group's cadence; null when not priced. | |
price.amount_minor | integer (int64) | yes | ||
price.unit | string | yes | ||
price.period | string | yes | "month", "year" |
VendorUsageFee
The usage fee — 0.75 % of each covered settlement received, capped at USD 0.40 a settlement, converted at the ECB rule, credited against the minimum (the tier and the additional endpoints paid; never the entry fee). Billed only above it.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
invoicing | string | yes | on: a billable month is invoiced at the meter's close on a monthly invoice of its own, whatever the cadence (v1.3.32) — the collection method of the vendor's subscription, automatic tax; its id is the statement's invoice_ref. off (the default until the counsel items of Platform Decision 15): the statement is recorded and shown, never invoiced. | "off", "on" |
rate_basis_points | integer | yes | 75 (0.75 %). | |
cap_micro_usdc | integer (int64) | yes | 400000 (USD 0.40) per settlement. | |
statements | array of VendorUsageStatement | yes | The monthly closes of the last 24 months, oldest first. |
VendorUsageStatement
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
period | string | yes | YYYY-MM (UTC). | |
settlements | integer (int64) | yes | Covered settlements received in the month. | |
fee_micro_usdc | integer (int64) | yes | The month's fee, each settlement's fee rounded down and capped before the sum. | |
fee_eur_cents | integer (int64) | yes | ||
fx_rule | string | yes | ||
fx_rate | string | yes | EUR per USD applied (eight decimals). | |
fx_rate_date | string (date) | yes | ||
fx_quote | string, nullable | no | The ECB quotation (1 EUR = q USD) the rate came from; null on the configured rate. | |
minimum_eur_cents | integer (int64) | yes | The annual minimum credited against (the tier and the additional endpoints). | |
cadence | string | no | "monthly", "annual" | |
minimum_credited_eur_cents | integer (int64) | yes | The minimum credited to date in the contract year (all of it billed annually; the twelfths invoiced billed monthly). | |
ytd_fee_eur_cents | integer (int64) | yes | ||
billable_eur_cents | integer (int64) | yes | What stands above the minimum credited, less what was billed earlier in the contract year. | |
state | string | yes | withheld_counsel: closed with the usage fee's invoicing off — shown, never invoiced. invoiced: on the provider — since v1.3.32 on the month's own invoice (invoice_ref). recorded: closed and not invoiced (nothing above the minimum, or the invoice not posted yet). | "recorded", "invoiced", "withheld_counsel" |
invoice_ref | string, nullable | no | v1.3.32 (ZADQ-470; Marc, 2026-11-08) — the provider's invoice the month's usage fee is billed on, a monthly invoice of its own (every cadence, yearly included; the collection method of the vendor's subscription — by invoice due in 30 days, or charged to its default payment method; automatic tax). Null while the month is not invoiced. |
OperatorEndpoints
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
endpoints | array of EndpointSummary | yes |
EndpointSummary
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
sellerId | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string | yes | ||
state | string | yes | "pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn" | |
attestationStatus | string | no | "active", "suspended", "revoked" |
InterestForm
The register-interest form's fields; contact data is not among them.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
side | string | yes | Which side of the trust perimeter the person stands on. | "vendor", "agent_operator" |
resource_url | string (uri) | no | The x402 resource URL a vendor sells at (optional, vendors). | |
agent_count_band | string | no | The size band of an operator's fleet (optional, agent operators). | "up_to_10", "up_to_100", "more_than_100" |
source | string | no | The 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" |
website | string | no | Trap field for automated submitters; a person leaves it empty. |
SellerIntake
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
segment | SegmentDeclaration | yes | ||
kycSandboxHint | KycSandboxHint | no | ||
biometric_consent | BiometricConsentGiven | no |
BiometricConsentGiven
The person's explicit consent to the face comparison (ZADQ-331; GDPR Art. 9(2)(a)), given on ZadQ's own page by the button whose label is the consent, before the verification link is opened: version is the label of the consent text the page showed. Every route that opens a verification session requires it — absent: 409 biometric_consent_required; a label other than the deployment's current one (GET /v1/me → biometric_consent.version_required): 409 biometric_consent_version_stale, the current label in the detail. Refused, nothing reaches the issuer and nothing is recorded. Accepted, ZadQ records the label, the time and the session it opened — no identity data. The field is spelled biometric_consent on the v0 bodies too (the one snake-case field there). A session opened without a consent record (before this rule, ZADQ-331) is served without its link until one is recorded on it: POST /v1/kyc/sessions/{id}/biometric-consent, POST /v0/sellers/{id}/biometric-consent (the v0 agent-operator route is retired since v1.3.33).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | The consent text's version label (e.g. 2026-10.2). |
KycSessionRestart
The body of the v0 routes that open a new verification session on an existing record (ZADQ-331): the consent to the face comparison.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
biometric_consent | BiometricConsentGiven | no |
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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
chain | Chain | yes | ||
address | string | yes | The address that receives the payment; on base stored and compared lowercase. |
SegmentDeclaration
PARAM-29 declaration. Recorded, not enforced in v0.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
annualVolumeUsdAtLeast300 | boolean | yes | ||
regulatedB2bCounterparties | boolean | yes |
Seller
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
payTo | PayTo | yes | ||
resourceUrl | string (uri) | yes | ||
operatorType | string | yes | "person", "organisation" | |
state | string | yes | kyc_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" |
billing | string | yes | Billing 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" |
billingTier | string | no | The 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" |
billingCadence | string | no | How 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" |
kycSessionId | string | no | Opaque session handle at the KYC boundary. Not identity data. | |
kyc | KycHandoff | no | ||
credential | CredentialState | no | ||
deposit | Deposit | no | ||
renewal | all of KycHandoff | no | The 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. | |
attestation | Attestation | no | ||
createdAt | string (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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "required", "awaiting_funds", "held", "below_level", "returning", "returned" | |
dashboardState | string | yes | One of the eight labels shown as state only. | "Deposit required", "Awaiting funds", "Held (≥ level)", "Below level (top-up)", "Claim pending", "Released (partial)", "Returning", "Returned" |
kyb | string | yes | The holder's verification of the vendor, as reported. | "none", "pending", "review", "validated", "refused", "expired", "out_of_date" |
requiredMinor | integer (int64) | yes | The level owed, in minor units of currency. | |
currency | string | yes | ||
balanceMinor | integer (int64) | yes | The wallet balance as last read from the holder. | |
syncedAt | string (date-time) | no | ||
openClaims | integer | yes | ||
returnDueAt | string (date-time) | no | When the return falls due after termination. |
DepositKybHandoff
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
url | string (uri) | yes | The holder's hosted verification page. |
DepositPayInInstructions
The holder's collection details for one bank wire, relayed once and never stored by this service.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
collectionAccount | string | yes | The holder's collection account to wire to. | |
bankName | string | yes | ||
bankCode | string | yes | ||
wireReference | string | yes | Must travel with the wire so the holder credits the right wallet. | |
amountMinor | integer (int64) | yes | ||
currency | string | yes |
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 and a consent to the face comparison is recorded for this session (ZADQ-331): without one it is absent (null) and biometric_consent_required reads true — record the consent with POST …/biometric-consent and the link comes back. Nothing here is identity data.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "pending", "approved", "rejected", "expired", "withdrawn" | |
handoffUrl | string (uri), nullable | no | ||
biometric_consent_required | boolean | no | While pending (ZADQ-331): true when no consent to the face comparison is recorded for this session — the link is withheld until POST …/biometric-consent records one; false once it is. | |
expiresAt | string (date-time) | no | Proofing deadline of the current session. | |
reusableUntil | string (date-time) | no | End 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). | |
freshnessBand | string | no | Age 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" |
reverificationDueAt | string (date-time) | no | When "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. | |
reverificationDue | boolean | no | True 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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
sessionId | string | yes | ||
outcome | string | yes | "approved", "rejected" | |
assuranceLevel | string | no | Assurance grade met by the proofing process (e.g. "G"). |
Attestation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
sellerId | string | yes | ||
assuranceLevel | string | yes | ||
status | string | yes | "active", "suspended", "revoked" | |
statusReason | string | no | Why 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" |
freshnessBand | string | no | Freshness band of the backing session, as the issuer reports it. | "F4", "F3", "F2", "F1" |
issuedAt | string (date-time) | yes | ||
updatedAt | string (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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
attestation_ref | string | yes | 32-byte opaque reference, hex. | |
issuer_id | string | yes | ||
chain | string | yes | ||
pay_to | string | yes | ||
resource_url | string | yes | ||
assurance_grade | integer | yes | ||
issued_at_unix | integer | yes | ||
signature | string | yes | Ed25519 by the issuer's registered status signing key, hex (64 bytes). |
AttestationStatusUpdate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
status | string | yes | "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. Issuer-standing 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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
outcome | string | yes | "human_backed", "revoked", "stale", "no_signal" | |
subject | object | yes | ||
subject.chain | Chain | yes | ||
subject.payTo | string | yes | ||
subject.resourceUrl | string | yes | ||
assuranceLevel | string | no | ||
verifiedAt | string (date-time) | no | ||
recheckEveryHours | integer | yes | ||
signature | string | no | Ed25519 over the canonical verdict payload, base64. | |
keyId | string | no | ||
reason | string | no | Why 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" |
extensions | VerdictExtensions | no |
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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
zadq | ZadqVerdictExtension | no |
ZadqVerdictExtension
ZadQ's own declarations about the seller, under ZadQ's Terms.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
deposit | DepositDeclaration | no |
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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | The 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" |
level | string | yes | The 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" |
verifiedAt | string (date-time) | yes | When ZadQ read its mirrored record for this answer. |
WebhookRegistration
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
url | string (uri) | yes |
Webhook
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
url | string (uri) | yes | ||
secret | string | no | Hex signing secret for X-Signature. Returned once at registration. | |
createdAt | string (date-time) | yes |
VerificationKeys
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
keys | array of VerificationKey | yes |
VerificationKey
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
keyId | string | yes | First 8 bytes of the public key's SHA-256, hex. | |
algorithm | string | yes | "Ed25519" | |
publicKey | string | yes | Raw 32-byte Ed25519 public key, base64. | |
status | string | no | current 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" |
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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
contentSha256 | string | yes | SHA-256 (hex) of the RFC 8785 canonical JSON of the vocabulary content it was read under. | |
version | string | no | ||
scopes | array of string | yes | The enumerated active values as an offer writes them (actions, mintid: categories). | |
axes | array of ScopeAxis | no | ||
units | array of ScopeValueUnit | no | ||
custodyClasses | array of string | yes | Key-custody class codes, lowest rank first. |
ScopeAxis
One axis of the vocabulary as an offer may write it.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
axis | string | yes | "action", "counterparty", "category", "geo" | |
values | array of string | yes | The enumerated active values of the axis (canonical form). | |
forms | array of ScopeForm | yes | The forms (counterparty) or namespaces (category, geo) and their canonical patterns. |
ScopeForm
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
form | string | yes | ||
pattern | string | yes | The canonical pattern a value of this form matches. |
ScopeValueUnit
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
code | string | yes | ||
minorExponent | integer | yes |
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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | <namespace>.agent-bundles[.<name>].v<N>; ZadQ's namespace is zadq. | |
vocabulary | string | yes | ||
digest | string | yes | Lowercase hex SHA-256 of the catalogue's canonical form. | |
bundles | array of AgentBundle | yes | ||
servedByIssuer | boolean | yes | Whether the network's issuer serves this catalogue (same id and digest). False also when its catalogue could not be read. | |
servedCatalogue | string | no | The id of the catalogue the issuer serves, when read. |
AgentBundle
One named, bounded scope an agent credential is minted from.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
bundleId | string | yes | ||
description | string | yes | ||
assuranceGradeMin | integer | yes | The lowest backing grade (the principal's KYC grade) an agent of this bundle may be minted at. | |
keyCustodyMin | string | yes | ||
leaseSeconds | AgentBundleRange | yes | ||
actions | array of string | yes | The actions every agent of the bundle is granted (never agent.delegate). | |
categories | AgentBundleCategories | yes | ||
regions | AgentBundleRegions | yes | ||
counterparty | AgentBundleCounterparty | yes | ||
limits | object | yes | Per 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. | |
defaultUnit | string | yes | ||
price | AgentBundlePrice | no |
AgentBundleRange
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
default | integer (int64) | yes | ||
max | integer (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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
allowed | array of string | yes | ||
default | array of string | yes | ||
max | integer | yes |
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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
allowed | array of string | yes | ||
max | integer | yes |
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.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
forms | array of string | yes | bIP-0004 named counterparty forms: merchant, url, caip10, verifier. | |
max | integer | yes |
AgentBundlePrice
ZadQ's price line for the bundle, in minor units of its unit; absent when the bundle is unpriced.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
amountMinor | integer (int64) | yes | ||
unit | string | yes |
MetricsReport
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
schema | string | yes | The wire shape's name (published-metrics/v1). | |
computedAt | string (date-time) | yes | ||
asOf | string (date) | yes | The cut-off — the last day of the last complete month (UTC). Partial months are never published. | |
period | MetricsPeriod | no | ||
cadence | object | yes | ||
cadence.publication | string | yes | monthly. | |
cadence.snapshot | string | yes | quarterly, aligned to the two-consecutive-quarters clock. | |
relatedParty | boolean | yes | Always true — the operator's position is a property of the dataset. | |
operator | MetricsOperator | yes | ||
series | array of MetricsSeries | yes | ||
contextNote | string | yes |
MetricsPeriod
Inclusive month range, YYYY-MM at both ends. Absent while no complete month holds a record.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
from | string | yes | ||
to | string | yes |
MetricsOperator
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
service | string | yes | ||
operator | string | yes | ||
relatedParty | boolean | yes | ||
position | string | yes | ||
disclosure | string | yes | The canonical metrics disclosure, embedded in every report. | |
managedLine | string | yes | The managed-line related-party sentence the corpus adds for every published dataset (seed section 6 v1.34; ZADQ-392), embedded in every report. |
MetricsSeries
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | "sellers_attested", "retention_r90", "verifications_free_path", "independent_verifiers", "anchor_service_revenue" | |
title | string | yes | ||
discipline | string | yes | "registry-based", "aggregate", "context" | |
definition | string | yes | ||
relatedParty | boolean | yes | Always true, on every series. | |
period | MetricsPeriod | no | ||
available | boolean | yes | False when the records hold no source for the series; unavailableReason says why and points is empty. | |
unavailableReason | string | no | ||
points | array of MetricsPoint | yes |
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).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
period | string | yes | YYYY-MM. | |
cumulative | integer | no | ||
active | integer | no | ||
independent | integer | no | ||
cohort | integer | no | ||
retained | integer | no | ||
r | number | no | Ratio, two decimals. | |
count | integer | no | ||
registrations | integer | no |
Problem
RFC 9457 problem details.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
type | string | no | ||
title | string | no | ||
status | integer | no | ||
detail | string | no | ||
instance | string | no |
V1Error
The /v1 error envelope (platform API v1 §5). Value-free: fields (400 person_invalid, profile_invalid) maps a field path to a code and missing (409 profile_incomplete) lists field paths — never a value.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
error | string | yes | session_required · passkey_required · last_passkey · ceremony_invalid · attestation_invalid · assertion_invalid · email_operational_invalid · body_invalid · origin_refused · not_found · not_available · internal · runtime_token_invalid · approval_not_pending · result_already_taken · declaration_invalid · request_invalid · cursor_invalid · rate_limited · offer_refused:<issuer code> (ZADQ-289) · kyc_current · kyc_required · entry_fee_due · reverification_required · invalid_state · sandbox_hint_not_available · invalid_sandbox_hint · issuer_unavailable (ZADQ-316) · kyc_grade_below_bundle (ZADQ-321) · person_invalid · profile_invalid · profile_incomplete · kind_locked · terms_changed · business_use_required · reauth_required (ZADQ-307) · account_blocked (ZADQ-311) · custody_version_conflict · last_wrap · passkey_not_on_account (ZADQ-293) · wraps_required (ZADQ-293, v1.3.2) · origin_invalid · key_invalid · private_key_refused · origin_in_use · key_reused · evidence_required · obligations_not_published · obligations_changed (ZADQ-362, v1.3.13) · mintid_unavailable (503, ZADQ-407: MintID unreachable since the start-up and the ids not discovered yet; nothing recorded, retry later) | |
detail | string | yes | ||
custody_version | integer (int64) | no | 409 custody_version_conflict (§5.8, v1.3.2) — the stored version, to read and retry on. | |
fields | object | no | The refused fields by path (400 person_invalid, profile_invalid). | |
missing | array of string | no | The field paths a payment still needs (409 profile_incomplete). |
PasskeyRegisterOptionsRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
new_account | object | no | With no session, the account the registration creates. kind (default organisation, so a v1.2 front still works) and country seed the customer record (ZADQ-307 §2.2); the kind may change until the first payment. | |
new_account.name | string | yes | The organisation's label in the dashboard. | |
new_account.kind | NewAccountKind | no | ||
new_account.country | string | no | ISO 3166-1 alpha-2, the country of registration. | |
new_account.referral | all of ReferralParams | no | v1.3.14 (§5.16): the door the sign-up came through — the landing URL's parameters. Checked here (404 referral_unknown, 409 referral_closed; 501 not_available while the door is off) and recorded in the account's transaction at the finish (account_referred). | |
consents | all of ConsentsUpdate | no | The consents given at Create your account (ZADQ-307 §2.3), recorded in the account's own transaction when the registration finishes. Checked here: 409 terms_changed for a stale Terms version or hash, 400 business_use_required for business_use: false. Only with new_account. | |
label | string | no | The passkey's label (e.g. the device). |
AccountKind
A legal entity, or a natural person acting for their trade, business or profession. Consumers are not customers.
Type: string, one of "organisation", "sole_trader".
PasskeyCeremonyOptions
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
publicKey | object | yes | WebAuthn PublicKeyCredentialCreationOptions or RequestOptions (JSON, base64url binaries). |
PasskeyRegisterRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
attestation | object | yes | The PublicKeyCredential the browser answered (toJSON form). |
PasskeyLoginRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
assertion | object | yes | The PublicKeyCredential the browser answered (toJSON form). |
PasskeyRegistered
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
passkey_id | string | yes | ||
prf_supported | boolean | yes | ||
session_expires_at | string (date-time) | yes |
PasskeySessionOpened
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_expires_at | string (date-time) | yes |
Me
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
account | MeAccount | yes | ||
person | MePerson | yes | ||
passkeys | array of MePasskey | yes | ||
payto_bindings | array of MePaytoBinding | yes | ||
products | MeProducts | yes | ||
biometric_consent | MeBiometricConsent | yes |
MeBiometricConsent
The consent to the face comparison (ZADQ-331): the label of the consent text the deployment requires now (BIOMETRIC_CONSENT_VERSION) — the page shows that text and no other — and the last consent the account's person gave (on the account or on one of its records), null before any. A last_given.version other than version_required means the text changed since: the next verification asks again.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version_required | string | yes | ||
last_given | all of BiometricConsentLast | yes |
BiometricConsentLast
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
at | string (date-time) | yes |
MeAccount
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
name | string, nullable | yes | The account's label; null for a migrated account until the person names it. | |
kind | AccountKind | yes | ||
erasure_requested_at | string (date-time), nullable | yes | When the person requested the erasure of the account's data (ZADQ-307 §2.4); null otherwise. | |
blocked_at | string (date-time), nullable | no | Since when the account is blocked (ZADQ-311): an erasure request or the contract's end. While set, the customer record is not served (409 account_blocked on the record routes) and the person's names and e-mail read null here. | |
closes_at | string (date-time), nullable | no | When the account closes after an erasure request (ZADQ-311): the end of the current billing period at the provider, or the moment the close was scheduled when nothing is billed periodically. Null until the retention job schedules it. | |
referral | all of AccountReferral | no | v1.3.14 (§5.16) — the referral the account arrived through (the first recorded); null otherwise. | |
created_at | string (date-time) | yes |
MePerson
The responsible person (ZADQ-307 §2.1): names, operational e-mail and preferred language — the customer record's, never KYC data. No phone, no identity-verification data and no job title (data minimisation).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
given_name | string, nullable | yes | ||
family_name | string, nullable | yes | ||
email_operational | string, nullable | yes | The operational contact address; never KYC data. | |
preferred_language | string | yes | ISO 639-1, from the service's supported set (en, es, ca, et, de, fr, it, pt, nl); en by default. | |
kyc | MeKyc | yes |
MeKyc
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | none before any session. | "none", "pending", "approved", "rejected", "expired", "withdrawn" |
session_id | string | no | The issuer's KYC session handle (opaque). | |
grade | integer, nullable | yes | The assurance grade of the approved session (ZADQ-321); null while unknown. | |
reusable_until | string (date-time), nullable | yes | ||
reverification_offer | MeKycReverificationOffer | no |
MeKycReverificationOffer
v1.3.10 (ZADQ-336): present while the Issuer operator's answer to a review or a rectification offered a re-verification and the person has not opened it yet. Show it as for a due re-verification: the person's next POST /v1/kyc/sessions opens it (after its own steps, the consent step included), at no cost — charge reads none.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | The session handle the re-verification renews. | |
offered_at | string (date-time) | yes | ||
charge | string | yes | "none" |
MePasskey
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
credential_id | string | yes | The passkey's WebAuthn credential id, base64url without padding (the browser's prf.evalByCredential key; ZADQ-293). | |
label | string, nullable | yes | ||
prf_supported | boolean | yes | ||
created_at | string (date-time) | yes |
MePaytoBinding
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
payto | string | yes | The wallet address. | |
chain | string | yes | ||
bound_at | string (date-time) | yes |
MeProducts
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
vendor | MeVendorProduct | yes | ||
agent_operator | MeAgentOperatorProduct | yes | ||
verifier | MeVerifierProduct | yes |
MeProductState
pending_payment (v1.3.14, §5.16): a principal plan chosen and not paid yet.
Type: string, one of "inactive", "pending_payment", "pending_kyc", "pending_entry_fee", "active", "suspended", "closed".
MeVendorProduct
The vendor product as derived from the account's seller records (platform API v1.3 §5.9, ZADQ-324): inactive without a record; pending_kyc while an endpoint is verifying or its session expired; pending_entry_fee with an admitted endpoint whose schedule is not paid yet (the tier's hosted checkout is the vendor's entry fee); active once the provider's completed event recorded the billing, plan then the endpoint's billing tier; closed when only rejected or withdrawn records remain. The best state across the account's endpoints wins; suspended is not derived for the vendor in this version.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | MeProductState | yes | ||
plan | string, nullable | yes |
PlatformSellerList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
sellers | array of PlatformSeller | yes |
PlatformSeller
One seller record of the account as the dashboard lists it (platform API v1.3 §5.9): the v0 record's public facts in the v1 spelling. Endpoint identifiers and states only — never identity data.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
chain | Chain | yes | ||
payto | string | yes | The payTo address. | |
resource_url | string (uri) | yes | ||
operator_type | string | yes | "person", "organisation" | |
state | string | yes | "pending_kyc", "kyc_expired", "admitted", "rejected", "withdrawn" | |
terms_acknowledged | boolean | yes | Whether the current terms version is acknowledged by the payTo's wallet (GET /v0/sellers/{id}/terms carries the message to sign when not). | |
billing | string | yes | Billing state at the operator's billing provider, as GET /v0/sellers/{id} serves it. | "none", "active" |
billing_tier | string | no | "attested_vendor", "regulated_compliance" | |
billing_cadence | string | no | "monthly", "annual" | |
kyc | KycHandoff | no | ||
attestation | Attestation | no | ||
credential | CredentialState | no | ||
verdict | Verdict | no | ||
created_at | string (date-time) | yes |
MeAgentOperatorProduct
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | MeProductState | yes | ||
plan | string, nullable | yes | ||
seats | object | yes | ||
seats.used | integer | yes | ||
seats.plan | integer, nullable | yes | ||
seats.cap_per_person | integer | yes | ||
mints_this_hour | object | yes | ||
mints_this_hour.used | integer | yes | ||
mints_this_hour.allowed | integer | yes | ||
principal_plan | MePrincipalPlan | no | ||
enterprise | MeEnterprise | no |
MeEnterprise
v1.3.30 (ZADQ-472, §5.20) — the account's Enterprise contract, as ZadQ activated it from the operator console once agreed: the seats agreed (products.agent_operator.seats.plan is the same number bounded by the issuer's cap per person), the period billed in advance, how its lines are collected (invoice: on the provider's invoice or ZadQ's manual invoice — never paid from the app), the end of the period paid where the record knows it, and its end once stopped. Absent on any other plan. Never an amount: the contract's amount is on its invoice.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
seats | integer | yes | ||
period | string | yes | "month", "year" | |
channel | string | yes | "invoice" | |
paid_until | string (date-time), nullable | no | ||
ends_at | string (date-time), nullable | no |
MePersonUpdate
PATCH /v1/me/person (ZADQ-307 §2.1): any of the fields; null clears a name or the e-mail. Unknown fields answer 400 body_invalid; 400 person_invalid with fields: {<field>: required | too_long | invalid} otherwise.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
given_name | string, nullable | no | ||
family_name | string, nullable | no | ||
email_operational | string, nullable | no | ||
preferred_language | string | no |
Organisation
The organisation (or the sole trader's trade) as the responsible person declared it. Nothing here was verified by a register check; vat_id.status is VIES's answer.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | AccountKind | yes | ||
legal_name | string, nullable | yes | Required to save; for a sole trader the trading name or the person's own name, as on their tax registration. | |
trade_name | string, nullable | yes | ||
legal_form | string, nullable | yes | ||
registration_number | string, nullable | yes | The national business-register number as declared (EE registry code, ES Registro Mercantil entry, DE HRB, FR SIREN…). | |
country | string, nullable | yes | ISO 3166-1 alpha-2, the country of registration. | |
vat_id | all of OrganisationVatId | yes | ||
tax_id | all of OrganisationTaxId | yes | ||
registered_address | all of OrganisationAddress | yes | ||
invoice_email | string, nullable | yes | The invoicing address; the operational e-mail is used when absent. | |
complete | boolean | yes | ||
missing | array of string | yes | The field paths a payment still needs, e.g. registered_address.line1, tax_id. |
OrganisationVatId
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
value | string | yes | The EU VAT number with its ISO prefix (Greece EL), normalised. | |
status | string | yes | "valid", "invalid", "unchecked", "unavailable" | |
checked_at | string (date-time), nullable | yes |
OrganisationTaxId
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
scheme | string | yes | es_nif covers the Spanish NIF, NIE and the entity NIF formerly called CIF (format and control character checked); other is free text. | "es_nif", "other" |
value | string | yes |
OrganisationAddress
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
line1 | string, nullable | yes | ||
line2 | string, nullable | yes | ||
postal_code | string, nullable | yes | ||
city | string, nullable | yes | ||
region | string, nullable | yes | ||
country | string, nullable | yes | ISO 3166-1 alpha-2. |
OrganisationUpdate
PUT /v1/organisation — the full object minus the computed fields.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | AccountKind | no | ||
legal_name | string | yes | ||
trade_name | string, nullable | no | ||
legal_form | string, nullable | no | ||
registration_number | string, nullable | no | ||
country | string | yes | ||
vat_id | string, nullable | no | The EU VAT number with its ISO prefix; checked against VIES on write. On PUT the record's own shape {value, status?, checked_at?} is accepted too — the contract's "object minus the computed fields" (zadq.app sends it); the computed fields are ignored. | |
tax_id | all of OrganisationTaxId | no | ||
registered_address | all of OrganisationAddress | no | ||
invoice_email | string, nullable | no |
Consents
The current view of the account's append-only consents log (addendum §1).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | object, nullable | yes | ||
terms.version | string | yes | ||
terms.sha256 | string | yes | ||
terms.accepted_at | string (date-time) | yes | ||
privacy_notice | object, nullable | yes | The Privacy Policy version shown — information, never a consent. | |
privacy_notice.version | string | yes | ||
privacy_notice.shown_at | string (date-time) | yes | ||
business_use | object, nullable | yes | ||
business_use.at | string (date-time) | yes | ||
marketing | object | yes | ||
marketing.opt_in | boolean | yes | ||
marketing.at | string (date-time), nullable | yes |
ConsentsUpdate
Any of the four; each appends to the log.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | object | no | ||
terms.version | string | yes | ||
terms.sha256 | string | yes | ||
privacy_notice | object | no | ||
privacy_notice.version | string | yes | ||
business_use | boolean | no | The declaration "I act for my business or profession"; false is refused (400 business_use_required). | |
marketing | boolean | no |
LegalCurrent
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | object | yes | ||
terms.version | string | yes | ||
terms.sha256 | string | yes | ||
terms.url | string | yes | ||
terms.effective_at | string (date-time) | yes | ||
privacy | object | yes | ||
privacy.version | string | yes | ||
privacy.url | string | yes | ||
privacy.effective_at | string (date-time) | yes |
LegalUpcoming
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
terms | array of LegalUpcomingTerms | yes | ||
privacy | array of LegalUpcomingPrivacy | yes |
LegalUpcomingTerms
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes | ||
url | string | yes | ||
published_at | string (date-time) | yes | ||
effective_at | string (date-time) | yes | ||
required_by_law | boolean | yes | The change is required by law and applies from its entry into force (Terms clause 20). |
LegalUpcomingPrivacy
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
url | string | yes | ||
published_at | string (date-time) | yes | ||
effective_at | string (date-time) | yes |
ChangeNotices
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
notices | array of ChangeNotice | yes |
ChangeNotice
One account's notice of a legal version (ZADQ-313). accepted (Terms only) is true when the account accepted this version or a later one; seen_at (Privacy Policy only) is the dismissal; mailed_at is when the e-mail to the Responsible Person went out (null until then, or without an operational e-mail).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
kind | string | yes | "terms", "privacy" | |
version | string | yes | ||
url | string | yes | ||
effective_at | string (date-time) | yes | ||
in_force | boolean | yes | The version applies already. | |
open | boolean | yes | The notice still asks for something — the acceptance, or reading it. | |
sha256 | string, nullable | yes | The Terms version's SHA-256, to accept it with (null for the Privacy Policy). | |
required_by_law | boolean | yes | ||
accepted | boolean, nullable | yes | ||
seen_at | string (date-time), nullable | yes | ||
mailed_at | string (date-time), nullable | yes |
LegalTermsText
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes | ||
text | string | yes |
ErasureState
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "requested" | |
at | string (date-time) | yes |
ApprovalKind
Type: string, one of "delegate", "present", "renew".
ApprovalState
Type: string, one of "pending", "approved", "declined", "expired", "failed".
ApprovalSummary
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
kind | ApprovalKind | yes | ||
state | ApprovalState | yes | ||
created_at | string (date-time) | yes | ||
expires_at | string (date-time) | yes | ||
summary | string | yes | One line for the inbox (the agent's name and bundle, or the purpose). |
ApprovalList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
approvals | array of ApprovalSummary | yes |
Approval
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
kind | ApprovalKind | yes | ||
state | ApprovalState | yes | ||
created_at | string (date-time) | yes | ||
expires_at | string (date-time) | yes | ||
decided_at | string (date-time) | no | ||
failure | string | no | The reason code of a failed approval (e.g. offer_refused:session_reuse_expired, result_not_taken). | |
result_taken | boolean | no | Present approvals only — the holder's result was delivered to the operator's poll (and deleted). | |
delegate | ApprovalDelegate | no | ||
present | ApprovalPresent | no | ||
renew | ApprovalRenew | no |
ApprovalDelegate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
enrolment_id | string | yes | ||
name | string | yes | The agent's name in the operator's runtime. | |
bundle | string | yes | ||
bundle_params | object | yes | ||
lease_seconds | integer | yes | ||
price_line | string, nullable | yes | The agent's recorded price line id (/v1/price-lines) where a deployment recorded one, null otherwise — and null on a principal plan (personal, premium; §5.16), which includes its bounded agents (ZADQ-423) — no line, no price clause, nothing authorised on a card. | |
principal_mode | PrincipalMode | no |
PrincipalMode
Where the person's holder answers (ZADQ-294); absent reads as runtime.
Type: string, one of "runtime", "browser".
ApprovalRenew
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
agent_id | string | yes | ||
enrolment_id | string, nullable | no | The renewal's own enrolment (ZADQ-294) — where a browser-mode renewal's material is posted (POST /v1/enrolments/{id}/mint) and a late offer collected (POST /v1/enrolments/{id}/offer). Null on renewals opened before 2026-10-18. | |
name | string | yes | ||
bundle | string | yes | ||
lease_seconds | integer | yes | ||
price_line | string, nullable | yes | The lease price line's id (/v1/price-lines), null until billing records one — and null on a principal plan (personal, premium; §5.16), which includes its bounded agents' leases (ZADQ-423). | |
principal_mode | PrincipalMode | no |
ApprovalPresent
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
purpose | string | yes | ||
from | ApprovalFrom | yes | ||
declaration | PresentDeclaration | yes | ||
principal_mode | PrincipalMode | no |
ApprovalFrom
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
agent_id | string | no | ||
enrolment_id | string | no | ||
runtime | object | yes | ||
runtime.kind | string | yes | ||
runtime.instance_ref | string | yes |
PresentDeclaration
The verifier's declaration — never a challenge.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
profile | string | yes | ||
verifier_origin | string | yes | The verifier's origin (https; http on loopback only). | |
challenge_endpoint | string | yes | Where the holder fetches the challenge after approval; on the origin's host or a subdomain. | |
claim_policy | array of ClaimRule | yes | ||
issuer_policy | any | yes | The verifier's accepted issuers, as the verifier states them. |
ClaimRule
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
claim | string | yes | ||
operator | string | no | ||
value | any | yes | The policy's threshold or value set, as the verifier states it. |
PresentApprovalRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | string | yes | "present" | |
purpose | string | yes | ||
declaration | PresentDeclaration | yes | ||
expires_in_s | integer | no | ||
principal_mode | PrincipalMode | no |
PresentApprovalCreated
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
state | ApprovalState | yes | ||
expires_at | string (date-time) | yes |
ApproveRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
assertion | object | yes | The PublicKeyCredential the browser answered to the login options (toJSON form). |
ApprovalDecided
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | ApprovalState | yes | ||
offer | object | no | Browser-mode delegate or renew only (ZADQ-294), once: the issuer's agent offer for the browser's credential step — {credential_offer, mint_challenge, expires_at, scope, bundle}, the operator's price line stripped. Never stored or logged. | |
offer_expires_at | string (date-time) | no |
HolderFailure
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
failure | string | yes | A code of the closed vocabulary (ZADQ-294), never a value. |
BrowserOffer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
offer | object | yes | The issuer's agent offer, the operator's price line stripped (the runtime-mode material shape). | |
expires_at | string (date-time) | yes |
EnrolmentMintRequest
Exactly one of mint and failure.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
mint | MintMaterial | no | ||
failure | string | no | A code of the closed vocabulary instead of a material. |
MintMaterial
The split mint's material, MintID's stage-2 interface v1.1 §1 (MintMaterial.to_json()): one use at the issuer, nothing of the principal. A bearer: held sealed only until the runtime's poll takes it, never logged.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
v | integer | yes | 1 | |
issuer_url | string | yes | ||
credential_configuration_id | string | yes | "mintid_agent_v1", "mintid_agent_v2" | |
access_token | string | yes | ||
c_nonce | string | yes | ||
expires_at | integer (int64) | yes | Unix seconds; the issuer's offer lifetime (token_ttl_seconds, 300). | |
scope | array of object | yes | ||
scope[].axis | string | yes | ||
scope[].value | any | yes | ||
scope[].value_id | string | yes | ||
scope_endpoint | string | yes | ||
bundle_id | string, nullable | no | ||
renews_credential_id | string, nullable | no |
ApprovalPoll
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | ApprovalState | yes | ||
failure | string | no | ||
result | PresentResult | no |
PresentResult
The holder's result, passed through once: the verifier's session id, the verifier's own signed request (it keeps none by session id) and the presentation envelope. ZadQ never reads inside it.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | ||
request | object | yes | ||
envelope | any | yes | The presentation envelope, opaque to ZadQ. |
ActivityPage
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
events | array of ActivityEvent | yes | ||
next_cursor | string | no |
ActivityEvent
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
at | string (date-time) | yes | ||
kind | string | yes | "passkey_added", "passkey_removed", "kyc_opened", "kyc_approved", "kyc_withdrawn", "product_activated", "enrolment_created", "enrolment_claimed", "approval_decided", "agent_registered", "agent_usable", "agent_stopped", "agent_renewed", "price_line_captured", "price_line_credited", "agent_reconciled", "agent_drift", "data_exported", "erasure_requested", "custody_uploaded", "custody_wrap_added", "custody_wrap_removed", "custody_revoked", "biometric_consent_given", "kyc_reverification_offered", "verifier_requested", "verifier_evidence_uploaded", "verifier_admission_requested", "verifier_key_rotated", "verifier_withdrawn", "verifier_admission_filed", "verifier_admission_decided", "verifier_commitment_recorded", "verifier_door_declared", "account_referred", "plan_chosen", "plan_period_opened", "verifier_line_opened", "verifier_line_voided", "plan_step_opened", "plan_switched", "relying_party_line_opened", "plan_refund_opened", "plan_refunded", "verifier_evidence_renewed", "verifier_evidence_renewal_checked", "enterprise_activated", "enterprise_stopped" | |
state | string | no | ||
reason_code | string | no | ||
ref | object | yes | At most one reference. | |
ref.enrolment_id | string | no | ||
ref.agent_id | string | no | ||
ref.approval_id | string | no | ||
ref.verifier_id | string | no | The verifier record (ZADQ-362, §5.15); on account_referred (ZADQ-365, §5.16) the refusing service's record. | |
actor | string | yes | "person", "runtime", "zadq", "issuer" |
EnrolmentState
Type: string, one of "created", "claimed", "approved", "minting", "registered", "expired", "cancelled", "declined", "failed".
EnrolmentKind
Type: string, one of "enrol", "renewal".
EnrolmentRuntime
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | string | yes | The runtime's software, e.g. mas-library-mintid (lowercase, digits, ., _, -). | |
version | string | no | ||
instance_ref | string | yes | The operator's own reference of the runtime instance; never a person's. |
EnrolmentRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
name | string | yes | The agent's name in the runtime, e.g. trip-planner/concierge_agent. | |
bundle | string | no | A bundle of the issuer's served catalogue (GET /v1/catalogue); required unless referral_id presets it. | |
referral_id | string | no | v1.3.14 (§5.16) — the first bounded agent preset from one of the account's referrals: the bundle (when left out; else it must be the referral's) and the refusing service's origin as a counterparty (added when left out). 404 referral_unknown; 409 referral_closed; 400 bundle_params_invalid for another bundle. | |
bundle_params | EnrolmentBundleParams | yes | ||
lease_seconds | integer | no | ||
principal_mode | string | yes | "runtime", "browser" |
EnrolmentBundleParams
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
counterparties | array of string | yes | ||
geo | array of string | yes | ||
categories | array of string | no | ||
limit_unit | string | no | ||
transaction_limit_minor | integer (int64) | no |
EnrolmentCreated
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
code | string | yes | The one-time code (8 characters), shown once. | |
claim_url | string | yes | The app's origin with the code in the fragment (<origin>/claim#<code>), for the QR code. | |
expires_at | string (date-time) | yes |
EnrolmentSummary
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
kind | EnrolmentKind | yes | ||
name | string | yes | ||
state | EnrolmentState | yes | ||
bundle | string | yes | ||
created_at | string (date-time) | yes | ||
expires_at | string (date-time) | yes | The code's expiry (enrol), or the material's / the approval's (renewal). | |
agent_id | string | no | ||
failure | string | no |
EnrolmentList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
enrolments | array of EnrolmentSummary | yes |
Enrolment
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
kind | EnrolmentKind | yes | ||
name | string | yes | ||
state | EnrolmentState | yes | ||
bundle | string | yes | ||
bundle_params | EnrolmentBundleParams | yes | ||
lease_seconds | integer | yes | ||
principal_mode | string | yes | "runtime", "browser" | |
runtime | EnrolmentRuntime | no | ||
approval_id | string | no | ||
agent_id | string | no | ||
price_line | string | no | The price line's id (§5.3); absent on a principal plan (§5.16), which includes its bounded agents (ZADQ-423). | |
failure | string | no | The reason code of a failed enrolment (e.g. token_expired, offer_refused:session_reuse_expired). | |
offer_ready | boolean | no | Browser mode (ZADQ-294) — an offer waits for the person's browser to collect it (POST …/offer). | |
referral_id | string | no | v1.3.14 (§5.16) — the referral the enrolment was preset from. | |
created_at | string (date-time) | yes | ||
expires_at | string (date-time) | yes |
EnrolmentClaimRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
code | string | yes | ||
runtime | EnrolmentRuntime | yes | ||
key_attestation | object | no | Accepted, not used, not kept (ZadQ sends the issuer no attestation evidence). |
EnrolmentClaimed
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
enrolment_id | string | yes | ||
runtime_token | string | yes | The runtime credential (rt1_…), shown once; sent as Authorization: Bearer on the runtime routes. | |
expires_at | string (date-time) | yes | When the delegate approval expires (keep polling until then). |
EnrolmentPoll
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | EnrolmentState | yes | ||
failure | string | no | ||
agent_id | string | no | ||
mint | object | no | The mint material, once (runtime mode: the issuer's agent offer, the price line stripped; browser mode: the browser's MintMaterial, ZADQ-294). |
EnrolmentControlHook
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
url | string | yes | https on a public address; ZadQ posts a signed kill here. | |
secret_ref | string | yes | The shared secret ZadQ signs with (HMAC-SHA256); the runtime keeps its copy, ZadQ keeps it sealed. |
EnrolmentRegisteredRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
credential_id | string | yes | The issuer's handle of the credential (64 hex), as the holder received it. | |
expires_at | string (date-time) | yes | ||
scope_endpoint | string | no | ||
control_hook | EnrolmentControlHook | no | ||
usable | boolean | no | The agent's scope is anchored (it can present its delegation); also on a later call. |
EnrolmentRegistered
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
agent_id | string | yes |
EnrolmentFailedRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
reason_code | string | yes |
EnrolmentStateAnswer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes |
PlatformAgentState
Type: string, one of "registered", "usable", "expiring", "revoked", "expired".
PlatformAgent
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
name | string | yes | ||
bundle | string | yes | ||
bundle_params | EnrolmentBundleParams | yes | ||
lease_ends_at | string (date-time) | yes | ||
state | PlatformAgentState | yes | ||
enrolment_id | string | yes | ||
runtime | EnrolmentRuntime | yes | ||
control_hook | boolean | yes | ||
issuer_state | string | no | The issuer's own state of the agent as the reconciliation last read it (ZADQ-296): active, revoked or expired. Absent until a pass matched the agent. When it disagrees with state, the issuer's is the truth the dashboard shows. | "active", "revoked", "expired" |
issuer_reason | string | no | The issuer's reason beside issuer_state when it is not active (a closed code, e.g. lease_expired, principal_revoked). | |
reconciled_at | string (date-time) | no | When the reconciliation last read the agent at the issuer. |
PlatformAgentList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
agents | array of PlatformAgent | yes |
AgentRenewalRequested
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
approval_id | string | yes |
PriceLineKind
v1.3.15 (§5.17, ZADQ-373) adds the verifier product's business lines: kit_setup (the verifier kit set-up — withdrawn in v1.3.16: no longer opened, an unpaid one voided), onboarding_at_cost (the responsible person's onboarding at cost), managed_environment and managed_setup (the managed deployment). v1.3.16 (ZADQ-382) adds the relying party's principal_enrolled (one month of principals enrolled through the business's door) — since v1.3.18 (ZADQ-389) the month's rebate credit on the business's invoice, a negative amount — and the plan step kinds agent_extra and grade_a3_option, no longer opened since v1.3.25 (no deployment offers a step). None is a verification line. v1.3.17 (ZADQ-387) adds plan_refund: a principal plan's refund after its identity check ended refused or withdrawn — the amount paid back, the verification cost retained (retained_minor). v1.3.31 (ZADQ-470) adds the vendor product's lines on an account whose seller records are bound to it: vendor_entry (the entry fee paid at the tier's checkout, once per operator) and vendor_endpoint (the additional endpoints on the subscription, quantity the endpoints above the tier's quota, period month or year); ref.seller_id names the seller record. Neither is payable on /v1/price-lines/{id}/pay.
Type: string, one of "entry", "seat", "bundle_mint", "lease_year", "usage", "kit_setup", "onboarding_at_cost", "managed_environment", "managed_setup", "agent_extra", "grade_a3_option", "principal_enrolled", "plan_refund", "vendor_entry", "vendor_endpoint".
PriceLineState
v1.3.17 (ZADQ-387) adds refunded — a plan_refund line paid back (the console's mark, or the provider's refund).
Type: string, one of "open", "authorised", "captured", "invoiced", "failed", "credited", "void", "refunded".
PriceLineRef
What the line belongs to (an enrolment, an agent, a verifier record); empty for the activation's own lines.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
enrolment_id | string | no | ||
agent_id | string | no | ||
verifier_id | string | no | v1.3.15 (§5.17) — the verifier record a business line was opened for. | |
seller_id | string | no | v1.3.31 (ZADQ-470) — the seller record a vendor line belongs to. |
PriceLine
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
period | string, nullable | no | v1.3.14 (§5.16) — the period a principal plan's seat line pays; its amount is the plan's whole price for it. v1.3.15 (§5.17) — the period a managed environment's line pays, in advance. | "month", "year" |
environment | string, nullable | no | v1.3.15 (§5.17) — a managed environment's environment; null on every other line. | "production", "test" |
kind | PriceLineKind | yes | ||
amount_minor | integer (int64), nullable | yes | v1.3.18 (ZADQ-389) — negative on a principal_enrolled line opened since (the month's rebate set off on the invoice; not payable). | |
unit | string, nullable | yes | ||
state | PriceLineState | yes | ||
ref | PriceLineRef | yes | ||
settlement | string | yes | "console", "stripe" | |
channel | string | yes | How the line is collected (ZADQ-324, derived at read time, never stored): invoice on the console settlement (a manual invoice) and for a provider customer whose subscription collects by invoice; card otherwise (the hosted checkout). The dashboard shows "Pay" for card, "on your invoice" for invoice. | "card", "invoice" |
quantity | integer, nullable | no | Seats (seat), lease days (lease_year); v1.3.16 — the month's count of principals enrolled (principal_enrolled); v1.3.18 — on a rebate credit, the rebates settled in the month. | |
bundle | string, nullable | no | ||
vat_treatment | string, nullable | no | v1.3.16 (ZADQ-382) — how the amount stands to VAT, on the lines opened since (null on the lines before). v1.3.29 (ZADQ-469) — every amount is net, ex-VAT: a line opens exclusive (the billing provider adds the VAT at checkout and on the invoice) or reverse_charge (the same net, no VAT, for a business whose customer record holds a valid VAT number of another member state). included is a legacy value: it is never opened now and stays only on lines opened before v1.3.29. | "included", "reverse_charge", "exclusive" |
covers_until | string (date-time), nullable | no | v1.3.16 — the end of the period a step's line (agent_extra, grade_a3_option) pays, from its settlement; null until settled and on every other line. No step is offered since v1.3.25. | |
credit_minor | integer (int64), nullable | no | v1.3.16 — on a switch's seat line (Personal → Premium), the credit of the unused period; amount_minor is the new period's price less it. | |
free_quantity | integer, nullable | no | v1.3.16 — on a principal_enrolled line, the free volume applied to the month's count; null on a rebate credit (v1.3.18). | |
billing_month | string (date), nullable | no | v1.3.16 — on a principal_enrolled line, the month counted (its first day); v1.3.18 — the rebate statement's month. | |
retained_minor | integer (int64), nullable | no | v1.3.17 (ZADQ-387) — on a plan_refund line, the cost of the identity check performed at the person's request, retained; amount_minor is what is paid back. v1.3.29 (ZADQ-469) — net, ex-VAT, on a line exclusive or reverse_charge: the provider's refund pays back amount_minor plus its share of the VAT the payment collected (a legacy included line keeps the amounts it was opened with). | |
refund_reason | string, nullable | no | v1.3.17 — on a plan_refund line, why the plan closed (ZadQ's own code; nothing of the issuer's reason); v1.3.34 (ZADQ-472) — enterprise_replaces_paid_plan, the paid plan replaced by an Enterprise contract (its unused period paid back by hand). | "identity_check_refused", "identity_check_withdrawn", "enterprise_replaces_paid_plan" |
created_at | string (date-time) | yes |
PriceLineList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
lines | array of PriceLine | yes |
PriceLinePay
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
return_to | string | no | The dashboard's account page the hosted checkout returns to (account, verification, agent-operator (default), enrolments, approvals, agents, billing, activity). | "account", "verification", "agent-operator", "enrolments", "approvals", "agents", "billing", "activity" |
PriceLinePayment
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
checkout_url | string | no | The billing provider's hosted checkout page. | |
state | PriceLineState | no |
ActivateAgentOperator
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
plan | string | yes | A principal plan's id (personal, premium — v1.3.16; plus is retired). v1.3.30 — enterprise answers 409 plan_by_contact (the console activates it, §5.20). | |
period | string | no | v1.3.14 (§5.16) — the principal plan's billing period, in advance (default year; on a switch, the current one). | "month", "year" |
PlanStepOpen
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | string | yes | "agent_extra", "grade_a3_option" | |
period | string | no | Billed in advance; the plan's period when left out. | "month", "year" |
PlanRefund
v1.3.17 (ZADQ-387; Marc's answer of 2026-10-29: "retain the verification cost, refund the rest") — the plan closed because its identity check ended refused (identity_check_refused) or was withdrawn after it started (identity_check_withdrawn). line is the plan_refund line (its amount_minor paid back, its state open until paid back, then refunded); paid_minor what the refund is computed from — the amount paid on the plan for the first check, the unused period for a re-check; retained_minor the cost of the identity check performed at the person's request (retained_for: identity_check_performed).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
line | PriceLine | yes | ||
reason | string | yes | "identity_check_refused", "identity_check_withdrawn" | |
paid_minor | integer (int64) | yes | ||
retained_minor | integer (int64) | yes | ||
retained_for | string | yes | "identity_check_performed" |
PlanSwitch
v1.3.16 (ZADQ-382) — a switch Personal → Premium asked; the plan stays Personal until line is paid.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
to | string | yes | "premium" | |
line | PriceLine | yes |
AgentOperatorActivation
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "pending_payment", "pending_kyc", "pending_entry_fee", "active", "suspended", "closed" | |
period | string, nullable | no | v1.3.14 — the principal plan's period. | "month", "year" |
plan_line | all of PriceLine | no | v1.3.14 — the principal plan's seat line for the period (pay it with POST /v1/price-lines/{id}/pay). | |
plan | string | yes | ||
settlement | string | no | "console", "stripe" | |
entry_fee | all of PriceLine | yes | v1.3.30 (ZADQ-472) — always null; no entry fee is sold (kept in the shape for the client app). | |
plan_switch | all of PlanSwitch | no | v1.3.16 — the switch Personal → Premium waiting on its line; null otherwise. |
CataloguePlan
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
seats | integer | yes | ||
label | string | yes | ||
kind | string | no | v1.3.14 — principal for the principal plans (v1.3.16 Personal and Premium; §5.16; amounts on GET /v1/plans). v1.3.30 (ZADQ-472) — contact for enterprise, sold by contact and activated by ZadQ (§5.20); operator is gone with the earlier plans. | "principal", "contact" |
CatalogueBundle
A bundle as the issuer serves it, on the keys the enrolment form reads (bundle_id, description, action, category, geo, counterparty, limits, lease_seconds, assurance_grade_min); never its price.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
bundle_id | string | yes |
PlatformCatalogue
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
bundles | array of CatalogueBundle | yes | ||
plans | array of CataloguePlan | yes |
KycSessionCreate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
sandbox | string | no | Staging only: the sandbox KYC driver's outcome grammar without its sandbox: prefix (<outcome>[:<option>…], e.g. approved:g2, rejected, expired). Identity options are refused. | |
biometric_consent | BiometricConsentGiven | no |
KycSession
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
session_id | string | yes | The issuer's KYC session handle (opaque). | |
state | string | yes | "pending", "approved", "rejected", "expired", "withdrawn" | |
handoff_url | string, nullable | no | Where the person completes the verification at the issuer's provider; while pending, and only once a consent to the face comparison is recorded for this session (ZADQ-331) — absent (null) otherwise, with biometric_consent_required: true. | |
biometric_consent_required | boolean | no | While pending (ZADQ-331): true when no consent to the face comparison is recorded for this session (one opened before the rule) — the link is withheld until POST /v1/kyc/sessions/{id}/biometric-consent records one. | |
expires_at | string (date-time) | no | The proofing deadline of a pending session. | |
grade | integer, nullable | yes | The issuer's assurance grade the approval was recorded at (ZADQ-321); null while not approved or where the boundary named none. | |
reusable_until | string (date-time), nullable | yes | The end of an approved session's reuse window; the principal credential expires exactly with it. | |
credential | KycCredential | yes |
KycCredential
The responsible person's identity credential in the operator's runtime, as this service knows it: state only. expired is derived (offered or held past the verification's window); revoked: by the issuer's policy (consent withdrawn); self_revoked: by its holder, terminal on this verification.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "none", "offered", "held", "expired", "revoked", "self_revoked" | |
offered_at | string (date-time) | no | ||
expires_at | string (date-time) | no | The verification's window end, which is the credential's. | |
credential_ref | string | no | The runtime's own opaque reference. Never a key, a code or a proof. |
KycCredentialOffer
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
location | CustodyLocation | no | ||
offer | object | yes | The credential offer object, as the issuer returned it — opaque, one-shot; redeem it at once. | |
expires_at | string (date-time) | yes | When the code and the credential it yields expire — the verification's own window end at the latest. No grace. | |
credential | KycCredential | yes |
KycCredentialReport
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | held, or self_revoked (revoked is the older spelling of the same report). | "held", "self_revoked", "revoked" |
credential_ref | string | no | An opaque reference of the runtime's choosing for the credential it holds. Never a key. |
KycCredentialOfferRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
location | CustodyLocation | no |
CustodyLocation
Where the person's identity credential lives (MintID ADR-0027): server — the holder in the operator's runtime (stage 1); browser — the person's browser holder (stage 2). Default server.
Type: string, one of "server", "browser".
CustodyLocations
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
credentials | array of CustodyLocationState | yes |
CustodyLocationState
One custody location's credential, state only.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
location | CustodyLocation | yes | ||
state | string | yes | "none", "offered", "held", "expired", "revoked", "self_revoked" | |
offered_at | string (date-time) | no | ||
issued_at | string (date-time) | no | ||
expires_at | string (date-time) | no | The verification's window end, which is the credential's. | |
credential_ref | string | no | The server location's opaque reference (the runtime's own). Never a key. | |
custody_version | integer (int64) | no | The browser location's stored version. | |
wraps | integer | no | The browser location's number of wraps (passkeys that can open it). | |
rotation_due | boolean | no | The browser location's rotation_due (v1.3.2); absent for the server location. |
BrowserCustody
The browser-location credential. ciphertext is the holder's storage bytes encrypted in the browser (base64; present on the read route only, and there absent before the first upload and after a revocation); wraps are the data key wrapped under each passkey. Opaque to this service: no key, no plaintext, no PRF output ever reaches it.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
location | CustodyLocation | yes | ||
state | string | yes | "offered", "held", "expired", "revoked", "self_revoked" | |
kyc_session_id | string | no | The session handle the credential was offered on. | |
scheme | string | yes | The browser's name for the wrap and AEAD construction (default prf-hkdf-aead-v1). Never interpreted here. | |
custody_version | integer (int64) | yes | ||
rotation_due | boolean | yes | v1.3.2: true once a wrap went without a rotation of the data key (a wrap removed, or a passkey removed with its wrap); cleared by the next rotation (PUT with rotation: true). | |
ciphertext | string (byte) | no | Base64 of the ciphertext, as uploaded. | |
issuer_credential_handle | string | no | The issuer's opaque credential handle, when the browser reported it. | |
offered_at | string (date-time) | no | ||
issued_at | string (date-time) | no | ||
expires_at | string (date-time) | no | ||
wraps | array of CustodyWrap | yes |
CustodyWrap
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
passkey_id | string | yes | ||
prf_salt | string (byte) | yes | Base64 of the PRF input and HKDF salt the browser drew for this passkey (16 to 64 bytes). Not a secret; opaque here. | |
wrapped_dek | string (byte) | yes | Base64 of the data key wrapped under this passkey's PRF-derived key-encryption key (32 to 512 bytes). Opaque here. | |
created_at | string (date-time) | yes |
CustodyWrapAdd
A wrap for one more passkey, with the custody version the browser read (v1.3.2).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
passkey_id | string | yes | One of the account's passkeys. | |
prf_salt | string (byte) | yes | ||
wrapped_dek | string (byte) | yes | ||
custody_version | integer (int64) | yes | The version the browser read; the addition advances it by one. |
CustodyWrapInput
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
passkey_id | string | yes | One of the account's passkeys. | |
prf_salt | string (byte) | yes | ||
wrapped_dek | string (byte) | yes |
BrowserCustodyUpload
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
ciphertext | string (byte) | yes | Base64 of the encrypted holder record (1 to 262144 bytes decoded). | |
custody_version | integer (int64) | yes | The version the browser read; 0 on the first upload. The stored version advances by one. | |
scheme | string | no | ||
issuer_credential_handle | string | no | The issuer's opaque credential handle. Never a key, a code or a proof. | |
issued_at | string (date-time) | no | ||
wraps | array of CustodyWrapInput | no | Required on the first upload (at least one); on a rotation the wrap of every passkey that stays, under the new data key (empty: 409 last_wrap); refused on a later plain upload. | |
rotation | boolean | no | v1.3.2: this upload rotates the data key — the ciphertext and every wrap replaced in one write, wraps not listed removed, rotation_due cleared. |
BrowserCustodyReport
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "revoked", "self_revoked" |
PinnedVerifierKeys
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
records | array of PinnedVerifierKeyRecord | yes | ||
pinned_at | string (date-time) | no | When the operator recorded the set from its proven read, when the configuration says. |
PinnedVerifierKeyRecord
One verifier's registry record as @mintid-net/holder 0.1.0's VerifierKeys reads it (identity.v1.verifier.Verifier: hex bytes, proto enum numbers).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
verifier_id | string | yes | 64 lowercase hex. | |
state | integer | yes | The record's authority state (proto enum number). | |
request_signing_keys | array of PinnedRequestKey | yes |
PinnedRequestKey
One identity.v1.core.KeyRecord of the verifier's request_signing_keys.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
key_id | string | yes | 64 lowercase hex. | |
algorithm | integer | yes | Proto enum number. | |
public_key | string | yes | Hex. | |
state | integer | yes | The key's state (proto enum number); the holder verifies only under an active key. |
HolderNetwork
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
issuer_url | string | yes | ||
chain_id | string | yes | ||
relay_url | string | yes | ||
chain_rpc_url | string, nullable | no |
VerifierState
Type: string, one of "requested", "evidence_pending", "filed", "admitted", "refused", "withdrawn".
VerifierAlgorithm
ed25519 or ecdsa_p256 (the request-signing key's algorithm, as the kit generated it).
Type: string.
VerifierRefusedReason
The closed list a refusal carries: the admission policy's refusal reason codes (ADR-0030, Accepted 2026-10-28; v1.3.24, ZADQ-433). A refusal recorded before v1.3.24 with ZadQ's provisional code reads the code it maps to.
Type: string, one of "not_registered_business", "identity_check_missing", "evidence_not_ok", "obligations_not_accepted", "request_invalid".
VerifierCommitmentRefusalReason
Why a request for the commitment did not bring one (v1.3.24): the answer is not the issuer's seven members (commitment_malformed), names another issuer (commitment_issuer_mismatch), its signature does not verify under the issuer's status key (commitment_signature_invalid), is for another origin (commitment_origin_mismatch), its grade is below A2 (commitment_grade_below_floor), its reuse window has ended (commitment_expired); or the issuer refused the request (issuer_refused).
Type: string, one of "commitment_malformed", "commitment_issuer_mismatch", "commitment_signature_invalid", "commitment_origin_mismatch", "commitment_grade_below_floor", "commitment_expired", "issuer_refused".
VerifierStatusKeyCheck
ZadQ's check of the commitment's signature under the issuer's status key: verified, the signature verifies under a status key the deployment holds; unverified, the deployment holds none — the signature is kept, and the admission tool and the chain's operator check it.
Type: string, one of "verified", "unverified".
VerifierRecordCommitment
The commitment as the record holds it, without asking anyone (v1.3.24): available (a commitment whose reuse window is open), expired (its window ended and no request since brought another), pending_issuer or refused (the last request's result when no commitment serves), not_requested (no request yet).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "not_requested", "pending_issuer", "refused", "expired", "available" | |
handle | string, nullable | yes | The commitment's commitment_hex (64 lowercase hex), also the record's commitment_handle. | |
issuer_id | string, nullable | yes | ||
assurance_grade | integer, nullable | yes | ||
reusable_until | string (date-time), nullable | yes | ||
status_key_check | all of VerifierStatusKeyCheck | yes | ||
refusal_reason | all of VerifierCommitmentRefusalReason | yes | ||
checked_at | string (date-time), nullable | yes | When the last request was made. |
VerifierKeyInput
A request-signing key as the kit generated it — the public half only; ZadQ never receives the private key.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
key_id | string | yes | 64 lowercase hex, as the kit wrote it. | |
algorithm | VerifierAlgorithm | yes | ||
public_key | string | yes | Lowercase hex — 32 bytes (ed25519) or the SEC1 point, 33 or 65 bytes (ecdsa_p256). |
VerifierCreate
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
origin | string | yes | The exact origin, https://<host>[:<port>], not normalised. | |
request_signing_key | VerifierKeyInput | yes |
VerifierKey
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
key_id | string | yes | ||
algorithm | VerifierAlgorithm | yes | ||
public_key | string | yes | ||
declared_at | string (date-time) | yes |
VerifierPreviousKey
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
key_id | string | yes | ||
algorithm | VerifierAlgorithm | yes | ||
declared_at | string (date-time) | yes | ||
replaced_at | string (date-time) | yes |
VerifierEvidenceSummary
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
digest | string | yes | SHA-256 over the exact bytes, 64 lowercase hex. | |
size_bytes | integer | yes | ||
uploaded_at | string (date-time) | yes |
VerifierRecord
A verifier record (§5.15): the exact origin, the current request-signing key and the ones it replaced, the evidence summary, the issuer's commitment handle and the admission request. active is true exactly when admitted; managed is false in this version (MINT-604's managed line is not built).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
origin | string | yes | ||
state | VerifierState | yes | ||
active | boolean | yes | ||
managed | boolean | yes | ||
evidence_format | string | yes | The evidence's format: bip-0005/1 (v1.3.22, ZADQ-431), the format a record without an upload expects too. A record that holds an upload made before v1.3.22 reads pending-MINT-599 until the business uploads the v1 document. | |
operator_account | string, nullable | yes | The bech32 account the bIP-0005 v1 evidence names — the account that signs the registration on the chain (v1.3.22, ZADQ-431); public. Null without a v1 upload. | |
request_signing_key | VerifierKey | yes | ||
previous_keys | array of VerifierPreviousKey | yes | ||
evidence | all of VerifierEvidenceSummary | yes | ||
commitment_handle | string, nullable | yes | The recorded commitment's commitment_hex (MINT-600; v1.3.24), null before one; kept after its reuse window ends. | |
commitment | VerifierRecordCommitment | yes | ||
admission | all of VerifierAdmission | yes | ||
created_at | string (date-time) | yes | ||
updated_at | string (date-time) | yes | ||
withdrawn_at | string (date-time), nullable | yes | ||
evidence_renewed_at | string (date-time), nullable | yes | v1.3.23 (ZADQ-436): when the current evidence document was uploaded as a renewal on the admitted record; null while it is the one the record was admitted with. | |
renewal_reminder_at | string (date-time), nullable | yes | v1.3.23: the revalidation's reminder date — the last renewal, or the admission's decision before one, plus the reminder (150 days by default; configuration). Null unless admitted. | |
renewal_due_at | string (date-time), nullable | yes | v1.3.23: the revalidation's due date — the same start plus the chain's revalidation window (180 days by default; configuration, never read from the chain). Null unless admitted. | |
renewal_due | boolean | yes | v1.3.23 — the due date is past and no renewal was uploaded since; false unless admitted. |
VerifierRenewalCheckResult
The console's served-file check of a renewed document (v1.3.23, ZADQ-436): the served bytes' SHA-256 is the renewed digest, the file is not served at publish_url, or it is served with another digest.
Type: string, one of "matched", "not_served", "digest_mismatch".
VerifierRenewalCheck
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
result | VerifierRenewalCheckResult | yes | ||
checked_at | string (date-time) | yes |
VerifierEvidencePrevious
A document a renewal replaced (v1.3.23, ZADQ-436).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
digest | string | yes | ||
format | string | yes | ||
digest_rule | string | yes | "sha256", "sha256-rfc8785" | |
operator_account | string, nullable | yes | ||
uploaded_at | string (date-time) | yes | ||
replaced_at | string (date-time) | yes |
VerifierList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
verifiers | array of VerifierRecord | yes |
VerifierEvidenceUpload
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
content_base64 | string | yes | The exact bytes of the file the kit produced, standard base64; 1 byte to 16 KiB decoded. |
VerifierEvidence
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
format | string | yes | bip-0005/1 (v1.3.22, ZADQ-431); pending-MINT-599 on a record that holds an upload made before v1.3.22. | |
digest | string | yes | ||
digest_rule | string | yes | sha256-rfc8785 for bip-0005/1: SHA-256 over the RFC 8785 canonical form (equal to the SHA-256 of the served bytes when the served file is canonical). sha256 for pending-MINT-599: over the exact bytes. | "sha256", "sha256-rfc8785" |
operator_account | string, nullable | yes | The bech32 account the v1 document names; null for pending-MINT-599. | |
size_bytes | integer | yes | ||
content_base64 | string | yes | ||
publish_path | string | yes | ||
publish_url | string | yes | ||
uploaded_at | string (date-time) | yes | ||
renewed_at | string (date-time), nullable | yes | v1.3.23 (ZADQ-436) — set when this document came as a renewal on the admitted record. | |
renewal_check | all of VerifierRenewalCheck | yes | v1.3.23 — the console's served-file check of this renewed document; null before it, or without a renewal. | |
history | array of VerifierEvidencePrevious | yes | v1.3.23 — the documents renewals replaced, the newest first; empty before a renewal. |
VerifierCommitment
The commitment's state (§5.15; v1.3.24, ZADQ-433). With available: the issuer's commitment for the record's origin — handle (its commitment_hex), issuer_id, assurance_grade, approved_at, reusable_until, signature and ZadQ's status_key_check — the session it came from and when it was recorded. With refused: refusal_reason. The other members are null otherwise.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "not_available", "kyc_required", "pending_issuer", "refused", "available" | |
handle | string, nullable | yes | The commitment's commitment_hex, 64 lowercase hex. | |
kyc_session_id | string, nullable | yes | ||
obtained_at | string (date-time), nullable | yes | ||
issuer_id | string, nullable | yes | ||
assurance_grade | integer, nullable | yes | ||
approved_at | string (date-time), nullable | yes | ||
reusable_until | string (date-time), nullable | yes | ||
signature | string, nullable | yes | ||
status_key_check | all of VerifierStatusKeyCheck | yes | ||
refusal_reason | all of VerifierCommitmentRefusalReason | yes | ||
checked_at | string (date-time), nullable | yes | When the last request was made. |
VerifierObligationsAcceptance
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes |
VerifierAdmissionRequest
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
obligations | VerifierObligationsAcceptance | yes |
VerifierAdmissionCommitment
What the request carries of the commitment (v1.3.24): available with the handle (commitment_hex), the issuer, the grade, the reuse window and ZadQ's status-key check; pending_issuer (the issuer did not answer) or refused — the request went ahead, and a commitment recorded before the filing joins it; not_available on a deployment that does not ask an issuer, or a request made before v1.3.24 without one.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "not_available", "pending_issuer", "refused", "available" | |
handle | string, nullable | yes | ||
issuer_id | string, nullable | yes | ||
assurance_grade | integer, nullable | yes | ||
reusable_until | string (date-time), nullable | yes | ||
status_key_check | all of VerifierStatusKeyCheck | yes |
VerifierObligationsAccepted
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes | ||
accepted_at | string (date-time) | yes |
VerifierTurnaround
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
working_days | integer | yes | Working days (Monday to Friday, UTC) from the filing to the decision, or to today while open. | |
target_working_days | integer | yes | The admission policy's target (five working days; ADR-0030). | |
open | boolean | yes | Filed and not decided. |
VerifierAdmission
The admission request ZadQ files with the operator of the single-node production chain under MINT-601's policy, and what became of it. The decision is the chain operator's; ZadQ records it.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "submitted", "filed", "admitted", "refused", "withdrawn" | |
origin | string | yes | ||
evidence_digest | string | yes | ||
commitment | VerifierAdmissionCommitment | yes | ||
obligations | VerifierObligationsAccepted | yes | ||
submitted_at | string (date-time) | yes | ||
evidence_checked_at | string (date-time), nullable | yes | ||
filed_at | string (date-time), nullable | yes | ||
decided_at | string (date-time), nullable | yes | ||
refused_reason | all of VerifierRefusedReason | yes | ||
turnaround | VerifierTurnaround | yes | ||
admissions_log_ref | string, nullable | yes | The public admissions log entry's reference, once recorded. |
VerifierObligations
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
version | string | yes | ||
sha256 | string | yes | ||
url | string, nullable | yes | ||
text | string | yes | ||
published_at | string (date-time) | yes |
MeVerifierProduct
The verifier product (§5.15, ZADQ-362), derived from the account's verifier records: none without a record, else the best state — admitted over filed over evidence_pending over requested over refused over withdrawn. plan is null in this version (no price line exists for this product until Marc decides; verification is never a line).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "none", "requested", "evidence_pending", "filed", "admitted", "refused", "withdrawn" | |
plan | string, nullable | yes | ||
verifiers | object | yes | ||
verifiers.live | integer | yes | ||
verifiers.admitted | integer | yes | ||
lines | MeVerifierLines | no | ||
relying_party | MeRelyingParty | no |
MeRelyingParty
v1.3.18 (§5.18, ZADQ-389) — the relying-party rebate on the business's account: the rebates pending, earned and not settled yet, held by the cap, the balance carried, the last statement's credit line and the payouts due. Counts and amounts, never who. Null where the deployment wires no billing. (v1.3.16's R1 members are withdrawn with the charge.)
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
month | string (date) | yes | ||
offered | boolean | yes | Whether the deployment offers the rebate. | |
pending | integer | yes | ||
earned | integer | yes | ||
held | integer | yes | ||
unit | string, nullable | yes | ||
balance_minor | integer (int64) | yes | ||
last_line | MeVerifierLine | yes | ||
payouts_due | integer | yes |
RelyingPartyStatus
v1.3.18 (§5.18, ZADQ-389) — the business's rebates: counts and amounts, never who.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
month | string (date) | yes | The current month (its first day, UTC). | |
offered | boolean | yes | Whether the deployment offers the rebate. | |
unit | string, nullable | yes | ||
pending | integer | yes | Rebates whose guards are not all met yet (the holding days, the identity check). | |
earned | integer | yes | Rebates earned and not settled yet (settled at their month's close). | |
earned_minor | integer (int64) | yes | ||
held | integer | yes | Rebates held beyond the cap of their month, for the operator's review. | |
held_minor | integer (int64) | yes | ||
balance_minor | integer (int64) | yes | The balance carried out of the last statement (below the payout threshold, or negative after reversals). | |
statements | array of RebateStatement | yes | The closed months, newest first. |
RebateStatement
v1.3.18 (§5.18) — a business's month closed: the rebates settled per plan and their amount, those held by the cap, the reversals deducted, the balance carried in, the set-off on the month's invoice (its credit line), the payout and the balance carried out.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
month | string (date) | yes | ||
unit | string | yes | ||
settled | integer | yes | Rebates settled in the month (earned, within the cap or released). | |
by_plan | array of object | yes | The rebates settled per plan the principal held when each was earned. | |
by_plan[].plan | string | yes | "personal", "premium" | |
by_plan[].count | integer | yes | ||
earned_minor | integer (int64) | yes | ||
held | integer | yes | ||
held_minor | integer (int64) | yes | ||
reversed | integer | yes | ||
reversed_minor | integer (int64) | yes | ||
carried_in_minor | integer (int64) | yes | ||
set_off_minor | integer (int64) | yes | ||
payout_minor | integer (int64) | yes | ||
carried_out_minor | integer (int64) | yes | ||
line_id | string, nullable | yes | The month's credit line (principal_enrolled, negative amount); null when nothing was set off. | |
payout | RebatePayout | yes |
RebatePayout
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
amount_minor | integer (int64) | yes | ||
unit | string | yes | ||
state | string | yes | "due", "paid" | |
paid_at | string (date-time), nullable | yes |
MeVerifierLines
v1.3.15 (§5.17, ZADQ-373) — the verifier product's business lines on the account; null where the deployment wires none. kit_setup and onboarding_at_cost are null until opened (and the onboarding stays null where an entry of a product is paid: onboarding: in_entry); onboarding is null before the first record; due counts the business lines open or failed (the managed ones included).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kit_setup | MeVerifierLine | yes | ||
onboarding_at_cost | MeVerifierLine | yes | ||
onboarding | string, nullable | yes | "at_cost", "in_entry" | |
due | integer | yes |
MeVerifierLine
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
state | PriceLineState | yes | ||
settled | boolean | yes | Captured or invoiced (on the provider, after the capture; on the console, once marked). |
BusinessLinePriceTable
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
lines | array of BusinessLinePrice | yes | ||
managed_kit_setup | string | yes | v1.3.15 — whether a managed business pays the kit set-up too; v1.3.16 (ZADQ-382, P-13) — always withdrawn, the kit set-up line is no longer opened. | "charged", "waived", "withdrawn" |
relying_party | RelyingPartyPrices | no | ||
onboarding_rule | string | yes | The onboarding at cost opens only where no entry of a product is paid; the re-check at the grade's renewal opens no line. | "at_cost_unless_entry_paid" |
RelyingPartyPrices
v1.3.18 (§5.18, ZADQ-389) — the relying-party rebate on this deployment (v1.3.16's R1 tiers and R2 are withdrawn).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
rebate | RebateTerms | yes |
RebateTerms
The discovery fee ZadQ pays a business per principal its door sends who keeps a paid plan: once per person, the plan's amount when earned, every figure from configuration (RELYING_PARTY_REBATE).
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
offered | boolean | yes | ||
unit | string, nullable | yes | ||
amounts | array of object | yes | ||
amounts[].plan | string | yes | "personal", "premium" | |
amounts[].amount_minor | integer (int64) | yes | ||
hold_days | integer, nullable | yes | The days a rebate waits from the plan's payment (the withdrawal period). | |
cap_per_month_minor | integer (int64), nullable | yes | The rebates settled per business and month at most; the excess is held for review. Null — no cap. | |
payout_min_minor | integer (int64), nullable | yes | The balance a payout needs; below it the balance carries forward. Null — no threshold. | |
onboarding_netting | boolean | yes | Whether the onboarding at cost is set off against the rebates too (the managed lines always are). | |
first_agent | boolean | yes | Whether a rebate is earned only once a bounded agent preset from the referral is registered. |
BusinessLinePrice
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | PriceLineKind | yes | ||
environment | string, nullable | yes | "production", "test" | |
period | string, nullable | yes | "month", "year" | |
on_sale | boolean | yes | ||
amount_minor | integer (int64), nullable | yes | ||
unit | string, nullable | yes |
ManagedEnvironmentOpen
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
environment | string | yes | "production", "test" | |
period | string | no | Billed in advance; month when left out. | "month", "year" |
VerifierDoorDeclare
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
market | integer, nullable | yes | The market the refusal sentence is chosen by (1 paid APIs and metered data, 2 reference and community content, 3 developer and orchestration platforms); null for the generic sentence. | |
bundles | array of string | yes |
VerifierDoor
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
verifier_id | string | yes | ||
market | integer, nullable | yes | ||
bundles | array of string | yes | ||
declared_at | string (date-time) | yes | ||
urls | array of VerifierDoorUrl | yes | The landing URL to configure in the refusal, one per bundle. |
VerifierDoorUrl
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
bundle | string | yes | ||
url | string | yes |
ReferralParams
The landing URL's parameters, passed through as the URL carries them.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
verifier | string | yes | The refusing service's verifier record id. | |
bundle | string | yes | The bundle id of the served catalogue the refusal names. |
Referral
What the refusing service accepts and why (§5.16). service, preset and the plans' fit only when valid. Never the business's customer data, never a proof, a pseudonym or an envelope.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
state | string | yes | "valid", "closed" | |
closed_reason | string, nullable | yes | "verifier_not_admitted", "door_not_declared", "bundle_not_accepted", "grade_not_offered" | |
verifier | string | yes | ||
bundle | ReferralBundle | yes | ||
service | all of ReferralService | yes | ||
market | integer, nullable | yes | 1, 2 or 3 — the refusal sentence's market as the business declared it; null for the generic sentence. | |
plans | array of ReferralPlanFit | yes | ||
preset | all of ReferralPreset | yes | ||
url | string | no | The landing URL of this referral (valid only). |
ReferralBundle
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | ||
description | string, nullable | yes | ||
grade_min | integer, nullable | yes | The served assurance_grade_min; null when the catalogue does not say. |
ReferralService
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
host | string | yes | The refusing service's origin host (and port), from its verifier record. |
ReferralPlanFit
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | "personal", "premium" | |
fits | boolean | yes | The grade the plan includes reaches the bundle's grade floor (since v1.3.25 both plans include A3 when a relying party requires it). | |
option | string, nullable | no | v1.3.16 — the step the plan needs for this bundle. Since v1.3.25 no deployment offers a step, so it reads null. | "grade_a3_option" |
ReferralPreset
The first bounded agent's preset — the enrolment's bundle and the refusing service's origin as its counterparty.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
bundle | string | yes | ||
counterparties | array of string | yes |
AccountReferral
A referral recorded on the account — an opaque reference of ZadQ's own.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | The referral's reference (rfl_…). | |
verifier | string | yes | ||
bundle | string | yes | ||
market | integer, nullable | yes | ||
at_signup | boolean | yes | ||
recorded_at | string (date-time) | yes |
AccountReferralList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
referrals | array of AccountReferral | yes |
PrincipalPlanList
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
plans | array of PrincipalPlan | yes | ||
contact | object | yes | v1.3.30 (ZADQ-472, §5.20) — beyond Premium, Enterprise — the agent-operator product by contract, agreed by contact and activated by ZadQ; never an amount. | |
contact.id | string | yes | "enterprise" | |
contact.label | string | yes | ||
contact.seats_from | integer | yes | The fewest bounded agents an Enterprise contract carries (6, beyond Premium's 5). | |
contact.by_contact | boolean | yes | true | |
default_period | string | yes | "month", "year" | |
eligibility | object | yes | ||
eligibility.account_kinds | array of AccountKind | yes | ||
eligibility.consumer | string | yes | "not_offered" |
PrincipalPlan
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
id | string | yes | "personal", "premium" | |
label | string | yes | ||
seats | integer | yes | The bounded agents the plan includes. | |
seats_min | integer | yes | The seats billed on the plan's line — the included agents (minimum = included). | |
seats_max | integer | yes | v1.3.16 — the most bounded agents alive at a time on the plan. v1.3.27 (the caps as decided 2026-11-07; supersedes the caps of v1.3.16 and v1.3.25) — Personal 1, Premium 5; beyond Premium, Enterprise by contact (v1.3.30). | |
grade | integer | yes | The assurance grade the plan's verification is at (2 = A2). | |
grade_included | integer | yes | v1.3.16 — the highest grade the plan includes when a relying party requires it; a verification at A3 renews by A3's own period. v1.3.25 (supersedes v1.3.16's per-plan grades) — 3 on both plans, A3 being included in every plan when a relying party requires it. | |
renewal_months | integer | yes | The verification's renewal at the plan's grade, no grace (12 at A2). | |
periods | array of PrincipalPlanPrice | yes | ||
usage_fee | boolean | yes | Always false — the principal plans carry no settlement-based fee of any kind; that fee belongs to the vendor tiers alone. | |
fair_use_presentations | integer, nullable | yes | v1.3.16 (P-8) — the fair-use allowance of presentations a month by the plan's bounded agents; a number, never billed, never metered. Null where the deployment states none. | |
vat | string | yes | v1.3.29 (ZADQ-469; Marc, 2026-11-07) — exclusive on every deployment — the amounts are net and VAT is added on top, computed by the billing provider at checkout per customer (location; reverse charge for a business with a valid VAT number of another member state). included is a legacy value, no longer answered. | "exclusive", "included" |
steps | array of PrincipalPlanStep | yes | v1.3.16 — the plan's steps with their prices. v1.3.25 — only the steps the deployment's price table prices; no deployment prices one, so the list is empty on both plans. |
PrincipalPlanStep
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
kind | string | yes | "agent_extra", "grade_a3_option" | |
periods | array of PrincipalPlanPrice | yes |
PrincipalPlanPrice
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
net_amount_minor | integer (int64), nullable | no | v1.3.16 — the net a business under reverse charge is invoiced. v1.3.29 (ZADQ-469) — every amount is net, so it equals amount_minor (kept for clients of v1.3.16); null when amount_minor is. | |
period | string | yes | "month", "year" | |
on_sale | boolean | yes | ||
amount_minor | integer (int64), nullable | yes | The plan's whole price for one period, in minor units, net — VAT is added on top at checkout (v1.3.29) — null when not on sale, or when it lives on the provider's price. | |
unit | string, nullable | yes | ||
first_period_amount_minor | integer (int64), nullable | no | Monthly only — the first month's amount when ZadQ's table sets one (the floor that covers the check). |
MePrincipalPlan
The account's principal plan (§5.16); null on an earlier plan or without one.
| Property | Type | Required | Description | Values |
|---|---|---|---|---|
seats | integer | no | v1.3.16 — the plan's seats now — the included agents (no step adds any since v1.3.25). | |
seats_max | integer | no | v1.3.16 — the most bounded agents alive at a time (v1.3.27 — Personal 1, Premium 5). | |
grade_included | integer | no | v1.3.16 — the highest grade the plan includes now (3 on both plans since v1.3.25 — A3 when a relying party requires it). | |
agent_steps | object | no | v1.3.16 — the step lines covering now and unpaid (ids). Since v1.3.25 no deployment offers a step; both lists read empty. | |
agent_steps.covering | array of string | yes | ||
agent_steps.due | array of string | yes | ||
grade_option | object | no | v1.3.16 — a grade step's covering period and unpaid line. Superseded by v1.3.25 — no deployment offers the step, and the object is absent. | |
grade_option.covered_until | string (date-time), nullable | yes | ||
grade_option.due | string, nullable | yes | ||
plan_switch | all of PlanSwitch | no | v1.3.16 — the switch Personal → Premium waiting on its line. | |
fair_use_presentations | integer, nullable | no | v1.3.16 — the plan's fair-use allowance (a number; never metered). | |
refund | all of PlanRefund | no | v1.3.17 (ZADQ-387) — the plan closed after its identity check ended refused or withdrawn, and its refund; null otherwise. | |
plan | string | yes | "personal", "premium" | |
period | string | yes | "month", "year" | |
grade_required | integer | yes | ||
renewal_months | integer | yes | ||
paid_until | string (date-time), nullable | yes | The end of the period paid; null before the first payment. | |
grade_met | boolean, nullable | yes | The person's verification reaches the plan's grade; null while unknown. | |
verified_until | string (date-time), nullable | yes | When the person's verification ends (renewal by grade, no grace). | |
plan_line | string, nullable | yes | The plan's current seat line (§5.3). |
NewAccountKind
The account kind a sign-up declares. consumer is refused with 409 consumer_not_offered until counsel answers the consumer-terms question (§5.16): plans are for organisations and for people acting for their business or profession.
Type: string, one of "organisation", "sole_trader", "consumer".