Skip to main content
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.

API Keys and Environment

  • No secret key client-side: search your rendered page source and all browser network traffic for sk_ — the Secret Key must never appear in the frontend. Snippets and the HPP use only the Public Key (pk_...) and merchant code
  • Secret Key for all backend calls: every server-side request (session creation, payments, captures, refunds, webhooks) is authorized with the Secret Key — the Public Key belongs to the frontend snippets only
  • All calls use the base URL matching the merchant’s region — see Base URLs
  • Capture, refund and close use the /api/v2/ endpoints (v1 is deprecated)

On-Site Messaging

  • Product and Cart snippets and pop-ups are present in accordance with the:
  • 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
  • Session is created only when the customer clicks “Place order” — check your backend logs: the full-payload /api/v2/checkout call is triggered by the Place-order action only, not by opening the checkout page (the background pre-scoring call is separate), and one click produces exactly one session
  • Sessions are disposable: a fresh session is created for every payment attempt — the HPP URL is never cached or reused, and your own checkout timeout is shorter than the HPP session lifetime
  • Price parity: the order total with Tabby selected equals the total with any other payment method — no Tabby-specific surcharges or reduced discounts
  • A rejected session is a business outcome, not an error — don’t log it as a failure or fire alerts. On a pre-scoring reject, hide Tabby or mark it unavailable with the rejection message (per Background pre-scoring); on a reject at session creation, show the rejection message instead of redirecting (there is no web_url to redirect to)
  • Cart behaviour: the cart is kept after cancellation/failure and cleared after a successful payment
  • If the store has both Arabic and English languages — your own redirect/result pages (success, cancel, failure messages) are localized too, not only the snippets
  • Payload data quality: place a second order with the same registered account and confirm buyer_history / order_history carry real values (actual registration date, real past orders, ISO-8601 dates) — omit optional fields instead of sending empty strings or placeholders
  • Success scenario is working
  • Cancellation scenario is working
  • Failure scenario is working
  • Corner case is supported — complete the OTP, close the tab before the redirect, and verify the payment is still captured via the webhook path

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
  • Your webhook endpoint answers 200 fast and tolerates duplicates — the same event can be delivered twice, and delivery order is not guaranteed (see Handling Edge Cases)
  • For a test payment you observe the full webhook sequence: authorizedauthorized with your capture in captures[]closed
  • A capture timeout is not a failure: if the Capture Request times out, your system retrieves the payment and retries the capture with the same reference_id — verify no duplicate capture is created and no order is left uncaptured
  • Every capture and refund carries a unique reference_id derived from your order (see Idempotent Requests)

Refunds and Cancellations

  • Refunds validate against the captured amount, not the authorized one — a refund on an uncaptured payment fails. To release an uncaptured amount use Close instead, including the leftover after a partial capture (it is not auto-closed)
  • Reusing a reference_id replays the first refund instead of creating a new one — a second, genuine refund needs a new reference_id, and the cumulative refunded total cannot exceed the captured amount (see refund test scenario)
  • Your code reads captures[] and refunds[] entries by created_at, never by array position — the order is not guaranteed
If you have any questions considering this Checklist - feel free to contact us in the Integrations thread.