---
title: "Tabby"
space: "BWH Payments (Next)"
url: "https://docs.bwh.tech/bwh-payments-next/gateways/tabby"
updated: "2026-10-11"
---

Let shoppers split an order into instalments with [Tabby](https://tabby.ai). Tabby is available in Saudi Arabia, the UAE, Kuwait, Bahrain and Qatar.

Tabby works differently from a card gateway in two ways:

- **Tabby can decline a shopper.** The shopper then sees a message asking them to choose another payment method.
- **An approved payment is only authorised credit.** BWH Payments captures it before it counts as Paid.

## Before you start

- A Tabby merchant account, with a **merchant code** and **secret key** for your market
- Your store must charge in **SAR, AED, KWD, BHD or QAR**. BWH Payments refuses any other currency before it calls Tabby.

## Set up Tabby

**1. Fill in Tabby Gateway Settings**

| Field | Value |
|---|---|
| Merchant Code | Your Tabby merchant code. Each code serves one market and currency. |
| Key Secret | Tabby's secret API key |
| Currency | Used when a payment has no currency |
| Success URL | Your [confirmation page](/bwh-payments-next/get-started/return-pages). `?reference_id=…` is added to it. |
| Cancelled URL, Failure URL | Your [payment-failed page](/bwh-payments-next/get-started/return-pages). `?reference_id=…` is added to each. |
| Webhook Secret | A token **you choose**. See step 3. |
| Webhook Source IPs | Pre-filled with Tabby's published webhook addresses. Deliveries from anywhere else are refused. |

**2. Create a Payment Gateway Profile** named `Tabby`, set **Gateway Settings** to `Tabby Gateway Settings`, and tick **Enabled**.

**3. Register the webhook with Tabby**, using your chosen token as its auth header value:

- **URL:** `https://your.site/api/v2/method/bwh_payments.bwh_payments.webhook.handle?gateway=Tabby`
- **Header:** `X-Webhook-Signature: <your Webhook Secret>`

:::caution
Tabby doesn't sign its webhooks. The token only proves the delivery came from someone who knows it. Keep it secret, and keep **Webhook Source IPs** up to date if Tabby changes its addresses.
:::

## How it behaves

| Tabby status | Payment status |
|---|---|
| `closed` (captured) | Paid |
| `authorized` | Captured, then Paid |
| `rejected` | Not Paid |
| `expired` | Expired |
| `created`, anything else | Pending |

<picture>
  <source srcset="/files/bwhp-tabby-capture-dark.svg" media="(prefers-color-scheme: dark)">
  <img src="/files/bwhp-tabby-capture-light.svg" alt="BWH Payments reads the Tabby payment, finds it authorised, captures it, reads it again as closed, and reports Paid.">
</picture>

- **Capture happens when your app checks the status, never in the webhook.** An "authorised" webhook leaves the payment Pending until the next status check captures it. Check the status when the shopper returns, and sync Pending payments on a schedule.
- If a capture fails, the payment stays Pending, so an order is never released against money that wasn't taken. `sync_status()` raises Tabby's error, so be ready to catch it in your scheduled job.
- **Amounts** are sent at the currency's precision. For example, `12.300` KWD.
- **Refunds** work on captured payments. Partial refunds are supported.
- **Cancelling** an open checkout isn't supported.

## Good to know

- Gateway settings are a single document, so a site can hold **one** merchant code. That means one Tabby market per site.
- An authorised payment that was never captured can't be refunded here. Void it in the Tabby dashboard.

## Next steps

- [Webhooks and security](/bwh-payments-next/build/webhooks-and-security): gateways that don't sign their webhooks
- [Build a payment gateway](/bwh-payments-next/build/build-a-payment-gateway): add a gateway that isn't listed
