Overview

Peabody Secure provides identity verification (KYC) and AML/sanctions screening as a hosted service.

The verification flow consists of three steps:

  1. ID Upload — the user photographs the front and back of their driver's license. The back barcode is parsed automatically.
  2. Liveness Check — the user completes a short challenge (blink, smile, etc.) captured via webcam.
  3. Face Match — the selfie from the liveness check is compared to the photo on the ID. Sanctions screening runs automatically against the name on the ID.

You can embed this flow in your own site using the JS Widget, or drive it directly via the REST API.

No account yet? Register here — your API key is returned on registration.

Authentication

All protected endpoints are authenticated via an HttpOnly JWT cookie named jwt. The cookie is set automatically when a user logs in via POST /api/login.php and is sent by the browser on every subsequent request to the same domain.

There is no Authorization header — the cookie is the credential. This means your front-end does not need to manage tokens manually for same-domain use.

Obtaining a session

POST /api/login.php
Content-Type: application/json

{
  "email": "user@example.com",
  "password": "yourpassword"
}

On success the server sets the jwt cookie (1-hour expiry, HttpOnly, Secure, SameSite=Lax) and returns:

{ "message": "Login successful" }

Ending a session

GET /api/logout.php

Clears the jwt cookie and redirects to /login.html.


Embeddable JS Widget

The Peabody Secure widget is a self-contained JavaScript library that renders the full ID upload + liveness + face-match flow inside a modal overlay on your page. The user must already be logged in (JWT cookie present) before you call open().

1. Include the script

<script src="https://peabodysecure.com/js/peabody-widget.js"></script>

2. Initialize and open

PeabodySecure.init({
  baseUrl: 'https://peabodysecure.com',
  onSuccess: function(verificationId) {
    console.log('Verified! ID:', verificationId);
    // Send verificationId to your backend to record the result
  },
  onError: function(err) {
    console.error('Verification error:', err);
  }
});

// Launch the verification modal
PeabodySecure.open();
Same-domain only: The widget relies on the browser automatically sending the jwt cookie. It will not work across origins unless the user has an active session on peabodysecure.com.

Widget options

OptionTypeRequiredDescription
baseUrlstringNoBase URL of the Peabody Secure service. Defaults to the current origin.
onSuccessfunctionYesCalled with (verificationId) when the flow completes successfully.
onErrorfunctionNoCalled with an error message string if the flow fails.

Auth Endpoints

All endpoints are direct PHP files — there is no URL rewriting. Use the exact paths shown below.

POST /api/register.php

Create a new account. Returns an API key you can use to identify your account.

Request body (JSON)
{
  "name": "Jane Smith",
  "email": "jane@example.com",
  "password": "minimum8chars"
}
Response 201
{
  "message": "Registration successful",
  "api_key": "a3f8c2..."
}
POST /api/login.php

Authenticate and receive a session cookie.

Request body (JSON)
{
  "email": "jane@example.com",
  "password": "yourpassword"
}
Response 200 — sets jwt cookie
{ "message": "Login successful" }
GET /api/logout.php

Clears the session cookie and redirects to /login.html.


KYC Flow

The three-step verification flow. All endpoints require an active session (JWT cookie). Call them in order.

Step 1 — Upload ID images

POST /api/kyc/upload.php

Upload the front and back of the user's driver's license. The back barcode is parsed automatically and the extracted data is stored against the verification record.

Request — multipart/form-data
front   (file)  Front of ID — JPEG, PNG, or PDF, max 10 MB
back    (file)  Back of ID  — JPEG, PNG, or PDF, max 10 MB
Response 200
{
  "verification_id": "uuid-string"
}

Store verification_id — it is required by all subsequent steps.

Step 2 — Liveness check

GET /api/kyc/liveness-challenge.php

Get a random liveness challenge to present to the user.

Response 200
{ "challenge": "Blink" }
// Possible values: "Blink", "Smile", "Look Left", "Look Right"
POST /api/kyc/liveness-check.php

Submit a short video clip of the user performing the challenge. Returns a best-frame selfie for use in the face match step.

Request — multipart/form-data
video      (file)    WebM video, ~3 seconds
challenge  (string)  The challenge string returned above
Response 200
{
  "live": true,
  "selfie_frame": "base64-encoded-jpeg"
}

// On failure:
{ "live": false, "error": "Liveness check failed or challenge not detected." }

Pass selfie_frame as the selfie image in Step 3.

Step 3 — Face match & final result

POST /api/kyc/face.php

Compare the liveness selfie to the photo on the uploaded ID. Runs AML/sanctions screening automatically using the name parsed from the ID barcode.

Request — multipart/form-data
verification_id  (string)  UUID from Step 1
selfie           (file)    JPEG selfie image (use selfie_frame from Step 2)
is_live          (string)  "1" if liveness passed, "0" otherwise
Response 200
{
  "status":             "passed",       // "passed" | "pending_review" | "failed"
  "face_matched":       true,
  "is_live":            true,
  "score":              0.42,           // ArcFace cosine distance — lower = more similar
  "sanctions_status":   "clear",        // "clear" | "hit" | "skipped" | "error"
  "sanctions_hit_count": 0,
  "sanctions_name":     "JANE SMITH"   // Name screened (from ID barcode)
}
Status values
StatusMeaning
passedFace matched, liveness confirmed, sanctions clear.
pending_reviewFace matched and liveness confirmed, but a sanctions hit was found — requires manual compliance review.
failedFace did not match or liveness check failed.

Mobile Camera Handoff

If a user is on a desktop and wants to use their phone camera to photograph the ID, generate a QR code linking to a mobile session. The desktop page polls for completion.

POST /api/kyc/create-mobile-session.php

Create a 15-minute mobile session. Display the returned URL as a QR code.

Response 200
{
  "session_token": "hex-string",
  "mobile_url":    "https://peabodysecure.com/...",
  "expires_in":    900
}
GET /api/kyc/mobile-session-status.php?session_token=<token>

Poll this endpoint (e.g. every 3 seconds) from the desktop page until status is complete.

Response
// Still waiting:
{ "status": "pending" }

// Phone submitted photos:
{ "status": "complete", "verification_id": "uuid-string" }

// Session timed out:
{ "status": "expired" }

When complete, use the returned verification_id to continue from Step 2 (liveness check).


Verification Results Reference

Sanctions / AML screening

Sanctions screening runs automatically during Step 3 using the name extracted from the ID barcode. The sanctions_status field in the face match response indicates the outcome.

ValueMeaning
clearNo matches found in OFAC/EU/UK sanctions databases.
hitOne or more potential matches found. Verification is set to pending_review for manual compliance assessment.
skippedName was not available from the ID (barcode could not be parsed).
errorScreening service error — will be flagged for manual review.

Face match score

The score field is an ArcFace cosine distance. Lower is more similar:

  • 0.00 – 0.40: High confidence match
  • 0.40 – 0.65: Match (within acceptance threshold)
  • Above 0.65: Not matched — face comparison failed

Pages

Key pages on the site (direct file URLs — no rewriting):

URLDescription
/index.htmlHomepage
/register.htmlCreate an account
/login.htmlLog in
/verify_identityV2.phpFull identity verification flow (file upload + liveness + face match)
/dashboard.htmlReview completed verifications
/pricing.htmlPricing
/public/swagger.htmlInteractive Swagger API explorer