Get a verification record.

GET /v1/certificates/{id} returns one issued verification record: the signed document itself, its lifecycle status, and the evidence that sits beside the document because nothing may edit a signed one. It is the call the quickstart makes to download certificate.json, and the only one a relying party needs before verifying offline.

Request

GET https://api.burnledger.io/v1/certificates/{id}
Authorization: Bearer $BURNLEDGER_API_KEY
ParameterInMeaning
idpathVerification Record UUID, as returned by the verify call that issued it or by GET /v1/certificates. Anything that does not parse as a UUID is a 400, not a 404.
AuthorizationheaderCustomer API key (dp_<hex>) as a bearer token. The key's team scopes the lookup: a verification record belonging to another team is a 404, never a 403, so IDs cannot be probed for existence.
curl -H "Authorization: Bearer $BURNLEDGER_API_KEY" \
  https://api.burnledger.io/v1/certificates/11111111-1111-4111-8111-111111111111 \
  -o certificate.json

No query parameters, no request body, and the response is not paginated. Read-only keys can call it; it never changes state.

Response

The envelope is {"data": …}, as for every single-resource endpoint. The interesting split is between the fields about the verification record and the verification record itself, which arrives verbatim in certificate:

FieldMeaning
idVerification Record UUID. Equal to certificate.certificate_id.
attestation_idThe attestation this verification record closes. Equal to certificate.attestation_id.
format_versionSchema of the signed document, currently 9.0; equal to certificate.certificate_format_version. Earlier versions remain verifiable indefinitely: a verifier reconstructs the payload for the version the verification record declares, so a 3.0 verification record keeps hashing exactly as issued. Format 10.0, which signs the run id of a bulk run, is defined and readable by every published verifier and not yet issued.
issued_atRFC 3339 UTC. When the enclave signed the document.
statusACTIVE or REVOKED. A database column, not a signed claim: for anything that must hold up outside your account, read status_statement instead.
transparency_statusPENDING, INCLUDED or FAILED. Whether the verification record has been appended to the public log. Only INCLUDED verification records carry an inclusion proof inside certificate.transparency.
revoked_at, revocation_reasonPresent only when status is REVOKED.
certificateThe full signed verification record JSON, byte for byte what the offline verifiers accept. The key is still certificate: the document was renamed in format 6.0, the wire was not. Field by field it is documented in Verification Record anatomy. Save this object on its own and you have the portable file.
status_statementThe enclave-signed revocation statement for this verification record, stapled here so the common path is one fetch and verification stays offline for the statement's validity window. It is the same object GET /v1/certificates/{id}/status returns publicly: certificate_id, status, statement_issued_at, statement_expires_at, the log head it was made against (sth_tree_size, sth_root_hash), signature and key_id, plus revoked_at, replacement_certificate_id and revocation_log_index when the record is revoked. Omitted, not errored, if the signer is briefly unavailable: verifiers treat a missing statement as revocation unknown, never as valid, so omission understates and never overstates.
nsm_attestationBase64 AWS Nitro NSM attestation document produced while this verification record was signed. Its PCR measurements identify the enclave image that held the key, and its user_data binds this verification record's canonical signing payload, so it cannot be moved to another verification record. Documents issued since ADR-030 bind the ASCII tag burnledger-sha384: followed by the 48-byte SHA-384 of the payload; earlier documents carry the payload itself, and both forms verify. Absent for verification records issued before it was recorded and for dev-mode issuance; absence is not a verification result. Today only the Go verifier checks it.

Example

A format 9.0 verification record covering two systems, shaped like the SDK conformance case matrix_v9.0_valid.json with the identifiers made obviously synthetic. Binary fields (keys, hashes, signatures) are JSON byte arrays and are abridged here with …; everything else is verbatim.

{
  "data": {
    "id": "11111111-1111-4111-8111-111111111111",
    "attestation_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
    "format_version": "9.0",
    "issued_at": "2026-06-15T12:05:01Z",
    "status": "ACTIVE",
    "transparency_status": "INCLUDED",
    "certificate": {
      "certificate_format_version": "9.0",
      "certificate_id": "11111111-1111-4111-8111-111111111111",
      "attestation_id": "aaaaaaaa-bbbb-4ccc-8ddd-eeeeeeeeeeee",
      "issued_at": "2026-06-15T12:05:01Z",
      "status": "ACTIVE",
      "issuer": {
        "name": "BurnLedger",
        "public_key": [5, 6, 136, 63, …],
        "key_id": "dp_k_d59705f498f0b0bfa02c2180d2a02b39f3ca26cb1f624ffab5da96ba4e541e82",
        "enclave_pcr0": "a5a5a5a5a5a5a5a5…a5a5a5a5a5a5a5a5",
        "legal_entity": "ProChatFlow LLC",
        "algorithm": "ed25519"
      },
      "subject": {
        "identifier_hash": [11, 140, 190, 29, …],
        "identifier_type_hint": "email"
      },
      "attestation": {
        "proof_mode": "count",
        "attested_at": "2026-06-15T12:00:00Z",
        "systems": null,
        "attestation_signature": [146, 25, 171, 254, …]
      },
      "systems": [
        {
          "system_id": "5111e111-1111-4111-8111-111111111111",
          "system_name": "users-db",
          "connector_type": "postgresql",
          "hash_scope": "existence",
          "query_hash": [16, 92, 51, 81, …],
          "attested_count": 11,
          "attested_at": "2026-06-15T12:00:00Z",
          "verified_count": 0,
          "verified_at": "2026-06-15T12:05:00Z",
          "read_only_enforcement": "verified_by_introspection",
          "transport_security": "verified",
          "recoverable_state": "probed_none_found",
          "authorization": "certified",
          "customer_key_id": "cust_k_a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5"
        },
        {
          "system_id": "5222e222-2222-4222-8222-222222222222",
          "system_name": "logs-s3",
          "connector_type": "s3",
          "hash_scope": "existence",
          "query_hash": [7, 60, 169, 2, …],
          "attested_count": 7,
          "attested_at": "2026-06-15T12:00:00Z",
          "verified_count": 0,
          "verified_at": "2026-06-15T12:05:00Z",
          "read_only_enforcement": "operator_asserted",
          "transport_security": "verified",
          "recoverable_state": "not_probed_engine_retains",
          "authorization": "none"
        }
      ],
      "scope": {
        "version": "2.0",
        "text_sha256": [26, 228, 163, 181, …]
      },
      "certificate_signature": [173, 215, 247, 252, …],
      "transparency_status": "INCLUDED",
      "transparency": {
        "log_url": "https://log.burnledger.io",
        "tree_size": 4,
        "entry_index": 1,
        "entry_type": "CERTIFICATE",
        "appended_at": "2026-06-15T12:05:01Z",
        "inclusion_proof": [[128, 54, 234, 84, …], [151, 37, 60, 75, …]],
        "signed_tree_head": {
          "tree_size": 4,
          "root_hash": [190, 134, 9, 50, …],
          "timestamp": "2026-06-15T12:05:01Z",
          "signature": [19, 39, 3, 174, …]
        }
      }
    },
    "status_statement": {
      "certificate_id": "11111111-1111-4111-8111-111111111111",
      "status": "ACTIVE",
      "statement_issued_at": "2026-06-16T09:00:00Z",
      "statement_expires_at": "2026-06-17T09:00:00Z",
      "sth_tree_size": 4,
      "sth_root_hash": "be860932…",
      "signature": "132703ae…",
      "key_id": "dp_k_d59705f498f0b0bfa02c2180d2a02b39f3ca26cb1f624ffab5da96ba4e541e82"
    },
    "nsm_attestation": "hEShATgioFkR…"
  }
}

Three things to notice. Every field the record has gained since 4.0 is per system and signed: read_only_enforcement and transport_security (7.0), recoverable_state (8.0), and authorization with customer_key_id (9.0), which say whether the enclave checked that system against a registration a customer key group signed; a system whose record says none is genuine, and only the reader can refuse it. issuer.enclave_pcr0 has been signed since 5.0, so the measurement of the image that held the key is part of the evidence. And status_statement and nsm_attestation sit outside the signed document on purpose: the first is signed on its own with a validity window, the second is the NSM's word on which image signed the payload.

Signed per-system fieldSinceMeaning
read_only_enforcement7.0How the connector established that its credential cannot write: verified_by_introspection, operator_asserted, write_access_detected or unknown.
transport_security7.0The enclave's classification of the connection config's transport: verified means TLS with a verified chain.
recoverable_state8.0Whether anything checked for a restorable copy of what the record certifies gone, and what it found: probed_none_found, probed_and_cleared, not_probed_engine_retains, not_probed_no_engine_mechanism, operator_asserted or unknown.
authorization, customer_key_id9.0certified with the key id when the enclave checked the system against a registration signed by that customer key group; none, with no key id, otherwise.

The full anatomy of the signed document, field by field and version by version, is in Verification Record anatomy.

Errors

Every error is {"error": {"code": …, "message": …}}.

StatusWhen
400id is not a UUID.
401Missing, malformed or revoked API key.
404No verification record with that ID in the key's team. Deliberately indistinguishable from a verification record that exists elsewhere.

What to do with it

  • Verify it offline. Write data.certificate to a file, fetch the published keys from /.well-known/burnledger-keys, and run burnledger check. Verify a record walks through the browser, CLI and transparency-log routes.
  • Hand it to a third party. They need the certificate object and nothing else: no account, no call back to BurnLedger. If they want current revocation status, GET /v1/certificates/{id}/status is public and needs no key.
  • Get the human-readable version. GET /v1/certificates/{id}/pdf renders the same verification record as a PDF for auditors and data subjects. The PDF is a rendering; the JSON is the evidence.
  • Check revocation from your own account. GET /v1/certificates/{id}/revocation-status returns the account-side status and reason without the signed statement.

The full endpoint list, including attest, delete, verify and the verification record list, is in the API reference.

Common questions

Which field is the actual verification record?

data.certificate. It is the complete signed document: issuer key, subject hash, every system's attested and verified counts, both Ed25519 signatures, the scope commitment and the transparency proof. The fields around it (status, status_statement, nsm_attestation) are evidence about the document and are not covered by its signature.

Why is status both a top-level field and a signed statement?

The top-level status is what BurnLedger's database says, useful inside your own account. status_statement is the same fact signed inside the enclave with a validity window, which is what a verifier outside your account can check. A signature commits to bytes at one instant, so revocation cannot be expressed by editing the verification record; it needs its own signed object.

Can I fetch a verification record without an API key?

Not through this endpoint. The verification record is your team's record and is scoped to your key. What is public is the revocation status (GET /v1/certificates/{id}/status), the published signing keys, and the transparency log; a relying party who already holds the verification record file needs nothing more.

© 2026 ProChatFlow LLC Last updated present → absent → proven