Moneybag

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:

  1. Redirect callback — appended as a query parameter when the customer is redirected back to your success_url, fail_url, or cancel_url
  2. 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

ParameterTypeRequiredDescription
transaction_idstringYesUnique transaction identifier received after payment (e.g., txn0370d893a26a46e4961a833aae4b020f)

Headers

HeaderValueRequired
X-Merchant-API-KeyYour merchant API keyYes

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

FieldTypeDescription
transaction_idstringUnique Moneybag transaction identifier
order_idstringYour order ID from the original checkout request
verifiedbooleantrue if the payment was confirmed by the payment provider
statusstringCurrent payment status (see Payment Statuses)
amountdecimalGross transaction amount in BDT
currencystringCurrency code (e.g., BDT)
charge_amountdecimalProcessing fee charged by Moneybag
payment_methodstringPayment method used (e.g., BKASH, NAGAD, CARD)
payment_reference_idstringReference ID from the payment provider
customerobjectCustomer 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

StatusDescriptionAction Required
SUCCESSPayment completed and confirmedFulfill the order
PENDINGPayment is still being processedWait and re-verify; do not fulfill yet
FAILEDPayment was declined or unsuccessfulCancel order, notify customer
CANCELLEDCustomer cancelled the paymentRestore cart, offer retry
EXPIREDPayment session timed out before completionAsk customer to restart checkout
REFUNDEDPayment was successfully refundedUpdate 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 transaction
  • status: "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_id is the Moneybag-generated ID (starts with txn), not your own order_id
  • The transaction ID is received from the redirect URL or webhook payload after payment

Unauthorized (401)

  • Confirm the X-Merchant-API-Key header 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