{"openapi":"3.1.0","info":{"title":"OmniPay API","version":"1.1.0","summary":"Deposits and withdrawals for Bangladesh payment methods.","description":"OmniPay exposes a REST API for redirect checkout, head-to-head (h2h)\ndeposits, and withdrawals. All money values are decimal strings in BDT.\n\nEvery merchant request uses a bearer API key. H2H requests also use a\ntimestamped HMAC-SHA256 signature over the exact request bytes. See the\nauthentication guide before integrating H2H.\n","contact":{"name":"OmniPay","url":"https://omnipay.page"}},"servers":[{"url":"https://omnipay.page/api","description":"Production"}],"tags":[{"name":"Deposits","description":"Create and inspect redirect or H2H deposits."},{"name":"H2H deposits","description":"Submit a payment transaction ID for asynchronous H2H verification."},{"name":"Withdrawals","description":"Create and inspect payout requests."}],"security":[{"bearerAuth":[]}],"paths":{"/v1/deposits":{"post":{"tags":["Deposits"],"operationId":"createDeposit","summary":"Create a deposit","description":"Creates either a backwards-compatible redirect checkout or an H2H\ndeposit. Omit `checkout_mode` (or send `redirect`) for the legacy\nbearer-only flow. Send `checkout_mode: h2h`, a payer phone, and both\nH2H signature headers for API-controlled checkout.\n\n`merchant_id` is the idempotency key within your organization. Repeating\nan identical H2H request returns the existing deposit. Reusing the same\nvalue with different immutable fields returns `409`.\n\n`next_action` is a discriminated union. For `display_instructions`, render\nthe returned values and submit the payer's transaction ID to the returned\nverification endpoint. For `redirect`, open the returned URL and do not\ncall the manual verification endpoint.\n","parameters":[{"$ref":"#/components/parameters/OmniTimestamp"},{"$ref":"#/components/parameters/OmniSignature"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/RedirectDepositRequest"},{"$ref":"#/components/schemas/H2HDepositRequest"}],"discriminator":{"propertyName":"checkout_mode"}},"examples":{"h2h":{"summary":"H2H bKash merchant deposit","value":{"amount":"500.00","payment_method":"bkash_merchant","redirect_url":"https://merchant.example/return","merchant_id":"order-123","checkout_mode":"h2h","payer":{"phone":"01712345678"},"metadata":{"invoice_id":"INV-123"}}},"redirect":{"summary":"Redirect checkout","value":{"amount":"1000","payment_method":"bkash","redirect_url":"https://merchant.example/return","merchant_id":"order-124","metadata":{"invoice_id":"INV-124"}}}}}}},"responses":{"200":{"description":"Redirect checkout created, or an identical H2H create request replayed.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/RedirectDeposit"},{"$ref":"#/components/schemas/H2HDeposit"}]},"examples":{"redirect":{"value":{"id":"cm7deposit01","amount":"1000","payment_method":"bkash","status":"pending","metadata":{"invoice_id":"INV-124"},"merchant_id":"order-124","redirect_url":"https://omnipay.page/api/v1/payments/cm7deposit01"}},"h2hReplay":{"$ref":"#/components/examples/H2HManualDeposit"}}}}},"201":{"description":"H2H deposit created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/H2HDeposit"},"examples":{"manual":{"$ref":"#/components/examples/H2HManualDeposit"},"redirectAction":{"$ref":"#/components/examples/H2HRedirectDeposit"}}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Deposits or H2H creation are not enabled for the organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The merchant ID exists with a different request contract.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The requested payment method is temporarily unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/deposits/{id}":{"get":{"tags":["Deposits"],"operationId":"getDeposit","summary":"Get a deposit","description":"Returns a deposit owned by the API key's organization. Redirect deposits\nneed bearer authentication only. H2H deposits also require a valid\nsignature; sign an empty request body.\n\nPoll this endpoint while a deposit is pending, including after redirect\ncheckout or after submitting a payment transaction ID for H2H verification.\nWhile a deposit is actionable, `next_action` is present. It becomes `null`\nafter expiry or any terminal transition.\n","parameters":[{"$ref":"#/components/parameters/DepositId"},{"$ref":"#/components/parameters/OmniTimestamp"},{"$ref":"#/components/parameters/OmniSignature"}],"responses":{"200":{"description":"Current deposit state.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/RedirectDepositStatus"},{"$ref":"#/components/schemas/H2HDeposit"}]},"examples":{"h2h":{"$ref":"#/components/examples/H2HManualDeposit"},"redirect":{"value":{"id":"cm7deposit01","amount":"1000","payment_method":"bkash","status":"succeeded","metadata":{"invoice_id":"INV-124"},"merchant_id":"order-124","bank_transaction_id":"B8F2L9X3"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/deposits/{id}/verify":{"post":{"tags":["H2H deposits"],"operationId":"verifyH2HDeposit","summary":"Submit an H2H payment transaction ID","description":"Queues strict verification of a `display_instructions` H2H action.\nOmniPay checks the payment transaction ID, recipient details, payer\nphone, payment status, exact amount, and payment window.\n\nThe first submission normally returns `202`. Submitting the same\nnormalized transaction ID again is idempotent and returns the existing\nattempt. Only one attempt can process at a time, and a deposit accepts\nat most three distinct transaction IDs. Redirect actions are confirmed\nautomatically and cannot use this endpoint.\n","security":[{"bearerAuth":[],"h2hSignature":[]}],"parameters":[{"$ref":"#/components/parameters/DepositId"},{"$ref":"#/components/parameters/RequiredOmniTimestamp"},{"$ref":"#/components/parameters/RequiredOmniSignature"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/H2HVerificationRequest"},"examples":{"bkash":{"value":{"provider_transaction_id":"ABC123DEF4"}}}}}},"responses":{"200":{"description":"An idempotent repeat returned an already resolved attempt.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/H2HVerificationResolved"}}}},"202":{"description":"Verification was queued or is still processing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/H2HVerificationQueued"}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The deposit is terminal, a different attempt is processing, the\nthree-transaction-ID limit was reached, the ID is already used, or the\naction is a redirect and does not accept manual verification.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Verification could not be queued; retry safely with the same payment transaction ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/withdraws":{"post":{"tags":["Withdrawals"],"operationId":"createWithdrawal","summary":"Create a withdrawal","description":"Creates a payout request. Mobile-wallet amounts must be between BDT 100\nand 25,000; bank payouts must be between BDT 50,000 and 300,000. The\n`merchant_id` must be unique within your organization.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WithdrawalRequest"},"examples":{"mobileWallet":{"value":{"amount":"1000","phone":"01341491353","payment_method":"bkash","merchant_id":"payout-123","metadata":{"invoice_id":"INV-900"}}}}}}},"responses":{"201":{"description":"Withdrawal accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Withdrawal"}}}},"400":{"$ref":"#/components/responses/InvalidRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Withdrawals are disabled or the available balance is insufficient.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The merchant ID already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The requested payout method is temporarily unavailable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/withdraws/{id}":{"get":{"tags":["Withdrawals"],"operationId":"getWithdrawal","summary":"Get a withdrawal","description":"Returns the current state of a withdrawal owned by the API key's organization.","parameters":[{"name":"id","in":"path","required":true,"description":"OmniPay withdrawal ID.","schema":{"type":"string"}}],"responses":{"200":{"description":"Current withdrawal state.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Withdrawal"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"OmniPay API key","description":"API key created in the OmniPay developer dashboard."},"h2hSignature":{"type":"apiKey","in":"header","name":"X-Omni-Signature","description":"`v1=` followed by an unpadded base64url HMAC-SHA256 digest."}},"parameters":{"DepositId":{"name":"id","in":"path","required":true,"description":"OmniPay deposit ID.","schema":{"type":"string"}},"OmniTimestamp":{"name":"X-Omni-Timestamp","in":"header","required":false,"description":"Required for H2H. Current Unix time in whole seconds; accepted within five minutes.","schema":{"type":"string","pattern":"^\\d+$","example":"1785259200"}},"OmniSignature":{"name":"X-Omni-Signature","in":"header","required":false,"description":"Required for H2H. Versioned HMAC signature of the canonical request.","schema":{"type":"string","pattern":"^v1=[A-Za-z0-9_-]+$"}},"RequiredOmniTimestamp":{"name":"X-Omni-Timestamp","in":"header","required":true,"description":"Current Unix time in whole seconds; accepted within five minutes.","schema":{"type":"string","pattern":"^\\d+$","example":"1785259200"}},"RequiredOmniSignature":{"name":"X-Omni-Signature","in":"header","required":true,"description":"Versioned HMAC signature of the canonical request.","schema":{"type":"string","pattern":"^v1=[A-Za-z0-9_-]+$"}}},"responses":{"InvalidRequest":{"description":"The body, checkout mode, amount, phone, or signature input is invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"invalid_request","message":"amount: Amount must be a plain positive decimal with at most 2 decimal places"}}}}},"Unauthorized":{"description":"The API key or H2H signature is missing, stale, or invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Invalid H2H request signature: stale_signature"}}}}},"NotFound":{"description":"The resource does not exist in the API key's organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"An unexpected server error occurred.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"Error":{"description":"Stable API error envelope. Branch on `error.code`; use `error.message` for logs or user-facing context.","type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","examples":["invalid_request"]},"message":{"type":"string","examples":["Invalid request"]}}}}},"Metadata":{"type":"object","additionalProperties":true,"description":"JSON object returned unchanged in API responses and webhooks."},"PaymentMethod":{"description":"Payment method accepted by redirect checkout.","type":"string","enum":["bkash","nagad","upi","upay","bank","bkash_agent","nagad_agent","upay_agent","bkash_merchant","nagad_merchant","upay_merchant","bangla_qr_merchant"]},"H2HPaymentMethod":{"description":"Payment method accepted when `checkout_mode` is `h2h`.","type":"string","enum":["bkash","nagad","bkash_agent","nagad_agent","bkash_merchant","nagad_merchant"]},"DepositStatus":{"description":"Current deposit lifecycle status. Fulfill an order only when the status is `succeeded`.","type":"string","enum":["pending","processing","succeeded","failed","cancelled","expired","rejected","refunded"]},"RedirectDepositRequest":{"description":"Create request for a bearer-authenticated redirect checkout.","type":"object","required":["amount","payment_method","redirect_url","merchant_id"],"properties":{"amount":{"type":"string","description":"BDT decimal. Bank deposits allow 25,000–300,000; other rails allow 100–25,000.","example":"1000"},"payment_method":{"$ref":"#/components/schemas/PaymentMethod"},"redirect_url":{"type":"string","format":"uri","description":"Merchant return URL after hosted checkout."},"merchant_id":{"type":"string","minLength":1,"description":"Merchant-controlled unique transaction ID."},"checkout_mode":{"type":"string","const":"redirect","default":"redirect"},"metadata":{"$ref":"#/components/schemas/Metadata"}}},"H2HDepositRequest":{"description":"Create request for a signed H2H checkout.","type":"object","required":["amount","payment_method","redirect_url","merchant_id","checkout_mode","payer"],"properties":{"amount":{"type":"string","pattern":"^(?:0|[1-9]\\d*)(?:\\.\\d{1,2})?$","description":"Plain positive BDT decimal with at most two fractional digits; 100–25,000.","example":"500.00"},"payment_method":{"$ref":"#/components/schemas/H2HPaymentMethod"},"redirect_url":{"type":"string","format":"uri","description":"Merchant return URL used after a redirect action completes."},"merchant_id":{"type":"string","minLength":1,"description":"Idempotency key within the organization."},"checkout_mode":{"type":"string","const":"h2h"},"payer":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string","description":"Valid Bangladesh mobile number; local and +880 forms are normalized.","example":"01712345678"}}},"metadata":{"$ref":"#/components/schemas/Metadata"}}},"RedirectDeposit":{"description":"Redirect-checkout create response.","type":"object","required":["id","amount","payment_method","status","metadata","merchant_id"],"properties":{"id":{"type":"string"},"amount":{"type":"string"},"payment_method":{"$ref":"#/components/schemas/PaymentMethod"},"status":{"$ref":"#/components/schemas/DepositStatus"},"metadata":{"$ref":"#/components/schemas/Metadata"},"merchant_id":{"type":"string"},"redirect_url":{"type":["string","null"],"format":"uri"}}},"RedirectDepositStatus":{"description":"Redirect-checkout status response, including the payment transaction ID after completion when available.","allOf":[{"$ref":"#/components/schemas/RedirectDeposit"},{"type":"object","properties":{"bank_transaction_id":{"type":["string","null"]}}}]},"H2HDeposit":{"description":"H2H create or status response. When `next_action` is not null, branch on its `type` before continuing.","type":"object","required":["id","amount","payment_method","status","metadata","merchant_id","checkout_mode","expires_at","next_action","verification","provider_transaction_id"],"properties":{"id":{"type":"string"},"amount":{"type":"string"},"payment_method":{"$ref":"#/components/schemas/H2HPaymentMethod"},"status":{"$ref":"#/components/schemas/DepositStatus"},"metadata":{"$ref":"#/components/schemas/Metadata"},"merchant_id":{"type":"string"},"checkout_mode":{"type":"string","const":"h2h"},"expires_at":{"type":"string","format":"date-time","description":"Payment transaction ID deadline or redirect checkout expiry."},"next_action":{"oneOf":[{"$ref":"#/components/schemas/DisplayInstructionsAction"},{"$ref":"#/components/schemas/RedirectAction"},{"type":"null"}]},"verification":{"$ref":"#/components/schemas/H2HVerificationState"},"provider_transaction_id":{"type":["string","null"],"description":"Normalized payment transaction ID after success; otherwise null."}}},"DisplayInstructionsAction":{"description":"Render the returned payment instructions exactly, then submit the payer's payment transaction ID to the verification endpoint.","type":"object","required":["type","channel","operation","recipient","amount","currency","verification"],"properties":{"type":{"type":"string","const":"display_instructions"},"channel":{"type":"string","enum":["bkash","nagad"]},"operation":{"type":"string","enum":["make_payment","cash_out"]},"recipient":{"type":"object","required":["type","value","name"],"properties":{"type":{"type":"string","const":"phone"},"value":{"type":"string"},"name":{"type":["string","null"]}}},"qr_payload":{"type":["string","null"]},"amount":{"type":"string"},"currency":{"type":"string","const":"BDT"},"verification":{"type":"object","required":["endpoint","required_fields"],"properties":{"endpoint":{"type":"string","example":"/api/v1/deposits/cm7deposit02/verify"},"required_fields":{"type":"array","prefixItems":[{"type":"string","const":"provider_transaction_id"}],"minItems":1,"maxItems":1}}}}},"RedirectAction":{"description":"Send the payer to `url` to complete payment. Do not call the manual verification endpoint for this action.","type":"object","required":["type","url"],"properties":{"type":{"type":"string","const":"redirect"},"url":{"type":"string","format":"uri"}}},"H2HVerificationState":{"description":"Verification progress and attempt counters. The top-level deposit status remains the authority for fulfillment.","type":"object","required":["state","attempts_used","attempts_remaining"],"properties":{"state":{"type":"string","description":"Current verification progress. Build fulfillment logic around the\ntop-level deposit status; treat any nonterminal value as pending.\n","examples":["awaiting_reference"]},"attempts_used":{"type":"integer","minimum":0,"maximum":3},"attempts_remaining":{"type":"integer","minimum":0,"maximum":3},"failure_code":{"type":["string","null"]}}},"H2HVerificationRequest":{"description":"The payer's payment transaction ID for a `display_instructions` action.","type":"object","required":["provider_transaction_id"],"properties":{"provider_transaction_id":{"type":"string","minLength":3,"maxLength":64,"description":"Payment transaction ID; normalized to uppercase."}}},"H2HVerificationQueued":{"description":"Accepted verification submission. Poll the deposit resource or wait for a webhook to learn the final result.","type":"object","required":["deposit_id","attempt_id","provider_transaction_id","status","attempts_used","attempts_remaining"],"properties":{"deposit_id":{"type":"string"},"attempt_id":{"type":"string"},"provider_transaction_id":{"type":"string"},"status":{"type":"string","const":"processing"},"attempts_used":{"type":"integer"},"attempts_remaining":{"type":"integer"}}},"H2HVerificationResolved":{"description":"Resolved response returned when the same verification submission is replayed idempotently.","type":"object","required":["deposit_id","attempt_id","provider_transaction_id","status","attempt_status","deposit_status"],"properties":{"deposit_id":{"type":"string"},"attempt_id":{"type":"string"},"provider_transaction_id":{"type":"string"},"status":{"type":"string"},"attempt_status":{"type":"string"},"deposit_status":{"$ref":"#/components/schemas/DepositStatus"},"failure_code":{"type":["string","null"]}}},"WithdrawalRequest":{"description":"Create a mobile-wallet or bank payout.","type":"object","required":["amount","phone","payment_method","merchant_id"],"properties":{"amount":{"type":"string","description":"Mobile wallet 100–25,000 BDT; bank 50,000–300,000 BDT."},"phone":{"type":"string","description":"Bangladesh mobile number, or bank account number for bank payouts."},"payment_method":{"type":"string","enum":["bkash","nagad","upay","bank"]},"merchant_id":{"type":"string","minLength":1},"metadata":{"$ref":"#/components/schemas/Metadata"}}},"Withdrawal":{"description":"Withdrawal create or status response.","type":"object","required":["id","phone","payment_method","amount","status","metadata","merchant_id"],"properties":{"id":{"type":"string"},"phone":{"type":"string"},"payment_method":{"type":"string","enum":["bkash","nagad","upay","bank"]},"amount":{"type":"string"},"status":{"type":"string","enum":["processing","succeeded","failed"]},"metadata":{"$ref":"#/components/schemas/Metadata"},"merchant_id":{"type":"string"}}}},"examples":{"H2HManualDeposit":{"value":{"id":"cm7deposit02","amount":"500.00","payment_method":"bkash_merchant","status":"pending","metadata":{"invoice_id":"INV-123"},"merchant_id":"order-123","checkout_mode":"h2h","expires_at":"2026-07-28T12:05:00.000Z","next_action":{"type":"display_instructions","channel":"bkash","operation":"make_payment","recipient":{"type":"phone","value":"01800000000","name":"Example Merchant"},"qr_payload":null,"amount":"500.00","currency":"BDT","verification":{"endpoint":"/api/v1/deposits/cm7deposit02/verify","required_fields":["provider_transaction_id"]}},"verification":{"state":"awaiting_reference","attempts_used":0,"attempts_remaining":3},"provider_transaction_id":null}},"H2HRedirectDeposit":{"value":{"id":"cm7deposit03","amount":"500.00","payment_method":"bkash","status":"pending","metadata":{},"merchant_id":"order-125","checkout_mode":"h2h","expires_at":"2026-07-28T12:10:00.000Z","next_action":{"type":"redirect","url":"https://pay.omnipay.page/checkout/session-123"},"verification":{"state":"processing","attempts_used":0,"attempts_remaining":0},"provider_transaction_id":null}}}}}