Hosted payments
Create a checkout
Create checkout from your backend, then redirect the customer to Moneybag's hosted payment experience.
/api/v2/payments/checkoutGenerate and persist a unique order_id before calling Moneybag. The reference
below is rendered from the reviewed public artifact, including nested customer,
shipping, line-item, metadata, and EMI fields.
Text alternative
The merchant backend creates and verifies checkout. The browser only follows hosted redirects and never receives the merchant API key.
Do not fulfill from the customer redirect. Continue with payment verification.
Collection Dashboard attribution
Add the optional, top-level checkout_source field to identify where a payment
originates. The values are case-sensitive:
WEBSITE_CHECKOUT→ Website Checkout: a customer starts checkout on your website, and your backend creates the session.API_INTEGRATION→ API Integration: your application or automated integration workflow initiates checkout, such as a backend billing workflow.
Any other value, including different casing, causes a request validation error. Omit the field if you are unsure which source applies.
All checkout requests still come from your backend. Choose the value for the payment's origin; calling the checkout API does not automatically make a website payment an API Integration payment.
For a native mobile app that starts checkout through your backend, use
API_INTEGRATION. If a WebView loads your merchant website and the customer
starts checkout there, use WEBSITE_CHECKOUT. Opening Moneybag's hosted payment
page in a WebView does not change the original source.
The API Lab checkout preset includes API_INTEGRATION. When adapting it for
website payments, change that value to WEBSITE_CHECKOUT; you can also omit the
field to keep checkout unclassified.
For example, a website checkout request can include:
{
"order_id": "ORDER-WEBSITE-10001",
"currency": "BDT",
"order_amount": "100.00",
"order_description": "Website order",
"checkout_source": "WEBSITE_CHECKOUT",
"success_url": "https://merchant.example/payments/success",
"cancel_url": "https://merchant.example/payments/cancel",
"fail_url": "https://merchant.example/payments/failure",
"customer": {
"name": "Sandbox Customer",
"email": "sandbox@example.com",
"phone": "+8801700000000"
}
}
Send checkout_source alongside order_id, not inside metadata. Metadata such
as source or platform does not set the dashboard channel.
Existing integrations can omit the field or send null. These payments appear
as Unclassified Checkout; their payment method and successful collection
amount are still recorded. Adding the field attributes newly created sessions.
Older transactions are not relabeled, and a reused session retains its original
channel through retries and redirects.
API reference
/api/v2/payments/checkoutCheckout
Checkout API This endpoint initiates the payment process for a merchant order. It creates a payment session, processes the initial payment request, and returns a redirect URL to the payment gateway. The merchant must provide a valid API key in the X-Merchant-API-Key header. Args: order_req: Order request data merchant_key: Merchant API key info Returns: CheckoutResponse: Response with checkout details and redirect URL Raises: HTTPException: For any validation or processing errors
- Operation ID
checkout_api_v2_payments_checkout_post- Environment
https://sandbox.api.moneybag.com.bd(Moneybag sandbox)- Authentication
X-Merchant-API-Key— Sandbox merchant API key. Live keys are rejected.
Parameters
No path or query parameters.
Request body
Required application/json body using OrderRequest.
| Field | Type | Required | Constraints and meaning |
|---|---|---|---|
cancel_url | string | Yes | maximum length 255 Callback URL if user cancels the transaction |
checkout_source | string | null | No | one of WEBSITE_CHECKOUT, API_INTEGRATION Optional collection attribution for authenticated website or API checkout. |
currency | string | Yes | — Three-letter currency code (e.g., BDT, USD, EUR) |
customer | Customer | Yes | — |
customer.address | string | null | No | maximum length 200 Customer's address |
customer.city | string | null | No | maximum length 50 Customer's city |
customer.country | string | null | No | maximum length 50 Customer's country |
customer.email | string | Yes | format email; maximum length 100 Customer's email address |
customer.metadata | object | null | No | — Additional customer-specific data |
customer.name | string | Yes | maximum length 255 Customer's full name |
customer.phone | string | Yes | — Customer's phone number |
customer.postcode | string | null | No | maximum length 20 Customer's postal code |
customer.state | string | null | No | — Customer's state/division/province (e.g. 'Dhaka', 'Chattogram'). Optional. Forwarded to processors that require a billing division; supplying a real value improves AVS accuracy and therefore risk and chargeback outcomes. |
fail_url | string | Yes | maximum length 255 Callback URL if payment failure occurs |
ipn_url | string | null | No | — Instant Payment Notification URL |
metadata | object | null | No | — Additional order-specific data |
order_amount | number | string | Yes | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ Transaction amount between 10.00 and 1000000.00 BDT |
order_description | string | Yes | maximum length 255 Description of the order |
order_id | string | Yes | minimum length 10; maximum length 36 Unique transaction ID to identify your order |
order_items | OrderItem[] | null | No | — List of items in the order |
order_items[].convenience_fee | number | string | null | No | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ Convenience fee (decimal value) |
order_items[].discount_amount | number | string | null | No | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ Discount amount (decimal value) |
order_items[].metadata | object | null | No | — Additional product-specific data |
order_items[].net_amount | number | string | null | No | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ Net amount after adding VAT and fees, subtracting discounts |
order_items[].product_category | string | null | No | maximum length 100 Product category (e.g., Electronic, topup) |
order_items[].product_name | string | null | No | maximum length 255 Product name |
order_items[].quantity | integer | null | No | — Product quantity |
order_items[].sku | string | null | No | — Product SKU |
order_items[].unit_price | number | string | null | No | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ Unit price of the product |
order_items[].vat | number | string | null | No | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ VAT amount (decimal value) |
payment_info | PaymentInfo | null | No | — Payment-related information |
payment_info.currency_conversion | boolean | No | default false Whether currency conversion is applied |
payment_info.emi_configuration_id | string | null | No | — Selected EMI configuration ID (if customer selected specific EMI option) |
payment_info.emi_payment_id | string | null | No | — Selected merchant payment service for EMI payment. Accepts the public UUID. |
payment_info.requires_emi | boolean | No | default false Whether EMI payment options should be shown |
shipping | Shipping | null | No | — Shipping information |
shipping.address | string | When parent is present | — Shipping address line 1 |
shipping.city | string | When parent is present | — Shipping city |
shipping.country | string | When parent is present | — Shipping country |
shipping.metadata | object | null | No | — Additional shipping-specific data |
shipping.name | string | When parent is present | — Shipping recipient's full name |
shipping.postcode | string | When parent is present | — Shipping postal code |
shipping.state | string | null | No | — Shipping state/province |
success_url | string | Yes | maximum length 255 Callback URL after successful payment |
Sandbox example
Set the merchant key and replace resource identifiers with values created in your sandbox workspace.
curl --request POST "https://sandbox.api.moneybag.com.bd/api/v2/payments/checkout" \
--header "X-Merchant-API-Key: $MONEYBAG_MERCHANT_KEY" \
--header "Content-Type: application/json" \
--data '{
"cancel_url": "https://merchant.example/cancel-url",
"currency": "BDT",
"customer": {
"email": "sandbox.customer@example.com",
"name": "Sandbox example",
"phone": "+8801700000000"
},
"fail_url": "https://merchant.example/fail-url",
"order_amount": 100,
"order_description": "Sandbox API example",
"order_id": "ORDER-1001",
"success_url": "https://merchant.example/success-url"
}'Run this reviewed operation in the API Lab →
Responses
200 Successful Response
Content type: application/json. Schema: PaymentResponses.
| Field | Type | Required | Constraints and meaning |
|---|---|---|---|
data | CheckoutResponse | SessionResponse | ProcessResponse | VerificationResponse | InvoiceDetailsResponse | CancelResponse | CheckoutResponse | SessionResponse | ProcessResponse | VerificationResponse | InvoiceDetailsResponse | CancelResponse[] | null | No | — |
data<CheckoutResponse>.checkout_url | string | When parent is present | — |
data<CheckoutResponse>.expires_at | string | When parent is present | — |
data<CheckoutResponse>.session_id | string | When parent is present | — |
data<SessionResponse>.bleeding | boolean | No | default false Whether merchant pays service charges (bleeding) |
data<SessionResponse>.business_name | string | null | No | — |
data<SessionResponse>.can_return_to_merchant | boolean | No | default false Whether the checkout may offer a 'return to merchant' action — true when the merchant's stored return URL passes moneybag.utils.redirect_guard. Deliberately a BOOLEAN, not the URL: this response is fetched by the hosted checkout from the browser, so any URL here would be readable by page scripts, devtools, error reporters and anyone holding the checkout link, and merchant cancel URLs routinely carry order tokens in their query string. The destination itself is never serialised — the checkout links to GET /payments/sessions/{session_id}/return, which resolves and validates it server-side at click time. |
data<SessionResponse>.currency | string | When parent is present | — |
data<SessionResponse>.customer | object | null | No | — |
data<SessionResponse>.emi_checkout_id | string | null | No | — Selected EMI configuration UUID if pre-selected |
data<SessionResponse>.emi_fee_bleeding | boolean | No | default false Whether merchant pays EMI fees (emi_fee_bleeding) |
data<SessionResponse>.emi_payment_options | object[] | null | No | — EMI payment options with calculations |
data<SessionResponse>.expires_at | string | When parent is present | — |
data<SessionResponse>.merchant_logo | string | null | No | — |
data<SessionResponse>.order_amount | string | When parent is present | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ |
data<SessionResponse>.order_description | string | null | No | — |
data<SessionResponse>.order_id | string | When parent is present | — |
data<SessionResponse>.payment_options | object[] | When parent is present | — |
data<SessionResponse>.requires_emi | boolean | No | default false Whether EMI payment options are available |
data<SessionResponse>.selected_emi_configuration | SelectedEMIConfiguration | null | No | — Selected EMI configuration with emi_configuration_id and service_id |
data<SessionResponse>.selected_emi_configuration.emi_configuration_id | string | When parent is present | — Selected EMI configuration ID |
data<SessionResponse>.selected_emi_configuration.service_id | string | null | No | — Public merchant payment service UUID, matches payment_options[].service_id |
data<SessionResponse>.session_id | string | When parent is present | — |
data<SessionResponse>.status | string | When parent is present | — |
data<ProcessResponse>.meta | object | null | No | — |
data<ProcessResponse>.redirect_url | string | null | No | format uri; minimum length 1 |
data<ProcessResponse>.transaction_id | string | When parent is present | — |
data<VerificationResponse>.amount | string | When parent is present | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ |
data<VerificationResponse>.charge_amount | string | When parent is present | pattern ^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$ |
data<VerificationResponse>.currency | string | When parent is present | — |
data<VerificationResponse>.customer | Customer | When parent is present | — |
data<VerificationResponse>.customer.address | string | null | No | maximum length 200 Customer's address |
data<VerificationResponse>.customer.city | string | null | No | maximum length 50 Customer's city |
data<VerificationResponse>.customer.country | string | null | No | maximum length 50 Customer's country |
data<VerificationResponse>.customer.email | string | When parent is present | format email; maximum length 100 Customer's email address |
data<VerificationResponse>.customer.metadata | object | null | No | — Additional customer-specific data |
data<VerificationResponse>.customer.name | string | When parent is present | maximum length 255 Customer's full name |
data<VerificationResponse>.customer.phone | string | When parent is present | — Customer's phone number |
data<VerificationResponse>.customer.postcode | string | null | No | maximum length 20 Customer's postal code |
data<VerificationResponse>.customer.state | string | null | No | — Customer's state/division/province (e.g. 'Dhaka', 'Chattogram'). Optional. Forwarded to processors that require a billing division; supplying a real value improves AVS accuracy and therefore risk and chargeback outcomes. |
data<VerificationResponse>.order_id | string | When parent is present | — |
data<VerificationResponse>.payment_method | string | When parent is present | — |
data<VerificationResponse>.payment_reference_id | string | When parent is present | — |
data<VerificationResponse>.status | string | When parent is present | — |
data<VerificationResponse>.transaction_id | string | When parent is present | — |
data<VerificationResponse>.verified | boolean | When parent is present | — |
data<InvoiceDetailsResponse>.all_total | number | When parent is present | — |
data<InvoiceDetailsResponse>.business_name | string | When parent is present | — |
data<InvoiceDetailsResponse>.customer | object | null | When parent is present | — |
data<InvoiceDetailsResponse>.due_date | string | null | When parent is present | — |
data<InvoiceDetailsResponse>.gross_discount | number | When parent is present | — |
data<InvoiceDetailsResponse>.invoice_id | string | When parent is present | — |
data<InvoiceDetailsResponse>.invoice_items | object[] | When parent is present | — |
data<InvoiceDetailsResponse>.invoice_status | string | When parent is present | — |
data<InvoiceDetailsResponse>.invoice_type | string | null | No | — |
data<InvoiceDetailsResponse>.merchant_logo | string | null | No | — |
data<InvoiceDetailsResponse>.payable_amount | number | When parent is present | — |
data<InvoiceDetailsResponse>.uuid | string | When parent is present | — |
data<CancelResponse>.order_id | string | When parent is present | — |
data<CancelResponse>.redirect_url | string | When parent is present | — |
data<CancelResponse>.session_id | string | When parent is present | — |
data<CancelResponse>.status | string | No | default "CANCELLED" |
message | string | null | No | — |
meta | object | null | No | — |
success | boolean | Yes | — |
422 Validation Error
Content type: application/json. Schema: HTTPValidationError.
| Field | Type | Required | Constraints and meaning |
|---|---|---|---|
detail | ValidationError[] | No | — |
detail[].loc | string | integer[] | When parent is present | — |
detail[].msg | string | When parent is present | — |
detail[].type | string | When parent is present | — |