00 · The Big Picture
Open demo
PusoPay · DigiCash eWallet × SVI · API Guide v1.0.0

Know your customer in minutes, not days.

PusoPay serves PWDs, senior citizens, and solo parents — people who can't afford a branch visit. This API lets the app verify identity with a selfie and an ID, under one session ID, and open a wallet on a pass.

7endpoints, one base URL
15 minaccess-token lifetime
80 / 75%liveness / face-match bars
15ID types incl. Other

PusoPay owns the wallet and the customer screens. SVI owns identity proofing. The two sides meet at exactly one concept: the TRN — a session ID created up front and stapled to every photo and check.

1. Tokenserver logs in
2. SessionTRN issued
3. Selfieliveness 80%
4. IDread + match 75%
5. DecisionPASSED / REVIEW
Plain-English rule: SVI answers three questions — are you live, is your ID real, does your face match — and PusoPay opens the wallet on a pass. PNID passes instantly; other IDs go to human review.
01 · Authentication

Logging the server in

OAuth 2.0 client-credentials. The server trades its provisioned credentials for a short-lived bearer token — the phone never sees secrets.

POST/auth/token

Headers

HeaderValue
Content-Typeapplication/x-www-form-urlencoded
AuthorizationHTTP Basic — base64(Client ID : Client Secret)
x-api-keyGateway key issued at onboarding

Body

FieldRequiredValue
grant_typerequiredclient_credentials

Sample response · 200

{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 900,
  "expires_at": "2026-07-14T22:48:46Z"
}

Field notes

FieldMeaning
access_tokenJWT → Authorization: Bearer on later calls
expires_in900 s = 15 min; the demo caches + refreshes silently
expires_atExact UTC expiry
Expired token surfaces as 401 UNAUTHORIZED downstream — the fix is always "log in again", never "retry the photo".
02 · Session

Opening a session (TRN)

One call, no body. The returned UUID is the claim ticket for the whole onboarding.

POST/transaction/create

Headers

HeaderValue
AuthorizationBearer <token>
x-api-keyGateway key

Body

None — empty JSON object.

Sample response · 200

{
  "transaction_id": "c5a21976-2e82-4ac0-b173-85aaa1e500a3"
}
Every endpoint from here on also sends X-Transaction-Id: <TRN>. Lose the TRN and the session is unrecoverable — the demo pins it in the backend panel with a copy button.
03 · Liveness

Is this a live person?

Passive liveness on a single selfie frame. The cheapest fraud filter: printed photos and screen replays fail here.

POST/liveness/passive

Headers

HeaderValue
AuthorizationBearer <token>
X-Transaction-IdTRN from §03
x-api-keyGateway key

Body

FieldRequiredMeaning
imagerequiredBase64 JPEG/PNG selfie

Sample response · 200

{
  "status": "success",
  "results": {
    "passed": true,
    "confidence_score": 0.82,
    "threshold": 0.8
  }
}
Read it right: HTTP 200 with passed: false is a completed check with a "not live" verdict — not an error. The bar is 0.80; the demo shows it as a percentage (82%) and asks for a retake on fail.
04 · ID read

Reading the ID

OCR extracts printed identity + personal data into a standard JSON shape. Missing fields come back null — never guessed.

POST/id/ocr

Headers

HeaderValue
AuthorizationBearer <token>
X-Transaction-IdTRN
x-api-keyGateway key

Body

FieldRequiredMeaning
id_front_base64requiredID front photo
id_back_base64optionalID back photo

Sample response · 200 (abridged)

{
  "status": "success",
  "extracted_information": {
    "id_information": {
      "code": "3",
      "type": "PNID",
      "id_number": "000-000-000",
      "expiration_date": "2026-12-12"
    },
    "personal_information": {
      "last_name": "Dela Cruz",
      "first_name": "Juan",
      "suffix": "Jr",
      "birthdate": "1990-01-01",
      "address": {
        "address_line_1": "45 Mabini Street",
        "barangay": "Barangay Poblacion",
        "city_municipality": "Makati City",
        "province": "Metro Manila",
        "zipcode": "1210"
      }
    }
  }
}
The demo auto-detects the ID type from code/type (unknown → code 0, Other) and auto-fills the review form — no typing, fewer errors, kinder to seniors.
05 · Face match

Does the face match?

1:1 biometric compare: the captured selfie against the captured ID portrait. Same TRN, verdict recorded as FACE_MATCH.

POST/face-match/check

Body

FieldRequiredMeaning
face_bio_base64requiredCaptured selfie
id_base64requiredCaptured ID front

Sample response · 200

{
  "status": "success",
  "results": {
    "is_matched": true,
    "confidence_score": 0.82,
    "threshold": 0.75
  }
}
Bar is 0.75. The demo shows the two exact photos being compared, side by side, before running it — no black box.
06 · PNID QR (alternate path)

Or verify by QR

For PhilSys cards: scan the QR, verify payload + selfie through eVerify. Same outcome, no ID photo needed.

POST/verifications/qr

Body

FieldRequiredMeaning
qr_valuerequiredRaw PNID QR string (camera scan or upload decodes it)
face_biometric_base64requiredCaptured selfie

Sample response · 200

{ "status": "success", "is_verified": true }
07 · Decision

Submitting for the verdict

Confirmed identity + captured photos go in; verification_status comes out: PASSED (PNID) or PENDING_REVIEW.

POST/transaction/submit

Body

FieldRequiredMeaning
id_information.code / .type / .id_numberrequirede.g. 3 / PNID / 000-000-000
id_information.expiration_dateoptionalYYYY-MM-DD
personal_information.last_name / .first_name / .birthdaterequired
personal_information.suffix / .addressoptionalAddress object: line 1, barangay, city, province, zip
images.face_bio_base64 / .id_front_base64requiredCaptures
images.id_back_base64optional

Minimal valid body

{
  "id_information": {
    "code": "3", "type": "PNID",
    "id_number": "000-000-000"
  },
  "personal_information": {
    "last_name": "Dela Cruz",
    "first_name": "Juan",
    "birthdate": "1990-01-01"
  },
  "images": {
    "face_bio_base64": "<base64>",
    "id_front_base64": "<base64>"
  }
}

Sample responses

{
  "verification_status": "PENDING_REVIEW",
  "session_transaction_id": "c5a21976-…",
  "create_at": "2026-09-18T09:57:00Z"
}
// PNID path:
{ "verification_status": "PASSED", ... }
Demo rule: PNID → PASSED, anything else → PENDING_REVIEW. The wallet unlocks either way for demo purposes; the badge color tells them apart (blue seal vs yellow clock).
08 · Safety rails

When things fail, they fail clearly

Every failure is HTTP status + error_code + human message. The demo surfaces all three in the backend log.

HTTPCodeWhat it means / what to do
400INVALID_REQUESTMalformed body/headers/JSON — fix the payload
400INVALID_ID_TYPEID code unknown or outside contract scope
401UNAUTHORIZEDToken missing/expired — re-login (§02)
403FORBIDDENToken lacks scope or IP not allowed
405METHOD_NOT_ALLOWEDWrong HTTP verb
415UNSUPPORTED_MEDIA_TYPEWrong Content-Type (json vs form-urlencoded)
422INVALID_BIOMETRICBad base64 or failed quality/liveness — recapture
429LIMIT_EXCEEDEDRate limit — back off and retry
502REGISTRY_UNAVAILABLEDownstream registry offline — retry later
502UPSTREAM_ERRORProcessing dependency failed
500SERVER_ERRORUnexpected — escalate to SVI support
09 · Accepted IDs

15 codes on the table

Guide §10 lists 14; the demo adds 0 = Other for anything the OCR can't classify. Contract scope applies: query only what our agreement covers.

CodeTypeCodeType
0OTHER_ID (demo)8TIN
1PASSPORT9PWD_ID
2PNID10SENIOR_CITIZEN_ID
3PNID (ePhil ID)11PHILHEALTH
4UMID12POSTAL_ID
5PRC_ID13DRIVERS_LICENSE
6SSS_ID14BATAENO_PASS
7GSIS_ID
10 · Proof

The live demo maps 1:1

Three columns: the customer app, the backend log, results + docs. Every screen calls exactly one endpoint.

App stepEndpointEvidence in demo
Send code / login— (mock SMS)Inbox panel, tap-to-fill OTP
Start verificationPOST /auth/token → /transaction/createTRN in session panel
SelfiePOST /liveness/passiveLIVE 82% chip
ID scanPOST /id/ocrAuto-fill + detected type
Match / QRPOST /face-match/check · /verifications/qrSide-by-side photos · decoded string
ConfirmPOST /transaction/submitResult screen + wallet unlock
11 · Recap

Secure. Verified. Instant.

Seven endpoints, one session ID, three questions answered
before PusoPay opens a wallet:

  1. Are you live?Selfie liveness clears photos of photos.
  2. Is your ID real?OCR reads it; the details are checked out.
  3. Does your face match?Selfie vs ID — or PNID QR instead.

Three checks. Zero friction.
Selfie to wallet in one smooth flow.
That's DigiCash's PusoPay onboarding, powered by SVI.

PusoPay demo · DigiCash eWallet · identity checks by SVI
base https://verify.dev.svi.cloud/api/v1
PusoPay logo and other details are placeholders for demo purposes only — no real money was used.
Demo by Kevin G. Vega