Testing Account Issuance

Test successful issuance, rejection, and expired links.

Sandbox scenarios simulate RFIs and account outcomes using the live API and webhook formats. They do not perform real KYC or reproduce every live requirement.

Prepare

Use a test API key, your test webhook receiver, and a person meeting the USD requirements. Use synthetic details and labelled test JPEG, PNG, or PDF evidence; document classes are still validated. No separate inquiry subscription is needed.

Replace the example keys and IDs. Autosweep is disabled; enabling it requires a test USD settlement wallet.

Run the success scenario

curl --request POST \
  --url 'https://api.useoval.com/bank_account' \
  --header 'Authorization: Bearer YOUR_TEST_API_KEY' \
  --header 'content-type: application/json' \
  --data '{
    "person_id": "TEST_PERSON_ID",
    "label": "RFI success test",
    "currency": "USD",
    "autosweep_enabled": false,
    "sandbox_scenario": "rfi_success"
  }'

Expect 201 with a pending account. Save data.id as ACCOUNT_ID. After an uncertain result, list accounts before retrying; scenarios add no idempotency key.

Answer the standard RFI

curl --request GET \
  --url 'https://api.useoval.com/inquiry_request?account_id=ACCOUNT_ID&page=1&per_page=20' \
  --header 'Authorization: Bearer YOUR_TEST_API_KEY' \
  --header 'accept: application/json'

Save the first inquiry's id as REQUEST_ID, then respond:

curl --request POST \
  --url 'https://api.useoval.com/inquiry_request/REQUEST_ID/responses' \
  --header 'Authorization: Bearer YOUR_TEST_API_KEY' \
  --header 'content-type: application/json' \
  --data '{"message":"Test account for salary receipts","documents":[]}'

Expect 201; the inquiry stays pending until simulated review completes. A message is sufficient; optional documents must be downloadable. Further submissions return 409. Check response history after an uncertain result.

Complete the hosted action

After review, a new link inquiry appears. List inquiries again or fetch the ID from inquiry_request.created. Open its link and select Complete simulated verification. Opening the URL alone does nothing; the page needs no API key or identity evidence.

Each step has its own inquiry ID and appears only after the previous step finishes. Processing normally checks each minute, but delays are possible.

After all steps complete, expect account.created. Fetch the account to confirm active status and test bank details. No operator review is needed.

Test other outcomes

Create a new test account for each preset:

sandbox_scenarioExpected result
rfi_successStandard then hosted RFI; account becomes active.
rfi_rejectedComplete both RFIs, then receive account.issuance.failed; account becomes failed.
rfi_expired_linkStandard then hosted RFI with link: null; refresh and complete it to reach active.

For an expired link, use the hosted inquiry's ID:

curl --request POST \
  --url 'https://api.useoval.com/inquiry_request/REQUEST_ID/refresh' \
  --header 'Authorization: Bearer YOUR_TEST_API_KEY' \
  --header 'accept: application/json'

Refresh takes no body, preserves the inquiry ID, and invalidates that step's old link. Open the new link and complete the action. Completed actions return current state without a new link; standard inquiries cannot be refreshed.

Sandbox links last 14 days from their creation or refresh, independently of earlier steps. Live lifetimes may differ. Invalid, expired, or superseded hosted URLs return 410; temporary page failures return 503. These differ from refresh API errors.

Custom sequences

Use sandbox_options instead of sandbox_scenario:

{
  "person_id": "TEST_PERSON_ID",
  "label": "Custom RFI sequence",
  "currency": "USD",
  "autosweep_enabled": false,
  "sandbox_options": {
    "rfi_sequence": [
      {"type": "link", "link_status": "available"},
      {"type": "standard"},
      {"type": "link", "link_status": "expired"}
    ],
    "outcome": "success"
  }
}
  • rfi_sequence: 1–10 step objects; standard and link may repeat. Omission defaults to standard then link.
  • link_status: available (default) or expired, on link steps only.
  • outcome: success (default) or rejected, after all steps complete.
  • {} uses all defaults. Options are fixed for the account.

Use only one sandbox field; omit both for ordinary test issuance. Invalid options, empty/oversized sequences, or use outside test person USD accounts return 400 before creation.

Webhooks and checks

For standard then link, expect these lifecycle events; delivery order may differ:

  1. Standard inquiry created.
  2. answered on response submission: pending, with response_id.
  3. answered after simulated review: completed, response_id: null.
  4. Hosted inquiry created.
  5. answered on hosted completion: completed, link and response_id null.
  6. account.created, or account.issuance.failed for rejection.

Expiry clearing a link or refresh replacing it can emit inquiry_request.updated. Deduplicate using data.event_id and fetch current state. See Inquiry Events.

Confirm that your UI handles person-owned inquiries with null account_id, discovers later RFIs, replaces expired links, and waits for account activation. Check that repeated or delayed events do not repeat user actions or restore stale state.