OmniPayDocs
H2H checkout

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 resultYour action
status: "pending" or "processing"Continue polling with backoff or wait for a webhook
status: "succeeded"Stop polling and fulfill idempotently
Any other terminal statusStop polling and show an appropriate retry or failure state
next_action: nullDo 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 redirect action returns 409 from 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:

StateMeaning
awaiting_referenceWaiting for the payer's transaction ID
processingA submitted transaction ID is being checked
succeededDeposit passed all verification checks
failedSubmitted transaction IDs could not be verified by the deadline
expiredNo transaction ID was submitted before the deadline
cancelled, rejected, refundedTerminal 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.

On this page