SITUSDemoDashboardMailboxesPolicyMandatesGrantsReceiptsVerifyPasskeysDocs

Docs

What Situs Pilot 1 is, and how to build against it.

Build an approver app

Any app can carry approvals: a phone app, a chat bot, a relay. The app moves messages; the person signs the exact action hash with their own enrolled key, at the assurance the route demands. The contract is docs/APPROVAL_API.md.

Registration, and who signs it

A device registers with a one-time enrollment code that the principal issues (POST /approvers/{approver}/enrollment-codes, principal-signed); one call to POST /approvals/enroll registers its app key and enrolls the person's signing key. A server app (relay, bot) is registered by the principal's signature (POST /approvals/apps) for named approvers.

Authentication

Every later call carries Authorization: Situs-App kid=<app kid>, ts=<unix>, sig=<hex>, the app key's signature over the hex sha256 of METHOD\nPATH_WITH_QUERY\nts\nsha256_hex(body). Stale or replayed requests are refused; keep ts strictly increasing.

Poll, stream, webhook

Events and webhooks are signed by the authority; pin its key from https://situs-vm.o11r.com/api/authority/.well-known/keys.json.

The challenge per key type

algwhat is signed
ed25519the 64 ASCII bytes of the hex action hash
es256the same 64 ASCII bytes, ECDSA P-256 / SHA-256, DER hex
webauthn-es256a passkey assertion; challenge = base64url(the 64 ASCII bytes)
appattest-es256an App Attest assertion over sha256(authenticator_data || sha256(JCS(client_data)))

Publishing a decision

POST /approvals/{grant_id} with the approver, approve or reject, the action hash and the signature. Repeating the same decision returns the current state; a different one on a decided grant is refused. Poll the item until resolution.receipt_id fills.

Enrolling keys at each assurance level

levelwhat it ishow the server knowsreceipt strength
softwarea key file or keychain key, ed25519verified by construction2
hardwarea secure-element key, P-256 (es256)declared by the app at enrollment, recorded as declared3
hardware_attesteda hardware key a vendor attests (App Attest, WebAuthn packed or apple)verified: the attestation chains to a trusted root4

A route in a mandate demands a level (software by default). A key below it gets assurance_insufficient and the grant stays pending: no app, channel or console can lower it.

examples/approver_bot.py, walked through

uv run python examples/approver_bot.py --authority https://situs-vm.o11r.com/api/authority --code SITUS-XXXX-XXXX --approver approver_jdoe

How the receipt records it

who.approval carries the approver, kid, alg, assurance, assurance_basis (verified or declared), app_id and approved_at; signatures.approver is the signature over the action hash. The proof report grades it 4 for hardware_attested, 3 for hardware, 2 for software.

Every approval route the authority serves

methodpathwhowhat
GET/approvals/configanyoneDiscovery: rp_id, origins, algs, assurance levels, server time, windows.
POST/approvers/{approver}/enrollment-codesprincipal's signatureA one-time enrollment code for an approver.
POST/approvals/enrollthe codeRegister a device's app key and enroll the person's signing key in one call.
POST/approvers/{approver}/keysapp + an existing key's signatureAdd a key to an approver.
GET/approvers/{approver}/keysappThe approver's keys with assurance and basis.
DELETE/approvers/{approver}/keys/{kid}a key of the approver, or the principalRevoke a key.
POST/approvals/appsprincipal's signatureRegister a server app (a relay or a bot) for named approvers.
GET/approvals/appsappThe calling app's own record.
DELETE/approvals/apps/{app_id}app, or the principalRevoke an app.
GET/approvals/apps/{app_id}/deliveriesappWebhook deliveries and their status.
PUT/approvals/apps/{app_id}/push-tokenappRegister or replace the app's push token; the relay only ever says an approval is waiting.
DELETE/approvals/apps/{app_id}/push-tokenappRemove the app's push token.
GET/approvals/pendingappPending items for an approver, with a cursor (poll).
GET/approvals/streamappServer-sent events, signed by the authority; resume with Last-Event-ID.
GET/approvals/{grant_id}appOne item as it is now; poll it for the receipt id after deciding.
POST/approvals/{grant_id}app, carrying the approver's signatureApprove or reject the exact action hash.