Verify Payment API
Verify the status of a payment transaction and retrieve full transaction details using the transaction ID
Endpoint Details
Endpoint:
GET /payments/verify/{transaction_id}
Base URLs:
- Sandbox:
https://sandbox.api.moneybag.com.bd/api/v2 - Production:
https://api.moneybag.com.bd/api/v2
Authentication
All requests require authentication via API key in the header:
X-Merchant-API-Key: <your_merchant_api_key>When to Use This Endpoint
Always verify a payment server-side before fulfilling an order. The transaction_id is received in two ways:
- Redirect callback — appended as a query parameter when the customer is redirected back to your
success_url,fail_url, orcancel_url - Webhook notification — delivered in the webhook payload to your
ipn_url
Never trust redirect URLs alone
Redirect URL query parameters can be manipulated by end users. Always call this endpoint to confirm the payment status before fulfilling any order.
Verification Flow
Request
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction_id | string | Yes | Unique transaction identifier received after payment (e.g., txn0370d893a26a46e4961a833aae4b020f) |
Headers
| Header | Value | Required |
|---|---|---|
X-Merchant-API-Key | Your merchant API key | Yes |
cURL Example
curl -X GET \
"https://sandbox.api.moneybag.com.bd/api/v2/payments/verify/txn0370d893a26a46e4961a833aae4b020f" \
-H "X-Merchant-API-Key: your_merchant_api_key"Response
Success Response
HTTP Status: 200 OK
{
"success": true,
"message": "Payment verification details retrieved",
"data": {
"transaction_id": "txn160725223bbd495baee2b3d581b41c6b",
"order_id": "ORD001",
"verified": true,
"status": "SUCCESS",
"amount": "1500.0000",
"currency": "BDT",
"charge_amount": "22.5000",
"payment_method": "BKASH",
"payment_reference_id": "TR0011HdlhWek1759048979602",
"customer": {
"name": "John Doe",
"email": "john.doe@example.com",
"phone": "+8801700000000",
"address": "123 Main Street",
"city": "Dhaka",
"postcode": "1000",
"country": "Bangladesh",
"metadata": {}
}
},
"meta": {
"timestamp": "2025-11-30T13:36:41.868679",
"status_code": 200
}
}Response Fields
| Field | Type | Description |
|---|---|---|
transaction_id | string | Unique Moneybag transaction identifier |
order_id | string | Your order ID from the original checkout request |
verified | boolean | true if the payment was confirmed by the payment provider |
status | string | Current payment status (see Payment Statuses) |
amount | decimal | Gross transaction amount in BDT |
currency | string | Currency code (e.g., BDT) |
charge_amount | decimal | Processing fee charged by Moneybag |
payment_method | string | Payment method used (e.g., BKASH, NAGAD, CARD) |
payment_reference_id | string | Reference ID from the payment provider |
customer | object | Customer details submitted at checkout |
Error Response
HTTP Status: 404
{
"success": false,
"error": {
"code": "TRANSACTION_NOT_FOUND",
"message": "No transaction found with the given ID"
}
}HTTP Status: 401
{
"success": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
}Payment Statuses
| Status | Description | Action Required |
|---|---|---|
SUCCESS | Payment completed and confirmed | Fulfill the order |
PENDING | Payment is still being processed | Wait and re-verify; do not fulfill yet |
FAILED | Payment was declined or unsuccessful | Cancel order, notify customer |
CANCELLED | Customer cancelled the payment | Restore cart, offer retry |
EXPIRED | Payment session timed out before completion | Ask customer to restart checkout |
REFUNDED | Payment was successfully refunded | Update order status accordingly |
Integration Best Practices
1. Always verify before fulfillment
// Example: Node.js verification before order fulfillment
async function handlePaymentReturn(transactionId) {
const response = await fetch(
`https://api.moneybag.com.bd/api/v2/payments/verify/${transactionId}`,
{ headers: { 'X-Merchant-API-Key': process.env.MONEYBAG_API_KEY } }
);
const { data } = await response.json();
if (data.verified && data.status === 'SUCCESS') {
await fulfillOrder(data.order_id);
} else {
await handlePaymentFailure(data.order_id, data.status);
}
}2. Check both verified and status
Always check both fields:
verified: true— the payment provider confirmed the transactionstatus: "SUCCESS"— the transaction completed without issues
A payment can have verified: true with a non-SUCCESS status (e.g., REFUNDED).
3. Implement idempotency
Prevent duplicate order processing when webhooks or redirects fire multiple times:
async function processPayment(transactionId) {
// Check if already processed
const existing = await db.transactions.findOne({ transactionId });
if (existing?.processed) return;
const verification = await verifyPayment(transactionId);
if (verification.data.status !== 'SUCCESS') return;
// Use a database transaction to prevent race conditions
await db.transaction(async (trx) => {
await trx.transactions.update({ transactionId }, { processed: true });
await trx.orders.fulfill({ orderId: verification.data.order_id });
});
}4. Handle PENDING status gracefully
Some payment methods (e.g., bank transfers) may return PENDING initially. Implement a polling or webhook strategy:
- Set order status to "Awaiting Payment"
- Re-verify after a delay (e.g., 30 seconds, then 2 minutes)
- Use Webhooks for reliable final status updates
Try in Playground
Common Issues
Transaction Not Found (404)
- Ensure the
transaction_idis the Moneybag-generated ID (starts withtxn), not your ownorder_id - The transaction ID is received from the redirect URL or webhook payload after payment
Unauthorized (401)
- Confirm the
X-Merchant-API-Keyheader is present and matches your merchant key - Sandbox and production keys are different — use the correct key for each environment
Status Remains PENDING
- Some payment methods take longer to confirm; wait and retry after a short delay
- Set up Webhooks to receive automatic notifications when status changes
Related Resources
- Checkout API — Initiate a payment session
- Webhooks — Receive real-time payment notifications
- Troubleshooting — Common integration issues