Registrar API
Every route on the registrar, grouped by actor. See the wire format
for envelopes, signed objects, and receipts. Routes are defined in
crates/tenure-registrar/src/http.rs.
Employer / onboarding
| Method & path | Body | Returns |
|---|---|---|
POST /onboard | OnboardRequest (descriptor + KYB + EpochOpen(1) + delegation, each signed) | { receipts } |
POST /invite | { employer_id, email, payroll_ref } | { claim_token } |
POST /batch | { manifest: Envelope, raw_batch_b64 } | { status: "processed", receipts } or { status: "skipped" } |
POST /epoch/close | { close: Signed } (tn-epoch-close-v1) | { ok: true } |
POST /checkpoint/:employer_id | — | the published Checkpoint |
GET /export/:employer_id | — | the ragequit file |
POST /import | { file, epoch_open: Signed, delegation: Signed, contact_email } | { employer_id } |
Notes:
/batchis the bulk-issuance endpoint. Themanifestenvelope wraps the Signer-signedtn-batch-v1(whose aggregates the Signer computed itself), andraw_batch_b64is the raw batch file — never a summary. The registrar cross-checks the signed aggregates against the file it received, and therun_idmakes the call idempotent: a replayed run returns{ status: "skipped" }./importis how a new registrar adopts an employer during a switch. It runs full import-time verification over the ragequit file before accepting the new epoch.
Worker / holder
| Method & path | Body / query | Returns |
|---|---|---|
POST /claim | { token, subject_pk } | { employer_id } |
GET /wallet/:subject_pk | — | { attestations } (sealed payloads + receipts) |
POST /grants | { grant: Signed, sealed_bundle_b64 } | { grant_id } |
POST /grants/revoke | { revoke: Signed } (tn-grant-revoke-v1) | { ok: true } |
GET /access_log/:grant_id | ?holder_pk=… | { access_log } |
Notes:
/claimredeems an invite token and binds a freshly generated per-employersubject_pkto the worker./grantsstores a holder-signedShareGranttogether with the pre-sealed verification bundle./grants/revokewithdraws it — killing future fetches and recency, never deleting copies already seen./access_logis fetch-scoped and worker-visible;holder_pkauthorizes the read.
Verifier
| Method & path | Body / query | Returns |
|---|---|---|
GET /share/:grant_id | ?verifier_account_id=… | { sealed_bundle_b64 } |
POST /verifier_accounts | { org_name, email } | { verifier_account_id } |
POST /verifications | { grant_id, verifier_account_id, verified_head_seq } | { billed, amount_cents } |
POST /monitors | { grant_id, verifier_account_id } | { monitor_id } |
GET /monitors/events | ?verifier_account_id=… | { events: [{ grant_id, event_class }] } |
Notes:
/share/:grant_idreturns the sealed bundle; the fetch lands in the worker’s access log. No account is needed to view; an account is needed to bill./monitors/eventsreturns event classes only —employment_status_changed,attestation_superseded,grant_revoked— never claim values. The payload type cannot carry a value.
Public (unauthenticated)
| Method & path | Returns |
|---|---|
GET /public/:employer_id/head | the latest signed LogHead |
GET /public/:employer_id/checkpoint | the latest Checkpoint |
GET /public/:employer_id/revocations | { commitments } — the public revocation commitments |
These are the data a verifier needs for a live recency check and the inputs
to the freshness check in the verify predicate.
They expose heads, checkpoints, and BLAKE3(attestation_id) commitments — never
worker identity or claim values.