# Refunds (/docs/guides/refunds)

This guide shows you how to give money back to a customer. You refund a whole order or part of it, refund a single payment, or give the money as store credit instead. Every refund moves money, so read the result before you tell the customer it is done.

Refunds need a secret or trusted token. Limited tokens get `403`.

## Refund an order or a payment [#refund-an-order-or-a-payment]

| You want to | Call | Answer |
|---|---|---|
| Refund an order, in full or in part | [Refund an order](/api/refunds/refund-order) | A `refund_list`, one refund per payment used |
| Refund one payment of an order | [Refund a payment](/api/payments/create-payment-refund) | One refund |

Use the order refund in most cases. An order can have more than one payment (for example store credit plus a card). The order refund spreads the amount over them, largest payment first and store credit last. Use the payment refund when you want to choose the payment yourself.

Money that was only authorized (`pending`) has not been taken yet: void the payment instead of refunding it. See [Accept payments](/docs/guides/accept-payments#authorize-now-capture-later).

## Full refund [#full-refund]

**Send an empty body to refund everything** that has not been refunded yet.

```bash title="Request"
curl -X POST https://api.comecero.com/api/v1/orders/8352-CSGYX-348/refunds \
  -H "Authorization: Bearer $COMECERO_TEST_TOKEN"
```

```json title="Response"
{
  "object": "refund_list",
  "currency": "USD",
  "refunds": [
    {
      "object": "refund",
      "refund_id": "0091408123355RFp3Kd8Lw",
      "success": true,
      "status": "completed",
      "total": 107.45
    }
  ]
}
```

Once the whole amount is refunded, the order's `payment_status` becomes `refunded`.

## Partial refund [#partial-refund]

Send exactly one of these. The other amounts, such as the tax part, are worked out for you.

- **`total`**: an amount with tax, in the payment currency.
- **`items`**: items by `item_id` and `quantity`. An item's `item_id` is its product id, which is stored in lowercase and ends in `.test` in test mode. Works on an order, an invoice, or a payment that belongs to one; a payment with no order or invoice ignores `items` and is refunded in full. Leave out `quantity` to refund all of an item that is left. You may add **`shipping`** to the same request.
- **`shipping`**: shipping only, with tax.
- **`tax`**: tax only, for example when tax was charged by mistake.

```bash title="Request"
curl https://api.comecero.com/api/v1/orders/8352-CSGYX-348/refunds \
  -H "Authorization: Bearer $COMECERO_TEST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [{ "item_id": "pdf-pro.test", "quantity": 1 }],
    "reason": "Customer request"
  }'
```

A refund and the refunds before it can never be more than what was paid. Send a `reason` from [Get refund options](/api/refunds/get-refund-options) to keep your reports tidy, and `reference` or `meta` for your own data.

## Read the result [#read-the-result]

Each refund in the answer has its own `success` and `status`:

- `completed`: the money is back with the customer.
- `pending`: the payment provider is still working on it. It completes or fails later.
- `failed`: the provider refused it.

When every refund fails, the order refund answers with an error and puts the `refund_list` in `error.meta.refund_list`. A refund that is still `pending` is not a failure: wait for its event.

Do not send a failed or unclear refund again by itself. [Get the order's refunds](/api/orders/list-order-refunds) first, so you never give the money back twice.

## Refund to store credit [#refund-to-store-credit]

To give the money as store credit instead of back to the card or wallet, send the store credit payment method:

```json
{
  "total": 20,
  "payment_method": { "type": "customer_account_balance" }
}
```

The amount goes to the customer's balance. [Get the customer's balance](/api/customers/get-customer-balance) to see it, and [list its transactions](/api/customers/list-customer-balance-transactions) for the history. The customer spends it by paying with `payment_method.type` set to `customer_account_balance`, and renewals use it before the saved payment method.

Store credit can also be bought: a payment with no cart or invoice and `apply_to_balance: true` adds the captured amount to the balance. See [Add store credit by payment](/api/customers/create-customer-balance-payment).

## What fires [#what-fires]

For each refund in the answer:

- [`refund:created_success`](/api/webhooks/refund-created-success) when it completes (later, for a `pending` one). The customer gets the refund email.
- [`refund:created_failure`](/api/webhooks/refund-created-failure) when it fails, or when a completed refund is reversed later by the payment provider.

## Chargebacks and refunds made elsewhere [#chargebacks-and-refunds-made-elsewhere]

Two flags write down money that already went back, so no money moves:

- `is_chargeback: true` with a `total` records a chargeback the bank took. It sends no email and cancels the subscription the order belongs to.
- `record_only: true` with a `record_only_memo` records a refund you paid some other way.

Both work only on accounts on the agent model, for payments made through your own gateway. A payment made through a Comecero platform gateway, such as Comecero Express Payments, gets `400`. `record_only_memo` needs at least 5 characters. On an order with more than one successful payment, record a chargeback on the payment.

<Callout type="warn">On an account that is not on the agent model, the API ignores both flags without an error, and the refund is real: the money goes back to the customer.</Callout>

<Cards>
  <Card title="Accept payments" href="/docs/guides/accept-payments" />
  <Card title="Webhooks" href="/docs/guides/webhooks" />
</Cards>
