Документация публикуется на английском языке.

DocumentationTrust

The public endpoints

Seven unauthenticated endpoints, the exact fields they return, and the proof endpoints that are not public.

Seven endpoints, no credential

None of these take an authorization header. There is no key to request, no rate-limited developer token, and nothing you have to agree to first.

Every public transparency endpoint, with the cache header it sets.

EndpointReturnsCache-Control
GET /v1/public/transparency/checkpointsA page of signed statements, newest firstpublic, max-age=60
GET /v1/public/transparency/checkpoints/latestThe newest statementpublic, max-age=60
GET /v1/public/transparency/checkpoints/{sequence}One statement by sequencepublic, max-age=3600, immutable
GET /v1/public/transparency/keysEvery key that ever signed a checkpointpublic, max-age=300
GET /.well-known/unifyid-checkpoint-keys.jsonThe same key set, at a well-known pathpublic, max-age=300
GET /v1/public/transparency/overviewLog id, channel status, recent checkpoints, key rotations, legal notice versionspublic, max-age=60, stale-while-revalidate=60
GET /v1/public/transparency/anchored-checkpoints/{sequence}One statement plus both channels' anchor statepublic, max-age=60

A checkpoint, as recorded

The list endpoint returns { items, nextBefore } at the top level — not wrapped in data. nextBefore is the sequence to pass back as ?before= for the next page, or null at the end of the log. limit defaults to 24 and must be 1 to 200; anything else is AUDIT_PROOF_RANGE_INVALID, status 400.

GET /v1/public/transparency/checkpoints/latest — a recorded response
{
  "checkpointId": "bdf7ec15-005a-472b-8bb8-bdc8ba637eb1",
  "sequence": "2",
  "version": 1,
  "logId": "555983597a1cb6517ef9c23949d3370e100c5ca637c833dd37abae204e2d2da6",
  "periodStart": "2026-09-18T02:05:00.000Z",
  "periodEnd": "2026-09-18T03:05:00.000Z",
  "combinedRoot": "4520f8ffeae3e86e37b1b5e5a0a3042e2fa7e745b25de71cf0e7f4b644d710b0",
  "previousCombinedRoot": "d2aebc8fb6f20a33a68bdf43ea160b0b88cf92b77136104a9ce75b1d03dabf7a",
  "fingerprint": "5d67966ffa2696fc221264bfa3d2efc7ce20603c7f0a2b00d958c41475f33add",
  "previousFingerprint": "1ce17299acf64a2f67804267be5877365188e4aae16bd5a2fdc785fd8538aff5",
  "statement": "0x00000000000000000000000000000000000000000000000000000000000000015559…",
  "signature": "0x024f78483fa196f05c753196a34741b3d7ed200b22d4f46c5156d81c9b5ffc142fa6fabeb1360a4622053aa7b95531bb8d5197de83f10481ee0559d04f7f2b5e",
  "signingKeyId": "audit-WvDfp1ygnv93KiceJlwn",
  "signingKeyFingerprint": "745896659f3fd078ae663119934bc6e2ec5e1fcfc8cac2ef94e6057836aef27a",
  "createdAt": "2026-09-18T03:05:00.111Z"
}

Every field, and what you do with it

sequencedecimal string
The checkpoint index. A string, not a number, because it can exceed 2^53.
version
1. The statement layout.
logId
Which log this is. Every statement in one deployment carries the same value; compare it before you compare anything else.
periodStart / periodEnd
ISO-8601. periodStart is 1970-01-01T00:00:00.000Z for sequence 1, which is how 0 renders.
combinedRoothex64
What this statement commits to.
previousCombinedRoot
The previous statement's combinedRoot, or null for sequence 1. The JSON says null; the statement bytes say 32 zeroes.
fingerprint
SHA-256(statement). The checkpoint's identity everywhere.
previousFingerprint
The previous statement's fingerprint, or null for sequence 1. A second, independent way to walk the chain backwards.
statement0x + 512 hex
The 256 bytes themselves. Everything above is decodable from this; the fields are a convenience, not the source.
signature0x + 128 hex
64 bytes, r || s, low-S.
signingKeyId
The kid of the key that signed. Look it up in the key set.
signingKeyFingerprint
SHA-256(0x04 || X || Y) of that key. It is also the eighth word of the statement, so the statement names its own key.
createdAt
When the row was written. This is a server clock, not a signed field — periodEnd is the one inside the statement.

The keys

GET /v1/public/transparency/keys and GET /.well-known/unifyid-checkpoint-keys.json return the identical document: every key that ever signed a statement, newest first, as JWKs with extra fields.

A recorded key set
{
  "keys": [
    {
      "kty": "EC",
      "crv": "P-256",
      "x": "PQq7G_MrYupj66ozneB85214GOHVUUxd2ac-q4A22vI",
      "y": "4KbXeKffwJbN7U8ss__sEnYuhY5jIA5Aq4F-i9GjEkc",
      "kid": "audit-WvDfp1ygnv93KiceJlwn",
      "alg": "ES256",
      "use": "sig",
      "fingerprint": "745896659f3fd078ae663119934bc6e2ec5e1fcfc8cac2ef94e6057836aef27a",
      "status": "active",
      "activatedAt": "2026-09-18T02:05:00.061Z",
      "retiredAt": null
    }
  ]
}

kid is "audit-" followed by the first 20 characters of the base64url SHA-256 of the canonical JWK. A retired key keeps retiredAt and stays in the list forever, because statements it signed are still in the log and still have to verify.

The overview

GET /v1/public/transparency/overview is the one endpoint wrapped in data. It is the whole public posture in a single request, and it is the endpoint to use when you want to check a claim this documentation makes rather than believe it.

Under `data`

generatedAt
When this view was assembled.
logId
The same log id that is inside every statement.
channels
One entry per anchoring channel — unifyid_contract with role: "authority", and sign_protocol with role: "witness" — each with enabled, network, chainId, contractAddress, contractUrl, hookAddress, schemaId and deployment. Recorded today: `enabled: false` and every other value `null` on both. From launch, deployment names the contract a channel is bound to (chainId, network, contractAddress, contractUrl, hookAddress, hookUrl, schemaId, genesisSequence, boundAt).
governance
owner, timelock, minDelaySeconds, paused and checkedAt, read from the contract itself, or null while the contract channel is off. When the chain does not answer, the values are null and checkedAt is still set. Cached for five minutes.
checkpoints
Recent checkpoints in a shorter form than the list endpoint: checkpointId, sequence, periodStart, periodEnd, combinedRoot, previousCombinedRoot, fingerprint, signingKeyId, signingKeyFingerprint, state, channels and downloadPath. Note that it carries no statement and no signature — for those, use the checkpoint endpoints above.
signingKeys
keys — each with kid, fingerprint, status, activatedAt, retiredAt and custody — and rotations. custody is "software" on a log whose signer is not KMS.
legalNotices
items: the published versions of the platform's legal notices.
verify
package, keysUrl, checkpointsUrl and a commands object. See the warning below before you act on any of it.

Each entry in checkpoints[].channels has channel, label, role, status, network, chainId, transactionHash, transactionUrl, attestationId, signscanUrl, confirmations and anchoredAt. The chain, the transaction link and the SignScan link come from the delivery row itself, so a checkpoint always names the chain it was actually published on. Recorded today every one of them is status: "pending" with confirmations: 0 and every other value null, while the checkpoint's own state is "sealed".

The proof endpoints are not public

This is the distinction people get wrong. The statements are public. A proof about one record is not, because it is about somebody's record.

EndpointWho may call it
GET /v1/admin/audit/proofs/events/{eventId}UnifyID staff only
GET /v1/admin/audit/proofs/streams/{stream}/{sequence}UnifyID staff only
GET /v1/admin/audit/proofs/consistencyUnifyID staff only

The one public route that looks like a proof endpoint is /v1/public/transparency/anchored-checkpoints/{sequence}, and it is not about a record: it returns the same checkpoint view as the endpoints above plus an anchors object with unifyid_contract and sign_protocol. With anchoring off there is nothing in that object to show. An unknown sequence, or one that is not a number, is AUDIT_CHECKPOINT_NOT_FOUND, status 404.

What this does not do

  • There is no public endpoint that will tell you whether a given person did something. By design. The public surface is roots and keys; everything about a record needs the record's owner.
  • `/checkpoints` is not wrapped in `data` and `/overview` is. They were built in different tracks and the envelopes differ. Read what you are parsing.
  • These endpoints are unauthenticated, not unlimited. Page with before and nextBefore rather than requesting limit=200 in a loop, and cache what you already hold — a sealed statement never changes.

Verified against API commit 234dba22 on 2026-10-18. The routes, scopes, checklist, events and limits on these pages are read from that export, not typed.