Skip to content

Hosted checkout

checkout_url points at /pay/<sessionId>. The page is rendered fresh on every request and is the only surface a buyer touches.

What the page shows

  • The amount in taka and your order reference, so the buyer can check both against what they are paying for.
  • Your public display name. Your account email is never shown to a buyer.
  • The receiving number or numbers taken from your active paired devices. The buyer does not type your order reference into their wallet app: a payment is matched by its TrxID and its exact amount, so the TrxID is the only thing they bring back.
  • A provider selector limited to the providers your active devices actually cover: bKash, Nagad, Rocket, Upay and Cellfin. An account with no paired device yet falls back to bKash so the page never renders with nothing to pick.
  • A screenshot picker and a Transaction ID field. The buyer can pick the wallet's confirmation screenshot and the TrxID is read from it in their own browser, then shown in the field for them to check; or they type it. The picture is not uploaded: the reader runs on the buyer's phone from files served by your ToruPay domain. The submit button reads ৳1,200 পরিশোধ যাচাই করুন / Verify payment ৳1,200.
  • A live countdown to expires_at, which turns red in the last five minutes and disables the button at zero.

Language

The page opens in the language of the session (Bengali unless you set otherwise) with a Bengali / English toggle at the top. Every label, instruction, status and error exists in both languages.

Session states

StateWhat the buyer sees
pendingThe payment form.
completedইতিমধ্যে পরিশোধ করা হয়েছে / Already paid, with a link onward to your success_url.
cancelled, expired, failed, or past expires_atসেশনের মেয়াদ শেষ / Checkout no longer available, with a link to your cancel_url.
Unknown session idচেকআউট পাওয়া যায়নি / Checkout not found.

What submitting does

The form POSTs sessionId, trxId and provider to /api/v1/checkout/submit. The TrxID is upper-cased and must match [A-Z0-9]{6,20}. A TrxID read from a screenshot is shown in the field for the buyer to check and is sent with via: "screenshot". On success the buyer sees a confirmation and, if you supplied a success_url, is redirected there after about a second and a half.

Ids read from a screenshot

A screenshot reader can swap characters that look alike (0 and O, 1 and I, 5 and S, 8 and B, 2 and Z) or add or drop one. When a request carries via: "screenshot" and its TrxID matches no payment exactly, ToruPay looks at the payments that are waiting for that merchant: same wallet, the session's exact amount, not yet claimed, inside the claim window. If exactly one of them is within one character of the submitted id (one added, dropped or changed), treating those lookalikes as the same, that payment is claimed by its real TrxID and the response carries the real one. If none or more than one qualifies, the request fails like any wrong TrxID, and every failed request counts towards the same ten-attempt limit per session. A typed TrxID is never adjusted.

A double-click is not an error.Submitting the same TrxID twice against a session that is already complete returns 200 with success: true, so a retry after a dropped response shows the buyer success rather than a failure.

Redirect safety

success_url and cancel_url are validated when the session is created and checked again in the browser immediately before navigating. Anything that is not https: is not followed, so a merchant-supplied URL cannot run script on the shared checkout origin.