# Create a session
Source: https://docs.tabby.ai/api-reference/checkout/create-a-session
post /api/v2/checkout
Creates a Checkout session. Creates Session and Payment, returns Pre-Scoring result (status), ids of Payment and Session.
# Session creation payload model
Source: https://docs.tabby.ai/api-reference/checkout/session-payload-model
The payload example for a session creation request with all required fields for a direct API custom integration can be found here:
```JSON theme={"dark"}
{
"payment": {
"amount": "100", // required. Up to 2 decimals for UAE and KSA, e.g. 100.00
"currency": "AED", // required. Use the ISO 4217 standard for defining currencies
"description": "test payload",
"buyer": {
"name": "John Doe", // required. Customer's full name
"email": "jsmith@example.com", //required. Customer's email address
"phone": "500000001", //required. Customer's phone number
"dob": "2000-01-20"
},
"shipping_address": {
"city": "Dubai", // required. Name of city, municipality, or village
"address": "Dubai", // required. Building name, apartment number
"zip": "1111" // required. Postal code
},
"order": {
"reference_id": "1001", // required. Merchant-assigned order number.
"updated_at": "2023-11-07T05:31:56Z",
"tax_amount": "0.00",
"shipping_amount": "0.00",
"discount_amount": "0.00",
"items": [
{
"reference_id": "SKU123",
"title": "Name of the product", // required. Name of the product.
"description": "Description of the product",
"quantity": 1, // required. Quantity of the product ordered. Should be >= 1
"unit_price": "0.00", // required. Price per unit of the product. Should be positive or zero.
"discount_amount": "0.00",
"image_url": "https://example.com/",
"product_url": "https://example.com/",
"gender": "Kids",
"category": "Clothes", // required. Name of high-level category (Clothes, Electronics,etc.)
"color": "white",
"product_material": "cotton",
"size_type": "EU",
"size": "M",
"brand": "Name of the Brand",
"is_refundable": true,
"barcode": "12345678",
"ppn": "MNXT2ZM/A",
"seller": "Name of the Seller"
}
]
},
"buyer_history": {
"registered_since": "2023-11-07T05:31:56Z", // required. Date and time the customer got registred with you
"loyalty_level": 0, // required. Customer's loyalty level within your store
"wishlist_count": 0,
"is_social_networks_connected": true,
"is_phone_number_verified": true,
"is_email_verified": true
},
"order_history": [
{
"purchased_at": "2023-11-07T05:31:56Z", // required. Date and time the order was placed
"amount": "100", // required. Up to 2 decimals for UAE and KSA, e.g. 100.00
"payment_method": "card",
"status": "new", // required. Status of the order
"buyer": {
"name": "John Doe", // required. Customer's full name
"email": "jsmith@example.com", //required. Customer's email address
"phone": "500000001", //required. Customer's phone number
"dob": "2000-01-20"
},
"shipping_address": {
"city": "Dubai", // required. Name of city, municipality, or village
"address": "Dubai", // required. Building name, apartment number
"zip": "1111" // required. Postal code
},
"items": [
{
"reference_id": "SKU123",
"title": "Name of the product",
"description": "Description of the product",
"quantity": 1,
"unit_price": "0.00",
"discount_amount": "0.00",
"image_url": "https://example.com/",
"product_url": "https://example.com/",
"gender": "Kids",
"category": "Clothes",
"color": "white",
"product_material": "cotton",
"size_type": "EU",
"size": "M",
"brand": "Name of the Brand",
"is_refundable": true,
"barcode": "12345678",
"ppn": "MNXT2ZM/A",
"seller": "Name of the Seller"
}
]
}
],
"meta": {
"customer": "#customer-id",
"order_id": "#1234"
},
"attachment": {
"body": "{\"flight_reservation_details\": {\"pnr\": \"TR9088999\",\"itinerary\": [...],\"insurance\": [...],\"passengers\": [...],\"affiliate_name\": \"some affiliate\"}}",
"content_type": "application/vnd.tabby.v1+json"
}
},
"lang": "en", // required. Session language
"merchant_code": "code provided to you from Tabby side", // required. Merchant's branch code
"merchant_urls": {
"success": "https://your-store/success",
"cancel": "https://your-store/cancel",
"failure": "https://your-store/failure"
},
"token": null
}'
```
# Approve disputes
Source: https://docs.tabby.ai/api-reference/disputes/approve-disputes
post /api/v1/disputes/approve
Approve disputes (refund money to the customer). Only 20 disputes can be approved within a single request.
# Challenge disputes
Source: https://docs.tabby.ai/api-reference/disputes/challenge-disputes
post /api/v1/disputes/challenge
Challenge disputes (request Tabby support to take a look at the case). Only 20 disputes can be challenged within a single request. Only disputes with status 'new' might be challenged.
# Get dispute by id
Source: https://docs.tabby.ai/api-reference/disputes/get-dispute-by-id
get /api/v1/disputes/{disputeId}
Returns detailed information about dispute.
# Get disputes list
Source: https://docs.tabby.ai/api-reference/disputes/get-disputes-list
get /api/v1/disputes
Returns list of 100 recently created disputes.
# Provide evidence for a dispute
Source: https://docs.tabby.ai/api-reference/disputes/provide-evidence
post /api/v1/disputes/{disputeId}/provide-evidence
Provide evidence (text and/or attachments) for a dispute. Used by the merchant to submit proof in response to an evidence request.
# Upload attachment
Source: https://docs.tabby.ai/api-reference/disputes/upload-attachment
post /api/v1/disputes/attachments/upload
Upload an attachment. Attachment must be in PNG, JPEG or PDF format and can be up to 5 megabytes in size. Files larger than 5 MB are rejected.
# API Reference Documentation
Source: https://docs.tabby.ai/api-reference/overview
In this part of the documentation all the needed API calls for Tabby Integration can be found and tested:
* Checkout - it is a whole process of customer data collection and payment authorization.
* Payments - the core of Tabby is a payments flow enabling you to handle payments at your webstore.
* Webhooks - serve to ensure a seamless payment verification flow.
* Disputes - help merchants resolve issues with customers orders more efficiently.
## Base URLs
Tabby uses region-specific domains. Choose the base URL based on the merchant's operating country:
| Region | API Base URL | Checkout / Promo | Merchant Dashboard |
| --------------- | ---------------------- | ------------------- | ------------------- |
| **UAE, Kuwait** | `https://api.tabby.ai` | `checkout.tabby.ai` | `merchant.tabby.ai` |
| **KSA** | `https://api.tabby.sa` | `checkout.tabby.sa` | `merchant.tabby.sa` |
All API paths and payloads are identical across both domains. Tabby identifies the environment (test or live) based on the API keys used.
| Contact | UAE, Kuwait | KSA |
| -------------------- | ------------------ | ------------------ |
| **Partner Support** | `partner@tabby.ai` | `partner@tabby.sa` |
| **Customer Support** | `help@tabby.ai` | `help@tabby.sa` |
## OpenAPI Specification
To access and download the raw OpenAPI specification file kindly use this: [openapi.yaml](https://docs.tabby.ai/openapi.yaml).
You can also view this API specification using [ReDoc](https://redocly.github.io/redoc/?url=https://docs.tabby.ai/openapi.yaml), the same is present below:
## Quick Links to Documentation
* [Direct API Integration Guide](/pay-in-4-custom-integration/quick-start)
* [Testing Credentials](/testing-guidelines/testing-credentials)
* [Postman API Collection](/testing-guidelines/postman-api-collections)
# Capture a payment
Source: https://docs.tabby.ai/api-reference/payments/capture-a-payment
post /api/v2/payments/{id}/captures
Send a Capture requests for Authorized payments only. If you capture the full payment amount, the payment will be automatically closed with full capture. If you capture partial amount, the payment will remain Authorized until the rest of the amount is captured or Close request sent.
# Close a payment
Source: https://docs.tabby.ai/api-reference/payments/close-a-payment
post /api/v2/payments/{id}/close
Closed is the final status of the payment. Your payment is going to be closed automatically if you capture the full amount of the payment. If an order is fully cancelled, please close the payment without capturing it - the customer will be refunded for all paid amount. If only a part of the order is delivered, please capture this part and close the payment – it will mean that another part of the order is not going to be delivered to the customer.
# List of all payments
Source: https://docs.tabby.ai/api-reference/payments/list-of-all-payments
get /api/v2/payments
Returns a list of success payments (`AUTHORIZED` or `CLOSED`) you’ve previously created. The payments are returned in sorted order, with the most recent payments appearing first. Each entry in the array is a separate payments object, including the status, any captures and any refunds. If no more payments are available, the resulting array will be empty. Payments might be filtered by creation date.
# Refund a payment
Source: https://docs.tabby.ai/api-reference/payments/refund-a-payment
post /api/v2/payments/{id}/refunds
Send a full or partial refund amount request. You can only refund the payment that has Closed status. By default refunds reflect instantly, which means Tabby initiates a refund through payment gateway.
# Retrieve a payment
Source: https://docs.tabby.ai/api-reference/payments/retrieve-a-payment
get /api/v2/payments/{id}
Retrieves the specified payment. Returns the entire payment object, including the payment Status, Captures and Refunds objects.
# Update a payment
Source: https://docs.tabby.ai/api-reference/payments/update-a-payment
put /api/v2/payments/{id}
Updates the reference_id. You can only use this endpoint to update this 1 field. If you send other fields in the request, they will simply be ignored by tabby. The payment to be updated can have a status of AUTHORIZED or CLOSED.
# Register a webhook
Source: https://docs.tabby.ai/api-reference/webhooks/register-a-webhook
post /api/v1/webhooks
Creates a new webhook. Webhooks are registered per `merchant_code` and per environment:
the environment is determined by the secret key you authorize the request with —
a production key (`sk_...`) registers webhooks for production payments, a test key
(`sk_test_...`) registers webhooks for test payments. Each `merchant_code` + key pair
can have up to 4 webhooks.
# Remove a webhook
Source: https://docs.tabby.ai/api-reference/webhooks/remove-a-webhook
delete /api/v1/webhooks/{id}
Removes the specified webhook.
# Retrieve a webhook
Source: https://docs.tabby.ai/api-reference/webhooks/retrieve-a-webhook
get /api/v1/webhooks/{id}
Retrieves the specified webhook.
# Retrieve all webhooks
Source: https://docs.tabby.ai/api-reference/webhooks/retrieve-all-webhooks
get /api/v1/webhooks
Retrieves all registred webhooks.
# Update a webhook
Source: https://docs.tabby.ai/api-reference/webhooks/update-a-webhook
put /api/v1/webhooks/{id}
Updates the specified webhook.
# ExpandCart
Source: https://docs.tabby.ai/e-commerce-platforms/expandcart
Install and configure the Tabby payment method on ExpandCart using your API keys.
Tabby works on the ExpandCart platform for the countries KSA and UAE with SAR and AED currencies accordingly.
## Installation Steps
Register with Tabby
(KSA: merchant.tabby.sa)
and fill all the business details to collect the Tabby API Keys
)}
/>
Install Tabby App for your Expand Cart store and populate the Live keys.
You can find Tabby settings in Home -> Payment -> Payment providers.
Please, make sure you have the following settings for the proper functioning:
)}
/>
Tabby Settings page
Your store is ready to accept Payments with Tabby.
)}
/>
# Magento 2 Plugin Installation
Source: https://docs.tabby.ai/e-commerce-platforms/magento-2/magento-2-plugin-installation
Install the Tabby plugin for Magento 2, configure your API keys, and connect to the live environment.
To access the latest features and updates, you can easily update the plugin via Composer.
Tabby works on the Magento 2 platform for all supported countries.
## Installation Steps
Register with Tabby
(KSA: merchant.tabby.sa)
and fill all the business details
)}
/>
Go to Stores -> All Stores page and provide the Store Codes to Tabby account manager. Then receive Test API Keys
)}
/>
Download Tabby
extension
from the Adobe store:
https://commercemarketplace.adobe.com/tabby-m2-payments.html
If due to any reason the Adobe store cannot be used - download the extension from
here
)}
/>
Install the plugin
and
configure Tabby as a payment method
)}
/>
Test your integration
)}
/>
Receive live API keys and
deploy to production
)}
/>
**Important Note**
* Install the extension in your sandbox or staging environment before pushing it live.
* Keep a copy of your Magento store and database to ensure you can revert to the version before the installation.
* If you set up Tabby plugin on your Staging site and copy this configuration to Production site, make sure you go to Tabby plugin settings and click Save to enable all settings and webhooks for on Production site.
* You may need to re-index all the produce and category tables after the extension is installed.
## 2 ways to install/update the Magento 2 Extension
### Using Composer
1. Add Tabby module to composer dependencies
2. Install the defined dependencies
3. Turn on Tabby module in Magento
4. Upgrade Magento database
5. Recompile your project
6. Deploy static view files
Here needed commands are shown:
```
composer require tabby/m2-payments
composer update
php bin/magento module:status
php bin/magento module:enable Tabby_Checkout Tabby_Feed
php bin/magento setup:upgrade
php bin/magento deploy:mode:set developer
php bin/magento deploy:mode:set production
```
#### Additional Commands
During the plugin installation / update the following error might occur: **"Higher matching version 7.0.1 of tabby/m2-payments was found in public repository packagist.org"**:
In this case you need to manually set the version for tabby m2-payments to the higher matching version of tabby/m2-payments in public repository packagist.org, e.g.:
```
tabby m2-payments >= 7.0.1
```
### Using Command Line
1. Download the extension from the Adobe store: [https://commercemarketplace.adobe.com/tabby-m2-payments.html](https://commercemarketplace.adobe.com/tabby-m2-payments.html)
If due to any reason the Adobe store cannot be used - download the extension from here
2. If it does not exist, create the directory **Magento2\_root/app/code/Tabby/Checkout/**
3. Unzip the extension and move all the files to **Magento2\_root/app/code/Tabby/Checkout/**
4. In the Magento 2 root directory run the following command to verify that **Tabby Checkout** exists in the **List of disabled modules**:
```
php bin/magento module:status
```
5. In the Magento 2 root directory run the following commands:
```
php bin/magento setup:upgrade
php bin/magento deploy:mode:set production
```
6. Clear the Magento 2 cache to use the default Magento 2 Tabby configuration
## Configure Tabby as a Payment Method
After installing the extension, enable Tabby as a payment method by updating Magento 2’s configurations:
1. Sign in to your Magento 2 admin portal
2. Go to ***Stores > Configuration > Sales > Payment Methods > Tabby Payments***
3. Go to **Tabby API** and configure the following settings:
* Enter the **Public API Key** and **Secret API Key** for testing
* Capture On - Order placed (required)
* Enable **Tabby Installments** (Pay later with Tabby) payment methods
An example of Tabby API settings:
### Manage Tabby Product Catalogue Feature
Kindly note that Tabby Product Catalogue Feature works with
Live API Keys
only.
1. Sign in to your Magento 2 admin portal
2. Go to ***Stores > Configuration > Sales > Payment Methods > Tabby Payments***
3. Go to **Tabby Feed** and configure the setting
For multi-store setup - in case you use the same store\_code for different websites (different countries) you need to enable Use local currency on the checkout setting from Tabby API settings tab. Please inform your integration manager about such changes.
If these changes do not take effect immediately:
1. In the Magento admin panel, go to ***System > Cache Management***
2. Click **Flush Magento Cache**
3. Sign out
4. Sign back in to reset permissions
### Test Your Integration
After completing your integration, make an order and refund it (create a Credit Memo) to ensure that everything works as expected.
**Coordinate Testing with Tabby**
Before deploying Tabby integration to your production site, Tabby needs to validate the correctness of the integration. Contact your account manager to coordinate this test.
### Connect to the Live Tabby Environment
1. Get your Live Public and Secret keys for the live environment. Ask your account manager to share the keys.
2. Set your public and secret keys in the Magento admin panel, go to ***Stores > Configuration > Sales > Payment Methods > Tabby***
3. **Launch to Production**
After you’ve connected to the live environment and we’ve tested your integration, you’re ready to deploy to your production environment and offer Tabby payment methods to your customers.
## Specific Settings
### No Price snippet
It is possible to turn on non-standard Tabby snippets in ***Stores > Configuration > Sales > Payment Methods > Tabby***, parameter ***Promotions theme*** should have **:non-standard** specified:
Promotions theme
No price snippet
### Promotions Only Mode
It is possible to set Tabby plugin for promotion purposes only if Checkout integration was done with another provider: the plugin will only enable PDP / Cart page snippets.
For this setup go to ***Stores > Configuration > Sales > Payment Methods > Tabby***, parameter ***Tabby plugin mode***, and select ***Promotions only*** there:
Promo only mode
# Magento 2 Product Catalogue
Source: https://docs.tabby.ai/e-commerce-platforms/magento-2/magento-2-product-catalogue
Enable the Magento 2 Product Catalogue feature to list your store's products on the Tabby Shop.
We've introduced an exciting new feature to the Tabby Magento 2 plugin – the **Product Catalogue Feature**, designed to help you list your store’s products seamlessly on the Tabby Shop.
The feature is enabled by default in new plugin versions starting from 5.0.11.
Update the plugin using composer:
```
composer require tabby/m2-payments
composer update
php bin/magento module:status
php bin/magento module:enable Tabby_Checkout Tabby_Feed
php bin/magento setup:upgrade
php bin/magento deploy:mode:set developer
php bin/magento deploy:mode:set production
```
Check that the setting is enabled in the Tabby API options located at:
**Stores -> Configuration -> Sales -> Payment methods -> Tabby Payments -> Tabby Feed -> "Share product feed with Tabby"**
**Key features:**
* **Automated Product Listing**: Easily list your entire Magento 2 store inventory on the Tabby Shop without manual intervention.
* **Real-Time Stock Updates**: Keep your product listings up-to-date effortlessly, as the plugin automatically syncs inventory availability and reflects out-of-stock items in real time.
* **Increased Visibility**: Showcase your products to a broader audience by making them visible to all Tabby app users.
* **Traffic Generation**: Drive interested shoppers directly to your Magento 2 store, increasing clicks and potential sales.
# Matjrah
Source: https://docs.tabby.ai/e-commerce-platforms/matjrah
Connect Tabby on the Matjrah platform by entering your API keys.
Tabby works on the Matjrah platform for the countries KSA and UAE.
1. Register with Tabby (KSA: merchant.tabby.sa) and fill all required business details to collect Tabby API Keys.
2. Fill in the keys using the instruction below:
# Odoo Plugin Installation
Source: https://docs.tabby.ai/e-commerce-platforms/odoo/odoo-plugin-installation
Install the Tabby module on Odoo, configure your API keys, and take the integration live.
Tabby works on the Odoo platform for all supported countries. Odoo versions 17, 18, and 19 are supported.
The Tabby module can be installed on self-hosted (on-premise) Odoo and Odoo.sh. Odoo Online (SaaS) does not support the installation of custom modules.
## Installation Steps
Register with Tabby
(KSA: merchant.tabby.sa)
and fill all required business details
)}
/>
Receive test API keys from your Tabby account manager
)}
/>
Download the Tabby module
matching your Odoo version
)}
/>
Install the module
and
configure Tabby as a payment method
)}
/>
Test your integration
)}
/>
Receive live API keys and
deploy to production
)}
/>
### Download the Tabby Module
Tabby provides a separate module build for each supported Odoo version. Download the archive matching the major version of your Odoo installation:
| Odoo version | Module download |
| ------------ | -------------------------------------------------------------------------------------- |
| Odoo 19 | odoo19-latest.zip |
| Odoo 18 | odoo18-latest.zip |
| Odoo 17 | odoo17-latest.zip |
Each archive contains the `payment_tabby` module folder — this folder is the unit of installation.
### Install the Odoo Module
1. Extract the downloaded archive and locate the `payment_tabby` module folder inside it
2. Copy the `payment_tabby` folder into your Odoo addons directory — any directory listed in the `addons_path` parameter of your `odoo.conf` (commonly a `custom_addons` folder). Make sure the copied files are readable by the user running the Odoo service
3. Restart the Odoo service
4. Activate the developer mode: go to ***Settings -> General Settings***, scroll down to **Developer Tools** and click **Activate the developer mode**
5. Go to ***Apps*** and click ***Update Apps List*** in the top menu, then confirm the update
6. In the Apps search bar remove the default filters, search for **Tabby** and click **Activate** on the "Payment Provider: Tabby" module
**Odoo.sh:** instead of copying files to the server, add the `payment_tabby` folder to your Odoo.sh project's GitHub repository and deploy the branch — the module then appears in the Apps list after **Update Apps List**.
#### Optional: Updating the Odoo Module
When a new version of the Tabby module is released:
1. Download the latest archive for your Odoo version and replace the existing `payment_tabby` folder in your addons directory with the new one
2. Restart the Odoo service
3. Go to ***Apps***, remove the default filters, find the **Tabby** module and click ***Upgrade*** from the module's menu
### Configure Tabby as a Payment Method
1. Go to ***Website -> Configuration -> Payment Providers*** (the same screen is also available via ***Invoicing -> Configuration -> Payment Providers*** and ***Sales -> Configuration -> Payment Providers***)
2. Open **Tabby** in the list of providers
3. In the **Credentials** tab, enter the **Tabby Public Key** and **Tabby Secret Key** you received from your account manager
4. Set the **State** to **Enabled**
5. Click **Save**
Once the provider is enabled, it is automatically published on your website and Tabby appears among the payment methods on Checkout.
Tabby requires the order currency to match the customer's country: UAE-AED, KSA-SAR, Kuwait-KWD. Make sure the currency of your website/pricelist is set accordingly — Tabby will not be displayed on Checkout for unsupported currencies.
### Test Your Integration
After completing your integration, make an order and refund it to ensure that everything works as expected.
**Coordinate Testing with Tabby**
Before deploying Tabby integration to your production site, Tabby needs to validate the correctness of the integration. Contact your account manager to coordinate this test.
### Connect to the Live Tabby Environment
1. Get your Public and Secret keys for the live environment. Ask your account manager to share the keys
2. Set your live keys in the Odoo admin panel: go to ***Website -> Configuration -> Payment Providers -> Tabby***, open the **Credentials** tab and replace the test keys
3. **Launch to Production**
After you've connected to the live environment and we've tested your integration, you're ready to offer Tabby payment methods to your customers.
### Feedback and Support
If you face any issues during installation or testing, don't hesitate to get in touch with `partner@tabby.ai` / `partner@tabby.sa` with the store link, issue description, and screenshots or screencasts of the observed behaviour.
# OpenCart Plugin Installation
Source: https://docs.tabby.ai/e-commerce-platforms/opencart/opencart-plugin-installation
Install the Tabby plugin for OpenCart, configure your API keys, and connect to the live environment.
Tabby works on the OpenCart platform for all supported countries. OpenCart versions 2.x, 2.1.x, and 3.x with the Journal Theme are supported.
## Installation Steps
Register with Tabby
(KSA: merchant.tabby.sa)
and fill all required business details
)}
/>
Receive test API keys from your Tabby account manager
)}
/>
To download Tabby Plugin,
click here
)}
/>
Install the plugin
and
configure Tabby as a payment method
)}
/>
Test your integration
)}
/>
Receive live API keys and
deploy to production
)}
/>
### Install the OpenCart Extension
1. Go to ***Extensions -> Installer*** and install the extension.
2. Go to ***Extensions -> Modifications*** and click the refresh button under your profile (without re-loading this page in the browser).
3. Check the Tabby payment in the modification list.
4. Go to ***Extensions -> Extensions -> Modules*** in your OpenCart admin panel and activate Tabby Module.
The example of Tabby Module settings:
#### Optional: Updating the OpenCart Extension
When you want to update your current version with the new one.
1. Go to ***Extensions -> Modifications*** and delete the Tabby payment
2. Go to ***Extensions -> Installer*** and delete all files named oc3-tabby-x.x.x.ocmod.zip from install history
3. Upload and install the extension
4. Go to ***Extensions -> Modifications*** and click the refresh button under your profile (without reloading the page in the browser)
5. Check the Tabby payment in the modification list;
6. Go to ***Extensions -> Extensions -> Modules*** in your Opencart admin panel and activate Tabby Module
7. Open **Tabby Module** settings and click on Save changes button
### Configure Tabby as a Payment Method
1. Go to ***Extensions -> Extensions -> Modules*** in your OpenCart admin panel, find Tabby Module, click "Edit" and enter the **Public API Key** and **Secret API Key** for testing.
2. Go to ***Extensions -> Extensions -> Payments*** in your OpenCart admin panel and enable Tabby Installments (Split in 4).
3. Make sure the following settings are configured in any Tabby option Installments: – **Capture on – order\_placed**
4. Go to ***Design -> Layouts -> Checkout*** and add Tabby Module to Content Top
**For Journal theme only:** Go to Journal → Layouts → Checkout, choose Top+, choose OpenCart (the last one) and choose Tabby Module →Tabby Checkout → Save changes.
### Test Your Integration
After completing your integration, make an order and refund it to ensure that everything works as expected.
**Coordinate Testing with Tabby**
Before deploying Tabby integration to your production site, Tabby needs to validate the correctness of the integration. Contact your account manager to coordinate this test.
### Connect to live Tabby environment
1. Get your public and secret keys for the live environment. Ask you account manager to share the keys.
2. Set your live public and secret keys in the OpenCart admin panel, for this go to ***Extensions -> Extensions -> Modules -> Tabby Module*** in your OpenCart admin panel.
3. **Launch to Production**
After you’ve connected to the live environment and we’ve tested your integration, you’re ready to deploy to your production environment and offer Tabby payment methods to your customers.
## Specific settings
### No Price snippet
It is possible to turn on non standard Tabby snippets in ***Extensions -> Extensions -> Modules -> Tabby module (Tabby Checkout),*** parameter ***Tabby Promo theme*** should have **:non standard** specified:
Promotions theme
No price snippet
# OpenCart Product Catalogue
Source: https://docs.tabby.ai/e-commerce-platforms/opencart/opencart-product-catalogue
Enable the OpenCart Product Catalogue feature to list your store's products on the Tabby Shop.
We've introduced an exciting new feature to the OpenCart plugin – the **Product Catalogue Feature**, designed to help you list your store’s products seamlessly on the Tabby Shop.
The feature is enabled by default in new plugin versions starting from 2.9.0.
Install or Update the plugin to the latest version via below link:
[https://storage.googleapis.com/plgns/opencart-latest.zip](https://storage.googleapis.com/plgns/opencart-latest.zip)
Check that the setting is enabled in the Tabby API options located at:
**Extensions -> Tabby Module -> "Tabby Product Feed"**
**Key features:**
* **Automated Product Listing**: Easily list your entire OpenCart store inventory on the Tabby Shop without manual intervention.
* **Real-Time Stock Updates**: Keep your product listings up-to-date effortlessly, as the plugin automatically syncs inventory availability and reflects out-of-stock items in real time.
* **Increased Visibility**: Showcase your products to a broader audience by making them visible to all Tabby app users.
* **Traffic Generation**: Drive interested shoppers directly to your OpenCart store, increasing clicks and potential sales.
# Salesforce
Source: https://docs.tabby.ai/e-commerce-platforms/salesforce
Install and configure the Tabby cartridge for Salesforce Commerce Cloud.
Tabby works on the Salesforce Commerce Cloud platform for all supported countries.
## Installation Steps
Register with Tabby
(KSA: merchant.tabby.sa)
and fill all the business details
)}
/>
Receive your Testing API keys from your Tabby account manager
)}
/>
Download and install Tabby Cartridge for your platform:
To download SFRA (Store Front Reference Architecture) Cartridge,
click here
To download SiteGenesis Cartridge,
click here
)}
/>
Test your integration and contact Tabby to have a green light for going live
)}
/>
Collect your Live API Keys, populate them for your store, make sure Live Webhooks are installed. You are ready for going live now
)}
/>
Salesforce integration supposes adding the necessary cartridges into an SFCC reference application.
Tabby cartridge package contains 3 folders:
1. int\_tabby\_core – Tabby core implementations both for Sitegenesis and SFRA
2. int\_tabby\_sfra – Tabby SFRA changes/implementations
3. bm\_tabby – Tabby Business Manager module
Compatibility: SFRA v6.0.0 Compatibility Mode 21.7
### Cartridges Installation
#### Adding Cartridges in Salesforce Commerce Cloud Studio
1. Open package.json and ensure the base path mentioned is correctly resolved (please provide the correct path to app\_storefront\_base)
2. Open the command prompt and run ‘npm install’ (assuming node.js (12.21.0 and above) is installed) to install all of the local dependencies
3. Run the “npm run compile”
4. Create the dw\.json file:
```
{
"hostname": "your-sandbox-hostname.demandware.net",
"username": "yourlogin",
"password": "yourpwd",
"code-version": "version_to_upload_to"
}
```
5. Upload this code to the environment using the command ‘npm run uploadCartridge’, that will upload the **int\_tabby\_core** , **int\_tabby\_sfra** and **bm\_tabby** cartridges to the sandbox you specified in dw\.json file
#### Activating Cartridges in Business Manager
Before Tabby functionality can become available to Reference Architecture, the cartridges need to be added to the cartridge path of the site. In order to do this, follow the following instructions:
* Log into Business Manager
* Navigate to *Administration -> Sites -> Manage Sites*
* Click on the site name
* Go to the "Settings" tab
* In the textbox cartridges add **int\_tabby\_sfra:int\_tabby\_core** before **app\_storefront\_base**
example: **int\_tabby\_sfra:int\_tabby\_core: app\_storefront\_base**
* Click **Apply**
* Repeat steps 3 to 5 for each site that is to use Tabby
* To run the Jobs and have tabby BM module, Navigate to *Administration -> Sites -> Manage Sites*
* Go to the "Manage the Business Manager site” tab
* In the textbox cartridges add **int\_tabby\_core:bm\_tabby** to the start
### Configuration
#### Importing Meta Data with a single Site Import
All import files are located in the import folder (metadata) within the cartridge installation pack. To import necessary Tabby settings:
* Open the metadata folder from the repository structure (open jobs.xml) and change the references of RefArchGlobal to your site id;
* Open the metadata/sites folder from the repository structure and change the folder name from RefArchGlobal to your site id. If you have multiple sites with Tabby, then copy RefArchGlobal folder and rename it with your other site id(s).
* Open the metadata/sites/YourSiteID/preferences.xml file from the repository structure;
* Fill in **tabbyServiceCredentialPublicKey** and **tabbyServiceCredentialSecretKey** with keys provided by your account manager from Tabby;
* Fill in **tabbyWebhooksTitle** and **tabbyWebhooksValue** values;
* Compress the metadata folder from the repository structure;
* Log in to the Business Manager and navigate to *Administration -> Site Development -> Site Import & Export*, upload the zipped folder, go back and use the import button to import the file;
* After a successful import, the entire configuration requirements needed for Tabby are available according to your Tabby account data.
#### Managing Tabby Custom Site Preferences
In Business Manager, navigate to the *Site -> Merchant Tools -> Site Preferences -> Custom Preferences*. A custom site preference group "Tabby" is available. Please select it and edit the attributes according to your Tabby account data.
| | | |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
| **Site Preference** | **Description** | **Values** |
| Is Tabby Enable | This field represents the enable/disable tabby implementation. | Boolean: True/FalseDefault: True |
| Tabby Environment | This field represents the type of the environment. | Enum of String: Development -> Development instancesProduction -> Production instancesDefault: Development |
| Service Credential Public Key | This field represents the tabby service credential public key (pk\_...). | String: (Mandatory) The public API key that Tabby provided to you |
| Service Credential Secret Key | This field represents the tabby service credential secret key (sk\_...). | String: (Mandatory) The secret API key that Tabby provided to you |
| Is Tabby Installments Enable | This field represents the Installments payment method is enabled. | Boolean: True/False Default: True |
| Is Tabby Credit Card Installments Enable(Deprecated) | This field represents the Credit Card Installments payment method is enabled. | Boolean: True/False Default: False |
| Is Tabby Pay Later Enable | This field represents the Pay Later payment method is enabled. | Boolean: True/False Default: False |
| Immediate Capture On Authorize | This field represents if the Immediate Capture on Authorize is enabled. If Yes -> Capture request will be triggered automatically after success Authorization. If No -> Tabby-Capture scheduled job will send the capture request. | Boolean: True/False Default: True |
| Installments Count | This field represents Installments counts. | Integer:Default: 4 |
| Tabby Merchant Code Per Country | This field represents the Merchant codes per country in a JSON format: \{ "AE": "uae","SA": "ksa","KW": "kwt"} | Text (JSON) \{ "AE": "uae","SA": "ksa","KW": "kwt"} - need to define Site countries only. |
| Card Size | This field represents the tabby card size, can be narrow or wide, depending on the width | Enum of String: Narrow/Wide Default: Narrow |
| Card Theme | This field represents the tabby card theme, can be default or black, depending on the styles | Enum of String: Default/Black Default: Default |
| Webhooks Title | This field represents the arbitrary header name to sign the request for the webhooks.Will be used to verify webhook requests that tabby system sends. | String: |
| Webhooks Value | This field represents the random string to sign the request for the webhooks.Will be used to verify webhook requests that tabby system sends. | String: |
#### Managing Tabby Payment Processor
In Business Manager select the required site from the dropdown and navigate to *Merchant Tools -> Ordering -> Payment Processors*.
#### Managing Tabby Payment Methods
In the integration package, a payment method definition is provided in the file that you have already imported
1. Navigate to *Merchant Tools -> Ordering -> Payment Methods*;
2. Enable/Disable the Payment Method under *Ordering -> Payment Methods* section that needs to be activated. Repeat these steps for all the Payment Methods that are required to be supported on the site.
#### Managing Jobs
In the integration package, a job definition is provided in the import zip (metadata.zip) file (jobs.xml). Make sure to associate the jobs with the respective merchant site.
*Tabby-CaptureShippedOrders*
It captures the payments that are authorized by Tabby. This job fetches the orders which have confirmationStatus=CONFIRMED, paymentStatus=NOTPAID, shippingStatus=SHIPPED and custom.tabbyPaymentStatus: AUTHORIZED.
Script file: int\_tabby\_core/cartridge/scripts/jobs/capture.js
If the site preference “**Immediate Capture On Authorize**” is set to "True", it is not necessary to enable this job.
*Tabby-RegisterWebhooks*
It registers the Webhooks for the sites defined by merchant*codes from the "Site preference" tab. Each* merchant\_code needs to be registered separately. This job is a one time job to register the Webhooks. It is important to fill in “Webhooks Title” and “Webhooks Value” in the "Site Preferences" before running this job.
Script file int\_tabby\_core/cartridge/scripts/jobs/webhooks.js
*Tabby-Feedback*
It processes the TabbyFeedback custom objects that are saved within the TabbyWebhooks-Process endpoint. Custom object details are to compare with the order payment statuses. If there is a difference between the order/payment status, the job will synchronize the order/payment statuses based on the TabbyFeedback details.
Script file int\_tabby\_core/cartridge/scripts/jobs/feedback.js
#### Tabby Business Manager Module
The cartridge for Business Manager module bm\_tabby is present in the installation package. It helps processing capture and refund APIs. To enable/activate it, do the following:
1. Navigate to *Administration -> Organization -> Roles & Permissions*;
2. Click **Administrator** in the Roles;
3. Click **Business Manager Modules**;
4. Select the sites where you have Tabby;
5. Click **Apply**;
6. Scroll to *Ordering -> Tabby Orders* and check the checkbox;
7. Click **Update** at the bottom of the page;
Once it is enabled, “Tabby Orders” will be placed under *Merchant Tools > Ordering*
# Salla
Source: https://docs.tabby.ai/e-commerce-platforms/salla
Tabby works on the Salla platform for the KSA only with SAR as currency.
1. Register with Tabby (KSA: merchant.tabby.sa) and fill all required business details to collect Tabby API Keys.
2. Fill in the keys using the instruction below:
# Shopify Plugin Installation
Source: https://docs.tabby.ai/e-commerce-platforms/shopify/shopify-plugin-installation
Install the Tabby app for Shopify, configure webhooks and settings, and go live.
Tabby works on the Shopify platform for all supported countries. Currency conversion may apply for multi-currency stores, check **Multi-Currency Processing and Currency Conversion** below.
## Installation Steps
No time to read or have questions on any of the steps? Watch video guide on
**How to set up Tabby on Shopify:**
[Register with Tabby](https://merchant.tabby.ai/) (KSA: [merchant.tabby.sa](https://merchant.tabby.sa/)) and fill all required business details to collect Tabby Live API Keys.
To install Tabby Payment App, [click here](https://apps.shopify.com/tabby-payment-1).
As soon as the payment method is installed, open **Settings → Payments** in your Shopify admin. In **Additional payment methods** click **Add payment method**, choose **Search by payment method** and input **"tabby"**. Click "Tabby" to see all options, choose the first line **"tabby >"** and click **Activate**.
At the Tabby settings page click **More actions → Manage**. Copy the **Live Public** and **Secret keys** from the [Merchant Dashboard](https://merchant.tabby.ai/business-profile/stores) (KSA: [merchant.tabby.sa](https://merchant.tabby.sa/business-profile/stores)) and paste them in the necessary fields. Leave the **Webhook Key** empty, you will get it in the next steps. Click **Save**.
Tabby requires Shopify Webhooks to update the order number, fetch the phone number and order lines from Shopify.
Open **Settings → Notifications → Webhooks** and click **Create webhook**. Add 4 webhooks:
| event | Callback URL | Format | API version |
| -------------------- | ------------------------------------------------------------- | ------ | ----------- |
| Transaction creation | `https://sfy-payment.tabby.ai/api/webhook/transaction/create` | JSON | Latest |
| Order creation | `https://sfy-payment.tabby.ai/api/webhook/order/create` | JSON | Latest |
| Checkout creation | `https://sfy-payment.tabby.ai/api/webhook/checkout/create` | JSON | Latest |
| Checkout update | `https://sfy-payment.tabby.ai/api/webhook/checkout/create` | JSON | Latest |
Copy the Webhook Verification Key which is generated after the first Webhook creation.
Webhook Verification Key
Paste the key in **Settings → Payments → Supported/Additional payment methods → tabby → More actions → Manage → Webhook Verification Key**.
1. Check that you have **"Automatic at checkout"** option in the "Payment capture method" setting in the "Payments" tab.
2. Make sure to uncheck **"Enable test mode"** as Tabby does NOT pay out for test / playground orders ever, even if a live customer places a real order while "Test mode" was checked.
3. Email and phone number are required for Tabby payment method. Please enable the following settings in your admin panel:
If you have installed Webhooks earlier and have issues with updating order numbers - please, make sure all 4 webhooks are set up and you are using the latest available API version. Kindly refer to the
Webhook API Version Update.
### Webhook API Version Update
Here **Webhook Update Demonstration** can be reviewed:
Shopify Webhooks are created for the particular API version. Shopify releases several versions per year, so it means your initial API version settings will inevitably expire. Tabby makes the necessary changes to support the latest updated API versions, but this also requires a manual action from the partner's end.
You need to go to Settings -> Notifications -> Webhooks and choose the **latest** API version from the dropdown of a particular Tabby Webhook.
## Add Tabby Snippets
Tabby snippets let your customers know they can split their payments with Tabby in your store. Snippets appear on the product and cart pages and may help improve conversion.
To add Tabby snippets to your product and cart pages, please follow our detailed instructions and video manuals here: Tabby Snippets for Shopify
Please note that snippets alone do not activate Tabby as a payment method in your store and don’t affect payment processing. Before adding snippets, make sure Tabby is already integrated and visible on your checkout page.
## Tabby is live now!
Tabby orders are captured automatically. Refunds can be initiated from Shopify admin panel and will reflect on Tabby Merchant Dashboard, Customer Portal and Settlements.
## Limitations and Known Constraints
### Language Settings
The locale for Tabby Hosted Payment Page and Payment Method will be set based on the store's language, Tabby supports English and Arabic. If the locale is not supported, English is used by default. You can configure your store's language in your Shopify admin under Settings -> Languages.
### Order Number Update
When an order is placed in Shopify, a payment id is set in the Shopify order timeline information under the "payment was processed on tabby." section, within the "**Information from the gateway**" subsection. This payment id is set in the Tabby order's "reference\_id" (order number). Shopify does not share the Shopify order number for this payment app integration and Tabby is not able to match the Shopify order number or order number in the Tabby order. The Webhooks allow to update order number or Tabby Merchant Dashboard, Customer Portal and Settlements.
### Order Editing
Please note that order details editing (as order lines, customer details, etc.) will be reflected in Shopify Dashboard only and will not updated for the payment on Tabby Merchant Dashboard, Customer Portal and Settlements.
### Order Lines
Shopify doesn't share order data via the Payment App and Shopify does not share any order line data for non-product order lines, e.g. VAT/taxes, discounts, surcharges, tip, etc. Tabby orders will have necessary Order Lines data after Webhook installation.
### Order Tagging
Tabby Payment App cannot currently set tags on a Shopify order. You can use the Shopify Flow app (free and available on all Shopify plans) which can set order tags within a flow for Tabby orders.
### Payment Method Presentation
The Tabby payment method name is provided with English and Arabic translations out of the box.
To reorder or hide payment methods in Shopify checkout, use Shopify's checkout customizations powered by Payment Customization Functions — either via a Functions-powered app from the Shopify App Store, or via Checkout Blocks (Shopify Plus). The legacy checkout scripts (Script Editor) stopped executing on June 30, 2026 and can no longer be used for payment method customization.
Customizations of the Tabby payment method presentation (logo, footer text) are currently supported only for Shopify Plus merchants. If you implement your own custom snippet, notify your Tabby account manager so we can keep your integration in sync with upcoming changes.
### Domain Filtering
Payment App uses a different hosted payment page URL: `checkout.tabby.ai` (UAE, Kuwait) or `checkout.tabby.sa` (KSA).
Merchants that filter this domain in Google Analytics will need to update their GA configurations accordingly.
### Market Limitation
Tabby Payment App accept orders only for the billing addresses in the markets of KSA, UAE, Kuwait. Customers for non-supported regions based on the order's currency are shown an error message on page load that the Tabby order cannot be processed.
We recommend limiting Tabby's visibility at checkout to the countries where your store works with Tabby — has a signed contract and an active integration. You can hide Tabby for other countries using Shopify's checkout customizations (available on all Shopify plans), so customers from non-supported regions don't see the error message.
### Multi-Currency Processing and Currency Conversion
Tabby processes payments in the following currencies: SAR (SR), AED (Dhs), and KWD (KD), which must correspond to the customer's billing address. Tabby Payment App is compatible with all Shopify stores, regardless of their base currency.
If the store’s base currency differs from the customer’s billing currency, currency conversion will be applied, and the converted amount will be displayed at Tabby checkout. Customer transactions and merchant settlements will be processed in the customer’s billing currency.
Currency conversion is also applied between supported currencies if the store’s base currency differs from the customer’s billing currency.
Please note that to enable conversion, the “Enable Multi-Currency Processing” option must be selected in the Tabby settings.
### Inventory Lock Limitation and Inventory Stock Check
When a customer places an order with an alternative payment integration, such as Tabby Payment App, Shopify redirects to the payment method but does not lock the order's product inventory and thus stock inventory cannot be guaranteed.
However, Tabby can check inventory immediately after payment is completed but before the order is created in Shopify. If an item goes out of stock during the payment process, the funds will be refunded to the customer, and the Shopify order will not be created.
To enable this functionality, please turn on the **Check Inventory Stock** feature in Tabby settings in your Shopify admin panel.
Note that this feature only works when the following settings are applied to your products in Shopify settings:
* **Inventory tracking** is enabled
* **Continue selling when out of stock** setting is disabled
### Additional Request of the Phone Number
Shopify may not share the customer's phone number with payment integrations at checkout (for example, when email is required instead of phone). Tabby fetches the phone number via the Shopify Webhooks set up during the Installation Steps. If the webhooks are not set up, Tabby will ask the customer to enter the phone number again within our Hosted Payment Page.
### Checkout Error Limitation
*"There was an issue processing your payment. Try again or use a different payment method." –* this message can happen for tech/authorization reasons only. The most common reason (for new integrations) is that the API keys haven't been populated fully. You can check the API credentials at merchant.tabby.ai (KSA: merchant.tabby.sa). Also, this message appears if country in shipping or billing address is different from country (countries) that your Tabby account is signed for. It can also appear if your integration hasn't been set up on the Tabby side yet — in this case contact Tabby partner support at `partner@tabby.ai` / `partner@tabby.sa`.
### Redirection for Background Pre-Scoring Rejection
Tabby now redirects the customers to our internal rejection screens where we explain the reason and advise how to avoid this rejection if possible. Customers may see the general rejection explanation (can't be avoided), too high cart total and too low cart total rejections (can be skipped by adjusting the cart total).
### The Amount Paid by the Customer to Tabby Doesn't Match the Shopify Order Total
If customers update a related, but different Shopify session separately from the Shopify session used to place the Tabby order, the order totals between the Shopify and Tabby orders may not match, but the amount "Paid by customer" for the Shopify order should always match the Tabby order total. While not ideal, this is working as expected and designed. Care should be taken to only fulfill order line items paid for by the customer.
### Feedback and Support
If additional support is needed, email `partner@tabby.ai` / `partner@tabby.sa` (please include your Shopify store name and add your Account Manager in CC) for specific Tabby support.
Customer Tabby Support available at `help@tabby.ai` / `help@tabby.sa`
[https://community.shopify.com](https://community.shopify.com) is a good place for Shopify questions, support, and feedback, in addition to [https://help.shopify.com/](https://help.shopify.com/)
# Shopify Snippets
Source: https://docs.tabby.ai/e-commerce-platforms/shopify/shopify-snippets
Add Tabby promotional snippets to your Shopify product and cart pages.
Tabby snippets let your customers know they can split their payments with Tabby in your store. Snippets appear on the product and cart pages and may help improve conversion.
Please note that snippets alone do not activate Tabby as a payment method in your store and don’t affect payment processing. Before adding snippets, make sure Tabby is already integrated and visible on your checkout page.
## Adding Tabby Snippets on Product Pages
Here you may see a video on **How to add Tabby snippet to product pages on Shopify**:
1. In your Shopify admin, go to **Online Store → Themes**.
2. Click the **Customize** button on your current theme.
3. At the top of the screen, click **Home page**, then choose **Products → Default product**.
4. In the left-side menu, add a block, click **Apps** and choose **Tabby Installments**.
5. Drag the **Tabby Installments** block to a desirable position — ideally just below the price.
6. Click **Save** and check your storefront to make sure the snippet appear properly.
If the installments don’t display correctly, your theme may not be fully compatible with default Tabby snippets. In that case, we recommend using “No-price” snippets, which don’t show installment amounts.
To activate “No-Price” snippets, please click on the **Tabby Installments** block and switch the **Enable “No-price” Snippet** toggle to the **on** position. Don't forget to save the changes.
## Adding Tabby Snippets on Cart Page
Here you may see a video on **How to add Tabby snippet to cart page on Shopify**:
1. In your Shopify admin, go to **Online Store → Themes**.
2. Click the **Customize** button on your current theme.
3. At the top of the screen, click **Home page**, then choose **Products → Cart**.
4. In the left-side menu, add a block, click **Apps** and choose **Tabby Cart Page**.
5. Drag the **Tabby Cart Page** block into a suitable spot.
6. Click **Save** and verify that the snippets appear correctly on the storefront.
If installments are incorrect, you can switch to a simplified "No-price" version of the snippet.
To activate "No-price" snippets, please click on the **Tabby Cart** block and switch the **Enable “No-price” Snippet** toggle to the **on** position. Don't forget to save the changes.
This is how the snippets look on the storefront:
Default snippet
"No-price" snippet
## Manual Snippet Installation
Some Shopify themes may not support adding blocks on product pages. In such cases, the Tabby snippets need to be added manually. For this, you should create a file with the snippet code in your theme and render it on your product page.
### Step 1. Create a file
1. In the Shopify Admin panel, click **Online Store** → **Themes**
2. On the Themes page, click the **“…”** → **Edit code**
3. In the navigation menu on your left, click the **Snippets** folder and click the symbol of adding a new file
4. Name it **tabby-installments.liquid**
### Step 2. Add code
1. Copy one of the following codes and paste it into the file you've created.
We offer two variants of snippets: **default snippets** with installments and **"No-price" snippets**. The "No-price" code should be used if the default snippets don't work properly, which may be the case for some themes. Please try the "default" code first.
**Default Snippet Code**
```HTML theme={"dark"}
{%- assign lang = localization.language.iso_code -%}
{%- assign currency = cart.currency.iso_code -%}
```
**No-price Snippet Code**
```HTML theme={"dark"}
{%- liquid
assign locale = localization.language.iso_code
-%}
```
2. Check the variables in the code:
*For default snippet*: Put your **Public API Key** in the line 9 replacing **YourAPIkey** text.
*For No-price snippet*: Put your **Public API Key** in the line 16. In the line 17, put your **merchant code** based on your store currency, instead of the text **yourMerchantCode**.
Please note that you can find your Public API key in the Tabby Dashboard or in the initial email from your Tabby manager.
3. Save the changes.
### Step 3. Render the Snippet
1. First, find the file in your theme that is responsible for the page layout.
The exact file name may vary depending on the theme, but it's typically located in the **Sections** folder.
For product page, the most common file names are *product.liquid*, *main-product.liquid*, *price.liquid*, etc.
For cart page, it may be *cart.liquid* or one of the files included in *templates/cart.json* (e.g., *main-cart-items.liquid*, *cart-footer.liquid*)
2. Once you find appropriate file in your theme, place the following command near the price element:
```
{% render 'tabby-installments'%}
```
3. Click Save and check if the snippets appear correctly in the desired place on the storefront.
If you notice any issues with the content of the default snippet, go back to Step 2 and replace the code in the **tabby-installments.liquid** file with the “No-price” option. After saving the changes, the "No-price" snippets should appear on the storefront.
# WooCommerce Plugin Installation
Source: https://docs.tabby.ai/e-commerce-platforms/woocommerce/woocommerce-plugin-installation
Install the Tabby plugin for WooCommerce, configure your API keys, and go live.
Tabby works on the WooCommerce platform for all supported countries.
## Installation Steps
Register with Tabby
(KSA: merchant.tabby.sa)
and fill all required business details to collect Tabby API Keys
)}
/>
Install Tabby directly from the
WordPress Store
or download the
plugin archive
and
install manually
)}
/>
Configure Tabby
as a payment method and
enable autoupdates
)}
/>
Copy the Live Public and Secret keys from the
Merchant Dashboard
(KSA: merchant.tabby.sa)
and paste them into the necessary fields
)}
/>
Test your integration
)}
/>
### Manual Plugin Installation
1. Go to “Plugins” in your WooCommerce admin panel
2. Click “Add new” -> “Upload plugin”
3. Choose the downloaded archive in zip format
4. Click “Install now” and click “Activate plugin”
### Configure Tabby as a Payment Method
1. Go to ***WooCommerce -> Settings -> Tabby API*** and enter the **Public API Key** and **Secret API Key**
2. Save plugin changes
3. Enable Tabby as a Payment method in ***WooCommerce -> Settings -> Payments***, parameter "**Pay later with Tabby**"
Find below the example of Tabby API settings:
### Enable Autoupdates
1. Find Tabby in the list of installed plugins
2. Click “Enable auto updates”
### Test Your Integration
This testing is performed on Production keys -> it means you will not be able to complete testing payment using testing credentials. If you want to get Testing keys - kindly request `partner@tabby.ai` / `partner@tabby.sa` to provide you with them.
Follow the steps to verify the integration is set up properly:
1. Add any product to a cart
2. Go to your checkout page
3. Enter Tabby Test Credentials based on the country on the checkout page (**important** to use email and phone number for **positive flow** which are provided in Tabby documentation)
4. Make sure that you've been redirected to Tabby HPP
5. You can't proceed with the payment using the test credential - it is an expected result since you already use the Production keys
6. Click on **Back to Store** button, confirm cancellation and make sure that you've been successfully redirected back to the checkout page.
If all steps are passed successfully - you are live and customers can pay with Tabby!
#### Tabby is not Present on Checkout
In case Tabby is not present on Checkout - kindly review the following possible options:
* needed countries are enabled in ***WooCommerce -> Settings -> Tabby API***, parameter "**Allowed Countries**"
* Tabby payment method is enabled in ***WooCommerce -> Settings -> Payments***, parameter "**Pay later with Tabby**"
* country-currency pair is specified correctly (UAE-AED, KSA-SAR, etc.). If not - install any currency switcher available on the WordPress store to ensure multi-currency support (it is a known constraint)
* option "**Payment gateway**" is selected in ***WooCommerce -> Settings -> Tabby API***, parameter "**Plugin mode**"
If these parameters are set up accordingly and Tabby still does not appear on Checkout - kindly email `partner@tabby.ai` / `partner@tabby.sa` (please, include your WooCommerce store name and add your Account Manager in CC) for specific Tabby support.
## Specific Settings
### No Price snippet
It is possible to turn on non standard Tabby snippets in ***WooCommerce -> Settings -> Tabby API***, parameter ***Tabby promotions theme*** should have **:non standard** specified:
Tabby promotions theme
No price snippet
### Promotions Only Mode
It is possible to set Tabby plugin for promotion purposes only: PDP / Cart snippets will be displayed, but Tabby will not be present among payment methods on Checkout.
For this setup go to ***WooCommerce -> Settings -> Tabby API***, parameter ***Plugin mode*** and select ***Promo only*** there:
Promo only mode
## Limitations and Known Constraints
### Multi-Currency support
In case you integrate Tabby in different countries - please, make sure that you use an automated currency converter on the checkout as Tabby requires currency to match the customer’s country depending on the shipping country.
You can use any currency switcher plugin available on the WordPress store.
Tabby currently operates in KSA, UAE and Kuwait.
If you use a currency switcher plugin, make sure to add Tabby payment method for every supported currency. To do that, go to ***Admin → Multi currency → Checkout → Checkout currency*** and add Tabby payment method next to each supported currency.
Multi currency → Checkout → Checkout currency
### Logo size Issue
The issue is relevant for WordPress sites with WooCommerce. It is connected with the different page templates and themes using.
Because the Tabby plugin can't control the specific theme usage at partners' sites, you may need to modify the CSS file to have the following parameters:
`max-width: 50px;`
`max-height: 30px;`
### Feedback and Support
If you face any issues during testing, don't hesitate to get in touch with `partner@tabby.ai` / `partner@tabby.sa` with the store link, issue description, and screenshots or screencasts of the observed behaviour.
# WooCommerce Product Catalogue
Source: https://docs.tabby.ai/e-commerce-platforms/woocommerce/woocommerce-product-catalogue
Enable the WooCommerce Product Catalogue feature to list your store's products on the Tabby Shop.
We've introduced an exciting new feature to the Tabby WooCommerce plugin – the **Product Catalogue Feature**, designed to help you list your store’s products seamlessly on the Tabby Shop.
The feature is enabled by default in new plugin versions starting from 5.0.8.
Update the plugin or download the latest version from the WordPress store: [https://wordpress.org/plugins/tabby-checkout](https://wordpress.org/plugins/tabby-checkout) or by enabling auto-updates on **Plugins section**.
Check that the setting is enabled in the Tabby API options located at:
**WooCommerce -> Settings -> Tabby API -> "Share product feed with Tabby."**
**Key features:**
* **Automated Product Listing**: Easily list your entire WooCommerce store inventory on the Tabby Shop without manual intervention.
* **Real-Time Stock Updates**: Keep your product listings up-to-date effortlessly, as the plugin automatically syncs inventory availability and reflects out-of-stock items in real time.
* **Increased Visibility**: Showcase your products to a broader audience by making them visible to all Tabby app users.
* **Traffic Generation**: Drive interested shoppers directly to your WooCommerce store, increasing clicks and potential sales.
# Zid
Source: https://docs.tabby.ai/e-commerce-platforms/zid
Tabby works on the Zid platform for the countries KSA, UAE and Kuwait.
1. Register with Tabby (KSA: merchant.tabby.sa) and fill all required business details to collect Tabby API Keys.
2. Fill in the keys using the instruction below:
# Tabby docs for AI & LLMs
Source: https://docs.tabby.ai/introduction/ai-tools
Use the Tabby documentation with ChatGPT, Claude, Cursor and other AI tools — via llms.txt, per-page Markdown, and the hosted MCP server.
These docs are built to be read by AI assistants and coding agents, not just people. Every page is available as plain Markdown, the whole site is exposed as `llms.txt`, and there is a hosted MCP server you can connect your AI tool to.
## Read any page as Markdown
Use the **Copy page** / **Open in ChatGPT** / **Open in Claude** menu at the top of any page, or append `.md` to a docs URL to get the raw Markdown:
```
https://docs.tabby.ai/pay-in-4-custom-integration/quick-start.md
```
## llms.txt
We publish the [llms.txt standard](https://llmstxt.org) so an LLM can discover and ingest the documentation in one pass:
* **[llms.txt](https://docs.tabby.ai/llms.txt)** — an index of every page with titles and descriptions.
* **[llms-full.txt](https://docs.tabby.ai/llms-full.txt)** — the full content of the documentation in a single file.
Paste either link into your AI tool when you want it to reason over the whole integration guide.
## MCP server
Tabby's documentation is also available as a [Model Context Protocol](https://modelcontextprotocol.io) server, so AI tools can search and read the docs directly:
```
https://docs.tabby.ai/mcp
```
The server exposes a documentation search tool and a read-only filesystem of every page and the OpenAPI spec — your assistant can look up endpoints, payloads and integration steps on demand.
```json Cursor theme={"dark"}
{
"mcpServers": {
"tabby-docs": {
"url": "https://docs.tabby.ai/mcp"
}
}
}
```
```bash Claude Code theme={"dark"}
claude mcp add --transport http tabby-docs https://docs.tabby.ai/mcp
```
This MCP server covers the **documentation** only. It does not call the Tabby API or move money —
use the [API Playground](/api-reference/overview) and your secret key for live requests.
# F.A.Q.
Source: https://docs.tabby.ai/introduction/faq
This page gives you answers to the most common questions about Tabby operating.
## Where can I find credentials to use Tabby?
### Live Credentials
Live API keys can be obtained:
* from Tabby Merchant Dashboard for **Self-Hosted plugin** integration listed in the Quick Start section.
* by contacting Tabby account manager after QA testing carried out by Tabby team is completed for **Custom API** integration. Also refer to Test Credentials.
If the credentials are missing or wrong, Tabby will respond with 401 Not authorized. Error codes for a session creation request can be found here: Session Creation Error Codes.
In this case kindly contact Tabby Partner Support at `partner@tabby.ai` (or `partner@tabby.sa` for KSA) or reach out to your assigned Business Manager. When doing so, kindly include:
1. your store name as registered with Tabby;
2. your integration details:
* website URL or app name (for online integrations);
* description of offline integration, if applicable.
### Test Credentials
To test your custom integration with Tabby you need to use the following:
* your testing keys, starting with pk\_test / sk\_test;
* download the Postman API Collection from here: Postman API Collection;
* or use Tabby endpoints provided here: API Playground;
Tabby identifies live or test environment based on the keys used. The endpoints for test are the same as for live.
* review the Full Testing Checklist;
* check the Testing Scenarios based on your type of integration:
* Online Custom integration: Testing Scenarios for Online Custom Integration
* Offline Integrations -> POS: Testing Scenarios for POS
* Offline Integrations -> Custom Payment Links: Testing Scenarios for Custom Payment Links
## Does Tabby provide any sandbox environment for testing?
Tabby provides a single environment for both integration and live launch. Use api.tabby.ai for UAE and Kuwait, or api.tabby.sa for KSA (see Base URLs). Payments can be created:
* in test mode using **Test API keys** from merchants' DEV and Stage environments;
* in live mode using **Live API keys**. Live keys are shared after development is completed and QA by Tabby team is done and confirmed.
Checkout, Payments and Webhooks are available for both test and live payments, while Disputes are supported for live payments only.
## What should I do if my platform is not present in the list of supported platforms?
In such case the integration is considered an Online Custom Integration - kindly follow its integration guidelines.
## What is the difference between Close and Capture API calls?
The main difference between these API calls is that when the **CLOSE** API call is used - you cancel the payment from your side, and Tabby will not release funds to you.
However, when you use **CAPTURE** API call - you confirm all is good with the order from your side, Tabby will release funds to you.
* Close API call cancels the payment without capturing it. The downpayment is returned to the customer, the payment gets status CANCELLED on Tabby Merchant Dashboard: [https://docs.tabby.ai/api-reference/payments/close-a-payment](https://docs.tabby.ai/api-reference/payments/close-a-payment)
* Capture API call captures the payment, the payment gets status CAPTURED on Tabby Merchant Dashboard: [https://docs.tabby.ai/api-reference/payments/capture-a-payment](https://docs.tabby.ai/api-reference/payments/capture-a-payment)
## How can I verify Payments via Webhooks?
Main article: Webhooks.
There are 3 ways to secure the Webhook notifications:
* allow these IP-addresses for Webhooks:
```
34.166.36.90
34.166.35.211
34.166.34.222
34.166.37.207
34.93.76.191
34.166.128.182
34.166.170.3
34.166.249.7
```
* add static AUTH HEADER during webhook registration: [https://docs.tabby.ai/api-reference/webhooks/register-a-webhook](https://docs.tabby.ai/api-reference/webhooks/register-a-webhook)
* webhooks should be treated as notifications only. To verify the payment status, use the payment\_id from the webhook and call the getPayment API: [https://docs.tabby.ai/api-reference/payments/retrieve-a-payment](https://docs.tabby.ai/api-reference/payments/retrieve-a-payment)
## What should I do if Payments remain in status NEW in Tabby Merchant Dashboard?
Associated articles:
* Payment Statuses;
* Payment Processing.
### Self-Hosted Platforms
Self-Hosted Platforms are: **WooCommerce, Shopify, Magento 2, OpenCart**.
These payments are likely lost (not linked to any created order). Merchants should select one of the options:
* either cancel them (i.e., refund the customer): [https://docs.tabby.ai/api-reference/payments/close-a-payment](https://docs.tabby.ai/api-reference/payments/close-a-payment)
* or manually create an order for such payments, as they are authorized by Tabby, and capture payments: [https://docs.tabby.ai/api-reference/payments/capture-a-payment](https://docs.tabby.ai/api-reference/payments/capture-a-payment)
* or just capture them if the orders exist.
Additionally, merchants should update the plugin to the latest version (following Tabby documentation) and check the plugin settings to prevent similar cases in the future.
### Zid and Salla Platforms
By default, everything is expected to be working successfully when live keys are saved. If you suspect an issue or have lost orders, kindly re-save the keys and contact your platform's support team to verify the situation or register webhooks to prevent such issues.
### Custom (Direct API) Integrations
Merchants may have immediate or delayed captures, meaning NEW statuses may simply be waiting for merchant action. However, in many cases, these payments are also lost.
Merchants should select one of the options:
* either cancel them (i.e., refund the customer): [https://docs.tabby.ai/api-reference/payments/close-a-payment](https://docs.tabby.ai/api-reference/payments/close-a-payment)
* or manually create an order for such payments, as they are authorized by Tabby, and capture payments: [https://docs.tabby.ai/api-reference/payments/capture-a-payment](https://docs.tabby.ai/api-reference/payments/capture-a-payment)
* or just capture them if the orders exist.
Merchants should also check payment logs and investigate integration issues to determine why the payment wasn't acknowledged or captured in time (following Tabby documentation).
The Integrations team can assist with investigating API calls and webhooks - kindly contact them via the integrations thread or an assigned business manager.
### Tabby Card and Payment Links
These are always expected to be Auto-Captured. If they are not - kindly provide your store name with Tabby to Tabby Partner Support `partner@tabby.ai` / `partner@tabby.sa` or to your assigned business manager.
## What is Eligibility check?
Associated articles:
* Background Pre-scoring Check;
* Integration overview.
### How can I know that a customer is not eligible to use Tabby?
In the Tabby Session creation response, you can receive a status like this if a customer is not eligible to use Tabby:
```
"status": "rejected",
"configuration"."products"."installments"."rejection_reason": "not_available"
```
You need to hide Tabby payment option or show it with the General Rejection message or specific reason message depending on the "rejection\_reason" value:
| Reason | English | Arabic |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| General Rejection (`not_available`) | Sorry, Tabby is unable to approve this purchase. Please use an alternative payment method for your order. | نأسف، تابي غير قادرة على الموافقة على هذه العملية. الرجاء استخدام طريقة دفع أخرى. |
| `order_amount_too_high` | This purchase is above your current spending limit with Tabby, try a smaller cart or use another payment method | قيمة الطلب تفوق الحد الأقصى المسموح به حاليًا مع تابي. يُرجى تخفيض قيمة السلة أو استخدام وسيلة دفع أخرى. |
| `order_amount_too_low` | The purchase amount is below the minimum amount required to use Tabby, try adding more items or use another payment method | قيمة الطلب أقل من الحد الأدنى المطلوب لاستخدام خدمة تابي. يُرجى زيادة قيمة الطلب أو استخدام وسيلة دفع أخرى. |
For detailed implementation guide check here: Background Pre-scoring Check
### What is the difference between eligibility check and checkout session creation?
Tabby's Checkout API serves two distinct purposes. Here's a side by side comparison:
| Aspect | Eligibility Check | Checkout Session Creation |
| ------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------ |
| **Purpose** | Determine if customer can use Tabby | Create payment session for actual checkout |
| **Timing** | Before showing Tabby payment method | When customer clicks "Place order" |
| **Payload** | Minimal (amount, currency, buyer) | Complete (all order details, items, shipping, merchant URLs) |
| **Response** | Status (`created` or `rejected`) + rejection reason | Status + `web_url` for redirect + `payment.id` |
| **Next Step** | Show or hide / mark unavailable Tabby payment method based on the response | Redirect to Tabby Hosted Payment Page |
### Example of a minimal payload for eligibility check
```json theme={"dark"}
{
"payment": {
"amount": "340.00",
"currency": "SAR",
"buyer": {
"email": "otp.success@tabby.ai",
"phone": "+966500000001"
}
},
"merchant_code": "your_merchant_code"
}
```
**Key principle**: Use the same endpoint (`POST /api/v2/checkout`) but with different payload sizes for different purposes.
### When should I perform eligibility check?
Perform the eligibility check **once per checkout session** before displaying payment methods to customer, when you have the basic order details (amount, currency, buyer.phone, buyer.email).
**Best practices:**
* **Payload**: Include as much data as possible (not just minimal payload) for better approval rates and conversion
* **Timing**: Check eligibility when customer enters checkout page with all main data available
* **Error handling**: If API times out or returns error, default to showing Tabby option (fail-safe approach) - never block checkout
* **Two separate calls**: Eligibility check (minimal/recommended data) ≠ Session creation (complete order details when customer clicks "Place order")
## How should I validate checkout session response?
Always validate the checkout session response before redirecting the customer. Here are the critical validation steps:
**Critical Validation Steps**:
1. **Check `status` field** - must be `"created"`. If `"rejected"`, show rejection message and don't redirect;
2. **Validate `web_url` presence** - never redirect without it. Show rejection message if missing;
3. **Store `payment.id`** - required for subsequent capture/refund operations.
For complete validation logic and edge cases check here: Checkout Flow - Response Validation.
## Is it possible to know the rejection reason for payments?
Unfortunately, due to compliance and regulatory restrictions, Tabby is not permitted to disclose the specific rejection reasons to merchants. Customers, however, typically see a rejection message on the Tabby-hosted payment page at the time of the transaction.
If you suspect a technical issue that may be causing multiple or all transactions to be rejected - please, contact Tabby Partner Support at `partner@tabby.ai` (or `partner@tabby.sa` for KSA) or reach out to your assigned Business Manager. When doing so, kindly include:
1. your store name as registered with Tabby;
2. your integration details:
* website URL or app name (for online integrations);
* description of offline integration, if applicable.
## Are there any transaction limits set for my store from Tabby side?
Tabby applies transaction limits based on a combination of factors, including your industry and associated risk levels. Additionally, customer-level limits are dynamically determined based on their historical transaction behaviour with your store and with other merchants using Tabby.
For this reason, we recommend **not setting hardcoded limits** for Tabby transactions on your end, as these may conflict with Tabby's dynamic risk and approval models.
## What should I do if a customer is not redirected back to the website?
When customers finish the Tabby session, they are redirected back to your site from the Tabby Payment Page via one of the three merchant\_urls, with the payment\_id after the separator, e.g. [https://your-store/success?payment\_id=string](https://your-store/success?payment_id=string):
```
"merchant_urls": {
"success": "https://your-store/success",
"cancel": "https://your-store/cancel",
"failure": "https://your-store/failure"
}
```
The merchant\_urls should be included in a Session Creation request sent to Tabby from your side.
## What should I do if I do not receive fields in a response from Tabby API?
If some fields do not return in the response:
* check the endpoint used for the request;
* check the fields format in the request - they should match those specified in the API Reference Documentation;
* check responses in the API Reference Documentation and that these fields are expected to be returned.
## Where can I see if Tabby is working normally?
Status Page Recommendations. Associated article: Technical Requirements -> Status Page.
Recommendations for status page maintenance and incidents:
* Tabby sends alerts through [https://www.tabby-status.com/](https://www.tabby-status.com/). Please, subscribe using your preferred channel for updates.
* Tabby posts alerts manually in real-time within 5-10 minutes of identifying and confirming an issue. The alerts provide details about the affected systems.
* If Checkout or Payments APIs are affected for all countries, we recommend disabling Tabby until the next message confirms the resolution.
* If only one country is affected, you can disable Tabby for that specific country.
* If non-real-time systems are affected, no action is required (incident details will still be posted).
* If you see a Scheduled Technical Maintenance notification, you can plan disabling Tabby for that duration of the maintenance window or mute monitors if the expected timeframe is less than 10 minutes, as it will recover automatically.
* If you suspect an issue with any flow, you can contact Tabby Partner Support `partner@tabby.ai` / `partner@tabby.sa` for more details. However, if you observe that Tabby APIs are not working (e.g., consistently returning 5xx or 4xx errors), please contact the Tabby Integrations Team via the integration thread or via your assigned business manager immediately to investigate and resolve the issue. In the meantime, disable Tabby until the issue is resolved.
## General information
For additional support and information, you may also find helpful resources here: Tabby Support Center.
# Quick Start
Source: https://docs.tabby.ai/introduction/quick-start
Choose your integration type below. Use pre-built plugins for popular platforms or implement custom integration via Tabby API.
## Custom Integrations
## E-Commerce Platforms
# Technical Requirements
Source: https://docs.tabby.ai/introduction/technical-requirements
This page gives you the common knowledge about Tabby operating.
## Status Page
Tabby Status Page offers live status, maintenance alerts and incident history reports for Tabby Services. Please subscribe to our Status Page to stay informed about all changes and maintenance works and be able to manage your sales according to it.
## Security Protocol
**TLS** is an industry-standard protocol for encrypting network communications and establishing the identity of websites over the Internet. Tabby API supports TLS version 1.2 and higher. Additionally, we rely on **HTTPS** to ensure all data is transmitted securely.
Strongly restricted cipher suites for compliance with the Payment Card Industry Data Security Standard. Enhances payment card data security:
```
TLSv1.3:
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLSv1.2:
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
```
## Allowlist
Tabby uses several IP addresses when sending webhook requests and new IPs may be utilized as our systems scale and new resources are brought online. Please allow this list of IP addresses to prevent webhook calls from failing:
```
34.166.36.90
34.166.35.211
34.166.34.222
34.166.37.207
34.93.76.191
34.166.128.182
34.166.170.3
34.166.249.7
```
## Data Format
Request and response data are formatted as **JSON**. The following data formats are used across all Tabby APIs:
### Currency
We use the
ISO 4217 standard for defining currencies.
```JSON theme={"dark"}
{
"currency": "AED"
}
```
### Amount
We expect amounts in minor units according to the
ISO 4217 standard. That means they are formatted in the smallest unit of currency.
Tabby allows to send:
* up to **2 decimals** for *AED* and *SAR*;
* up to **3 decimals** for *KWD*.
```JSON theme={"dark"}
{
"amount": "100.00"
}
```
### Phone
The following mobile phone formats are accepted, using the UAE +971 mask and phone number as an example:
```JSON theme={"dark"}
{
"phone": "+971500000001" // OR "971500000001", "500000001", "0500000001"
}
```
### Merchant Code
Merchant code is a unique store identifier under one brand and should be sent as a string value. Usually merchant\_code represents a merchant country or a specific store within the country.
### Dates
The
ISO 8601 standard with combined Date and Time in UTC for all API dates. The exceptions to this are dob fields where we accept values in the **YYYY-MM-DD** format.
```JSON theme={"dark"}
{
"registered_since": "2019-08-24T14:15:22Z",
"dob": "2019-08-24"
}
```
### Locale
Operating in the GCC region, Tabby supports the English and Arabic languages and refers to the
RFC 1766 standard.
```JSON theme={"dark"}
{
"lang": "en"
}
```
### String Length Validation
We are processing a maximum of 255 symbols in the **"string"** field.
### Allowed characters in redirect URLs ("success", "cancel", "failure")
1. Latin letters (a-z, A-Z)
2. Arabic letters (ء-ي)
3. Digits (0-9)
4. Special characters - \ | / : ;., + \{}? & @ = # %
## Rate limit
API rate limiting is implemented to maintain stable operations for Tabby services. If an excessive number of requests are sent in a short time, rate limiting may be applied to your requests.
The response will include an HTTP status code 429 error when rate limiting is triggered.
Rate limits are enforced per API Key and are measured on a per-operation basis. Operations are categorized into **Create Session** and **Payment** operations.
* **Live API Keys**: The rate limit is 200 Create Session operations per 10 seconds, while other operations are limited to 100 requests per second.
* **Testing API Keys**: The rate limit is 10 requests per 10 seconds for Create Session operations and 50 requests per second for other operations.
Tabby doesn't allow any Performance testing with the Production APIs involved. Kindly exclude Tabby method from checkout when executing load or stress testing.
These Keys and IP addresses might be automatically limited by a firewall. Also such Test or Live API keys payments might be limited manually upon detection.
## Authentication
To authenticate with Tabby you will use your API credentials and HTTP basic auth.
These credentials consist of two elements:
* **Secret Key**: Associated with your merchant account, this key is used to authorize requests to Tabby’s Checkout and Payments APIs. Include the Secret key as an authorization header with every request.
* **Public Key**: Associated with your merchant account, this key is used for promo snippets, plans, and customization support.
Live API keys can be obtained:
* from Tabby Merchant Dashboard for **Self-Hosted plugin** integration;
* by contacting Tabby account manager after QA testing carried out by Tabby team is completed for **Custom API** integration.
If the credentials are missing or wrong, Tabby will respond with 401 Not authorized. More information on HTTP Basic auth can be found in the API Reference article.
## Errors
Tabby APIs use HTTP status codes alongside the error objects to handle errors. When an API call fails, Tabby will respond with a 4xx status code and a response body containing an error object with the error code, an array of error messages and a unique correlation ID to identify the request.
The error object contains an error\_code and an errorType value (or errors).
The error object is a human-readable English message to aid in debugging. The message is not meant to be displayable to end-users, nor it is meant to be machine-readable. It should be seen as something that the client would log to assist in debugging, but it's never meant to be in any way parsed by the client.
## Supported Browsers & Devices
We support all common-spread desktop and mobile browsers and mobile devices.
As part of our development process, we test among all major browsers and across different versions of browsers. However, we do not support browsers that no longer receive security updates. Please, contact us if you have an issue with Tabby Checkout on a specific browser so we can improve its support.
### Browsers & Versions
Chrome, Firefox, Safari and Microsoft Edge are supported on all platforms for three years from the version release. We also test across different mobile platforms: iOS 12 and above and Android 7 and above.
# What is Tabby?
Source: https://docs.tabby.ai/introduction/what-is-tabby
Tabby is MENA's biggest Buy Now Pay Later, operating in KSA, UAE and Kuwait. Tabby lets merchants grow their business by offering their shoppers flexible payments, and is constantly growing its product offering.
* Pay in Installments - Split your purchase into several payments
* Online - easily through nearly any e-commerce platform
* In-Store - with the Tabby Card, through paylinks or with a QR code
* Pay next month - Pay for groceries, food, rides at the end of the month
# Marketing Guidelines
Source: https://docs.tabby.ai/marketing/approved-messaging
Use these guidelines any time Tabby appears in your communications: your own copy, your ads, your store. This page covers how to talk about Tabby: which message to lead with for your business, the approved language to use, the phrases to avoid and the disclaimers each market requires.
## Choosing the right messaging
Tabby gives your shoppers more than one way to pay. The bigger the cart, the longer they can choose to spread it, from 4 months up to 12.
What a shopper sees depends on their cart, not anything you configure. So tailor your copy to the plan that fits your typical basket.
### Pay in 4
Splits any purchase into 4 payments. This is your default. It works for every cart size and every channel, so lead with it unless the rule below applies.
### Pay over time
Offers longer plans on larger purchases. Shoppers can choose how long to spread the cost, up to 12 months.
Pay over time is available on purchases above SAR 1,000 / AED 100. Lead with this messaging if you sell high-ticket items like electronics, furniture, jewellery or travel.
### Core messages
These are your building blocks. Use them as-is or adapt within the approved language below.
| Market | | Lead message | Supporting line |
| :------ | :----------------------- | :------------ | :------------------------------------------- |
| **KSA** | Items under SAR 1,000 | Pay it in 4 | 0% interest. No late fees. |
| | Items SAR 1,000 and over | Pay over time | Up to 12 months. No late fees. |
| **UAE** | Items under AED 100 | Pay it in 4 | No fees. No interest. |
| | Items AED 100 and over | Pay over time | 4 interest-free payments or up to 12 months. |
### More approved phrases
You can copy and paste these directly:
* Pay later with Tabby
* Pay over time with Tabby
* Tabby available at checkout
* Get more time to pay with Tabby
* Now accepting Tabby
## What to avoid
Some phrases feel natural but create misleading impressions—and aren't permitted. Here's the full list.
| Don't say | Why | Say this instead |
| :---------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------- |
| Free / it's free / no cost | Misleading. Only Pay in 3 (KSA) and Pay in 4 (UAE) have no cost, so it doesn't cover all scenarios. | Use the approved core messages above for your product and market. |
| Interest-free \[standalone] | Only permitted paired with "when you pay in 4" in the UAE. | "4 interest-free payments or up to 12 months"—UAE only. |
| Instalments | We prefer "payments" because instalments have connotations of interest and fees. | 4 payments |
| Affordable / cheap | Tabby doesn't reduce the cost of a purchase. | Pay over time / spread your payments |
| No credit checks / instant approval / guaranteed acceptance | Customers are subject to eligibility criteria. | Select Tabby at checkout |
| Strapped for cash? / Don't wait until payday | Encourages spending beyond means. We have an obligation to ensure our customers stay financially healthy. | Focus on flexibility and cash flow: "More flexibility with how you pay", "More ways to pay, more room to plan" |
## Disclaimer requirements
Any communication referencing Tabby's financial terms needs a disclaimer. No exceptions.
### UAE disclaimer
> Pay Later (Short Term Credit) is provided by Tabby LLC. Terms and conditions apply.
> For more information or to contact us, visit tabby.ai.
### Saudi disclaimer
> Shariah-compliant.
> Tabby Financing Company JSC is subject to the control and supervision of the Saudi Central Bank. Call us on 800 111 0999.
## Brand usage
* Always write Tabby with a capital T: not *TABBY*, not *tabby*
* Use the Tabby logo and assets as provided. Don't modify colours, proportions or fonts
* Don't refer to Tabby as a credit card or loan. It's buy now, pay later or flexible payments
# Logos
Source: https://docs.tabby.ai/marketing/brand-assets
Download the files, use them as provided. A few things to know before you place them.
## Choosing the right logo
The pack includes 2 logo types and 3 colourways. Here's when to use each.
### Wordmark vs. icon
Use the **Tabby wordmark** (the full name) as the default everywhere. Use the **standalone T icon** only in very small spaces where the wordmark won't read, such as in a row of accepted payment method logos.
### Colourways
The primary colourway is a black logo on Tabby green. When that's not possible, use the green or white logo variants to maintain contrast. Never place the logo on a busy background or anywhere the logo is hard to read.
### Don't modify the files
Use the logos exactly as downloaded. Don't recolour, rotate, stretch or apply any effects. If you're building co-branded materials with your own logo alongside Tabby's, match the two logos in size.
All formats: PNG, SVG, AI. Light and dark variants included.
# Email Assets
Source: https://docs.tabby.ai/marketing/email-assets
Your email list is full of customers who already want to buy from you. Adding Tabby to your campaigns and flows removes the price hesitation that stops them completing a purchase, turning existing engagement into more revenue.
## Make every send work harder
**Launch announcement**\
Your existing customer base already trusts you. Telling them you now offer Tabby gives them a new reason to come back and buy something they've been holding off on.
**Campaigns and newsletters**\
A single Tabby banner near your call-to-action button gives hesitating shoppers the nudge to purchase, without redesigning your email.
Add Tabby messaging to your announcements, promotions and cart abandon emails.
# In-store Assets
Source: https://docs.tabby.ai/marketing/in-store-assets
Most shoppers won't ask if you offer flexible payments. They will see the full price, decide it's too much in one go and leave. In-store Tabby signage answers the question before they ask it.
At the entrance, customers walk in knowing they can split the cost. At the shelf, a higher-ticket item becomes easier to pick up. At the register, the last moment of hesitation disappears. That's more conversions from the customers already in your store, without spending anything more on acquisition.
## Request a free in-store pack
We'll send you tent cards, stickers and Tabby badges, ready to place around your store.
[→ Request your in-store collateral](https://survey.tabby.ai/r/BzgB0e)
## Download and print yourself
Get the print-ready files and print them with your own supplier, in the country, language and payment solution you need.
Checkout sticker
Tabby badge
Tent card
Window sticker
Wobbler
Price tag
Easel
Tag label
## Brief your store staff
Give your team the guidelines for placing Tabby collateral and talking about it with shoppers.
[→ In-store guidelines](https://drive.google.com/drive/folders/1Hkw858zouACB-Km4V5osgzFESAUbAh7e?usp=drive_link)
# Social Media Assets
Source: https://docs.tabby.ai/marketing/social-media-assets
You've added Tabby, now tell your audience. A launch post does two things: it brings back customers who've browsed without buying, and it tells new visitors you offer a more flexible way to pay before they've even landed on your site. The templates below give you ready-to-use design templates and copy for the announcement.
Simple post layouts you can recreate quickly or use directly on your socials to show shoppers you offer Tabby.
## Get more from every post
* Lead with the benefit, not the brand name. "Pay in 4, no interest" outperforms "Tabby is now available"
* Animated assets drive higher engagement than static. Use them for paid
* For Stories and Reels, one line of text is enough. The asset does the work
# Marketing Toolkit
Source: https://docs.tabby.ai/marketing/toolkit
Customers who know you offer Tabby spend more and come back more often. This toolkit has everything you need to spread the word: on your site, in your store and everywhere in between.
Pick a channel. Grab the assets. Go.
## What's in here
Which message to lead with, approved language and required disclaimers
Official Tabby logos and icons, and how to use them
Banners and on-site snippets that show Tabby alongside your prices
Add Tabby to your campaigns and flows to turn engagement into revenue
Ready-to-use templates and copy for your launch announcement
Signage for the entrance, the shelf and the register
# Website / App Assets
Source: https://docs.tabby.ai/marketing/website-app-assets
Price is the number one reason shoppers don't buy. Banners and on-site snippets show Tabby's split payment right alongside the price, making the cost feel manageable before it becomes a reason to leave.
Ready-to-use banners sized for homepage, product pages and cart.
Place Tabby's ready-made snippets on product, cart and checkout pages to reinforce the flexibility Tabby offers on payments.
# Custom Payment Links Integration
Source: https://docs.tabby.ai/offline-payment-methods/custom-payment-links
## Integration Overview
This integration allows customers to pay using Tabby by receiving a payment link via SMS/Push. The flow involves:
1. Creating a payment session
2. Sending payment link to customer
3. Customer completes payment on their device
4. Merchant receiving payment confirmation
To implement sending payment link via SMS/Push from Tabby side to a customer a POST request to an API endpoint `/api/v2/checkout/{id of session}/send_hpp_link` should be triggered from your side first. Instructions on how and when to implement it can be found below.
## Quick Reference
| **API Endpoint** | **Purpose** | **Method** |
| ------------------------------------------------ | ------------------------------ | ---------- |
| `/api/v2/checkout` | Create session and payment | POST |
| `/api/v2/checkout/{id of session}/send_hpp_link` | Send payment link via SMS/Push | POST |
| `/api/v2/payments/{payment.id}` | Retrieve payment status | GET |
| `/api/v2/checkout/{id of session}/cancel` | Cancel session | POST |
| **Key Status Codes** | **Description** |
| ------------------------------- | ------------------------------------------ |
| `CREATED` | Payment initiated, waiting for completion |
| `AUTHORIZED` | Payment approved, not yet captured |
| `CLOSED` with "captures" object | Payment approved and captured successfully |
| `REJECTED` | Payment declined |
| `EXPIRED` | Session/payment expired or cancelled |
## Steps to Integrate Tabby using Custom Payment Links
Register with Tabby
(KSA: merchant.tabby.sa)
and finish the application
)}
/>
Collect the Test API Keys and Merchant codes from Tabby Merchant Dashboard or your Tabby Account manager
)}
/>
Set up the
Tabby session creation from your terminal
)}
/>
Make sure a payment link is successfully
sent as an SMS to the customer
)}
/>
Set up
Payment Processing
on your Backend
)}
/>
Once the payment is complete -
print the receipt for the customer
)}
/>
Test your Integration,
contact Tabby Integrations Team in the Integration email thread to complete the testing process
)}
/>
After successful testing passed receive the Live API keys and deploy to production
)}
/>
## Integration Flow
```mermaid theme={"dark"}
sequenceDiagram
autonumber
participant Customer
participant POS as POS Terminal
participant Provider as POS Backend
participant Checkout as Tabby Checkout
participant TabbyAPI as Tabby API
Customer ->>+ POS: Request to pay with Tabby
POS ->>+ Provider: Initiate payment
Provider ->>+ TabbyAPI: POST /api/v2/checkout
{ amount, buyer.phone, ... }
TabbyAPI -->>- Provider: Response
{ id of session, status of session, payment.id, web_url }
alt "status" of session == "created"
Provider ->>+ TabbyAPI: POST /api/v2/checkout/{id of session}/send_hpp_link
TabbyAPI -->>- Customer: Send checkout link via SMS/Push
Provider -->> POS: Display "Waiting
for customer payment"
Note right of Customer: Customer receives
and opens the link
else "status" of session == "rejected"
Provider -->> POS: Return "Payment rejected"
POS -->> Customer: Show failure screen
Note right of Customer: A different payment method
should be selected
end
Customer ->>+ Checkout: Open Tabby Checkout and go through payment steps
loop Tabby checkout steps
Checkout -->> Customer: Guide through required steps
end
opt
alt Cashier cancels
POS -->> Provider: Cancel request
Provider -->> TabbyAPI: POST /api/v2/checkout/{id of session}/cancel
else Customer cancels
Customer -->> Checkout: Clicks 'Cancel' button on Tabby Checkout Page
end
end
Provider ->>+ TabbyAPI: Check payment status
(GET /api/v2/payments/{payment.id})
TabbyAPI -->>- Provider: { payment.status:
AUTHORIZED | CLOSED | REJECTED | EXPIRED }
Note over Provider,TabbyAPI: Or receive webhook with the same status
alt payment.status ==
"AUTHORIZED" OR "CLOSED"
Provider -->> POS: Payment successful
POS -->> Customer: Show success screen, Print receipt
else payment.status ==
"REJECTED" or "EXPIRED"
Provider -->> POS: Payment failed
POS -->> Customer: Show failure screen
end
```
## Create Session and Payment Using Checkout API
Call the Create a session API. The required payload parameters for the session:
```JSON theme={"dark"}
{
"payment": {
"amount": "string", // Up to 2 decimals for AED and SAR, 3 decimals for KWD, e.g. 100.00
"currency": "string", // Use the ISO 4217 standard for defining currencies: AED, SAR, KWD
"buyer": {
"phone": "string" // Required for sending Payment link
},
"order": {
"reference_id": "string", // Merchant's Order Number to match the order with the payment.id
"items": [
{
"title": "string", // Name of the product.
"quantity": 1, // Quantity of the product ordered. Should be >= 1
"unit_price": "0.00", // Price per unit of the product. Should be positive or zero.
"category": "string" // Required as name of high-level category (Clothes, Electronics,etc.)
}
]
},
"attachment": {
"body": "{\"latitude\": latitude of the terminal as float,\"longitude\": longitude of the terminal as float,\"timestamp\": \"timestamp of the purchase in UTC, displayed in ISO 8601 datetime format\"}", // Example: "\"latitude\":24.4763,\"longitude\":54.3209,\"timestamp\": \"2026-02-27T14:35:10.123Z\""
"content_type": "application/vnd.tabby.v1+json"
},
},
"merchant_code": "string" // Merchant's branch code or MID
}
```
Even though other parameters are technically optional for offline integration, we highly recommend sharing other data marked as required in the API Docs, as additional data allows Tabby to increase the AOVs and conversion approval rates.
### Eligibility Check
As a response you receive one of the two session statuses - "created" or "rejected":
* if the session status is "created" - save the **id of the session** (will be required for cancellation step) and **payment.id** (will be required for payment status check and refund steps) received in the response:
```
"status": "created"
"id": "string" // ID of the session
"payment"."id":"string" // ID of the payment
```
* if the session status is "rejected" - show the Payment failure screen and offer the customer an alternative payment method.
Please, do not proceed with any further steps with Tabby. The rejection might be related to order amount being too high, disabled branch code, or other reasons.
The response payload will contain the following:
```
"status": "rejected",
"configuration"."products"."installments"."rejection_reason": "string" // reason for rejection
```
The "rejection\_reason" field can take the following values, you may optionally add human readable messages for cashier:
| Reason | English | Arabic |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `not_available` | Sorry, Tabby is unable to approve this purchase. Please use an alternative payment method for your order. | نأسف، تابي غير قادرة على الموافقة على هذه العملية. الرجاء استخدام طريقة دفع أخرى. |
| `order_amount_too_high` | This purchase is above your current spending limit with Tabby, try a smaller cart or use another payment method | قيمة الطلب تفوق الحد الأقصى المسموح به حاليًا مع تابي. يُرجى تخفيض قيمة السلة أو استخدام وسيلة دفع أخرى. |
| `order_amount_too_low` | The purchase amount is below the minimum amount required to use Tabby, try adding more items or use another payment method | قيمة الطلب أقل من الحد الأدنى المطلوب لاستخدام خدمة تابي. يُرجى زيادة قيمة الطلب أو استخدام وسيلة دفع أخرى. |
## Customer payment options
* **First option: Send the Payment Link** to the customer via SMS using **send\_hpp\_link API** (provided in a Postman Collection). You can use this method only if you receive a "created" status in the response to the previous request.
* **Second option: use the POS QR Code integration** as a fallback option.
## Payment Processing
Verify the payment status using:
* Webhooks
* or Retrieve Payment API call
### Webhooks
* Tabby sends you a notification payment status update. The initial payment status is CREATED.
* If the Webhook with the authorized or closed status is received - mark the order as successful in your OMS. You can ignore other Webhooks received for this payment.id.
* If the Webhook returns a rejected status - mark the payment as unsuccessful and ask the customer to pay with another payment method.
* If no status is received - the cashier should have an option to cancel the payment.
**Optional**: You can also add a cancel button using the Cancel Session API (provided in a Postman Collection) when you want to expire the Tabby session if a customer asks to pay with another payment method or start a new Tabby session.
### Retrieve Request
An alternative way to verify a payment status is by polling status with the Retrieve Payment API call. You can call Retrieve Request by cron or by cashier's action (add button **Check status** to the POS). The following statuses can be received:
* CREATED - the payment has not been completed yet, wait for it to change to one of the terminal statuses.
* AUTHORIZED or CLOSED - a payment was placed successfully, mark orders as successful and proceed with the order on your POS/OMS.
* REJECTED or EXPIRED - a payment is not successful. Ask the customer to pay with a different payment method.
**You can use both** Retrieve Payment API call and Webhooks methods for speed and reliability.
It is an expected behaviour that webhooks return payment status in lower case - e.g., authorized, while Retrieve Request - in upper case: AUTHORIZED.
### Cancel a Payment
A request to cancel a payment is available in the Postman collection. The payment can only be canceled if its status is CREATED. Once canceled - the status will change to EXPIRED.
If the payment has already been authorized, attempting to cancel it will return the following error: 400 Bad Request
```JSON theme={"dark"}
{
"status": "error",
"errorType": "bad_data",
"error": "session is finalized"
}
```
In this case check the payment status via the Retrieve Payment API call and verify the status is AUTHORIZED or CLOSED. Then show a success screen, print a receipt and proceed with the order.
The Cancel API does not refund payments and can only be used to expire not finalised sessions. Once the payment receives one of the terminal statuses - AUTHORIZED, CLOSED, REJECTED or EXPIRED - the session cannot be cancelled.
### Refund a Payment
You can process a Full or Partial Refund. Call Refund API for a specific payment.id with the desired amount. You can find the payment.id by matched payment.order.reference\_id in your OMS.
You can also process a refund from the Tabby Merchant Dashboard.
Only payment in status CLOSED with a captured amount present in the "captures":\[] array of objects can be refunded.
*On Merchant Dashboard such payment will have status CAPTURED.*
## Print a Receipt
Show a success screen and print a receipt. The receipt data can be used to identify the order and payment, and (optionally) initiate a refund if your POS system provides this functionality.
| Receipt data template |
| ------------------------------- |
| Merchant Order / Transaction ID |
| Date and Time |
| Tabby logo |
| Tabby Payment ID (optional) |
| Merchant name (optional) |
## Testing Scenarios
Kindly verify that your integration can handle all listed below scenarios.
### 1. Payment Success
**Testing Steps:**
1. From a Cashier's POS choose Tabby.
2. Enter payment amount and a real phone number to receive the real payment link.
If your phone number is not eligible for Tabby and the session is rejected, use another phone number or contact Tabby Integrations Team.
3. Open received payment link.
4. On Tabby Checkout page enter credentials:
```
Positive flow:
UAE: otp.success@tabby.ai, phone: +971500000001
KSA: otp.success@tabby.ai, phone: +966500000001
Kuwait: otp.success@tabby.ai, phone: +96590000001
```
5. Complete the payment using OTP:8888 on Tabby Checkout Page.
6. Verify that the successful payment status is received.
**Expected Results:**
1. Session creation response has status "created" - the customer is eligible to use Tabby.
2. A payment link is successfully sent as an SMS to the customer and Tabby Checkout Page opened.
3. Credentials are entered.
4. The success Tabby screen appears.
5. Payment is successful and captured:
* on Merchant Dashboard payment status is CAPTURED
* via a Retrieve Payment API call response Payment status is CLOSED, captured amount is present in the "captures":\[] array of objects.
If a payment status remains NEW on the Merchant Dashboard or AUTHORIZED via Retrieve Payment API call - kindly contact your Tabby Account manager or `partner@tabby.ai` / `partner@tabby.sa` to update auto-capture settings.
### 2. Eligibility Check Reject
**Testing Steps:**
1. From a Cashier's POS choose Tabby.
2. The session should be created with the following phone number:
```
Eligibility Check Reject flow:
UAE: +971500000002
KSA: +966500000002
Kuwait: +96590000002
```
**Expected Results:**
1. Session creation response has status "rejected" - the customer is **not** eligible to use Tabby.
* **Optionally**: one of the rejection reasons can be shown to cashier.
### 3. Payment Cancellation
**Testing Steps:**
1. From a Cashier's POS choose Tabby.
2. Enter payment amount and a real phone number to receive the real payment link.
If your phone number is not eligible for Tabby and the session is rejected, use another phone number or contact Tabby Integrations Team.
3. Open received payment link.
4. Click 'Cancel' button on Tabby Checkout Page or cancel the payment from a Cashier's POS.
5. Verify the payment status via Retrieve Payment API.
**Expected Results:**
1. Session creation response has status "created" - the customer is eligible to use Tabby.
2. A payment link is successfully sent as an SMS to the customer, Tabby Checkout Page opens.
3. A session is cancelled.
4. On checking Payment Status via Retrieve Payment API call it should be EXPIRED.
By default, Tabby session expires after **20 minutes** since creation and customer is not able to continue the session. This **session expiry timeout** can be reduced by the request from the Merchant side to your assigned business manager in the Integrations thread.
A payment status may change to "EXPIRED" after **session expiry timeout + 5 minutes** (20 + 5 by default). After that the payment will remain in status "EXPIRED", no need to check it further.
### 4. Payment Failure
**Testing Steps:**
1. From a Cashier's POS choose Tabby.
2. Enter payment amount and a real phone number to receive the real payment link.
If your phone number is not eligible for Tabby and the session is rejected, use another phone number or contact Tabby Integrations Team.
3. Open received payment link.
4. On Tabby Checkout page enter credentials:
```
Negative flow:
UAE: otp.rejected@tabby.ai, phone: +971500000001
KSA: otp.rejected@tabby.ai, phone: +966500000001
Kuwait: otp.rejected@tabby.ai, phone: +96590000001
```
5. Finish the payment using OTP:8888 on Tabby Checkout Page.
6. Verify the payment status via Retrieve Payment API.
**Expected Results:**
1. Session creation response has status "created" - the customer is eligible to use Tabby.
2. A payment link is successfully sent as an SMS to the customer.
3. Tabby Checkout Page opens, credentials are entered.
4. The rejection screen with the message 'We can't approve this purchase' appears.
5. On checking Payment Status via Retrieve Payment API call it should be REJECTED.
## Postman Collection
1. Download the JSON file and import it into Postman.
2. Set your base\_url, secret\_key, merchant\_code, and currency in Collection Variables. See Base URLs for regional domains.
Payment Links / POS Collection
This API collection is used for both POS Integration and Custom Payment Links integration and includes all the integration steps.
# POS Integration
Source: https://docs.tabby.ai/offline-payment-methods/pos-integration
## Integration Overview
This integration allows customers to pay using Tabby by scanning a QR code displayed on the POS terminal. The flow involves:
1. Creating a payment session
2. Displaying QR code on POS screen
3. Customer scans QR code and completes payment
4. Merchant receives payment confirmation
## Quick Reference
| **API Endpoint** | **Purpose** | **Method** |
| ---------------------------------------------- | -------------------------- | ---------- |
| `/api/v2/checkout` | Create session and payment | POST |
| `/api/v2/checkout/{id of session}/hpp_link_qr` | Get QR code image (PNG) | GET |
| `/api/v2/payments/{payment.id}` | Retrieve payment status | GET |
| `/api/v2/checkout/{id of session}/cancel` | Cancel session | POST |
| **Key Status Codes** | **Description** |
| ------------------------------- | ------------------------------------------ |
| `CREATED` | Payment initiated, waiting for completion |
| `AUTHORIZED` | Payment approved, not yet captured |
| `CLOSED` with "captures" object | Payment approved and captured successfully |
| `REJECTED` | Payment declined |
| `EXPIRED` | Session/payment expired or cancelled |
## Steps to Integrate Tabby with your POS
Register with Tabby
(KSA: merchant.tabby.sa)
and finish the application
)}
/>
Collect the Test API Keys and Merchant codes from Tabby Merchant Dashboard or your Account Manager
)}
/>
Set up the
Tabby session creation from your terminal
)}
/>
Show a
QR code on the POS screen
)}
/>
Set up
Payment status check
on your Backend. This can be done automatically by checking until the payment is completed or manually from the POS
)}
/>
Once the payment is complete -
print the receipt for the customer
)}
/>
Test your Integration,
contact Tabby Integrations Team in the Integration email thread to complete the testing process
)}
/>
After successful testing, receive the Live API keys and deploy to production
)}
/>
## Integration Flow
```mermaid theme={"dark"}
sequenceDiagram
autonumber
participant Customer
participant POS as POS Terminal
participant Provider as POS Backend
participant Checkout as Tabby Checkout
participant TabbyAPI as Tabby API
Customer ->> POS: Request to pay with Tabby
POS ->> Provider: Initiate payment
Provider ->> TabbyAPI: POST /api/v2/checkout {amount, ...}
TabbyAPI -->> Provider: Response {id of the session, status of the session,
payment.id, web_url, qr_code}
alt "status" of session == "created"
Provider -->> POS: Return QR Code
POS -->> Customer: Show QR Code
else "status" of session == "rejected"
Provider -->> POS: Return "Payment rejected"
POS -->> Customer: Show failure screen
end
Customer ->> Checkout: Scans QR Code and go through payment steps
loop Tabby checkout steps
Checkout -->> Customer: Guide through required steps
end
opt Cashier cancels or timeout (300 seconds)
POS -->> Provider: Cancel or timeout
Provider -->> TabbyAPI: POST /api/v2/checkout/{id of session}/cancel
end
Provider ->> TabbyAPI: Check payment status
(GET /api/v2/payments/{payment.id})
TabbyAPI -->> Provider: {payment.status:
AUTHORIZED | CLOSED | REJECTED | EXPIRED}
Note over Provider,TabbyAPI: Or receive webhook with the same status
alt payment.status ==
"AUTHORIZED" or "CLOSED"
Provider -->> POS: Payment successful
POS -->> Customer: Show success screen, Print receipt
else payment.status ==
"REJECTED" or "EXPIRED"
Provider -->> POS: Payment failed
POS -->> Customer: Show failure screen
end
```
## Create Session and Payment Using Checkout API
Call the Create a session API. The required payload parameters for the POS session:
```JSON theme={"dark"}
{
"payment": {
"amount": "string", // Up to 2 decimals for AED and SAR, 3 decimals for KWD, e.g. 100.00
"currency": "string", // Use the ISO 4217 standard for defining currencies: AED, SAR, KWD
"order": {
"reference_id": "string" // Merchant's Order or Transaction ID to match with the Tabby Payment ID
},
"description": "string", // Unique terminal id
"attachment": {
"body": "{\"latitude\": latitude of the terminal as float,\"longitude\": longitude of the terminal as float,\"timestamp\": \"timestamp of the purchase in UTC, displayed in ISO 8601 datetime format\"}", // Example: "\"latitude\":24.4763,\"longitude\":54.3209,\"timestamp\": \"2026-02-27T14:35:10.123Z\""
"content_type": "application/vnd.tabby.v1+json"
},
},
"merchant_code": "string" // Merchant's branch code or MID
}
```
### Eligibility Check
As a response you receive one of the two session statuses - "created" or "rejected":
* if the session status is "created" - save the **id of the session** (will be required for cancellation step) and **payment.id** (will be required for payment status check and refund steps) received in the response:
```
"status": "created"
"id": "string" // ID of the session
"payment"."id":"string" // ID of the payment
"configuration"."available_products.installments[0].qr_code": "string" // QR code link which you can use to get the image of the QR code and show it on the POS screen
"configuration"."available_products.installments[0].web_url": "string" // Session link, if you want to use it to generate your own QR code
```
* if the session status is "rejected" - show the Payment failure screen and offer the customer an alternative payment method. Please, do not proceed with any further steps with Tabby. The rejection might be related to order amount being too high, disabled branch code, or other reasons. The response payload will contain the following:
```
"status": "rejected"
```
## Show QR Code
When the session has status "created" you will receive two links in the response. Use either of them to show the QR Code on the POS screen:
| **Response field** | **What it returns** | **When to use** |
| ---------------------------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `configuration.available_products.installments[0].qr_code` | A link to a **ready-to-display QR code image** (PNG, 200×200 px) | **Recommended.** Fetch the image with a plain HTTP GET and render it directly on the POS screen — no QR generation library is required |
| `configuration.available_products.installments[0].web_url` | The Tabby Checkout session link | Generate your own QR code from this link if you need a custom size or design |
### Using the Ready-Made QR Image
The qr\_code link points to the GET /api/v2/checkout/\{id of session}/hpp\_link\_qr endpoint, which responds with a black-and-white PNG image (Content-Type: image/png, 200×200 px, under 1 KB):
* Use the link **exactly as returned** in the session response — do not construct or modify it manually, all required query parameters are already included.
* The request requires **no authentication headers**, so the POS application can fetch the image directly, without proxying it through your backend.
* Render the PNG in a native image component (for example, an ImageView on Android-based POS terminals) — no WebView or browser is needed.
### QR Code Display Recommendations
* **Size.** Display the QR code at least **3×3 cm** on the physical screen. When upscaling the 200×200 px image, use integer scale factors with nearest-neighbor (non-smoothing) scaling so the QR modules stay sharp. If your framework only supports smooth scaling, generate your own QR code from web\_url at the native resolution instead.
* **One code per payment.** The QR code is unique for each payment session. Never cache or reuse the image between payments — fetch a fresh one for every new session.
* **Fallback.** If the image fails to load (for example, due to a network error), create a new payment session and show the QR code from the qr\_code link of the new response.
## Payment Processing
Once QR Code is shown, check the payment status using the Retrieve Payment API call. We recommend calling the Retrieve API **every 5 seconds** until a terminal status is received. Alternatively, you can add a **“Check status”** button on the POS terminal to manually check this.
The following statuses can be received:
* CREATED - the payment has not been completed yet, wait for it to change to one of the terminal statuses.
* AUTHORIZED or CLOSED - the payment is successful, mark order as successful, print a receipt.
* REJECTED or EXPIRED - the payment is not successful. Ask the customer to pay with a different payment method.
### Cancel a Payment
A request to cancel a payment is available in the Postman collection.
You can cancel a payment in two cases:
1. The cashier presses the “Cancel” button on the POS.
2. Automatically, after a timeout. The **recommended** period is **300 seconds**, but the timeout should **never be less than 180 seconds**.
The payment can only be canceled if its status is CREATED. Once canceled - the status will change to EXPIRED.
If the payment has already been successful, attempting to cancel it will return the following error: 400 Bad Request
```JSON theme={"dark"}
{
"status": "error",
"errorType": "bad_data",
"error": "session is finalized"
}
```
In this case check the payment status via the Retrieve Payment API call and verify the status is AUTHORIZED or CLOSED. Then show a success screen, print a receipt and proceed with the order.
The Cancel API does not refund payments and can only be used to expire not finalised sessions. Once the payment receives one of the terminal statuses - AUTHORIZED, CLOSED, REJECTED or EXPIRED - the session cannot be cancelled.
### Refund a Payment
You can process a Full or Partial Refund. Call Refund API for a specific payment.id with the desired amount. You can find the payment.id by matched payment.order.reference\_id in your OMS.
You can also process a refund from the Tabby Merchant Dashboard.
Only payment in status CLOSED with a captured amount present in the "captures":\[] array of objects can be refunded.
*On Merchant Dashboard such payment will have status CAPTURED.*
## Print a Receipt
Show a success screen and print a receipt. The receipt data can be used to identify the order and payment, and (optionally) initiate a refund if your POS system provides this functionality.
| Receipt data template |
| ------------------------------- |
| Merchant Order / Transaction ID |
| Date and Time |
| Tabby logo |
| Tabby Payment ID (optional) |
| Merchant name (optional) |
## Recommended Designs
Native Screen POS Journey
## Testing Scenarios
Kindly verify that your integration can handle all listed below scenarios.
### 1. Payment Success
**Testing Steps:**
1. Choose Tabby on the POS terminal and enter the payment amount, press Enter.
2. Show the QR code on the POS terminal for the customer to scan.
3. On Tabby Checkout Page enter credentials:
```
Positive flow:
UAE: otp.success@tabby.ai, phone: +971500000001
KSA: otp.success@tabby.ai, phone: +966500000001
Kuwait: otp.success@tabby.ai, phone: +96590000001
```
4. Complete the payment using OTP:8888 on Tabby Checkout page.
5. Verify that the successful status is received.
**Expected Results:**
1. Session creation response has status "created", and a QR code is shown successfully on the POS screen.
2. Tabby Checkout Page opens from the QR code.
3. Credentials are entered.
4. The success Tabby screen appears.
5. Payment is successful and captured:
* on Merchant Dashboard payment status is CAPTURED
* via a Retrieve Payment API call response Payment status is CLOSED, captured amount is present in the "captures":\[] array of objects.
If a payment status remains NEW on the Merchant Dashboard or AUTHORIZED via Retrieve Payment API call - kindly contact your Tabby Account manager or `partner@tabby.ai` / `partner@tabby.sa` to update auto-capture settings.
### 2. Tabby Unavailable / API Error Handling
**Testing Steps:**
1. Choose Tabby on the POS terminal and enter a payment amount.
2. Simulate one of the following failure scenarios on the Create a session API call:
* **No response from Tabby** - network timeout or loss of connectivity.
* **Error response from Tabby** - any 4xx or 5xx status code.
* **Incomplete response** - session is received but configuration.available\_products.installments\[0].qr\_code and web\_url are not present.
3. Observe POS behavior while the terminal attempts to create the session and display a QR code.
4. Select an alternative payment method on the POS terminal to complete the order.
**Expected Results:**
1. Tabby is present among payment methods on the POS terminal.
2. Session creation does not complete successfully - the POS receives no response, an error status, or an incomplete payload.
3. No QR code is shown; a failure screen or error message is displayed to the cashier, prompting to retry or select an alternative payment method. No payment is created in Tabby.
4. The order can be completed via another payment method on the POS terminal.
### 3. Payment Cancellation
**Testing Steps:**
1. Choose Tabby on the POS terminal and enter the payment amount.
2. Show the QR code on the POS terminal for the customer to scan.
3. Click cancel (Cross icon) on Tabby Checkout page (you may also cancel the session from your POS terminal).
**Expected Results:**
1. Tabby is present among payment methods on POS terminal.
2. Session creation response has status "created", and a QR code is shown successfully on the POS screen.
3. Tabby Checkout Page opens, a session is cancelled. On checking Payment Status via Retrieve Payment API call it should be EXPIRED status. A new session can be created from POS terminal.
By default, Tabby session expires after **20 minutes** since creation and customer is not able to continue the session. This **session expiry timeout** can be reduced by the request from the Merchant side to your assigned business manager in the Integrations thread.
### 4. Payment Failure
**Testing Steps:**
1. Choose Tabby on the POS terminal and enter the payment amount.
2. Show the QR code on the POS terminal for the customer to scan.
3. On Tabby Checkout Page enter credentials:
```
Negative flow:
UAE: otp.rejected@tabby.ai, phone: +971500000001
KSA: otp.rejected@tabby.ai, phone: +966500000001
Kuwait: otp.rejected@tabby.ai, phone: +96590000001
```
4. Finish the payment using OTP:8888 on Tabby Checkout page.
5. Verify the payment status via Retrieve Payment API.
**Expected Results:**
1. Tabby is present among payment methods on POS terminal.
2. Session creation response has status "created", and a QR code is shown successfully on the POS screen.
3. Tabby Checkout Page opens, credentials are entered.
4. The rejection screen with the message 'We can’t approve this purchase' appears.
5. On checking Payment Status via Retrieve Payment API call it should be REJECTED.
## Postman Collection
1. Download the JSON file and import it into Postman.
2. Set your base\_url, secret\_key, merchant\_code, and currency in Collection Variables. See Base URLs for regional domains.
Payment Links / POS Collection
This API collection is used for both POS Integration and Custom Payment Links integration and includes all the POS steps.
# Checkout Flow
Source: https://docs.tabby.ai/pay-in-4-custom-integration/checkout-flow
Tabby's Buy Now, Pay Later solution allows your customers to split the purchase price into several payments with the downpayment and monthly repayments.
Enable
Background Pre-scoring
)}
/>
Create
Checkout Session
and redirect a customer to the Tabby Payment Page
)}
/>
Redirect the customer
back to your store
)}
/>
## Tabby on Checkout
Use the standard Tabby naming and Logo to present Tabby method at your checkout:
| | English | Arabic |
| ----------------------- | -------------------- | ------------------- |
| **Payment Method Name** | Pay later with Tabby | ادفع لاحقًا مع تابي |
### Recommended: Checkout Snippet
Display the Checkout snippet under the Tabby payment method when it is selected. The snippet shows the actual cost breakdown for the order amount and the key benefits, and keeps this information always up to date:
### Alternative: Payment Method Description
If the Checkout snippet cannot be embedded (e.g., due to checkout platform constraints), add a static description under the payment method name showing the cost breakdown:
| | English | Arabic |
| ------------------------------ | ----------------------------------------------------- | ------------------------------------------------------- |
| **Payment Method Description** | 4 payments of XX.XX/mo or up to 12 months. Learn more | 4 دفعات بقيمة XX.XX شهريًا أو حتى 12 شهرًا. اعرف المزيد |
* **XX.XX** is the monthly payment amount with your store currency: order total × 1.015 / 4 (3 decimal places for KWD)
* **Learn more** should open the Tabby pop-up with the payment schedule
## Background Pre-scoring Check
Background pre-scoring (also known as eligibility check) determines whether a customer is eligible to use Tabby before displaying it as a payment option. This check takes place at your checkout when the total amount and customer contact details are known.
For detailed implementation including when to perform checks, error handling, caching strategies, rejection messages, and complete code examples, see: FAQ - Eligibility Check Best Practices
### Quick Implementation
Call `POST /api/v2/checkout` endpoint with minimal required data (but more is better): **amount**, **currency**, **buyer.email**, **buyer.phone**, and **merchant\_code**.
Use the base URL for your region: `api.tabby.ai` (UAE, Kuwait) or `api.tabby.sa` (KSA). See Base URLs.
Providing additional details like **order.items**, **shipping\_address**, and customer information - **buyer\_history**, **order\_history**, etc. - helps improve scoring accuracy and increases approval rates.
### Response handling
Check the `status` field to determine eligibility:
* `status: "created"` → customer is eligible, show Tabby;
* `status: "rejected"` → customer is not eligible, hide Tabby or show rejection message.
You can extract the rejection reason from: `configuration.products.installments.rejection_reason`
### Possible rejection\_reason values
Here are possible `"rejection_reason"` values and corresponding messages to show to customers:
| Reason | English | Arabic |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| General Rejection (`not_available`) | Sorry, Tabby is unable to approve this purchase. Please use an alternative payment method for your order. | نأسف، تابي غير قادرة على الموافقة على هذه العملية. الرجاء استخدام طريقة دفع أخرى. |
| `order_amount_too_high` | This purchase is above your current spending limit with Tabby, try a smaller cart or use another payment method | قيمة الطلب تفوق الحد الأقصى المسموح به حاليًا مع تابي. يُرجى تخفيض قيمة السلة أو استخدام وسيلة دفع أخرى. |
| `order_amount_too_low` | The purchase amount is below the minimum amount required to use Tabby, try adding more items or use another payment method | قيمة الطلب أقل من الحد الأدنى المطلوب لاستخدام خدمة تابي. يُرجى زيادة قيمة الطلب أو استخدام وسيلة دفع أخرى. |
### Best Practices
**Key principles**:
* **Fail-safe approach** - always default to showing Tabby on API errors or timeouts
* **Loading states** - show appropriate UI feedback during checks
* **Background checks** - perform eligibility checks when customer enters checkout or cart amount changes
* **Rejection handling** - hide Tabby (recommended) or show rejection message.
Show rejection message for ineligible customers
### Eligibility Check vs Session Creation
Tabby's Checkout API serves two distinct purposes. Here's a side by side comparison:
| Aspect | Eligibility Check | Checkout Session Creation |
| ------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------ |
| **Purpose** | Determine if customer can use Tabby | Create payment session for actual checkout |
| **Timing** | Before showing Tabby payment method | When customer clicks "Place order" |
| **Payload** | Minimal (amount, currency, buyer) | Complete (all order details, items, shipping, merchant URLs) |
| **Response** | Status (`created` or `rejected`) + rejection reason | Status + `web_url` for redirect + `payment.id` |
| **Next Step** | Show or hide / mark unavailable Tabby payment method based on the response | Redirect to Tabby Hosted Payment Page |
## Checkout Session Initiation
When the customer who passed eligibility check clicks "Place order" with Tabby selected, call Checkout API with the **full payload** including all order details, items, shipping address, and merchant URLs.
**This is different from the eligibility check** - you must now provide complete order information.
### Example of a minimal payload for eligibility check
```json theme={"dark"}
{
"payment": {
"amount": "340.00",
"currency": "SAR",
"buyer": {
"email": "otp.success@tabby.ai",
"phone": "+966500000001"
}
},
"merchant_code": "your_merchant_code"
}
```
**Key principle**: Use the same endpoint (`POST /api/v2/checkout`) but with different payload sizes for different purposes.
### Response and Validation
In a successful response you will receive `status`, `web_url`, and `payment.id`:
**Always validate that `web_url` is present** in the response before redirecting. If `web_url` is missing or `status` is "rejected", show the rejection message instead of redirecting.
This validation handles edge cases where:
* Cart amount or customer details changed between eligibility check and session creation;
* Customer was blacklisted between checks;
* Eligibility check timed out (fail-safe showed Tabby as available).
Save "payment"."id" **from the response** - it will be used to verify, capture and refund the payment on the next steps.
### At Tabby Hosted Payment Page
At Tabby Checkout your customers will be asked:
* To verify the phone number by OTP (each transaction);
* To link Apple Pay or regular card (only for new Tabby customers);
* Additional data may be asked during customer's flow for some customers.
## Redirection to the Store
When customers finish Tabby session, they are redirected to one of three URLs you provide in the session creation request, with `payment_id` appended as a query parameter:
| Redirect URL | Use Case | Payment Status | Next Steps |
| ------------ | ---------------------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `success` | Customer completed payment verification | `AUTHORIZED` or `CLOSED` | Show "Thank you" page, verify status on backend, proceed to Payment Processing |
| `cancel` | Customer cancelled the payment willingly | `EXPIRED` | Return to checkout or cart, allow retry |
| `failure` | Payment was rejected by Tabby | `REJECTED` | Show rejection message, offer alternative payment methods |
### Handling redirects
* Redirect the customer immediately to avoid delays - do not block with payment status checks
* The redirect is a frontend navigation signal only. Verify payment status asynchronously on your backend via webhooks or `getPayment` API
* Show "Confirming payment..." on Thank you page if status is pending, update once backend confirms final status
Always verify payment status via your backend. Never rely on redirect URLs or query parameters alone as the source of truth.
### Approved messages for redirects
The following messages can be used to show to customers after a redirect:
| Reason | English message | Arabic message |
| -------------- | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `Cancellation` | You aborted the payment. Please retry or choose another payment method. | لقد ألغيت الدفعة. فضلاً حاول مجددًا أو اختر طريقة دفع أخرى. |
| `Failure` | Sorry, Tabby is unable to approve this purchase. Please use an alternative payment method for your order | نأسف، تابي غير قادرة على الموافقة على هذه العملية. الرجاء استخدام طريقة دفع أخرى. |
### Allowed characters in redirect URLs ("success", "cancel", "failure")
1. Latin letters (a-z, A-Z)
2. Arabic letters (ء-ي)
3. Digits (0-9)
4. Special characters - \ | / : ;., + \{}? & @ = # %
# Dispute webhooks
Source: https://docs.tabby.ai/pay-in-4-custom-integration/dispute-webhooks
Get notified when a dispute is opened on your payment and when its status changes: payload, statuses, and delivery.
Dispute webhooks notify your endpoint about disputes raised on your payments — when a customer opens a dispute, when you challenge it, and when it is resolved. This lets you react to disputes without polling the Disputes API.
Dispute webhooks **cannot be managed through the API**. Unlike payment webhooks, they are not registered via the [Register a webhook](/api-reference/webhooks/register-a-webhook) endpoint. To start receiving them, **ask the Integrations Team to enable them** for your `merchant_code` and provide your endpoint URL.
Disputes have **no test mode**: dispute webhooks are sent for live payments only (the same as the Disputes API).
## Payload
A dispute webhook is a POST request with a JSON body that links the dispute to the affected payment:
```JSON theme={"dark"}
{
"status": "pending",
"dispute_id": "string",
"payment_id": "string",
"amount": "100.00",
"currency": "SAR",
"created_at": "2026-06-15T13:08:54Z"
}
```
| Field | Description |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status` | The dispute event — see [Dispute statuses](#dispute-statuses) below. |
| `dispute_id` | ID of the dispute. Use it with the Get dispute by ID endpoint to fetch full details. |
| `payment_id` | ID of the payment the dispute was raised against. Use it to correlate the dispute with the order in your system. |
| `amount` | Disputed amount, as a string. The number of decimals follows the currency — `SAR` and `AED` use 2 (e.g. `"100.00"`), `KWD` uses 3 (e.g. `"100.000"`). |
| `currency` | ISO currency code of the payment (`SAR`, `AED`, `KWD`). |
| `created_at` | When the dispute was created, in UTC, ISO 8601 datetime format. |
## Dispute statuses
The `status` field tells you what happened to the dispute:
| `status` | Meaning |
| ------------------- | ------------------------------------------------------------------------------------------ |
| `pending` | The customer opened a dispute on your payment. |
| `arbitration` | You challenged the dispute (for example, the amount is wrong) and it moved to arbitration. |
| `evidence_merchant` | Tabby support requested supporting evidence from you. |
| `approved` | The dispute was approved and the amount was refunded to the customer. |
| `declined` | The dispute was declined by Tabby support. |
| `cancelled` | The dispute was cancelled by the customer. |
## Delivery
Dispute webhooks use the **same delivery mechanism as payment webhooks** — the same endpoint(s), optional authentication header, retry policy, and server IPs. In particular:
* Acknowledge each delivery with `200` and process it asynchronously — see Best Practices.
* Delivery order is not guaranteed and a notification may occasionally be delivered twice — deduplicate by `dispute_id` + `status`.
* Failed deliveries are retried — see Retry Attempts.
# Disputes
Source: https://docs.tabby.ai/pay-in-4-custom-integration/disputes
Handle customer disputes programmatically with the Disputes API.
The Disputes API simplifies handling disputes and helps you resolve issues with customers' orders more efficiently. Use it to:
* retrieve a list of disputes;
* view details about a specific dispute;
* approve or challenge disputes (one challenge per dispute);
* upload attachments (up to 5 per dispute).
The API mirrors the functionality available on Tabby Merchant Dashboard. It operates exclusively with **live payments** and live credentials — including testing.
A secret key is required for using the Disputes API.
Want to react to disputes in real time instead of polling? Tabby can push dispute webhooks to your endpoint when a dispute is opened, challenged, or resolved — ask the Integrations Team to enable them.
API documentation:
* Disputes API
* Disputes API in Chinese
# Full Testing Checklist
Source: https://docs.tabby.ai/pay-in-4-custom-integration/full-testing-checklist
After the integration is completed from your side - the QA will be performed by the Tabby team. To make sure that all the requirements are covered - kindly review the below checklist which contains the points assessed by our side.
If any of the points cannot be applied to your website/application architecture - please, notify us about that in an email thread and this point will be discussed separately.
This page covers **Website (desktop and mobile), iOS and Android** custom (direct API) integrations. When integrating Tabby on the E-commerce Platform from the list this section is not applicable.
## On-Site Messaging
* **Product and Cart snippets and pop-ups** are present in accordance with the:
* custom integration documentation
* or the SDK documentation used
* **Product snippets** are shown for all products, there is no amount limitation on displaying snippets
* **Cart snippet** is shown for all amounts, there is no amount limitation on displaying snippets
* **Cart snippet** amount is updated successfully when changes are performed with the items in the Cart: addition / removal / deletion of the items
* If the store has both **Arabic and English languages** - snippets should be displayed correctly for both of them
* **Website:** snippets should fit the width of a Mobile Web screen and have suitable width for a Desktop Web as well
* *In case your store has several countries*: **Tabby snippets** should be displayed only for countries you have already registered with Tabby
* *If our code is not compatible with yours or you have a non-standard plan*: kindly use one of the following custom snippets after the confirmation from your assigned business manager is received
## Tabby as a Payment Method
* **Payment method name** is present in accordance with the documentation
* **Tabby logo** is present near the payment method name
* **Checkout snippet** is displayed under the selected Tabby payment method (recommended), or the **payment method description** matches the approved copy — see Tabby on Checkout
* There should be no restrictions on displaying Tabby payment method from your side - this behaviour should be handled by background pre-scoring process
* If the store has both **Arabic and English languages** - Payment method should be displayed correctly for both of them
* *In case your store has several countries*: **Tabby payment method** should be displayed only for countries you have already registered with Tabby
## Checkout
* Background Pre-scoring check is present and working in accordance with the documentation
* **Website:** when a customer decides to place an order with Tabby - Tabby Checkout is opened in the same browser window
* **Mobile apps:** no control buttons (e.g., X, close, back, etc.) from your app are present on Tabby Checkout
* **Total amount** on Checkout = amount shown on Tabby Checkout
* If the store has both **Arabic and English languages** - language marker is sent correctly in a session creation request: object "lang", enum "ar" / "en"
* **Session creation request** contains all the required parameters from Tabby API
* Success scenario is working
* Cancellation scenario is working
* Failure scenario is working
* Corner case is supported
## Payment Verification and Processing
* Webhooks are registered for each `merchant_code` + secret key pair (up to 4 webhooks per pair). To receive webhooks for test payments, register them with your test key (`sk_test_...`)
* After a payment is placed successfully with Tabby you receive a webhook to your registered url with status "authorized"
* On receiving it you should **trigger a** getPayment request to verify the status of the payment
* If a status is "AUTHORIZED" - a capture request should be triggered from your side
* It is an expected behaviour that webhooks return "authorized" in lower case while getPayment - in upper case: "AUTHORIZED".
* A **full amount** must be captured
If you have any questions considering this Checklist - feel free to contact us in the Integrations thread.
# App Promo Messaging
Source: https://docs.tabby.ai/pay-in-4-custom-integration/mobile-apps/app-promo-messaging
Promo messaging in mobile apps: SDK snippet components, or custom snippets with the standard copy and Tabby pop-up URLs.
Tabby SDKs contain ready-made snippet components for the Product, Cart, and Checkout pages of your app — use them whenever possible.
If you build your own promo components instead, use the standard Tabby copy below and open the Tabby "Learn more" pop-up in a webview.
### Promo Text
Use the same copy as the Payment Method Description on the web:
| | English | Arabic |
| ------------------------------ | ----------------------------------------------------- | ------------------------------------------------------- |
| **Payment Method Description** | 4 payments of XX.XX/mo or up to 12 months. Learn more | 4 دفعات بقيمة XX.XX شهريًا أو حتى 12 شهرًا. اعرف المزيد |
* **XX.XX** is the monthly payment amount with your store currency: order total × 1.015 / 4 (3 decimal places for KWD)
* **Learn more** should open the Tabby pop-up with the payment schedule in a webview
### Pop-up URLs and live examples
The pop-up URL pattern, parameters, screenshots and a live demo all live on the main On‑Site Messaging → Custom Promo Snippets page — nothing app-specific there, use it as-is with a webview.
# Integration without SDK (WebView)
Source: https://docs.tabby.ai/pay-in-4-custom-integration/mobile-apps/integration-without-sdk
Open the Tabby checkout in your mobile app without our SDK: how to render it, read the payment status correctly, and recover from corner cases.
If our SDK solutions do not meet your requirements, you can open the Tabby Hosted Payment Page in your own mobile app — in a WebView or the system browser — using backend API calls.
## Choose how to render the checkout
There are two ways to open the checkout. The **payment-status and recovery rules on this page apply to both** — only the rendering and the permissions differ.
**Recommended — the system browser + deep links.** Open the Hosted Payment Page in a **Chrome Custom Tab** (Android) or **`SFSafariViewController` / `ASWebAuthenticationSession`** (iOS), and pass your `merchant_urls` as **deep links** back into your app. This is the most resilient option: the browser session survives even if the OS reclaims your app while the customer confirms the payment, and you avoid managing in-app camera permissions.
An **embedded WebView** is also supported, and many merchants use one — but then you own more of the flow: the camera/gallery [permissions](#webview-permissions) for ID upload, and state recovery when your app is reclaimed. WebView-specific guidance below is marked as such; everything else applies to both.
## Checkout flow
The Checkout session request, payment method display, and code snippets are integrated the same way as in the Online Custom Integration. The mobile-specific part is what happens **after** you open the page:
Create the session on your backend and open the returned URL in your WebView (or a Custom Tab /
`ASWebAuthenticationSession`).
To confirm the payment, the customer can be handed off to the **Tabby app** or their **banking
app**, then returned to your app.
On return, confirm the payment status server-side — see [Handling the payment
status](#handling-the-payment-status) below. The returning navigation is a trigger to
**verify**, not proof of the outcome.
When the customer finishes, read the outcome from your `merchant_urls` (as deep links with the browser approach, or redirect URLs inside a WebView) together with your backend webhooks — always confirming server-side, as described below. The example below shows in-WebView event handling for iOS (Swift), and applies only if you embed a WebView:
tabby-ios-manual-integration.md
## Handling the payment status
This is the most important part of an in-app integration. Getting it wrong is the single biggest source of corner cases — customers who paid successfully but are shown a failure or a reset checkout.
**The client is never proof of payment — the status lives on Tabby's backend.**
Closing the WebView, backing out of the checkout, or returning from the Tabby or banking app is a **navigation event, not a payment result**. The customer may also never reach your success page at all — they can pay and then lose connection, or the OS can kill your app first.
So never map a checkout close, back‑press, or app return to reject/cancel. Always follow the same chain: **event trigger → retrieve the payment (`getPayment`) → decide**. Treat webhooks as notifications only, and confirm the status with getPayment (see the FAQ).
There are two separate channels — don't conflate them:
| Channel | Purpose | Trust |
| -------------------------------------------- | ------------------------------------------------------- | ---------------------------------------- |
| `merchant_urls` (success / cancel / failure) | Client-side UX signal — where to send the customer next | A trigger to verify, **not** the outcome |
| Webhook → `getPayment` | Server-side notification + retrieval | **Source of truth** for the final status |
### Confirm the status from Tabby
Make confirmed-by-backend status the thing that drives your UI, and re-fetch at the moments where customers are most likely to think the flow "ended":
Your backend receives Tabby webhooks and keeps the latest status by calling
getPayment (which needs your secret key,
so call it server-side — never from the app). Your app polls **your backend** for the active
`payment_id`. Use a capped, backed-off interval and show a
"Confirming your payment…" state rather than a hard success/failure screen.
On `onResume` (Android) / `sceneDidBecomeActive` / `applicationDidBecomeActive` (iOS), re-fetch
the status. This single addition resolves the large majority of false "rejections" caused by the
customer returning from a banking app.
Treat WebView close as "go ask the backend", not as a result. Fetch the status once more before
you decide what to show.
**A pending status is not a failure.** Right after the checkout closes, the payment is often still `CREATED` — the customer has not been authorized yet — and can move to `AUTHORIZED` moments later. Never finalize on a non-terminal status: keep polling until Tabby returns a terminal status (`AUTHORIZED`, `CLOSED`, `REJECTED`, or `EXPIRED`), and let your backend reconcile late transitions from the webhook — it receives the `AUTHORIZED` webhook even if the customer never returned to your app. See [Payment Statuses](/pay-in-4-custom-integration/payment-statuses).
**Silent push (optional accelerator).** If you already deliver push notifications, a data-only / `content-available` push can wake the app to fetch the status sooner. Delivery is **not guaranteed** (throttled in the background, dropped under Low Power Mode, disabled Background Refresh, poor network, or after force-quit), so always keep the polling above as the fallback. A real-time channel you already operate (WebSocket / gRPC) is also a valid transport, but is not worth building solely for checkout.
## Recovering from corner cases
While the customer is in an external app (the Tabby app, their banking app, or a browser handling the confirmation), the OS may terminate your app's process in the background to free memory. This is normal OS behaviour, not an error. When the customer returns, the system recreates your screen — and, if you embed a WebView, it is recreated too, reloading its **initial URL** instead of resuming the in-progress checkout. Heavy apps (such as banking apps) make this far more likely, because launching them pushes your app deep into the background.
**The one rule that prevents lost checkouts:** persist the `payment_id` to durable storage **as soon as the checkout session is created** — before the customer can leave your app. Then, even after a full process restart, your return handler can re-query `getPayment` and restore the correct outcome, regardless of whether the WebView survived.
**Persist first.** Store the active `payment_id` immediately, and re-verify on `sceneDidBecomeActive` / `applicationDidBecomeActive`.
**Restore the screen.** Use UIKit/SwiftUI state restoration (`stateRestorationActivity` on the scene, or `restorationIdentifier` + `encodeRestorableState`) so the hosting screen is rebuilt instead of reset.
**Redirect via the system browser.** For any external confirmation redirect, prefer [`ASWebAuthenticationSession`](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession) (or `SFSafariViewController`) over an external Safari launch — it keeps your app foregrounded for the round-trip and delivers the callback URL back to you, which markedly reduces the chance of the OS reclaiming your app.
`WKWebView` does not persist in-page JavaScript state across a process restart, so the persisted `payment_id` is what guarantees continuity.
**Save and restore state.** Implement `onSaveInstanceState()` / `onRestoreInstanceState()` on the Activity/Fragment hosting the WebView, using `webView.saveState()` and `webView.restoreState()` to keep navigation history. Back durable state with a `ViewModel` + `SavedStateHandle` so it survives [system-initiated process death](https://developer.android.com/topic/libraries/architecture/saving-states).
**Redirect via a Custom Tab.** For any external confirmation redirect, use [Chrome Custom Tabs](https://developer.android.com/develop/ui/views/layout/webapps/overview-of-android-custom-tabs) with a warmed-up session (bind to `CustomTabsService`, call `warmup()` early, reuse a single `CustomTabsSession`, reconnect on `onServiceDisconnected()`). Custom Tabs keep your process at foreground priority for the redirect, far better than a plain `Intent.ACTION_VIEW` browser launch.
`WebView.saveState()` restores navigation history but **not** arbitrary in-page JavaScript state, so the persisted `payment_id` is still required for full continuity.
If the confirmation happens in a **separate banking app** (via deep link / App Link) rather than a browser, neither WebView state nor Custom Tabs / `ASWebAuthenticationSession` can prevent your process from being reclaimed — control has passed to another app entirely. In that case the persisted `payment_id` + backend re-verify is the **only** reliable solution.
### Most robust pattern: browser + deep links
This is the **recommended approach** from the top of the page — here is why it holds up. Because the checkout runs in the **system browser** (or a Custom Tab / `SFSafariViewController`) rather than your WebView, the session survives even if your app is evicted from memory: the browser recovers the Tabby confirmation screen, the payment completes, and your `merchant_urls.success` deep link re-opens your app to show the result — while your backend confirms the final status in parallel.
To make the return leg reliable, register your return URLs as app links before you start:
**Register the URLs.** Set up a custom URL scheme plus Universal Links (iOS) / App Links (Android) for your success / cancel / failure URLs.
**Wire the platform hooks.** Add the matching intent-filter (Android) / associated-domains entitlement (iOS).
**Avoid duplicate tasks.** Launch your return activity with `launchMode="singleTask"` (or `singleTop`) so the deep link re-enters your existing task instead of spawning a duplicate.
### Best-practice checklist
* **Persist `payment_id`** to durable storage at session creation, so recovery works even after a full process restart.
* **Treat webhooks as notifications only**, and **dedupe by `payment_id`** — a webhook, a push, and your polling can all fire for the same payment, and a webhook can be delayed or delivered more than once.
* **Never map a checkout close, back-press, or external-app return to reject/cancel** — always confirm with `getPayment` first.
* **Wait for a terminal status** — a `CREATED`/pending payment can still turn `AUTHORIZED` after the checkout closes; never finalize on a non-terminal status, and let your backend reconcile the late webhook.
* **Always provide `merchant_urls`** (success, cancel, failure) so a deep-link recovery path exists regardless of WebView survival.
* **Don't tear down the WebView** the instant a `merchant_url` loads — confirm the status first.
* **Show a "Confirming your payment…" state** with capped, backed-off polling instead of an immediate success/failure screen.
## WebView permissions
**Only needed if you embed a WebView** — the browser approach handles this natively. Your WebView must be able to **access the camera and pick images from the gallery** on both iOS and Android — required so new customers can capture and upload their national ID during checkout. Without them, a new customer who needs to verify their ID can't complete the purchase. The platform-specific setup is below.
Declare the usage descriptions below in your `Info.plist`. `WKWebView` uses the native camera and photo picker once these keys are present — no extra runtime-permission plumbing is required. Adapt the description copy to your app:
```xml theme={"dark"}
NSCameraUsageDescription
This allows Tabby to take a photo
NSPhotoLibraryUsageDescription
This allows Tabby to select a photo
NSMicrophoneUsageDescription
For secure verification on the checkout step
```
Our web app accepts **images only** — other file types (e.g. PDF) are not supported by the picker.
On Android you have to relay the WebView's permission and file-chooser requests to the OS yourself.
When a web page requests the camera or microphone, the WebView calls `onPermissionRequest` on your `WebChromeClient` with a `PermissionRequest` listing the requested resources. The simplest possible handler grants everything immediately — fine for testing, but **not recommended for production**, where you should request the matching Android runtime permission from the user first.
**1. Map the WebView resource to an Android permission**
```kotlin theme={"dark"}
// PermissionRequest.RESOURCE_VIDEO_CAPTURE -> Manifest.permission.CAMERA
// PermissionRequest.RESOURCE_AUDIO_CAPTURE -> Manifest.permission.RECORD_AUDIO
```
**2. Declare the permissions and features in `AndroidManifest.xml`**
```xml theme={"dark"}
```
`android:required="false"` declares that the camera hardware is not mandatory for the app to run.
**3. Request the "dangerous" permissions at runtime, then grant them to the WebView**
`CAMERA` and `RECORD_AUDIO` are classified as dangerous and must be requested at runtime. Grant the WebView request only after the user approves:
```kotlin Kotlin theme={"dark"}
class MainActivity : ComponentActivity() {
private val permissionRequester: PermissionRequester = PermissionRequester()
private val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission(),
permissionRequester
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
permissionRequester.activityResultLauncher = permissionLauncher
setContent {
TabbyLiveCodingTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
CheckoutWebScreen(
modifier = Modifier.padding(innerPadding),
url = "https://url.to.web-app.net",
webChromeClient = object : WebChromeClient() {
override fun onPermissionRequest(request: PermissionRequest) {
lifecycleScope.launch {
val result = permissionRequester.requestPermissions(
request.resources.mapNotNull {
WebViewPermissions.byPermission(it)
}
)
val granted = result.filter { it.isGranted == true }
if (granted.isNotEmpty()) {
request.grant(granted.map { it.permission.permission }
.toTypedArray())
} else {
request.deny()
}
}
}
},
)
}
}
}
}
}
class PermissionRequester : ActivityResultCallback {
lateinit var activityResultLauncher: ActivityResultLauncher
private var currentRequest: CompletableDeferred? = null
private var inProgress: Boolean = false
suspend fun requestPermissions(permissions: List): List {
if (inProgress) {
return permissions.map { PermissionsCheck(it, false) }
}
inProgress = true
val result = permissions.map {
currentRequest = CompletableDeferred()
activityResultLauncher.launch(it.androidPermission())
val result = currentRequest?.await()
currentRequest = null
PermissionsCheck(it, result)
}
inProgress = false
return result
}
override fun onActivityResult(result: Boolean) {
currentRequest?.complete(result)
}
}
data class PermissionsCheck(
val permission: WebViewPermissions,
var isGranted: Boolean? = null,
)
enum class WebViewPermissions(val permission: String) {
VideoCapture(PermissionRequest.RESOURCE_VIDEO_CAPTURE),
AudioCapture(PermissionRequest.RESOURCE_AUDIO_CAPTURE);
companion object {
fun byPermission(permission: String): WebViewPermissions? {
return entries.find { it.permission == permission }
}
}
}
fun WebViewPermissions.androidPermission(): String = when (this) {
WebViewPermissions.VideoCapture -> Manifest.permission.CAMERA
WebViewPermissions.AudioCapture -> Manifest.permission.RECORD_AUDIO
}
```
```java Java theme={"dark"}
import android.webkit.PermissionRequest;
import android.webkit.WebChromeClient;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class PermissionRequester implements ActivityResultCallback
To let the customer pick an image, override `onShowFileChooser` on your `WebChromeClient`. We recommend the **Android photo picker** (`PickVisualMedia`) — it requires no storage permissions. If you wire up a custom file chooser instead, you must handle the required permissions yourself. Our web app accepts **images only**.
```kotlin theme={"dark"}
var uploadMessageCallback: ValueCallback>? = null
val fileChooserContract = registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { result ->
val callback = uploadMessageCallback ?: return@registerForActivityResult
val URIs = result?.let { arrayOf(it) }
callback.onReceiveValue(URIs)
uploadMessageCallback = null
}
// Web chrome client implementation here. This implementation should be set to your WebView.
object : WebChromeClient() {
override fun onShowFileChooser(
webView: WebView?,
filePathCallback: ValueCallback>?,
fileChooserParams: FileChooserParams?
): Boolean {
uploadMessageCallback = filePathCallback
fileChooserContract.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
)
return true
}
}
```
## Next steps
Reading the status in the app is only half of it — the order is then captured and processed on your backend, exactly as in the web integration:
* Payment Processing — capture the payment and process the order.
* Webhooks — receive payment status updates server-side.
# Mobile App SDKs
Source: https://docs.tabby.ai/pay-in-4-custom-integration/mobile-apps/sdk-all
Native SDKs for iOS, Android, Flutter, and React Native: checkout initialisation and promo snippets.
Tabby offers SDKs for all major mobile platforms:
* **iOS SDK** — github.com/tabby-ai/tabby-ios-sdk
* **Android SDK** — github.com/tabby-ai/tabby-android-sdk
* **Flutter SDK** — pub.dev/publishers/tabby.ai
* **React Native SDK** — npmjs.com/package/tabby-react-native-sdk
The SDKs cover:
1. App checkout initialisation
2. Product, Cart, and Checkout page snippets
Payment verification and processing are integrated on your backend with the Tabby Payments API and webhooks, the same way as for the web integration:
* Payment Processing
* Webhooks
# On‑Site Messaging
Source: https://docs.tabby.ai/pay-in-4-custom-integration/on-site-messaging
Tabby's JavaScript snippets show split-price messaging right where customers decide to buy — on your Product, Cart and Checkout pages. They raise awareness of flexible payments before checkout, which directly increases conversion. Each snippet includes a "Learn more" link that opens a pop-up with the payment schedule.
## Add the snippets
Two components cover all pages:
* **`TabbyPromo`** — Product and Cart pages. Place the container near the product price, next to the "Add to cart" button, or below the cart total.
* **`TabbyCard`** — Checkout page, the recommended way to present Tabby payment details at checkout (see Tabby on Checkout). Place it under the Tabby payment method option and show it when Tabby is selected.
```html your-store-page.html expandable theme={"dark"}
```
Snippets only need your Public Key and merchant code — never expose the Secret Key in frontend code.
Make sure snippets fit mobile screen widths (320px minimum).
## Live demo
Everything below is rendered live by `tabby-promo.js` and `tabby-card.js` — exactly what your customers will see. Switch the market to preview English/AED and Arabic/SAR, and click "Learn more" to open the real pop-up.
## Custom Promo Snippets
If you can't load Tabby's JavaScript (security policies, native mobile apps, full styling control), build your own message and open the Tabby "Learn more" pop-up via a direct URL:
| Description | URL |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UAE pop-up, English | [**https://checkout.tabby.ai/promos/product-page/installments/en/?price=2000.00\¤cy=AED\&merchant\_code=your\_merchant\_code\&public\_key=pk\_xyz**](https://checkout.tabby.ai/promos/product-page/installments/en/?price=2000.00\¤cy=AED\&merchant_code=your_merchant_code\&public_key=pk_...) |
| KSA pop-up, Arabic | [**https://checkout.tabby.sa/promos/product-page/installments/ar/?price=2000.00\¤cy=SAR\&merchant\_code=your\_merchant\_code\&public\_key=pk\_xyz**](https://checkout.tabby.sa/promos/product-page/installments/ar/?price=2000.00\¤cy=SAR\&merchant_code=your_merchant_code\&public_key=pk_...) |
#### URL Parameters
| Parameter | Required | Description | Values |
| --------------- | -------- | --------------------- | ----------------------------------------------------------- |
| `merchant_code` | Yes | Your merchant code | Provided by Tabby |
| `public_key` | Yes | Your Tabby public key | `'pk_test_...'`, `'pk_...'` |
| `price` | Yes | Product or cart price | `'1200.00'`, `'99.99'`, `'5.500'` (3 decimals for KWD only) |
| `currency` | Yes | Currency code | `AED`, `SAR`, `KWD` |
| `lang` | No | Language code | `en`, `ar` |
If you implement your own custom snippet, notify your Tabby account manager so we can keep your integration in sync with upcoming changes.
For promo messaging inside native mobile apps, see App Promo Messaging.
# Payment Processing
Source: https://docs.tabby.ai/pay-in-4-custom-integration/payment-processing
What to do after the customer completes the Tabby checkout: verify the payment, capture it, and process refunds when needed.
Once the customer completes the Tabby checkout, three server-side steps remain:
Verify
the payment status server-to-server
)}
/>
Capture
the payment — only captured payments are settled to you
)}
/>
Refund
the payment when needed
)}
/>
## Payment Verification
Never rely on the redirect alone — always verify the payment server-to-server before processing the order.
When the customer lands on one of your redirect URLs, call the Retrieve Request with the `payment_id` you received at session creation and check the `status` field:
| Customer redirected to | Expected payment `status` |
| ---------------------- | ------------------------- |
| Success URL | `AUTHORIZED` |
| Cancel URL | `EXPIRED` |
| Failure URL | `REJECTED` |
What to do next depends on the status (see Payment Statuses for the full lifecycle):
| Payment `status` | Your action |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AUTHORIZED` | Process the order in your OMS, capture the payment, and notify the customer that the order is confirmed (Tabby also sends its own payment confirmation) |
| `REJECTED` / `EXPIRED` | Cancel or delete the order in your OMS |
| `CREATED` | The checkout is not finished yet — keep checking until the status changes or the session expires |
### Don't Miss Authorized Payments
A payment can become `AUTHORIZED` without a successful redirection — for example, the customer pays and then closes the browser page or mobile WebView before being redirected, or a network issue interrupts the redirect. Catch such payments in one of two ways:
* **Webhooks (recommended).** Webhooks are sent on every status change regardless of redirection. When you receive a webhook with the `authorized` status: if the order is still pending, process it in your OMS and capture the payment; if the order was already processed after the redirect, no action is needed.
* **Polling (fallback).** Set up a cron job calling the Retrieve Request every couple of minutes until the payment reaches `AUTHORIZED`, `REJECTED`, or `EXPIRED`.
Webhooks use lowercase statuses (`"authorized"`), while the Retrieve Request returns uppercase (`"AUTHORIZED"`) — this is expected. See Payment Statuses.
### Session Expiration
By default, a Tabby checkout session expires **20 minutes** after creation, and the payment status changes to `EXPIRED` about **10 minutes** after that — roughly 30 minutes since creation in total. Once the payment is `EXPIRED`, it is terminal: stop checking it.
The session expiry timeout can be reduced on request — contact your assigned business manager in the Integrations thread.
## Payment Capture
After you verify that the payment is `AUTHORIZED`, send a Capture Request from your OMS to confirm the order to Tabby. Capturing does not charge the customer anything extra — it confirms the order from your end. Only captured payments are settled to you, and customer disputes are possible only for captured payments.
Capture the **full payment amount** — Tabby verifies that the amount in the Capture Request matches the payment amount. A successful capture returns `200` with the payment status `CLOSED`; if you get any other response, investigate before retrying. Partial captures are supported, but the best-practice flow is a full capture right after verification.
Only an `AUTHORIZED` payment can be captured. Capture attempts in `CREATED`, `EXPIRED`, `CLOSED`, or `REJECTED` return a `400` error.
### Missing Captures
Tabby tracks non-captured payments. For the first **21 days** after authorization the payment is left untouched — you can capture or cancel it at any moment. After 21 days, Tabby may capture the remaining amount in full on its side, as a missing capture is usually caused by a technical issue. Tabby also notifies merchants when we observe regular capture issues.
You can find all `AUTHORIZED` payments on Merchant Dashboard by filtering orders by the `NEW` status (or by exporting payments as a CSV file) — resolve them by capturing or cancelling.
## Payment Refund
Use a refund to return a captured amount to the customer. Refunds can be made with the Refund Request or on Merchant Dashboard (merchant.tabby.ai / merchant.tabby.sa for KSA).
The request is the same for full and partial refunds — provide the `payment_id` and the amount:
* **Full refund** returns the total captured amount and can be performed only once.
* **Partial refund** returns less than the captured amount. A payment can be refunded multiple times, but the total cannot exceed the captured amount.
Refund constraints:
* Only a `CLOSED` payment can be refunded.
* Refunds are processed in the same currency as the captured payment.
* Refunds can be initiated within **180 days** from the payment creation.
* A processed refund cannot be cancelled.
### Refunds Troubleshooting
If your refund request didn't respond with `200`, check the following:
* Is the payment status `CLOSED`?
* Is the refund amount higher than the captured amount?
* Has the payment already been fully refunded?
* Does the amount format follow the requirements?
## Idempotent Requests
Capture and Refund requests support idempotency, so you can safely retry them after a connection error without performing the same operation twice. Pass your own unique key in the `reference_id` parameter of the request:
```JSON theme={"dark"}
{
"reference_id": "some_key"
}
```
A retry with the same `reference_id` will not create a second capture or refund.
# Payment Statuses
Source: https://docs.tabby.ai/pay-in-4-custom-integration/payment-statuses
How a Tabby payment moves through its lifecycle, and how API statuses map to what you see on Merchant Dashboard.
## Payment Lifecycle
The `status` field of a payment (`GET /api/v2/payments/{id}`) has five possible values: `CREATED`, `AUTHORIZED`, `CLOSED`, `REJECTED`, and `EXPIRED`.
```mermaid theme={"dark"}
flowchart LR
CREATED -- "order placed" --> AUTHORIZED
AUTHORIZED -- "full capture or close" --> CLOSED
CREATED -. "Tabby declines" .-> REJECTED
CREATED -. "cancelled or timed out" .-> EXPIRED
classDef happy fill:#E8FBF3,stroke:#10B981,stroke-width:1.5px,color:#065F46
classDef terminal fill:#F3F4F6,stroke:#9CA3AF,color:#6B7280
class CREATED,AUTHORIZED,CLOSED happy
class REJECTED,EXPIRED terminal
```
Two statuses allow repeated actions without changing: a **partial capture** keeps the payment `AUTHORIZED`, and a **refund** keeps it `CLOSED`.
| API `status` | Meaning | Triggered by | Terminal? |
| ------------ | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ----------------------------- |
| `CREATED` | Payment created together with the checkout session; the customer hasn't completed the Tabby checkout yet | Your Create Checkout Session request | No |
| `AUTHORIZED` | Order placed; funds are reserved but not captured yet | Customer completes the Tabby checkout | No |
| `CLOSED` | Final state: captured in full, cancelled, or partially captured and then closed | Your Capture or Close request | Yes — but refunds are allowed |
| `REJECTED` | Tabby declined the order at checkout | Tabby scoring | Yes |
| `EXPIRED` | The checkout was never completed | Customer cancelled on the Tabby checkout, or the session timed out | Yes |
Note that `EXPIRED` does **not** mean an authorization expired — it always refers to the checkout. Payments in `REJECTED` and `EXPIRED` require no action from your end and are not shown on Merchant Dashboard.
## Merchant Dashboard Statuses
Merchant Dashboard uses its own display statuses on top of the API ones. The mapping:
| Merchant Dashboard | API `status` | How the payment got there |
| -------------------- | ------------ | ------------------------------------------------------------ |
| `NEW` | `AUTHORIZED` | Authorized; nothing captured yet, or captured only partially |
| `CAPTURED` | `CLOSED` | Captured in full, or partially captured and then closed |
| `CANCELLED` | `CLOSED` | Closed without any capture |
| `REFUNDED` | `CLOSED` | Captured, then refunded in full |
| `PARTIALLY REFUNDED` | `CLOSED` | Captured, then refunded partially |
## Lifecycle in Detail
When you create a checkout session, Tabby creates a payment with status `CREATED` along with it — before the customer opens the Tabby checkout page.
*Payments in this status are not shown on Merchant Dashboard.*
After successful order placement the payment becomes `AUTHORIZED`: the funds are reserved on the customer's side, but not transferred yet.
*Shown on Merchant Dashboard as `NEW`.*
Instead of `AUTHORIZED`, the payment can end up `REJECTED` (Tabby declined the order) or `EXPIRED` (the customer cancelled on the Tabby checkout, or the session timed out). Both are terminal — no action is required from your end.
Send a Capture request as soon as the payment is authorized. When the full amount is captured, the payment automatically becomes `CLOSED`.
*Shown on Merchant Dashboard as `CAPTURED`.*
**Partial capture** is supported: the payment stays `AUTHORIZED` (Dashboard: `NEW`) until you capture the full amount or send a Close request.
Don't leave payments in `AUTHORIZED` longer than necessary — the payout for a payment is processed only after it is closed.
Use a Close request when part of the order won't be delivered:
* **After a partial capture** — Close cancels and refunds everything that wasn't captured. The payment becomes `CLOSED`, shown on Merchant Dashboard as `CAPTURED`.
* **Without any capture** — Close cancels the payment completely. The payment becomes `CLOSED`, shown on Merchant Dashboard as `CANCELLED`.
Only a `CLOSED` payment can be refunded, and the refund amount cannot exceed the captured amount. Full and multiple partial refunds are supported; the payment stays `CLOSED`.
*Shown on Merchant Dashboard as `REFUNDED` or `PARTIALLY REFUNDED`.*
## Statuses in API Responses vs Webhooks
API responses return statuses in uppercase (`"AUTHORIZED"`), while webhook payloads use lowercase (`"authorized"`). Compare statuses case-insensitively.
To make sure any text you send in JSON is transmitted and displayed correctly in Tabby interfaces, use **UTF-8** encoding.
# Quick Start
Source: https://docs.tabby.ai/pay-in-4-custom-integration/quick-start
## Integration Overview
Get started with Tabby's Buy Now, Pay Later solution. This guide walks you through integrating Tabby Payments into your website or mobile app, allowing your customers to split purchases into interest-free installments.
## See It In Action
## Integration Steps
### Setup
Register for a Tabby merchant account
(KSA: merchant.tabby.sa)
and complete your application to obtain access to Tabby Merchant Dashboard
)}
/>
Retrieve your test API keys and merchant codes from Tabby Merchant Dashboard or your Tabby account manager
)}
/>
### Development
Implement checkout integration for your platform:
Web
or
Mobile
)}
/>
Integrate
Payment Processing
to handle payment status updates and order fulfillment
)}
/>
Add
Tabby Promo snippets and widgets
to your site (required for optimal conversion)
)}
/>
Test basic scenarios
with test credentials, then complete the
full testing checklist
before submitting for Tabby QA review
)}
/>
### Going Live
Submit your integration for Tabby QA review after completing the full testing checklist
)}
/>
After successful QA approval, coordinate your go-live plan and marketing campaign with your Tabby account manager
)}
/>
Request live API keys and deploy to production
)}
/>
## How It Works
Here's what happens when a customer uses Tabby:
1. **Customer chooses Tabby at checkout**\
Your site checks if the customer is eligible using Tabby's API (background check based on purchase amount and customer details).
2. **Customer completes purchase**\
If eligible, customer selects Tabby, clicks "Place order", and is redirected to Tabby's secure payment page to complete verification.
3. **You get paid, customer pays in installments**\
Tabby authorizes the payment immediately. You capture the full amount and fulfill the order. The customer pays Tabby in interest-free installments.
For detailed technical implementation, see the Checkout Flow Guide.
## Complete Integration Flow
This diagram shows the complete end-to-end integration flow including eligibility checks, session creation, payment processing, and all possible outcomes:
```mermaid theme={"dark"}
sequenceDiagram
autonumber
participant Customer
participant Merchant Site
participant Merchant Backend
participant Tabby Checkout
participant Tabby API
Customer ->>+ Merchant Site: Opens Checkout page
Merchant Site ->>+ Merchant Backend: Check customer eligibility with Tabby
Merchant Backend ->>+ Tabby API: POST /api/v2/checkout
{ amount, currency, buyer.phone, buyer.email, merchant_code }
Tabby API -->>- Merchant Backend: Response
{"status" of session}
alt "status" of session == "created"
Merchant Backend -->> Merchant Site: Customer is eligible
Merchant Site -->> Customer: Show Tabby on Checkout
Note right of Customer: Customer can select Tabby payment
Customer ->>+ Merchant Site: Selects Tabby & clicks Place Order
Merchant Site ->>+ Merchant Backend: Create Tabby payment session
Note over Merchant Backend,Tabby API: New session is created (not eligibility check)
Merchant Backend ->>+ Tabby API: POST /api/v2/checkout
{ all required attributes }
Tabby API -->>- Merchant Backend: Response
{"payment.id", "web_url"}
else "status" of session == "rejected"
Merchant Backend -->> Merchant Site: Customer is not eligible
Merchant Site -->> Customer: Hide Tabby on Checkout
end
Merchant Backend ->>+ Tabby Checkout: Redirect to Tabby Checkout
loop Tabby Checkout steps
Tabby Checkout -->> Customer: Guide through payment steps
end
alt Customer is redirected back to Merchant Site
Tabby Checkout ->> Merchant Site: Redirect via success/cancel/failure url
Merchant Site ->> Customer: Show success/cancel/failure screen and message
Note right of Customer: If payment is unsuccessful, customer can retry
or select a different payment method
Merchant Backend ->>+ Tabby API: GET /api/v2/payments/{payment.id}
Tabby API -->>- Merchant Backend: { "status" of the payment }
else Customer is not redirected
Note over Tabby API,Merchant Backend: Tabby sends payment status
via webhook or merchant checks it via API
Tabby API -->>+ Merchant Backend: POST webhook
{ "id" of the payment, "status" of the payment }
Merchant Backend ->>+ Tabby API: GET /api/v2/payments/{payment.id}
Tabby API -->>- Merchant Backend: { "status" of the payment }
end
Note over Merchant Backend: Always verify payment status via Tabby API
Do not rely on redirect URL or query params alone
alt payment.status == "AUTHORIZED" or "CLOSED"
Merchant Backend ->>+ Merchant Site: Create order in backend
Merchant Backend -->> Tabby API: POST /api/v2/payments/{payment.id}/captures
{ amount, reference_id}
else payment.status == "REJECTED" or "EXPIRED"
Merchant Backend -->> Merchant Site: Payment failed/cancelled
end
```
## Next Steps
After completing this guide, you're ready to:
**📚 Explore Advanced Features**
* Webhooks configuration for real-time payment updates
* Refunds and cancellations
* Disputes handling and customer support
**🎯 Optimize Your Integration**
* FAQ for common implementation questions
* Website / app assets for better conversion
* Marketing toolkit with assets for every channel
**🚀 Additional Resources**
* Payment statuses reference
* Complete API Reference
## Need Help?
**Integration support:**\
Contact your assigned Business Manager or Integrations Team via your integration email thread.
**Technical or API questions:**\
Email `partner@tabby.ai` / `partner@tabby.sa` or use Partner Support in Tabby Business App.
**Direct your customers to:**\
Customer Support in Tabby App or `help@tabby.ai` / `help@tabby.sa`.
# Payment webhooks
Source: https://docs.tabby.ai/pay-in-4-custom-integration/webhooks
Get notified about payment status changes: registration, payload, supported events, delivery order, and retries.
Tabby Webhooks are HTTPS callbacks that notify you about payment-related and token-related events. You register a URL once, and Tabby sends a POST request to it whenever an event related to your account occurs — even when the customer never returns to your site. This makes webhooks the most reliable way to catch authorized payments.
## How They Work
Register a webhook for each `merchant_code` + secret key pair. The environment is determined by the key you register with: a production key (`sk_...`) registers webhooks for production payments, a test key (`sk_test_...`) — for test payments. Each pair can have up to **4 webhooks**. An optional auth header can sign the requests so you can verify their authenticity.
Tabby sends a POST request to your URL whenever the payment status changes.
Respond with a `200` HTTP status code to confirm the reception, and check the auth header to verify the request. Any other response (or no response) counts as a delivery error and triggers retries.
## Payload
Webhooks are POST requests with a JSON body:
```JSON theme={"dark"}
{
"id": "string",
"created_at": "2021-09-14T13:08:54Z",
"expires_at": "2022-09-14T13:08:54Z",
"closed_at": "2021-09-14T13:09:45Z",
"status": "closed",
"is_test": false,
"is_expired": false,
"amount": "100",
"currency": "SAR",
"order": {
"reference_id": "string"
},
"captures": [
{
"id": "string",
"amount": "100",
"created_at": "2021-09-14T13:09:45Z",
"reference_id": "string"
}
],
"refunds": [
{
"id": "string",
"amount": "100",
"created_at": "2021-09-14T14:14:02Z",
"reference_id": "string",
"reason": "string"
}
],
"meta": {
"order_id": null,
"customer": null
},
"token": "string"
}
```
Webhook payloads use lowercase statuses (`"authorized"`), while the Retrieve Request returns uppercase (`"AUTHORIZED"`) — this is expected. See Payment Statuses.
## Supported Events
The payload content depends on the event:
| Event | Webhook payment status | Payload update |
| ----------------- | :-----------------------------------: | ------------------------------------------------------------ |
| Authorize | authorized | "status": "authorized" |
| Capture | authorized | capture info is added to captures.\[] array |
| Close | closed | "status": "closed" and "closed\_at" updated |
| Reject | rejected | "status": "rejected" |
| Expire (Optional) | expired | "status": "expired", "expired\_at" and "is\_expired" updated |
| Refund | closed | refund info is added to refunds.\[] array |
| Update | the same as before the Update Request | order.reference\_id updated |
The "expire" event is optional — ask the Tabby team to enable it for your store if you want notifications when a payment is cancelled by the customer or expires.
## A Typical Payment
For a regular successful order you will receive three notifications:
1. **Payment authorized** — the payload status is `authorized`. Check the order and process it in your OMS if it wasn't processed yet, then send the Capture Request.
2. **Payment captured** — the payload status is still `authorized`, with your capture added to the `captures` array. No action is required.
3. **Payment closed** — the payload status is `closed`: the payment is completed and confirmed from both sides. No action is required.
Looking for notifications about disputes raised on your payments? See Dispute webhooks — a separate, opt-in webhook enabled by request to the Integrations Team.
## Best Practices
Webhooks are asynchronous: the delivery order is not guaranteed, and the same event may occasionally be delivered twice.
* **Respond fast.** Acknowledge the webhook with `200` right away and process it asynchronously, instead of holding the response until processing is done.
* **Handle out-of-order delivery.** A capture event may arrive before an authorization event — use a finite state machine or similar logic instead of assuming the order.
* **Deduplicate.** Ignore a webhook if the same notification was already processed.
* **Filter events.** You receive notifications for all payment events — process only the ones you need.
* **Allowlist Tabby server IPs:**
```
34.166.36.90
34.166.35.211
34.166.34.222
34.166.37.207
34.93.76.191
34.166.128.182
34.166.170.3
34.166.249.7
```
To test and debug webhooks, use a tool like Webhook.site to inspect the payload and headers Tabby sends to your endpoint.
## Retry Attempts
A webhook request times out after **1 minute**. If it times out or gets any response other than `200`, Tabby resends it up to **4 more times** with an exponential interval between attempts (1–4 minutes). Retries don't block other notifications — Tabby keeps sending webhooks for other payment events as they occur.
# Shopify Product Catalogue
Source: https://docs.tabby.ai/product-catalogue/shopify-product-catalogue
This page describes the installation process for Tabby Catalogue in Shopify.
* In Tabby Merchant Dashboard go to the “Marketing” tab;
* Сheck the status of your store. It should be published to start the item uploading process;
* Once the store is published, click the “Upload products” button and choose Shopify;
Shopify Product Catalogue in Dashboard
* Wait for the redirection here to the documentation and installation link;
* In Shopify App Store click "Install" and choose a necessary store from the list of suggested stores;
* You will be redirected to your Shopify store's admin panel and requested to install the application with the following permissions:
App Permissions
* Click "Connect" and in the appearing pop-up enter the secret key of your store (you can find it in the Tabby Payment application or in the Merchant Dashboard "Integration" tab), as the app is not connected by default.
Connection Step
Key Installation
* Once you connect the application with the secret key, you will observe the "Publish" button;
Publishing Step
* After publishing, you are ready to use Tabby Catalogue, the synchronization starts immediately.
# Zid Product Catalogue
Source: https://docs.tabby.ai/product-catalogue/zid-product-catalogue
Here you will find the instruction how to install Tabby Catalogue in Zid.
* In Tabby Merchant Dashboard go to the “Marketing” tab;
* Сheck the status of your store. It should be published to start the item uploading process;
* Once the store is published, click the “Upload products” button and choose Zid;
* You are redirected here to the instructions and the Zid App Market installation links:
* **KSA market** - Tabby Catalogue (KSA);
* **UAE / Kuwait markets** - Tabby Catalogue (UAE/Kuwait).
Merchants operating in more than one of these markets should install both apps - each app handles its own region.
* In Zid App Market install and activate the relevant Tabby Catalogue app(s);
* Upon activation you will be redirected back to the Tabby Merchant Dashboard to undergo the OAuth process. The KSA app connects to merchant.tabby.sa and the UAE/Kuwait app connects to merchant.tabby.ai;
Make sure your store is published before uploading the items
Tabby Catalogue in Zid App Market
Activation Page
# Postman API Collection
Source: https://docs.tabby.ai/testing-guidelines/postman-api-collections
Download the Postman collection, import it into Postman, and set the Collection Variables:
* base\_url — `https://api.tabby.ai` (UAE, Kuwait) or `https://api.tabby.sa` (KSA). See Base URLs.
* secret\_key — your Tabby Secret API Key
* merchant\_code — your merchant code
* currency — `AED`, `SAR`, or `KWD`
Tabby API Collection
# Testing Credentials
Source: https://docs.tabby.ai/testing-guidelines/testing-credentials
* Full testing is required for all Custom API and SFCC Integrations, and is optional for Magento and OpenCart Integrations.
* Other integrations do not require testing and can be launched with the Live Keys.
Ensure that you've added snippets on the **Product**, **Cart** and **Checkout** pages.
## 1. Payment Success
**Testing Steps:**
1. Add an item to your shopping cart and proceed to checkout.
2. Fill in all the required fields at checkout, and use the following email and phone numbers:
```
Positive flow:
UAE: otp.success@tabby.ai, phone: +971500000001
KSA: otp.success@tabby.ai, phone: +966500000001
Kuwait: otp.success@tabby.ai, phone: +96590000001
```
3. Choose Tabby as the payment method and click "Place order."
4. Complete the payment using OTP:8888 on Tabby HPP and redirect to the store's success page.
5. Verify that the capture of the successful payment occurred - check for status CAPTURED on the Merchant Dashboard or Payment status AUTHORIZED and CLOSED via Retrieve Payment API.
**Expected Results:**
1. Store checkout opens.
2. Tabby payment method is available on the checkout page (background pre-scoring passed successfully).
3. Tabby Hosted Payment Page opens.
4. The success Tabby screen appears and redirects to the Success URL; the store's 'Thank you' page appears.
5. Order is captured:
* Payment Status is CLOSED;
* captured amount is present in the "captures":\[] array of objects.
## 2. Background Pre-scoring Reject
**Testing Steps:**
1. Add an item to your shopping cart and proceed to checkout.
2. Fill in all the required fields at checkout, and use the following email and phone numbers:
```
Background Pre-scoring reject flow:
UAE: otp.success@tabby.ai, phone: +971500000002
KSA: otp.success@tabby.ai, phone: +966500000002
Kuwait: otp.success@tabby.ai, phone: +96590000002
```
3. Attempt to choose Tabby as the payment method.
**Expected Results:**
1. Store checkout opens.
2. Tabby payment method is hidden or marked as unavailable with the message:
* English: Sorry, Tabby is unable to approve this purchase, please use an alternative payment method for your order.
* Arabic: نأسف، تابي غير قادرة على الموافقة على هذه العملية. الرجاء استخدام طريقة دفع أخرى.
3. Tabby is hidden from the payment methods list or marked as unavailable.
## 3. Payment Cancellation
**Testing Steps:**
1. Add an item to your shopping cart and proceed to checkout.
2. Fill in all the required fields at checkout, and use the following email and phone numbers:
```
Positive flow:
UAE: otp.success@tabby.ai, phone: +971500000001
KSA: otp.success@tabby.ai, phone: +966500000001
Kuwait: otp.success@tabby.ai, phone: +96590000001
```
3. Choose Tabby as the payment method and click "Place order."
4. Click on the 'Back to Store' button (Desktop) or the left corner cross button (Mobile), and confirm cancellation.
**Expected Results:**
1. Store checkout opens.
2. Tabby payment method is available on the checkout page (background pre-scoring passed successfully).
3. Tabby Hosted Payment Page opens.
4. Redirect to the Cancel URL - store checkout or cart page. Verify that the cart is not emptied, and a text message with a cancellation reason is shown:
* English: You aborted the payment. Please retry or choose another payment method.
* Arabic: لقد ألغيت الدفعة. فضلاً حاول مجددًا أو اختر طريقة دفع أخرى.
## 4. Payment Failure
**Testing Steps:**
1. Add an item to your shopping cart and proceed to checkout.
2. Fill in all the required fields at checkout, and use the following email and phone numbers:
```
Negative flow:
UAE: otp.rejected@tabby.ai, phone: +971500000001
KSA: otp.rejected@tabby.ai, phone: +966500000001
Kuwait: otp.rejected@tabby.ai, phone: +96590000001
```
3. Choose Tabby as the payment method and click "Place order."
4. Finish the payment using OTP:8888 in Tabby HPP.
5. Confirm returning to the store by clicking the 'Back to store' button.
6. Verify the payment status via Retrieve Payment API.
**Expected Results:**
1. Store checkout opens.
2. Tabby payment method is available on the checkout page (background pre-scoring passed successfully).
3. Tabby Hosted Payment Page opens.
4. The rejection screen with the message 'We can’t approve this purchase' appears.
5. Redirect to the Failure URL - store checkout or cart page. Verify that the cart is not emptied, and a text message with a failure reason is shown:
* English: Sorry, Tabby is unable to approve this purchase, please use an alternative payment method for your order.
* Arabic: نأسف، تابي غير قادرة على الموافقة على هذه العملية. الرجاء استخدام طريقة دفع أخرى.
6. Tabby payment method is still available for selection among payment methods on Checkout.
7. No order appears in the Merchant Dashboard (unsuccessful orders are not displayed in the Dashboard), Payment Status REJECTED.
## 5. Corner Case
**Testing Steps:**
1. Add an item to your shopping cart and proceed to checkout.
2. Fill in all the required fields at checkout, and use the following email and phone numbers:
```
Negative flow:
UAE: otp.success@tabby.ai, phone: +971500000001
KSA: otp.success@tabby.ai, phone: +966500000001
Kuwait: otp.success@tabby.ai, phone: +96590000001
```
3. Choose Tabby as the payment method and click "Place order."
4. Finish the payment using OTP:8888 in Tabby HPP.
5. Once you see the Success Tabby screen (with the tick), **close the browser tab before the redirection.**
6. Verify that the **capture** of the successful payment occurred - check **order status CAPTURED on the Merchant Dashboard** or Payment status via Retrieve Payment API is CLOSED. Ensure the order is marked **successful** on your side.
**Expected Results:**
1. Store checkout opens.
2. Tabby payment method is available on the checkout page (background pre-scoring passed successfully).
3. Tabby Hosted Payment Page opens.
4. There is no redirection to the Success page as the browser tab is closed before redirection.
5. Payment Status changes to AUTHORIZED, then after capture is triggered, it changes to CLOSED with a captured amount in the "captures":\[] array of objects, triggered by the Webhook notifications or Cron Job.
Retrieve payment status returned status AUTHORIZED **before capture** and CLOSED **after capture**.
If you encounter any non-captured payments (with AUTHORIZED status on Payments API or NEW status on Merchant Dashboard), you can initiate a **Manual Capture** or **Cancel** on the Merchant Dashboard, or **Capture** or **Close** Payment API Request.
## 6. Payment Refund via API
If you are not using the Tabby dashboard.
**Testing Steps:**
1. Choose an order on your OMS and perform a refund.
2. Check the order on the Tabby Merchant Dashboard and Payment status via Retrieve request.
**Expected Results:**
1. The refund is reflected on the OMS without any API errors.
2. The order has Refunded/Partially Refunded status in the Tabby Merchant Dashboard, and the Payment status is CLOSED with the refunded amount in the refunds":\[] array of objects.
## 7. Tabby Checkout Focus Change (Mobile Apps)
**Precondition:** Tabby Checkout is opened using positive flow credentials at the OTP step.
**Testing Steps:**
1. At the OTP step on Tabby Checkout opened in the Webview/In-App browser, minimize the app by navigating to the home screen.
2. Wait a few seconds and then return to the app.
**Expected Results:**
1. The app correctly recovers the Tabby checkout screen at the same step. No crashes or hangs of the app after the return.
2. No App or Webview issues appear.