Developers · 5-minute quickstart
Presence verification you can enforce in one endpoint.
PBI hardens irreversible actions. You keep SSO/OAuth/JWT. You add one strict gate: compute an action hash, issue a challenge, require WebAuthn UP+UV, and execute only if verify returns PBI_VERIFIED.
Strict invariant
Execute only on PBI_VERIFIED. Everything else is deny.
Action binding
Challenges are bound to actionHash. Approvals can’t be repurposed.
Replay resistance
Single-use + expiry make replays fail by construction.
Receipts
Store receiptHash as your durable evidence reference.
Recommended path for most teams: use the SDK for typed integration, consistent error semantics, and receipts pagination. The SDK page includes install, quickstart, error handling, compatibility, and an end-to-end WebAuthn ceremony example.
Quickstart
5 minutes to first verification
Use the SDK for the fastest path, or wire directly into your endpoint. The only requirement is strict enforcement on VERIFIED.
1) Canonicalize the action, then hash it
The action hash must represent the exact irreversible operation you are about to execute. Deterministic serialization matters.
// Example canonical action (conceptual)
{
"kind": "treasury_payout",
"to": "acct_123",
"amount": "100000",
"currency": "USD",
"nonce": "server_generated_nonce",
"ts": "server_time_iso"
}
// actionHash = SHA-256(canonical_json_bytes)2) Issue a challenge bound to actionHash
Use your API key. Challenges must be single-use and time-bounded.
curl -X POST "https://api.kojib.com/v1/pbi/challenge" \
-H "authorization: Bearer $PBI_API_KEY" \
-H "content-type: application/json" \
-d '{ "actionHashHex": "<32-byte sha256 hex>" }'3) Perform WebAuthn UP+UV ceremony
The client completes WebAuthn on-device. The server verifies the assertion and emits a receipt.
POST https://api.kojib.com/v1/pbi/verify
Authorization: Bearer $PBI_API_KEY
Content-Type: application/json
{
"challengeId": "<server-issued>",
"assertion": { /* WebAuthn assertion bundle */ }
}
→ { decision: "PBI_VERIFIED", receiptHashHex: "..." }4) Enforce
This is the whole point: if not VERIFIED, do not execute. Store the receipt hash as your evidence reference.
if (verify.decision !== "PBI_VERIFIED") {
throw new Error("Presence verification required");
}
// execute irreversible action now
// store receiptHashHex with action contextExport packs + webhooks
Verify receipts offline & validate webhook signatures
Enterprise exports ship as a signed zip pack. Webhooks are signed per-delivery for tamper-evidence.
1) Verify file hashes
Compute SHA-256 for each file in the pack and compare to the manifest entries.
sha256sum receipts.ndjson sha256sum policy.snapshot.json sha256sum trust.snapshot.json # optional
2) Verify the manifest signature
Canonicalize manifest.json (sorted JSON keys) and verify the Ed25519 signature in manifest.sig.json using the included public key.
signature = ed25519_verify(publicKeyPem, canonical_manifest_bytes) assert(signature === manifestSig.signatureB64Url)
3) Parse receipts.ndjson
Each line is one JSON object of the form:
{ receipt, challenge }.for line in receipts.ndjson: obj = JSON.parse(line) receipt = obj.receipt challenge = obj.challenge
Webhook signature verification
Use the secret from the portal to compute HMAC-SHA256 over
<timestamp>.<deliveryId>.<rawBody>.base = timestamp + "." + deliveryId + "." + rawBody
expected = hmac_sha256(secret, base)
assert("v1=" + expected === headers["X-PBI-Signature"])Patterns
Where PBI belongs (and where it doesn’t)
Large companies keep UX clean by gating only high-blast-radius actions.
Gate
Money movement, role changes, key rotation, deploy approvals, legal/ownership actions.
Do not gate
Low-risk browsing, list endpoints, harmless preference changes.
Roll out
Start with 1 endpoint, prove stability, then expand coverage.
Canonicalization
Canonical action hashing guidance
To prevent ambiguity and disputes, action hashes must be deterministic and represent the exact operation.
Stable field set
Hash only fields that define the irreversible effect (amount, destination, policy, nonce, etc.).
Deterministic serialization
Use stable ordering and encoding. Avoid locale/float ambiguity.
Server-minted nonce
Include a server nonce to prevent re-submission of identical actions.
Bind to execution
Compute hash from the exact request that will execute, not an earlier preview.
Next
Go deeper
For the most complete integration path, use the SDK page or the API reference.