VW ATTEST Developer documentation
You are onattestregistry.com
Developer portal

API reference

Two surfaces: a public verification plane that anyone may call, and an administrative plane for Authority systems, authenticated with capability-scoped credentials.

Authentication Public verification plane Administrative plane Attestations Webhooks Errors and rate limits

Authentication

Public endpoints need no credential. Administrative endpoints take a bearer token issued in the console under API credentials:

Authorization: Bearer ak_1a2b3c4d5e6f7890.<secret>

Each credential carries an explicit capability list. A call outside that list returns 403 naming the capability it needed, so a read-only reporting integration cannot be repurposed into a revocation tool. Rotate a credential by issuing a new one and revoking the old; both actions are written to the audit ledger.

Public verification plane

GET /v1/load.js

The loader script. Short cache lifetime so the Authority can roll out changes. Pin a version with /v1/load.js if your change-management policy requires it.

POST /v1/seal/render

Issues a fresh seal asset and verification stamp. Validates the request Origin against the declared domain server-side.

curl -X POST https://seal.attestregistry.com/v1/seal/render \
  -H 'content-type: application/json' \
  -H 'origin: https://operator.example' \
  -d '{"seal_id":"<64 hex>","domain":"operator.example"}'
{
  "state": "VALID",
  "seal_id": "…",
  "stamp": "<32 hex>",
  "domain": "operator.example",
  "licence_number": "VW-2026-00001",
  "verification_url": "https://attestregistry.com/validate?…",
  "svg": "<svg …>",
  "signature": "<base64 Ed25519>"
}

GET /v1/license/status

Structured licence status, signed so you can verify it offline instead of re-querying. Parameters: seal_id, domain, optional stamp.

curl 'https://attestregistry.com/v1/license/status?seal_id=<64 hex>&domain=operator.example'

Returns {"licence": {…}, "signature": "…", "algorithm": "Ed25519"}. Verify the signature over the canonical JSON form of the licence object (sorted keys, no whitespace, UTF-8) against the key at /.well-known/attest-signing-key.

GET /validate

The human-readable verification page. Renders one of five public states: VALID, EXPIRED, SUSPENDED, REVOKED, INVALID.

POST /v1/telemetry

Analytics collector. Accepts a single event or {"events": [...]}. Event types accepted from the client: impression, hover, click, validation_interaction.

GET /evidence/{id}

Look up an evidence identifier printed on a verification record and confirm that exact check took place at that exact moment. Response is signed.

Administrative plane

Base path /admin/v1, served only on admin.attestregistry.com.

EndpointCapabilityPurpose
GET /licenceslicence:read List with filters: status, domain, licensee, expiring_within_days.
POST /licenceslicence:issue Issue a licence. Returns the record, the embed snippet, and the certificate URL.
POST /licences/bulklicence:issue Batch issuance. Rows commit independently and are reported per row.
GET /licences/{id}licence:read Full record, snippets, attestations, ledger history.
PATCH /licences/{id}licence:modify_minor / modify_material Change detail. Set material: true for changes the public should see.
POST /licences/{id}/activatelicence:issuePENDING → VALID.
POST /licences/{id}/suspendlicence:suspend Needs reason_category. Takes effect on the next status check.
POST /licences/{id}/reinstatelicence:reinstateSUSPENDED → VALID.
POST /licences/{id}/revokelicence:revoke Permanent. Needs reason_category and a written justification.
POST /licences/{id}/renewlicence:renewNeeds new_valid_until.
POST /licences/{id}/closelicence:closeRetire the record, optionally naming a successor.
POST /licences/{id}/verify-embedlicence:read Run the integration verifier. A clean pass activates a PENDING licence.
GET /auditaudit:readQuery the ledger; full-text search on search.
GET /audit/verifyaudit:readRecompute the hash chain and report any divergence.
GET /audit/exportaudit:readSigned, time-stamped export for regulatory proceedings.
GET /analytics/realtimeanalytics:readMinute-level rollups across the estate.
GET /analytics/licence/{id}analytics:readPer-licence detail over a window.
POST /analytics/queryanalytics:readAd-hoc aggregation over a fixed dimension set.
GET /analytics/ageinganalytics:readExpiring, overdue audit, elevated fraud, display non-compliance.
GET /enforcement/queueenforcement:readOpen cases by severity.
POST /enforcement/cases/{id}/actionenforcement:actionProgress a case through triage, investigate, action, closed.
GET /surveillance/feedsurveillance:readProbe and look-alike findings.
GET /referencelicence:readEvery vocabulary this API accepts. Call this first.

Attestations

Record a compliance attestation against a licence. Published attestations appear on the public verification page, so every write is audit-ledgered.

curl -X POST https://attestregistry.com/admin/v1/licences/<licence-id>/attestations \
  -H "Authorization: Bearer $ATTEST_TOKEN" \
  -H 'content-type: application/json' \
  -d '{
        "label": "Annual AML audit completed",
        "body": "Independent audit by Example LLP, no material findings.",
        "published": true
      }'

GET /admin/v1/licences/{id}/attestations lists them; DELETE /admin/v1/licences/{id}/attestations/{attestation-id} withdraws one. Both need attestation:write.

Webhooks

Register an endpoint to be told about changes as they happen rather than polling.

curl -X POST https://attestregistry.com/admin/v1/webhooks \
  -H "Authorization: Bearer $ATTEST_TOKEN" \
  -H 'content-type: application/json' \
  -d '{"url":"https://authority.example/hooks/attest",
       "event_classes":["licence_state","fraud","surveillance"]}'

The response carries the signing secret once. Every delivery includes X-Attest-Signature, the SHA-256 HMAC of the raw request body under that secret. Compare it in constant time before trusting the payload.

Errors and rate limits

StatusMeaning
400The request is malformed, or a required field is missing. The body names it.
401No credential, or the credential is unknown, revoked, or expired.
403The credential or role lacks the capability. The body names the capability.
404No such record — or the administrative plane was called on a public hostname.
409The action conflicts with the current state, such as a transition the lifecycle does not permit.
429Rate limited at the edge. Back off and retry.

The public verification plane is rate limited per source address at the edge. If you operate a legitimate compliance-monitoring service, ask the Authority to add your source to the allow list rather than working around the limit — allow-listed sources stop generating fraud signals as a side effect.