SCROLL
UK→US  ·  IN→US  ·  KE→US  ·  Portable credential protocol Groth16 + Ed25519 Verifier API UK→US  ·  IN→US  ·  KE→US  ·  Portable credential protocol Groth16 + Ed25519 Verifier API
Developer docs
Pilot access available

Integrate in hours, not months.

One endpoint. One API key. Verified credential claims returned after token validation, with institutions staying fully in control of decisions.

From zero to verified in 3 steps.

Drop a PASSID verification field into your existing application form. It returns signed credential claims and verification metadata instead of self-reported data or redirects. The customer opens their PASSID app, taps Share, and reads out a one-time code. Claims land in your onVerified callback after verification.

1. Install the SDK and add one field to your form

Install @passidio/react and drop <PassidCodeVerification /> directly into your application form. It renders as a compact inline widget. Keep production API keys server-side and use the field to collect the applicant's one-time PASSID token.

Embeds in any form — loan application, rental, onboarding, KYC
No redirect, no new tab — customer stays inside your product
Inline verification state after token validation
Sandbox tokens included for deterministic integration testing
loan-application.jsx YOUR APP
// terminal
npm install @passidio/react

// drop into any existing form
import { PassidCodeVerification } from "@passidio/react";

function LoanApplicationForm() {
  return (
    <form>
      {/* your existing fields */}
      <input name="full_name" />
      <input name="email" />

      {/* PASSID replaces self-reported income/identity */}
      <PassidCodeVerification
        apiKey="pk_live_..."
        environment="live"
        onVerified={(result) => {
          setVerified(result.verified_claims);
        }}
      />

      <button type="submit">Submit</button>
    </form>
  );
}
2. Customer taps Share in their PASSID app and reads out a code

The customer opens their PASSID app and taps Share. The app generates a one-time share code (e.g. KE8V-3TXY-Z72L). They read it out or paste it into the field on your page. No QR scan required, no app redirect — it works over the phone, in person, or fully remote.

One-time code bound to the applicant's selected credential claims
Works in person, over phone, or fully online — no camera needed
Customer controls what they share — consent is in-app
Token status updates through the verification flow
Your form stays in place throughout
The customer can stay inside your application. They enter a one-time code, and verified financial claims arrive in your callback after the token is checked.
PASSID Mobile App — consent screen USER DEVICE
First National Bank
is requesting verification

Permissions:
 ✓ Income Verified
 ✓ Identity Verified
 ✓ Sanctions Screening

One-time use · Expires in 9:47

[ Decline ] [Share & Verify]

// User taps [Share & Verify]
// Claims fulfilled -> request resolved
3. Claims arrive in your callback

After the customer submits the code and the token is verified, onVerified(result) fires with the verified claims object under result.verified_claims. A verification.completed webhook can also hit your backend server.

Verified credential claims — income, identity, sanctions, payment & savings behavior
Claims are generated from credentialed sources, not self-reported form fields
Also delivered via webhook — verification.completed fires on your server
Report outcomes later with POST /v1/outcome to close the verification loop
onVerified(result) - fired after token verification YOUR APP
// result.verified_claims - verified credential object
{
  "identity_verified": true,
  "income_verified": true,
  "income_band": "$3,000–4,000/mo",
  "sanctions_screening_clear": true,
  "payment_behavior_verified": true,
  "savings_behavior_verified": true,
  "identity_and_fraud_checks_passed": true,
  "data_window_days": 180,
  "freshness_hours": 2,
  "linked_accounts": 3
}

// Your institution makes the decision - PASSID provides the claims
const c = result.verified_claims;
if (c.identity_verified && c.income_verified) routeApplicant();

@passidio/node - server-side integration.

Protect API routes, verify tokens, and assemble verified claim packages from your backend. Works with Express, Next.js App Router, Next.js Pages Router, or any Node.js server.

Install
npm install @passidio/node
passidMiddleware — Express drop-in route guard
withPassid — Next.js App Router wrapper
withPassidPages — Next.js Pages Router wrapper
PASSIDClient — verify tokens, assemble claim packages, report outcomes
verifyWebhookSignature — HMAC-SHA256 webhook verification
Policy enforcement built in — requireClaims, freshness gates, identity & sanctions checks
server.ts — Express
import { passidMiddleware } from "@passidio/node";

app.post("/api/apply",
  passidMiddleware({
    apiKey: process.env.PASSID_API_KEY,
    policy: {
      requireClaims: ["income_verified", "sanctions_screening_clear"],
      maxCredentialAgeHours: 72,
    },
  }),
  (req, res) => {
    // req.passid is fully typed VerificationClaims
    // institution applies its own policy to the verified claims
    res.json({ verified: req.passid.identity_verified, income_band: req.passid.income_band });
  }
);
app/api/apply/route.ts — Next.js App Router
import { withPassid } from "@passidio/node";

export const POST = withPassid(
  {
    apiKey: process.env.PASSID_API_KEY,
    policy: {
      requireClaims: ["income_verified", "sanctions_screening_clear"],
      maxCredentialAgeHours: 72,
    },
  },
  async (req, claims) => {
    // claims is fully typed VerificationClaims
    // institution applies its own policy to the verified claims
    return Response.json({ verified: claims.identity_verified, income_band: claims.income_band });
  }
);
PASSIDClient - verify + package
import { PASSIDClient } from "@passidio/node";

const passid = new PASSIDClient({ apiKey: process.env.PASSID_API_KEY });

// Verify a token - returns verified claims
const claims = await passid.verify(token);

// Assemble a structured claim package for institution review
const pkg = await passid.package({
  token,
  institutionRef: applicationId,
});

// pkg.claims -> signed claim summaries
// pkg.freshness_hours -> recency of the source signals
// pkg.audit_id -> verifier audit reference
// Your institution applies its own policy
if (pkg.claims.identity_verified && pkg.claims.income_verified) {
  routeApplicant(pkg);
}

Endpoints

All endpoints require X-Institution-Key: <your-api-key> unless marked public. Base URL: https://api.passid.io

POST
/v1/sessions
Create a verification session
Called automatically by <PASSIDVerify /> on mount. Returns requestId, code (e.g. AB3X-7YQM), deepLink (passid://verify-request?r=…&i=…), and expiresAt. Body: { institutionName?, permissions?, ttlSeconds? } — TTL defaults to 600 s, max 3600 s.
GET
/v1/sessions/:requestId
Poll for completion
SDK polls this every 2.5 s after creating a request. Returns status: "pending" | "completed" | "declined" | "expired". When completed, response includes the full claims object and verifiedAt. Requires institution API key.
GET
/v1/sessions/:id/public
NO AUTH
Public request info (mobile app)
Called by the PASSID mobile app after scanning a QR — no institution API key needed. Returns institution name, requested permissions, and seconds until expiry. Returns 410 if already expired, fulfilled, or declined.
GET
/v1/sessions/by-code/:code/public
NO AUTH
Resolve 8-char fallback code
Resolves the human-readable code (e.g. AB3X-7YQM or AB3X7YQM) to the same response as the public request endpoint. Used by the in-app manual code entry screen.
POST
/api/v1/bridge/verify
Verify a PASSID token
Accepts a PASSID share token directly. Returns signed claim summaries, signature status, freshness, revocation state, and audit metadata. The verifier response does not include raw financial statements or transaction feeds. Pass Idempotency-Key header so retries do not double-verify. Response includes X-PASSID-API-Version: 1.
POST
/v1/outcome
Report verification outcome context
Report what happened after a PASSID-verified application — weeks or months later. Body: { token, outcome, productType?, amountUsd?, observationDays?, notes? }. Valid outcomes: repaid · no_default · delinquent · defaulted · fraud_confirmed · account_closed · other. The verification context at time of outcome reporting is captured automatically. One outcome per token per institution. Fires outcome.reported webhook.
GET
/v1/outcome/cohort
Your cohort calibration data
Returns outcome rates broken down by verification coverage level for all outcomes your institution has reported. Shown on your institution performance dashboard. Requires institution JWT.
POST
/api/institution/token/refresh
Refresh session token
Exchange a 30-day refresh token for a new access token + rotated refresh token. Enables long-lived sessions without re-authentication. Reuse of a consumed token triggers automatic revocation of the entire token family.
GET
/api/v1
API version discovery
Returns the current API version, model version (1.0.0), release date, and a full map of all endpoint paths. Use to confirm your integration is on the versioned surface.

Event-driven verification.

verification.completed
Fires after a token is successfully verified. Includes signed claim summaries, signature status, freshness, revocation state, and audit identifiers. Safe to retry - use Idempotency-Key on the verify call to prevent duplicate webhooks.
verification.failed
Fires when a token is rejected — expired, revoked, or institution mismatch. Includes deny_reason string. Only fired when the request carries a valid institution API key.
outcome.reported
Fires when an institution submits a verification outcome context via POST /v1/outcome. Payload includes the token, outcome type, product type, amount, and the verification context at time of outcome reporting. Use for audit trails and coverage improvement.
webhook.test
Manual ping from your dashboard to confirm your endpoint is reachable. Use to validate signature verification before going live.
Delivery: HMAC-SHA256 signed via X-PASSID-Signature: sha256=<hex>. Automatic retries on non-2xx: immediate - 30 s - 5 min - 30 min - 2 h (5 attempts total). Pending deliveries survive server restarts.
Webhook payload — verification.completed · X-PASSID-Signature: sha256=…
{
  "event": "verification.completed",
  "institution_id": "42",
  "timestamp": "2026-03-27T10:22:14Z",
  "data": {
    "token": "pid_K3px...",
    "verified_at": "2026-03-27T10:22:14Z",
    "proof_type": "groth16/bn254",
    "verified_claims": { "identity_verified": true, "income_verified": true, "sanctions_screening_clear": true, "payment_behavior_verified": true }
  }
}

Test without production data.

Use your sandbox API key with the same endpoints. The sandbox returns deterministic results — identical API shape to production, isolated from live data.

Use these exact strings with POST /api/v1/bridge/verify · { "token": "PASSID-SANDBOX-..." }
HIGH COVERAGE · KE->GB · Credential verified
PASSID-SANDBOX-TIER1AAA
Amara Osei · income OK · identity OK · sanctions clear · fraud checks passed · verified
PARTIAL COVERAGE · NG->US · Credential verified
PASSID-SANDBOX-TIER2BBB
Tobenna Eze · income OK · identity OK · sanctions clear · fraud checks passed · verified
TIER C · GH->EU · Partial claims
PASSID-SANDBOX-TIER3CCC
Efua Mensah · income OK · identity review · fraud medium · review
verified_credential_summaryFull standard claim set — all verified claims in one request
income_verifiedBoolean + income band (e.g. $3,000–$4,000/mo)
identity_verifiedIdentity verification boolean
sanctions_clearSanctions screening — OFAC · EU · UN watchlist clear
payment_reliabilityPayment behavior verified — derived from payment history
savings_consistencySavings behavior verified — derived from savings pattern
fraud_riskIdentity and fraud checks — passed / review required
Synthetic profiles
3 pre-seeded sandbox tokens (above) covering high coverage, partial coverage, and manual review states. Call POST /api/v1/bridge/verify with the exact token string to test the same response shape used by production verification.
Webhook simulator
Trigger verification.completed, verification.failed, and outcome.reported test events from your institution dashboard → API & Webhooks panel.
PASSID
Thank you — we'll be in touch.