> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tabby.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 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:

<Steps>
  <Step
    stepNumber={1}
    title={(
  <span>
    <a href="/pay-in-4-custom-integration/payment-processing#payment-verification">
      Verify
    </a>
    <span style={{ fontWeight: 'normal' }}>
      &nbsp;the payment status server-to-server
    </span>
  </span>
)}
  />

  <Step
    stepNumber={2}
    title={(
  <span>
    <a href="/pay-in-4-custom-integration/payment-processing#payment-capture">
      Capture
    </a>
    <span style={{ fontWeight: 'normal' }}>
      &nbsp;the payment — only captured payments are settled to you
    </span>
  </span>
)}
  />

  <Step
    stepNumber={3}
    title={(
  <span>
    <a href="/pay-in-4-custom-integration/payment-processing#payment-refund">
      Refund
    </a>
    <span style={{ fontWeight: 'normal' }}>
      &nbsp;the payment when needed
    </span>
  </span>
)}
  />
</Steps>

## 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 <a href="/api-reference/payments/retrieve-a-payment">Retrieve Request</a> with the `payment_id` you received at <a href="/pay-in-4-custom-integration/checkout-flow#checkout-session-initiation">session creation</a> 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 <a href="/pay-in-4-custom-integration/payment-statuses">Payment Statuses</a> for the full lifecycle):

| Payment `status`       | Your action                                                                                                                                                                                                                           |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AUTHORIZED`           | Process the order in your OMS, <a href="/pay-in-4-custom-integration/payment-processing#payment-capture">capture the payment</a>, 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).** <a href="/pay-in-4-custom-integration/webhooks">Webhooks</a> 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`.

<Tip>
  Webhooks use lowercase statuses (`"authorized"`), while the Retrieve Request returns uppercase (`"AUTHORIZED"`) — this is expected. See <a href="/pay-in-4-custom-integration/payment-statuses#statuses-in-api-responses-vs-webhooks">Payment Statuses</a>.
</Tip>

### 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 <a href="/api-reference/payments/capture-a-payment">Capture Request</a> 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.

<Warning>
  Only an `AUTHORIZED` payment can be captured. Capture attempts in `CREATED`, `EXPIRED`, `CLOSED`, or `REJECTED` return a `400` error.
</Warning>

### 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 <a href="/api-reference/payments/refund-a-payment">Refund Request</a> or on Merchant Dashboard (<a href="https://merchant.tabby.ai/">merchant.tabby.ai</a> / <a href="https://merchant.tabby.sa/">merchant.tabby.sa</a> 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 **45 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 <a href="/introduction/technical-requirements#amount">requirements</a>?

## 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.
