What you can accept
| Rail | Payer experience | Token prefix |
|---|---|---|
| Botim Pay wallet | The Botim app opens, the payer confirms, returns to you | botim: (scene EWALLET) |
| Botim hosted page | Botim's own page with every method enabled on your MID | botim: (scene PAYPAGE) |
| Cards on your form | 3-D Secure OTP page, then back to you | botimcard: |
| Hold now, capture later | Same as cards; capture or void within the hold window | botimcard: with capture: false |
| Apple Pay, Google Pay, Samsung Pay | Native wallet sheet, usually frictionless | botimdevice: |
| Subscriptions and instalments | One authenticated payment, then charges without the payer | botimcard: with an agreement, then botimmit: |
Everything is AED. Botim is available to merchants onboarded on MoneyBee's UAE profile. Ask us to enable it on your MID.
How it works
You never talk to Botim directly. Every call below is a normal MoneyBee payment intent with connector_id: "botim" and a payment method token that tells MoneyBee which Botim rail to use. MoneyBee builds the Botim order, signs it with your merchant key, encrypts any card fields with Botim's public key, and maps Botim's statuses back to MoneyBee states.
curl -X POST https://api.moneybee.world/v1/payment_intents \
-H "authorization: Bearer $MONEYBEE_KEY" \
-H "idempotency-key: order-2041" \
-H "content-type: application/json" \
-d '{"amount": {"minor": 25000, "currency": "AED"}, "capture": true,
"connector_id": "botim", "payment_method_token": "botim:eyJzY2VuZSI6IkVXQUxMRVQiLCJyZWRpcmVjdFVybCI6Imh0dHBzOi8vc2hvcC5leGFtcGxlL3JldHVybiJ9"}'
The response is a payment intent. When the payer still has something to do, its status is requires_action and Next actions tells you where to send them.
Payment method tokens
A token is a prefix, a colon, and a base64url-encoded JSON object. Build it on your server:
const token = (prefix, obj) => prefix + ':' + Buffer.from(JSON.stringify(obj)).toString('base64url');
| Prefix | Fields |
|---|---|
botim | scene (EWALLET default, or PAYPAGE), redirectUrl, subject (max 12), osType (IOS or ANDROID), terminalType (WEB, WAP, APP), customerId, email |
botimcard | redirectUrl, card {number, holderName, cvv, expYear, expMonth} or enc (already encrypted), customerId, email, realIP, saveCard, threeDSecure (default true), agreement (see subscriptions) |
botimdevice | redirectUrl, devicePayType (APPLE_PAY, GOOGLE_PAY, SAMSUNG_PAY), card {number (DPAN), expYear, expMonth, cryptogram} or enc, eci, cryptoFmt (default 3DSECURE), customerId |
botimmit | authProtocolNo from the first payment, subject |
MoneyBee appends ?Orderid=<reference> to your redirectUrl so you can match the return to the payment.
Botim Pay wallet
Create the intent with a botim: token and scene EWALLET. The next action is a deep_link. On a phone, send the payer to it and the Botim app opens; on desktop, show it as a QR code. The payer confirms in Botim and is returned to your redirectUrl. Poll the intent or wait for the webhook; MoneyBee has already confirmed the order with Botim by then.
Botim hosted page
Scene PAYPAGE returns a redirect next action: Botim's own checkout with every method enabled on your Botim profile. Use it for payers without the Botim app. If you prefer to keep the payer on your site, the same URL can be rendered with Botim's JavaScript SDK (PayBy.createIframe).
Cards on your form (Direct Pay)
If your systems are PCI DSS compliant for handling card data, send the card in a botimcard: token. MoneyBee encrypts the number, name and CVV with Botim's public key before anything leaves our server. Botim answers with a 3-D Secure step; the next action is type 3ds with a URL on MoneyBee that renders Botim's OTP page. Send the payer there. After the OTP, Botim redirects to your redirectUrl.
{
"redirectUrl": "https://shop.example/return",
"card": { "number": "5123450000000008", "holderName": "A Payer", "cvv": "100", "expYear": "31", "expMonth": "05" },
"customerId": "cust_8812", "email": "payer@example.com", "realIP": "94.200.1.1", "saveCard": false
}
Already encrypting on your side? Pass enc with cardNo, holderName and cvv as Botim-encrypted Base64 instead of card.
Hold now, capture later
Send "capture": false with a card token. MoneyBee places a PREAUTH order. After 3-D Secure the intent is authorized. Then:
POST /v1/payment_intents/{id}/capture # places Botim's CAPTURE order, intent becomes captured
POST /v1/payment_intents/{id}/void # places PREAUTHVOID, the hold is released
Botim's authorisation code and RRN are kept on the payment for your reconciliation.
Apple Pay, Google Pay, Samsung Pay
Register with Apple, Google or Samsung and have the wallet enabled on your Botim profile. Decrypt the wallet token on your server, then send the device card (DPAN), expiry, cryptogram and ECI in a botimdevice: token. MoneyBee encrypts them for Botim and submits a DEVICE_PAY order. DPAN payments are normally approved without an OTP; a Google Pay FPAN may return a 3DS step like a card.
Subscriptions and instalments (CIT and MIT)
The first payment is customer-initiated: a botimcard: token with saveCard: true, a stable customerId and an agreement:
"agreement": {
"agreementType": "RECURRING", // or UNSCHEDULED, INSTALLMENT
"numberOfPayments": 12, "amountVariability": "FIXED",
"expiryDate": "2027-11-01", "paymentFrequency": "MONTHLY", "minimumDaysBetweenPayments": 28
}
Once that payment is captured, read it: the payment carries authProtocolNo. Store it against the customer. Every later charge is merchant-initiated with no payer present:
"payment_method_token": "botimmit:"
MIT charges settle synchronously: the intent comes back captured or failed in the same call.
Next actions
When an intent is requires_action, ask MoneyBee what to do:
GET https://api.moneybee.world/uae/intents/{id}/next
{ "type": "deep_link", "url": "https://botim.me/botim/payby/open-iap-cashdesk?ft=..." } // open the Botim app
{ "type": "redirect", "url": "https://checkout.payby.com/..." } // Botim's page
{ "type": "3ds", "url": "https://api.moneybee.world/uae/3ds/{id}" } // OTP page, hosted by MoneyBee
Results and webhooks
Botim tells MoneyBee the outcome on your payer's return and, separately, by a signed notification that MoneyBee verifies with Botim's public key and retries are deduplicated. You see one of two events on your MoneyBee webhook: payment.captured or payment.failed, signed with mb-signature as described in the main docs. Decline codes are prefixed botim_ and carry Botim's fail code, for example botim_ORDER_EXPIRED.
Refunds and voids
Refunds go back to the original method, full or partial, for orders up to 180 days old:
POST /v1/payment_intents/{id}/refunds {"amount": {"minor": 5000, "currency": "AED"}}
A hold that was never captured is released with a void, not a refund.
Testing
| What | Use |
|---|---|
| Botim Pay wallet | Botim UAT app (Android), accounts +971 56 000 0000 to 0009, OTP 123456, payment password 132580 |
| Cards | 5123 4500 0000 0008, expiry 05/31, CVV 100, then choose Success, Pending or Failure on the 3DS page |
| Sandbox base | Your MoneyBee sandbox key routes to Botim UAT automatically |
PCI and security
- Wallet, hosted page and device-pay flows keep card data away from your systems. Only
botimcard:requires you to handle card data, so use it only if you are PCI DSS compliant, or send fields you encrypted yourself. - MoneyBee signs every Botim request with SHA256withRSA and verifies every Botim response and notification. Encrypted card fields can only be read by Botim.
- Card numbers, CVVs and cryptograms are never logged. Audit records keep brand, last four, auth code and RRN.
Questions or a MID to enable? pt@moneybee.world or WhatsApp +971 55 861 2001.