Refunds
Return all or part of a succeeded payment to the customer.
You can refund a payment whose status is succeeded, in full or in several partial refunds, until the whole amount has been refunded. Refunds go back to the method the customer paid with.
Create a refund
POST /v1/payments/:id/refunds
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | No | Amount to refund in minor units. Omit it to refund everything not yet refunded. |
reason | string | No | requested_by_customer (the default), duplicate, fraudulent or other. |
Send a JSON body with Content-Type: application/json. An empty object ({}) refunds everything not yet refunded; a POST with no body at all is treated the same way.
Full refund
curl https://api.teyra.co/v1/payments/pay_01JBX4T9W2/refunds \
-H "Authorization: Bearer $TEYRA_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: refund-order-1042" \
-d '{}'Partial refund
Refund 5.000 KWD of a 12.500 KWD payment:
curl https://api.teyra.co/v1/payments/pay_01JBX4T9W2/refunds \
-H "Authorization: Bearer $TEYRA_SECRET_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: refund-order-1042-item-3" \
-d '{ "amount": 5000, "reason": "requested_by_customer" }'The response is 201 Created with a Refund. The payment's amount_refunded goes up by the refunded amount; its status stays succeeded.
The Refund object
{
"id": "re_01JBX6M1QK",
"object": "refund",
"livemode": false,
"payment_id": "pay_01JBX4T9W2",
"amount": 5000,
"currency": "KWD",
"status": "pending",
"reason": "requested_by_customer",
"created_at": "2026-10-29T09:12:00.000Z",
"succeeded_at": null,
"failure_message": null
}| Status | Meaning |
|---|---|
pending | Accepted and being processed. |
succeeded | The money is on its way back to the customer. A refund.succeeded webhook is sent. |
failed | The refund could not be completed. See failure_message. A refund.failed webhook is sent, and the amount can be refunded again. |
canceled | The refund was canceled before it completed. |
How long the money takes to appear on the customer's statement depends on their bank and payment method.
The refunded amount comes out of your balance, and Teyra Pay's commission on the original payment isn't returned. On some accounts, partial refunds in three-decimal currencies (KWD, BHD, OMR, JOD) must end in 0, like payment amounts: see Payment methods and your account.
Rules and errors
| Case | Error |
|---|---|
The payment is not succeeded (for example failed or expired) | 422 payment_not_refundable |
amount is more than amount minus amount_refunded, or nothing is left to refund | 422 refund_exceeds_amount (details.remaining holds what is left) |
amount is zero, negative or not an integer, or reason is not one of the values above | 422 validation_error |
| The payment doesn't exist (or belongs to the other mode) | 404 payment_not_found |
Retrieve and list refunds
curl https://api.teyra.co/v1/refunds/re_01JBX6M1QK \
-H "Authorization: Bearer $TEYRA_SECRET_KEY"
curl -G https://api.teyra.co/v1/refunds \
-H "Authorization: Bearer $TEYRA_SECRET_KEY" \
-d payment_id=pay_01JBX4T9W2An unknown refund ID returns 404 refund_not_found.
You can also refund from the dashboard: open the payment and click Refund.
Disputes
A dispute (or chargeback) is when a cardholder asks their bank to reverse a card, Apple Pay or Google Pay payment, for example because they don't recognise it or say the order never arrived. It is not a refund you started: the cardholder's bank opens it, and the card network decides the outcome.
Whether disputes are reported in your dashboard depends on your account. On accounts where they are, including UAE accounts:
- Every owner of the account gets a "A payment was disputed" email with the disputed amount, the payment ID and your
reference, the reason, and the date to respond by. - Refunds → Disputes in the dashboard lists each dispute with its amount, reason, respond-by date and status, and the payment's timeline shows when it opened, each update and how it closed.
- The disputed amount is held until the dispute is decided. The payment's
statusstayssucceededandamount_refundeddoesn't change.
| Dispute status | Meaning |
|---|---|
needs_response | Opened. Send your evidence before the respond-by date. |
under_review | Evidence was sent; the cardholder's bank is deciding. |
won | Decided in your favour. The held amount is released to you. |
lost | Decided for the cardholder. The disputed amount is recovered from your balance. |
closed | Closed without a win or loss decision, for example withdrawn by the cardholder. |
On other accounts, Teyra Pay support contacts you when one of your payments is disputed.
What to do:
- Respond before the respond-by date. Email support@teyra.co with proof of the order: the invoice, proof of delivery or of the service, and your messages with the customer. Teyra Pay submits it to the card network for you.
- Don't refund a disputed payment. If the cardholder also wins the dispute, they are paid back twice.
- Reduce disputes: use a clear
description(it appears at checkout), a business name customers recognise, and refund quickly when a customer asks.
Disputes are not available in the /v1 API and don't send webhook events yet; follow them in the dashboard.