Sandbox & test IDs

Test your Myaza KYC integration end to end: webhooks, polling, the full result payload (biodata, facial match, OCR data, captured-media URLs), and every failure branch, all without calling any government database or consuming paid verification credits.

EnvironmentKey prefixReal IDs?Test IDs?Charged?
Sandboxpk_test_ / sk_test_rejectedcanned resultnever
Productionpk_live_ / sk_live_yestreated as realyes

Sandbox accepts only published test IDs. A real (non-test) idNumber is rejected immediately at POST /verify with 422 only_test_ids_allowed.

All sandbox results are fully fake: fake biodata, fake government photos, fake OCR, and fake gov-DB data. No external API is ever called.

How test IDs work

Pass a test ID in the idNumber field of POST /verify. The last one or two digits encode the scenario; everything before is zero-padding so the value stays format-valid for its ID type. Example for NG BVN:

code
00000000001   verified
00000000002   not_found
00000000004   selfie_mismatch
00000000007   document_expired   (document IDs only)
00000000012   provider_error

Scenario reference

Scenarios 5 and 6 follow your workflow's identity details policy. When the workflow records every field the scenario disagrees on (5: first and last name; 6: first name and date of birth) instead of failing on it, the test ID verifies with dataMatch: false, exactly as a real mismatch would.

IdxScenarioStatusreasonCodeApplies to
1verifiedverifiedall
2not_foundnot_foundidentity_not_foundall
3gov_validation_failedfailedgov_validation_failedall
4selfie_mismatchfailedselfie_mismatchall
5gov_data_mismatchfailedgov_data_mismatchall
6document_data_mismatchfaileddocument_data_mismatchdocument
7document_expiredfaileddocument_expireddocument
8document_type_mismatchfaileddocument_type_mismatchdocument
9document_unreadablefaileddocument_unreadabledocument
10document_blurryfaileddocument_blurrydocument
11id_number_not_foundfailedid_number_not_founddocument
12provider_errorerrorprovider_errorall
13unsupported_id_typeerrorunsupported_id_typeall
14media_not_founderrormedia_not_foundall
15insufficient_creditserrorinsufficient_creditsall
16system_errorerrorsystem_errorall
17id_type_not_enablederrorid_type_not_enabledall
18document_verification_disablederrordocument_verification_disableddocument
19gov_db_check_disablederrorgov_db_check_disabledall
20sandbox_not_foundnot_foundsandbox_not_foundall
21sandbox_failedfailedsandbox_failedall
22age_restrictedfailedage_restrictedall
23age_unverifiedfailedage_unverifiedall
24document_photo_no_facefaileddocument_photo_no_facedocument

Scenarios 22 and 23 follow your workflow's age restriction. Scenario 22 returns a date of birth just outside your own limits (a year under the minimum, or a year over the maximum) and scenario 23 returns none, so both fail exactly as a real holder would. On a workflow with no age restriction, both verify. If your workflow sends that case to review instead of declining it, scenario 22 verifies with the out-of-range date of birth and your decision rule sends it to review; scenario 23 always fails.

Scenario 24 follows your workflow's settings for the photo on the document. It stands for a document ID whose selfie could only be compared with the photo printed on the document, where no face could be read on that photo. If your workflow compares that ID with the photo on the document and declines the case, it fails with document_photo_no_face. If your workflow sends that case to review, it verifies with facialMatchSkipped: "no_face_on_document", and your decision rule on verification.documentPhotoNoFace sends it to review. If your workflow does not compare that ID with the photo on the document, it verifies.

Document-only scenarios (6–11, 18) are not published for number-only IDs (BVN/NIN/vNIN).

The verified test ID per ID type

Change the trailing digits per the table above to pick a different scenario.

CountryID typeFormatverified test ID
NGbvn / nin11 digits00000000001
NGvnin16 chars0000000000000001
NGpassportA + 8 digitsA00000001
NGdrivers-licenseTST + 8 digitsTST00000001
NGpvc19 digits0000000000000000001
GHghana-cardGHA-NNNNNNNNN-NGHA-000000001-0
GHvoters10 digits0000000001
GHssnitC + 12 digitsC000000000001
GHpassportG + 8 digitsG00000001
KEnational-id8 digits00000001
KEpassportK + 8 digitsK00000001
ZAnational-id13 digits0000000000001
ZApassportZ + 8 digitsZ00000001
CIcniCI + 9 digitsCI000000001
CIresidence-cardCR + 9 digitsCR000000001

Example: number-only ID

shell
curl -X POST https://your-server/api/kyc/verify \
  -H "Authorization: Bearer pk_test_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "country": "NG",
    "idType": "bvn",
    "idNumber": "00000000001",
    "userData": { "firstName": "Chidi", "lastName": "Okafor", "dateOfBirth": "1990-04-12" },
    "metadata": { "requestId": "test-001" }
  }'

Document IDs

In sandbox, OCR is never run; a fake OCR result is returned instead. Either let the SDK document flow default to the verified fixture (no ID number collected), or pick a scenario by passing the document test ID in idNumber (e.g. A00000007 for an expired passport) or via the sandboxOutcome override below.

Business (KYB)

Business verification never calls a real registry outside production: a registry lookup incurs an external check cost in whichever environment requests it, so sandbox and development serve canned data instead.

  • Any registration number is accepted and resolves to a verified fixture that echoes the name you searched for. The catalogue values still pick their scenario: RC0000001 is verified, RC0000002 is not found. A business picked from the real company search (which does work in every environment) can therefore be checked on sandbox against fixture data.
  • sandboxOutcome on the submit ("verified" or "not_found") pins the result for any number, and is ignored silently in production.
  • The sandbox company carries a full key-people set for exercising due diligence: a 60% beneficial owner, directors, a signatory, a persona named "Pep" that the sandbox screening stub flags (set SCREENING_PROVIDER=stub), and a corporate shareholder, Sandbox Holdings Ltd (RC0000900), whose own register resolves to a person majority-owner and a second company above it (RC0000901), so ownership-chain look-through, effective percentages, and the depth limit are all testable at no cost.

Address presence

Presence verification has its own personas and a compressed clock so a multi-day watch is testable in minutes; they are documented with the feature on the Address Intelligence page. In short: outside production the watch window runs in minutes, and an externalUserId containing presence_verified, presence_fail or presence_inconclusive seeds a canned observation stream through the real scorer. A plain id gets no seed, so you can drive the ingest endpoint yourself.

Overrides

Both go in metadata and are ignored in production.

  • sandboxOutcome: force any scenario regardless of the test ID, e.g. "sandboxOutcome": "selfie_mismatch".
  • sandboxDelayMs: how long pending → completed takes (0–60000 ms). Defaults to ~1200 ms; set 0 for an instant result.

Captured media

Media uploaded under a test ID is kept for 3 days, then the bytes are replaced with a placeholder (an image for stills, a sample clip for videos). The data.media URLs in webhooks keep working; they just serve the placeholder after the sweep.

Webhook simulator

From a webhook endpoint's detail page (or POST /api/dashboard/webhooks/:id/simulate with { "event": "verification.completed" }), fire a realistic, correctly-signed sample payload of any event at your endpoint to test signature verification and your handler, without running a verification. It uses the real delivery path (HMAC signing + retry).

Notes

  • Sandbox verifications are never charged, even for the insufficient_credits scenario.
  • Test IDs bypass the ID-type allowlist, so a new organisation can test immediately. Use the id_type_not_enabled scenario to simulate a revoked allowlist.
  • Branch on the stable reasonCode, not the human-readable reason.