Courier Passport

For developers

Validate a courier with one API.

Ask whether the driver holds an issued, currently valid Courier Passport. You receive status — never identity images, DVLA payloads, or DBS files.

The integration

  1. 1. Create a sandbox key in the business hub
  2. 2. POST /api/v1/consents — wait for the driver to approve
  3. 3. GET /api/v1/passports/{number}
  4. 4. Treat valid as a pass. Expiring can pass with a warning.

Start here

Register as a business with your Companies House number. Sandbox keys are available at once. Live keys after KYB and a signed partner DPA. Keys are shown once — store them in a secrets manager. Never ship a key in a browser, driver app, or git repository.

Base URL

https://api.courierpassport.com

Local development: http://127.0.0.1:8000

Sandbox

Prefix cdp_test_. Use a live issued number from a driver who has approved you. Demo format: CP-UK-7H3M-K2NQ-W.

Live

Prefix cdp_live_. Issued only after KYB approval. Same paths, same status rules.

Authenticate

Partner API routes under /api/v1 use the API key. The signed-in business hub uses a user session and is not for server-to-server calls. The Courier Passport iOS and Android apps use /api/app/v1 with a driver JWT — never ship a partner key in a native app.

Header

Authorization: Bearer cdp_test_00000000_your_sandbox_key

Look up a passport

Re-evaluate on every call. Do not cache valid for days. Subscribe to webhooks for lapses between lookups. The public QR page is not a substitute for this API — it never tells an anonymous scanner whether the passport is still valid.

GET /api/v1/passports/{number}

curl -sS https://api.courierpassport.com/api/v1/passports/CP-UK-7H3M-K2NQ-W \
  -H "Authorization: Bearer cdp_test_00000000_your_sandbox_key" \
  -H "Accept: application/json"

200 body

{
  "passport_number": "CP-UK-7H3M-K2NQ-W",
  "status": "valid",
  "issued_at": "2026-09-15T12:00:00+00:00",
  "valid_until": "2026-12-15T12:00:00+00:00",
  "driver": { "legal_name": "Alex Driver" },
  "checks": {
    "identity": { "label": "Identity", "status": "passed", "expires_at": "...", "evidence_strength": "provider", "result_band": null },
    "insurance": { "label": "Courier van insurance", "status": "passed", "expires_at": "...", "evidence_strength": "document", "result_band": null }
  }
}

How to treat status

statusYour decision
validPass. Required checks are in date.
expiringPass with a warning. A required check lapses within 30 days.
not_issuedFail. No issued passport for that number — including unknown numbers.
expiredFail. A required check has lapsed. Same number can revalidate.
suspendedFail. Ops has suspended this passport.

Webhooks

Register an HTTPS endpoint in the business hub (POST /api/partner/webhooks while signed in). The signing secret is shown once. We POST JSON and sign the raw body with HMAC-SHA256 in X-Courier-Passport-Signature. No document payloads. Localhost HTTP is allowed only in development.

  • passport.issued
  • passport.expiring
  • passport.expired
  • passport.revalidated
  • passport.suspended
  • consent.revoked

POST body

{
  "event": "passport.expired",
  "passport_number": "CP-UK-7H3M-K2NQ-W",
  "status": "expired",
  "occurred_at": "2026-09-15T12:00:00+00:00"
}

Verify signature (Node.js)

import crypto from "node:crypto";

const expected = crypto.createHmac("sha256", signingSecret).update(rawBody).digest("hex");
const header = request.headers.get("x-courier-passport-signature") ?? "";
if (
  expected.length !== header.length ||
  !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header))
) {
  throw new Error("Invalid webhook signature");
}

Errors and limits

HTTPWhen
400Malformed passport number, or no issued passport for that number on consent.
401Missing or invalid API key.
403Driver has not granted a live consent for this lookup.
429Rate limit — 120 requests per minute per IP on /api/v1.
500Unexpected error. Message is generic. Retry with backoff.

Error bodies are { "error": "…" }. Unknown passport numbers on lookup return not_issued rather than 404, so you cannot probe the directory.

What you receive

  • Passport number, overall status, issue and valid-until dates
  • Driver legal name
  • Required-check summary: type, status, dates, evidence strength
  • DBS result band only (for example clear)

What you never receive

  • Veriff or identity images
  • Raw DVLA enquiry payloads
  • DBS certificate PDFs or health files
  • A transfer of right-to-work or insurance legal duty

Ready to integrate

Create a sandbox key, request consent on a test passport, then wire valid / expiring into your onboarding decision.