Enterprise-grade API for Presence-Bound Identity (PBI) — a strict trust primitive for irreversible actions.
What it does
- Issues action/artifact-bound challenges (single-use + expiry)
- Verifies presence attestation bundles (WebAuthn assertion + UP+UV)
- Emits receipts (
receiptHash) for audit, disputes, and chain-of-custody - Tracks usage and supports monthly invoicing workflows
What it does NOT do
- No KYC
- No biometric storage
- No end-user account database (unless you build mapping on top)
- No “soft approvals” — you must enforce
PBI_VERIFIEDin your app
- Category site: https://presencebound.com
- Product: https://pbi.kojib.com
- Trust Center: https://pbi.kojib.com/trust
- Status: https://pbi.kojib.com/status
- API Docs: https://api.kojib.com/docs
- OpenAPI (repo):
./openapi.yaml
If you’re integrating PBI into an application, use the official SDK:
- npm:
presencebound-sdk
npm install presencebound-sdk| Runtime | Supported | Notes |
|---|---|---|
| Node.js | 18+ | Uses built-in fetch, URL, AbortController |
| ESM | ✅ | import { PresenceBound } from "presencebound-sdk" |
| CommonJS | ✅ | const { PresenceBound } = require("presencebound-sdk") |
| Browsers | Not currently targeted (CORS + credential handling is app-specific) |
Need Node 16? Polyfill
fetch(e.g.undici) before using the SDK.
import { PresenceBound, PresenceBoundError } from "presencebound-sdk";
const client = new PresenceBound({
apiKey: process.env.PRESENCEBOUND_API_KEY ?? "",
baseUrl: "https://api.kojib.com", // optional (defaults to api.kojib.com)
timeoutMs: 15000, // optional
userAgent: "my-app/1.0.0" // optional
});
async function run() {
const challenge = await client.createChallenge({
actionHashHex: "a".repeat(64),
purpose: "ACTION_COMMIT"
});
// Pass challenge.data.challengeB64Url to your WebAuthn client ceremony.
console.log("challengeId:", challenge.data.id, "requestId:", challenge.requestId);
// Example: iterate receipts (auto-pagination)
for await (const item of client.iterateReceipts({ limit: 100, order: "desc" })) {
console.log(item.receipt.id, item.receipt.decision);
}
}
run().catch((err) => {
if (err instanceof PresenceBoundError) {
console.error("PresenceBoundError", {
status: err.status,
requestId: err.requestId,
message: err.message,
details: err.details
});
process.exit(1);
}
throw err;
});Non-2xx responses throw a typed PresenceBoundError with:
status(HTTP status code)requestId(when server provides one)details(when server returns anErrorResponsepayload)
End-to-end Node + Express + WebAuthn demo (SDK + browser assertion + verify):
./packages/presencebound-sdk/examples/node-sdk/
- Node.js 18+ (recommended)
- Docker (for Postgres)
-
Create env:
cp .env.example .env
-
Start database:
docker-compose up -d db
-
Install deps:
npm i
-
Run migrations:
npm run migrate
-
Start API:
npm run dev
API: http://localhost:8080
All protected endpoints require:
Authorization: Bearer <API_KEY>
Customers are API-key holders. There are no end-user accounts in the core model.
-
POST /v1/pbi/challengeCreate a single-use challenge bound to anactionHash(or artifact hash) with expiry. -
POST /v1/pbi/verifyVerify a WebAuthn UP+UV ceremony for the bound challenge and return a decision. Applications MUST only proceed when decision ==PBI_VERIFIED. -
GET /v1/pbi/receiptsList receipts with challenge metadata for audit/export workflows.
GET /v1/billing/usageGET /v1/billing/invoices
Proofs are bound to:
- deterministic
actionHash(or artifact hash) - nonce + expiry (single-use)
- WebAuthn ceremony flags: User Present + User Verified (UP+UV)
Receipts provide durable audit references:
receiptHash+ decision + time window + action binding
Security notes and threat model:
./SECURITY.md./pbi-stdlib/security/threat-model.md
Vulnerability reporting:
security@kojib.com
The API may return a requestId header. Persist it in application logs for support/debugging.
Clients should set reasonable timeouts (15s default in the official SDK) and treat timeouts as retriable only when your business action is idempotent.
Your application must enforce:
- Only proceed when
decision === "PBI_VERIFIED" - Treat all other decisions as “do not execute” (FAILED/EXPIRED/REPLAYED)
Your actionHashHex must be a deterministic hash of the exact irreversible action you are about to execute (amount + recipient + operation + policy + metadata). If the action changes, the hash must change.
src/— API server implementation (routes, middleware, DB, PBI verification)apps/portal/— customer portal (keys, billing, usage) (if included in this repo)pbi-stdlib/— reference verifier tooling + docs/spec/test vectorspackages/presencebound-sdk/— official TypeScript SDK (published to npm)examples/— integration examples (web, express, fastapi, axum wrappers)
npm i
npm run dev
npm run test
npm run typecheck- Do not commit secrets:
.envfiles are ignored (examples only). - Test vectors may include WebAuthn blobs. This repo includes a
.gitleaks.tomlallowlist for known false-positives in deterministic vectors.
This project is dual-licensed:
-
AGPL-3.0-or-later for open source use. If you modify and run this as a network service, AGPL requires you to provide the source code of your modified version to users.
-
Commercial License for proprietary use. Required if you want to run as SaaS without releasing modifications, embed in closed-source software, or distribute under proprietary terms.
See:
LICENSELICENSE-AGPL-3.0.txtCOMMERCIAL_LICENSE.mdTRADEMARKS.md
“PresenceBound” and “PBI” branding usage is governed by TRADEMARKS.md.