---
title: "Refund a payment | Timbro"
description: "Request a refund and retrieve its outcome"
canonical: "https://timbro.do/en/docs/cobros/reembolsos/"
---

Collect

# Refund a payment

[Read `refundable`](https://timbro.do/en/docs/cobros/reembolsos/#before-you-refund-read-refundable) first to learn whether the money will be returned without the Timbro team stepping in. Then use the id of the captured payment and a new reference for the refund:

- [TypeScript](https://timbro.do/en/docs/cobros/reembolsos/#tab-panel-0-0)
- [Python](https://timbro.do/en/docs/cobros/reembolsos/#tab-panel-0-1)

```ts
import { createTimbroPayments } from "@timbro/payments";

const timbro = createTimbroPayments({ apiKey: process.env.TIMBRO_PAYMENTS_SECRET_KEY! });
const refund = await timbro.refunds.create({
  paymentId: "payment_123456789abcdefghjkmnpqr",
  refundReference: "order-123-return-1",
});
```

```python
import os

from timbro_payments import TimbroPayments

timbro = TimbroPayments(api_key=os.environ["TIMBRO_PAYMENTS_SECRET_KEY"])
refund = timbro.refunds.create({
    "paymentId": "payment_123456789abcdefghjkmnpqr",
    "refundReference": "order-123-return-1",
})
```

Omitting `amount` reserves the remaining refundable balance once. Repeat the same request with the same `refundReference` if you lose the response; you will recover that reservation and its current status. To find it without repeating the request, list refunds with the exact `paymentId` and `refundReference` filters. Do not use a new reference to recover an earlier request.

To request a partial refund, add `amount: { currency: "DOP", value: "100.00" }` and the exact returned ITBIS in `taxAmount`, for example `{ currency: "DOP", value: "15.25" }`. Use the tax from the returned items or credit note; Timbro does not estimate it proportionally. Do not change the amount on a refund that has already been created. Read `refundable` before you choose the amount, as described next.

## Before you refund, read `refundable`

A `succeeded` payment includes `refundable`. Retrieve it before you call `POST /v1/refunds` to learn what Timbro will do with each amount:

- [TypeScript](https://timbro.do/en/docs/cobros/reembolsos/#tab-panel-1-0)
- [Python](https://timbro.do/en/docs/cobros/reembolsos/#tab-panel-1-1)

```ts
const payment = await timbro.payments.retrieve("payment_123456789abcdefghjkmnpqr");
const automaticAmount = payment.refundable?.automaticAmount ?? null;

if (automaticAmount !== null) {
  await timbro.refunds.create({
    paymentId: payment.id,
    refundReference: "order-123-return-1",
    amount: automaticAmount,
  });
}
```

```python
payment = timbro.payments.retrieve("payment_123456789abcdefghjkmnpqr")
refundable = payment["refundable"]
automatic_amount = refundable["automaticAmount"] if refundable else None

if automatic_amount is not None:
    timbro.refunds.create({
        "paymentId": payment["id"],
        "refundReference": "order-123-return-1",
        "amount": automatic_amount,
    })
```

- `refundable.amount` is the balance a new refund can reserve: the captured amount minus every processing, succeeded, verifying, and `operator_required` refund.
- `refundable.automaticAmount` is the one amount whose refund moves money without the Timbro team stepping in. It is `null` when every refund needs the Timbro team.
- `refundable` is `null` until the payment reaches `succeeded`.

When `automaticAmount` has a value, send it as `amount`. Timbro returns the money and the refund reaches `succeeded` without the Timbro team stepping in.

When `automaticAmount` is `null`, or when you send any other amount, Timbro accepts the request but creates the refund as `operator_required`: it keeps its reservation, and the Timbro team returns the money. Decide before you create it:

- If the customer needs the money now, return it another way, such as cash, and do not also create the refund in Timbro.
- If the customer can wait, create the refund with your `refundReference` and let the Timbro team act. You receive `refund.operator_required` when it is waiting for the Timbro team.

## When the payment includes a voluntary tip

A payment offers a voluntary tip only when it includes a legal-tip item and `checkoutPreferences.tips` is enabled; see [how to configure it](https://timbro.do/en/docs/cobros/impuestos-y-articulos/#offer-a-voluntary-tip).

`amount` is the refund total, including any tip being returned. For a partial refund, omitting `voluntaryTipAmount` returns zero voluntary tip. To return RD$ 100.00, including RD$ 20.00 of voluntary tip:

- [TypeScript](https://timbro.do/en/docs/cobros/reembolsos/#tab-panel-2-0)
- [Python](https://timbro.do/en/docs/cobros/reembolsos/#tab-panel-2-1)

```ts
const partialRefund = await timbro.refunds.create({
  paymentId: "payment_123456789abcdefghjkmnpqr",
  refundReference: "order-123-return-2",
  amount: { currency: "DOP", value: "100.00" },
  voluntaryTipAmount: { currency: "DOP", value: "20.00" },
});
```

```python
partial_refund = timbro.refunds.create({
    "paymentId": "payment_123456789abcdefghjkmnpqr",
    "refundReference": "order-123-return-2",
    "amount": {"currency": "DOP", "value": "100.00"},
    "voluntaryTipAmount": {"currency": "DOP", "value": "20.00"},
})
```

When `amount` is omitted to return the remaining balance, the remaining voluntary tip is included by default, and the refund reports `kind: "full"` even after an earlier partial refund. A refund for the full captured total also includes the remaining tip by default. The sale and tip portions must each fit their remaining balances. The legal tip belongs to the sale; `voluntaryTipAmount` identifies only the voluntary tip.

The credit note (E34) must reflect the refunded fiscal sale and exclude voluntary tip. Issuing the note and returning the money are separate tasks. After issuing it, associate it with the refund:

```ts
await timbro.refunds.attachInvoice({
  refundId: refund.id,
  invoiceId: "f35b7ae4-c484-4c63-981e-4f0f15e913b5",
  idempotencyKey: "order-123-return-2-credit-note",
});
```

Timbro checks that the credit note total equals the refund amount minus the refunded voluntary tip and that its ITBIS matches the refund’s ITBIS when known. The association does not change the refund outcome.

## What can run automatically

`refundable.automaticAmount` has a value only when all of these are true:

- The payment is a Test mode, Dominican peso (DOP), unsplit card payment.
- The refund is for the full captured amount.
- The payment has no earlier refund other than declined ones.
- The payment and the refund go through Azul or CardNet, with the original payment’s merchant account and credentials.

`refundable.automaticPartial` separately identifies payments eligible for a smaller refund, with `maximumAmount` and `maximumTaxAmount`. It currently supports one partial refund of an Azul DOP Sale in Test mode when the request declares exact `taxAmount`. The amount must be below the captured total, and the tax must fit both the refund amount and the original captured tax. Repeat both values unchanged when recovering a request.

Partial refunds through CardNet or of held amounts that were later captured, partial requests without exact tax, split payments, Live payments, Apple Pay and Google Pay payments, and payments with an earlier successful or unresolved refund remain `operator_required`. So does a payment whose merchant account lacks the capture evidence or refund credentials; no money movement is attempted. Contact the Timbro team to continue those cases.

The refund keeps the original merchant account and capture even if the merchant’s default merchant account changes later.

## Confirm the outcome

- [TypeScript](https://timbro.do/en/docs/cobros/reembolsos/#tab-panel-3-0)
- [Python](https://timbro.do/en/docs/cobros/reembolsos/#tab-panel-3-1)

```ts
const current = await timbro.refunds.retrieve(refund.id);
```

```python
current = timbro.refunds.retrieve(refund["id"])
```

`succeeded` confirms the refund; `pending`, `processing`, and `verifying` do not confirm it yet. If the outcome is unknown, retrieve this refund: do not create another. `declined` means it was rejected, and `operator_required` keeps its reservation and needs the Timbro team.

To avoid polling, subscribe your [webhook](https://timbro.do/en/docs/cobros/webhooks/) to `refund.succeeded` and `refund.declined`. When one arrives, retrieve the refund with `event.data.id` and act on that status.

A refund does not issue an e-CF. If the sale requires a credit note, issue it as type E34 through `/v1/invoices` and keep the refund and invoice outcomes separate. Then associate the note with `refunds.attachInvoice`.

[Previous\
Collect with a QR code](https://timbro.do/en/docs/cobros/qr-y-nfc/)[Next\
Connect your merchant account](https://timbro.do/en/docs/negocio/conectar-afiliacion/)

Sell, serve your customers, and collect payments from your phone

© 2026 Timbro. All rights reserved

[Español](https://timbro.do/docs/cobros/reembolsos/)[English](https://timbro.do/en/docs/cobros/reembolsos/)

## Products

[Invoicing](https://timbro.do/en/facturacion-electronica/)[Serve](https://timbro.do/en/atiende/)[Collect](https://timbro.do/en/pagos/)[Portal Timbro](https://timbro.do/en/portal-timbro/)[Integrations](https://timbro.do/en/integraciones/)[Cuenta Timbro](https://timbro.do/en/cuenta-timbro/)[Pricing](https://timbro.do/en/precios/)

## Developers

[SDKs and API](https://timbro.do/en/desarrolladores/)[Documentation](https://timbro.do/en/docs/)[API reference](https://timbro.do/en/docs/reference/payments/)

## Company

[INDEXA, the company behind Timbro](https://indexa.do/)[Presentations](https://timbro.do/en/presentaciones/)

## Help

[How to start](https://timbro.do/en/como-empezar/)[Electronic invoicing guide](https://timbro.do/en/guias/facturacion-electronica-republica-dominicana/)[Contact](https://timbro.do/en/contacto/)<hola@timbro.do>

## Legal

[Business Terms](https://timbro.do/en/politicas/negocios/)[Terms of use](https://timbro.do/en/politicas/uso/)[Privacy](https://timbro.do/en/politicas/privacidad/)[Security](https://timbro.do/en/politicas/seguridad/)[All documents](https://timbro.do/en/politicas/)
