# Refund

> Return captured funds fully or partially, and track refund status through to the customer.

A refund returns captured funds to the customer on the same rail as the original payment. Refunds are asynchronous objects with their own lifecycle and dedicated events — you never need to poll for the outcome.

To void an authorization before any funds are captured, use [Cancel](/docs/payments/payment-operations/cancel). To undo a captured payment on the same business day before settlement, use [Reverse](/docs/payments/payment-operations/reverse).

## Create a refund

Refund a payment by its ID. Without an `amount`, VINR refunds the full remaining refundable balance.

```typescript
import { Vinr } from '@vinr/sdk';

const vinr = new Vinr({ secretKey: process.env.VINR_SECRET_KEY });

const refund = await vinr.refunds.create({
  payment: 'pay_3Nf8x2a',
  reason: 'requested_by_customer',
  metadata: { ticketId: 'ZD-4821' },
});

// refund.id     → "re_7Qp2m1c..."
// refund.status → "pending"
// refund.amount → 5000   (full original amount)
```

```bash
curl -X POST https://api.vinr.com/v1/refunds \
  -H "X-Api-Key: $VINR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "payment": "pay_3Nf8x2a", "reason": "requested_by_customer" }'
```

| Field      | Type      | Description                                                                     | Default             |
| ---------- | --------- | ------------------------------------------------------------------------------- | ------------------- |
| `payment`  | `string`  | ID of the payment to refund (pay\_…). Required.                                 | `—`                 |
| `amount`   | `integer` | Minor units to refund. Omit for the full remaining balance.                     | `remaining balance` |
| `reason`   | `enum`    | One of: requested\_by\_customer, duplicate, fraudulent, product\_not\_received. | `—`                 |
| `metadata` | `object`  | Up to 40 key/value pairs echoed on the refund object and its events.            | `—`                 |

## Partial refunds

Pass an explicit `amount` to refund only part of the captured total. The same payment can be refunded multiple times until the refundable balance reaches zero.

```typescript
// €50.00 charge — refund €10.00
const partial = await vinr.refunds.create({
  payment: 'pay_3Nf8x2a',
  amount: 1000,
  reason: 'product_not_received',
});
```

Once `amountRefunded` equals the captured amount the payment moves to `refunded`. While a balance remains, the status is `partially_refunded`. Requesting more than the remaining balance returns `422` with code `amount_too_large`.

## Refund status and timing

| Status      | Meaning                                                                                            |
| ----------- | -------------------------------------------------------------------------------------------------- |
| `pending`   | Accepted by VINR, queued to the rail.                                                              |
| `succeeded` | Funds confirmed on their way to the customer.                                                      |
| `failed`    | Rejected — see [Refund failure reasons](/docs/payments/payment-operations/refund/failure-reasons). |
| `cancelled` | Withdrawn before reaching the rail.                                                                |

Settlement time is controlled by the customer's card issuer or bank:

| Rail                 | Typical time to customer            |
| -------------------- | ----------------------------------- |
| Cards                | 5–10 business days                  |
| SEPA / bank transfer | 1–3 business days                   |
| Stablecoins          | Minutes after on-chain confirmation |

Subscribe to events rather than polling:

```typescript
const event = vinr.webhooks.verify(rawBody, req.headers['x-vinr-signature']);

if (event.type === 'refund.succeeded') {
  const refund = event.data;
  await markOrderRefunded(refund.metadata.ticketId, refund.amount);
}
```

Relevant events: `refund.created`, `refund.succeeded`, `refund.failed`. See [Webhooks](/docs/integration/webhooks) for setup and signature verification.

## Fees

Processing fees on the original charge are not returned when you issue a refund — this mirrors card scheme rules. The refunded principal is debited from your VINR balance; if insufficient, the shortfall is recovered from your next settlement.

> Refunding more than your available balance pushes it negative and can delay the next payout. Maintain a buffer if you process high refund volume.

## Next steps

[Refund failure reasons](/docs/payments/payment-operations/refund/failure-reasons) — Why a refund can fail and what to do in each case.

[Reverse](/docs/payments/payment-operations/reverse) — Same-day undo of a captured payment before it settles.

[Disputes](/docs/payments/payment-operations/disputes) — When a customer reverses a payment through their bank.
