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

# Create Refund

> Refund a completed order (full or partial)

# Create Refund

Issue a full or partial refund for a completed order. Refunds are processed back to the original payment method (HSA/FSA card or regular card).

## Authentication

```bash theme={null}
Authorization: Bearer glm_test_YOUR_API_KEY
```

## Request Body

```json theme={null}
{
  "order_id": "ord_abc123xyz",
  "amount": 4235,
  "reason": "customer_request",
  "notes": "Customer requested refund due to delayed shipping",
  "metadata": {
    "support_ticket": "TICKET-12345"
  }
}
```

<Info>
  All monetary amounts are integers in cents (e.g., 4995 = \$49.95).
</Info>

## Parameters

| Parameter  | Type    | Required | Description                                      |
| ---------- | ------- | -------- | ------------------------------------------------ |
| `order_id` | string  | Yes      | ID of the order to refund                        |
| `amount`   | integer | No       | Amount to refund in cents (omit for full refund) |
| `reason`   | enum    | Yes      | Refund reason (see below)                        |
| `notes`    | string  | No       | Additional notes (max 500 chars)                 |
| `metadata` | object  | No       | Custom key-value pairs                           |

<Info>
  **Finding Order ID**: You can get the `order_id` from:

  * Webhook event data (`order.created` event)
  * Order API response (`GET /api/v2/orders`)
  * Your database (store it when receiving `order.created` webhook)
  * Dashboard order details
</Info>

## Refund Reasons

| Reason                | Description               | Example Use Case                        |
| --------------------- | ------------------------- | --------------------------------------- |
| `customer_request`    | Customer requested refund | Customer changed mind, no longer needed |
| `duplicate`           | Duplicate payment         | Customer accidentally paid twice        |
| `fraudulent`          | Fraudulent order          | Detected fraudulent transaction         |
| `product_unavailable` | Product out of stock      | Item went out of stock after order      |
| `damaged_product`     | Product arrived damaged   | Item damaged during shipping            |
| `wrong_product`       | Wrong product shipped     | Fulfillment error, sent wrong item      |
| `other`               | Other reason              | Any other reason (explain in `notes`)   |

## Request

```bash theme={null}
POST /api/v2/refunds
```

## Response

```json theme={null}
{
  "success": true,
  "message": "Refund created",
  "data": {
    "id": "re_3Toy...",
    "order_id": "ord_abc123xyz",
    "amount": 4235,
    "reason": "customer_request",
    "notes": "Customer requested refund due to delayed shipping",
    "status": "succeeded",
    "refund_breakdown": {
      "hsa_amount": 2995,
      "regular_amount": 1240
    },
    "refunds": [
      { "refund_id": "re_3Toy...", "success": true }
    ],
    "metadata": {
      "support_ticket": "TICKET-12345"
    },
    "created_at": "2026-07-23T16:00:00Z"
  },
  "metadata": { "request_id": "..." }
}
```

Fields are returned under `data`.

## Response Fields

| Field              | Type   | Description                                                     |
| ------------------ | ------ | --------------------------------------------------------------- |
| `id`               | string | Processor refund reference                                      |
| `status`           | enum   | Refund status: `pending`, `succeeded`, `failed`, `cancelled`    |
| `refund_breakdown` | object | Refund amount per payment type (`hsa_amount`, `regular_amount`) |
| `refunds`          | array  | Per-payment refund results                                      |

## Examples

### Full Refund

```bash theme={null}
curl -X POST https://api.withgale.com/api/v2/refunds \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "ord_abc123xyz",
    "reason": "customer_request",
    "notes": "Customer not satisfied with product"
  }'
```

### Partial Refund

```bash theme={null}
curl -X POST https://api.withgale.com/api/v2/refunds \
  -H "Authorization: Bearer glm_test_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "order_id": "ord_abc123xyz",
    "amount": 1000,
    "reason": "damaged_product",
    "notes": "Partial refund for damaged item"
  }'
```

## Refund Status

| Status      | Description                   |
| ----------- | ----------------------------- |
| `pending`   | Refund initiated, processing  |
| `succeeded` | Refund processed successfully |
| `failed`    | Refund failed                 |
| `cancelled` | Refund cancelled              |

## Split Card Refunds (Automatic)

**Gale automatically handles split card refunds.** You don't need to specify how much goes to each card.

When an order is paid with both HSA/FSA and regular card:

```json theme={null}
{
  "order": {
    "amounts": {
      "hsa_amount": 4995,       // Paid with HSA/FSA card
      "regular_amount": 895,    // Paid with regular card
      "total": 5890
    }
  }
}
```

### Full Refund

Just provide the `order_id` - Gale splits automatically:

```bash theme={null}
POST /api/v2/refunds
{
  "order_id": "ord_abc123",
  "reason": "customer_request"
}
```

**Response shows the breakdown:**

```json theme={null}
{
  "id": "ref_xyz789",
  "amount": 5890,
  "refund_breakdown": {
    "hsa_amount": 4995,       // Refunded to HSA/FSA card
    "regular_amount": 895     // Refunded to regular card
  }
}
```

### Partial Refund

Gale splits proportionally based on the original payment ratio:

```bash theme={null}
POST /api/v2/refunds
{
  "order_id": "ord_abc123",
  "amount": 2945,  // Partial refund
  "reason": "damaged_product"
}
```

**Response:**

```json theme={null}
{
  "id": "ref_xyz789",
  "amount": 2945,
  "refund_breakdown": {
    "hsa_amount": 2498,       // ~84.7% (same ratio as original)
    "regular_amount": 447     // ~15.3%
  }
}
```

**Key Points:**

* You only specify total `amount`
* Gale calculates the split automatically
* Each amount refunds to its original payment method
* Response shows the breakdown for your records

## Webhooks

Refunds trigger the following webhook events:

```json theme={null}
{
  "type": "refund.created",
  "data": {
    "id": "ref_xyz789",
    "order_id": "ord_abc123xyz",
    "amount": 4235,
    "status": "pending"
  }
}
```

```json theme={null}
{
  "type": "refund.succeeded",
  "data": {
    "id": "ref_xyz789",
    "order_id": "ord_abc123xyz",
    "status": "succeeded",
    "processed_at": "2025-10-18T16:05:00Z"
  }
}
```

See [Webhooks Reference](/developer-manual/webhooks) for all refund events.

## Errors

| Status Code | Error Code         | Description                       |
| ----------- | ------------------ | --------------------------------- |
| 400         | `invalid_amount`   | Refund amount exceeds order total |
| 400         | `already_refunded` | Order already fully refunded      |
| 400         | `invalid_state`    | Order not in refundable state     |
| 401         | `unauthorized`     | Invalid or missing API key        |
| 404         | `not_found`        | Order not found                   |
| 422         | `validation_error` | Field validation failed           |

### Amount Too Large

```json theme={null}
{
  "error": {
    "code": "invalid_amount",
    "message": "Refund amount exceeds order total",
    "details": {
      "requested": 10000,
      "maximum": 4235
    }
  }
}
```

### Already Refunded

```json theme={null}
{
  "error": {
    "code": "already_refunded",
    "message": "Order has already been fully refunded"
  }
}
```

### Invalid State

```json theme={null}
{
  "error": {
    "code": "invalid_state",
    "message": "Cannot refund order with payment status 'pending'"
  }
}
```

## Refund Timeline

| Payment Method | Typical Arrival Time |
| -------------- | -------------------- |
| HSA/FSA Card   | 5-10 business days   |
| Regular Card   | 5-10 business days   |

**Note:** Actual timing depends on the customer's card issuer.

## Important Notes

<Warning>
  **Refunds cannot be undone.** Once a refund is processed, it cannot be reversed. Double-check order ID and amount before submitting.
</Warning>

<Info>
  **Partial refunds are supported.** You can issue multiple partial refunds up to the order total. The remaining refundable amount is tracked automatically.
</Info>

## Related Endpoints

* [Get Order](/api-reference/endpoint/get-order) - GET /api/v2/orders/{id}
* [List Orders](/api-reference/endpoint/list-orders) - GET /api/v2/orders

## Related Resources

* [Order Object](/api-reference/objects/order)
* [Webhooks Reference](/developer-manual/webhooks)
