Verification
Submit payment transaction IDs safely and interpret asynchronous verification state.
A display_instructions action requires the payer's payment transaction ID:
POST /api/v1/deposits/:id/verify
Authorization: Bearer <api-key>
X-Omni-Timestamp: <unix-seconds>
X-Omni-Signature: v1=<signature>
Content-Type: application/json{
"provider_transaction_id": "ABC123DEF4"
}The request field is named provider_transaction_id. Sign the exact JSON
bytes. OmniPay trims the value and normalizes it to uppercase.
Using the signedRequest helper from the
request-signing guide:
const attempt = await signedRequest<{
deposit_id: string;
attempt_id: string;
provider_transaction_id: string;
status: "processing";
attempts_used: number;
attempts_remaining: number;
}>({
method: "POST",
url: `https://omnipay.page/api/v1/deposits/${deposit.id}/verify`,
body: {
provider_transaction_id: payerTransactionId,
},
});Queued response
Verification is asynchronous. A new transaction ID returns HTTP 202:
{
"deposit_id": "cm7deposit02",
"attempt_id": "cm7attempt01",
"provider_transaction_id": "ABC123DEF4",
"status": "processing",
"attempts_used": 1,
"attempts_remaining": 2
}Poll the signed GET /api/v1/deposits/:id endpoint with reasonable backoff, and
process webhooks independently. A suggested polling interval is 2–5 seconds.
Polling decisions
| Deposit result | Your action |
|---|---|
status: "pending" or "processing" | Continue polling with backoff or wait for a webhook |
status: "succeeded" | Stop polling and fulfill idempotently |
| Any other terminal status | Stop polling and show an appropriate retry or failure state |
next_action: null | Do not restore cached instructions or accept another transaction ID |
Pause polling when the payer leaves the page, but keep webhook processing active. Set a client-side upper bound so a network problem cannot create an infinite polling loop.
Strict match rules
A transaction ID succeeds only when the payment matches the created deposit:
- transaction ID;
- recipient details returned in
next_action; - normalized payer phone;
- successful payment status;
- exact requested amount;
- payment completion inside the allowed window.
OmniPay never changes the requested amount to match a payment. An underpayment or overpayment cannot succeed the deposit.
Attempt limits
- The same normalized transaction ID is idempotent and returns the existing attempt.
- Only one queued, processing, or temporarily delayed attempt runs at a time.
- At most three distinct transaction IDs are accepted for one deposit.
- A transaction ID already submitted for the same payment method cannot be reused by another deposit.
- A
redirectaction returns409from the verification endpoint because it is confirmed automatically.
A new attempt normally returns 202. An idempotent repeat returns 202 while
it is still queued or processing and 200 when it has resolved.
Status fields
The deposit response includes:
{
"verification": {
"state": "processing",
"attempts_used": 1,
"attempts_remaining": 2,
"failure_code": null
},
"provider_transaction_id": null
}Build fulfillment logic around the deposit status, not an individual
verification state. Common states include:
| State | Meaning |
|---|---|
awaiting_reference | Waiting for the payer's transaction ID |
processing | A submitted transaction ID is being checked |
succeeded | Deposit passed all verification checks |
failed | Submitted transaction IDs could not be verified by the deadline |
expired | No transaction ID was submitted before the deadline |
cancelled, rejected, refunded | Terminal payment or business outcome |
Other nonterminal state values may appear while OmniPay finalizes the result.
Treat them as pending and continue using the top-level deposit status and
signed webhooks as the fulfillment contract.
On success, provider_transaction_id contains the normalized transaction ID.
The field remains null before success.
Safe retry behavior
Retry a network failure with the same transaction ID and a fresh timestamp and signature. Because the ID is idempotent, this cannot consume another attempt. Do not substitute a new transaction ID automatically—each distinct value uses one of the three attempts.