Skip to content

Testing a verification integration end to end in sandbox

Use the published sandbox test IDs, whose last digits pick the outcome, to drive every result your code must handle, then test your webhook receiver with signed simulated events before switching to live keys.

Charles Archibong

, Co-founder

· 5 min read

Headline "Testing verification in sandbox" beside an illustration of a laboratory flask with bubbles, on a deep indigo gradient.

Key takeaways

  • Sandbox accepts only published test IDs; their last digits choose the scenario.
  • Test the failures you will branch on, not only the happy path.
  • sandboxOutcome and sandboxDelayMs in metadata force a scenario and control timing; production ignores them.
  • Test the webhook receiver separately with signed simulated events, including resends and rotations.

Test every outcome your code will handle, including the failures, by driving each one deliberately with the sandbox test IDs. In Myaza Trust's sandbox, the last digits of a published test ID choose the scenario: verified, not found, a selfie mismatch, an expired document, a provider error, and so on. Nothing external is called and nothing is charged, so you can run the full matrix as often as you like.

Then test your webhook receiver on its own, with signed simulated events, resends and a failing response. Most integration bugs found after launch are in the failure paths and the receiver, not in the happy path everyone tested by hand.

How sandbox behaves

Sandbox is selected by the key prefix: pk_test_ for the client SDKs, sk_test_ for your backend. According to the sandbox guide, three rules apply:

  • Only published test IDs are accepted. A real ID number is rejected at submission with 422 only_test_ids_allowed, so real ID numbers stay out of your test data.

  • Results are fake. Biodata, government photos, document reads and database results are canned. No government database or other external service is called.

  • Nothing is charged, including the insufficient-credits scenario.

Test IDs also bypass your organisation's ID-type allowlist, so a new organisation can start testing immediately.

Sandbox and production are separate: keys, verifications, webhook endpoints and configuration do not cross between them. Whatever you set up in sandbox, you set up again for production.

How a test ID picks the outcome

A test ID is zero-padding followed by the scenario number, so it stays valid for its ID type. For a Nigerian BVN:

00000000001  → verified
00000000002  → not_found
00000000004  → selfie_mismatch
00000000012  → provider_error

Each ID type has its own format for the same idea: A00000001 for a Nigerian passport, GHA-000000001-0 for a Ghana Card, 00000001 for a Kenyan national ID. Change the trailing digits to change the scenario. The full table of 24 scenarios and every ID type's format is in the guide.

A verified BVN test from your backend, following the documented example:

curl -X POST https://trust.myaza.app/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" }
  }'

For document IDs, sandbox never reads the image. Let the SDK document flow default to the verified fixture, or pick a scenario by passing the document's test ID in idNumber, for example A00000007 for an expired passport.

The outcomes worth testing, grouped by what your code does

Twenty-four scenarios is more than most integrations need to exercise one by one. Group them by the branch in your code each one reaches:

Your code's branch

Scenarios to run

What to assert

Pass

1 verified

Access is granted only after your backend receives the result

The ID does not exist

2 not_found

You ask the user to check the number, keyed on identity_not_found

Retake a photo

4 selfie_mismatch, 9 document_unreadable, 10 document_blurry

The user is sent to the right capture step, not to a dead end

Fix the input

5 gov_data_mismatch, 8 document_type_mismatch

The message matches the reasonCode, not a generic failure

New document

7 document_expired

The user is asked for a current document

Myaza's side failed

12 provider_error, 16 system_error

The user sees a generic message; your team sees the reason

Configuration problem

17 id_type_not_enabled, 15 insufficient_credits

An alert reaches your team, and the user is not blamed

Some scenarios follow your workflow's own settings, which is useful because it tests your configuration rather than a fixed answer. Scenarios 5 and 6 fail by default, but verify with dataMatch: false when your workflow records those identity details instead of failing on them. Scenarios 22 and 23 follow your age restriction: 22 returns a date of birth just outside your limits, 23 returns none, and both verify on a workflow with no age restriction. Scenario 24 follows your settings for matching the selfie to the photo printed on a document, and verifies when your workflow does not use that photo for the ID.

Forcing outcomes and timing

Two overrides go in metadata and are ignored in production:

  • sandboxOutcome forces any scenario regardless of the test ID, for example "sandboxOutcome": "selfie_mismatch". Useful when the SDK's document flow does not collect an ID number.

  • sandboxDelayMs controls how long a verification takes to settle, from 0 to 60,000 milliseconds, defaulting to roughly 1,200.

Use the delay deliberately. Set it to 0 for fast automated tests. Set it to tens of seconds to test the part people forget: what your app shows while it waits, whether the user can leave the screen and come back, and whether a slow webhook leaves the screen stuck.

"metadata": {
  "requestId": "test-slow-002",
  "sandboxOutcome": "document_expired",
  "sandboxDelayMs": 30000
}

While you are there, submit the same requestId twice. You should get the existing verification back, not a second one, which is the behaviour your retry logic depends on.

Test the decision, not only the checks

If your workflow has decision rules, the checks are only half the answer. Run each scenario through the published sandbox workflow and confirm the outcome your policy expects: a selfie_mismatch that should go to review arrives as in_review, not declined. Remember that verification.completed reflects the checks alone; the workflow's verdict follows as verification.status_updated, and your backend should act on that one.

Business verification has its own sandbox fixtures. Any registration number is accepted and resolves to a verified fixture, RC0000001 is verified and RC0000002 is not found, and the sandbox company carries a set of key people for exercising due diligence.

Test the webhook receiver separately

Create a sandbox webhook endpoint and use the simulator on its page, which sends a realistic, correctly signed sample of any event through the real delivery path, without running a verification. The webhook testing guide recommends a sequence; the steps that catch most bugs are:

  1. Confirm the receiver verifies the V2 signature over the raw body and returns 2xx quickly.

  2. Resend a delivery from the dashboard and confirm your side effect happens once, because your deduplication is keyed on the event ID.

  3. Return a non-2xx response temporarily and confirm a retry is scheduled.

  4. Rotate the secret and confirm both signatures are accepted during the grace period.

  5. Deliver two events out of order and confirm your handler still ends in the right state.

Before you switch to live keys

Media uploaded under a test ID is kept for three days and then replaced by a placeholder, so do not build tests that depend on the original images later. When the matrix passes, the environments guide lists what production needs:

  1. Your business profile is approved for production. Until then, production verify and upload requests are rejected with business_not_approved.

  2. You have created live keys: publishable for the client, secret for backend results.

  3. You have registered production webhook endpoints and verified their signatures.

  4. Your credit balance is funded and a low-balance threshold is set.

  5. You have swapped test keys for live keys.

Add one item of your own: point the SDK at your production workflow ID, since workflows are scoped to one environment.

Run one real verification of your own in production before opening the flow to customers. Sandbox proves your code handles every outcome; that first live run proves the configuration you copied across is the one you meant.

Sources

Charles Archibong

About the author

Charles Archibong

Co-founder

Charles Archibong co-founded Myaza Trust. He writes about identity verification, financial technology, and the practical work of building trusted digital services.

Build your product.We'll handle the rest.

Identity and compliance, end to end, built to global standards, priced for founders.

Test a verification integration end to end in sandbox · Myaza Trust