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

# Refunds

> Refund a completed payment in full or in part.

A refund can only be created against a `completed` payment intent. Partial refunds are allowed; multiple refunds may be issued against the same intent as long as the refundable amount permits it.

## Create a refund

```
POST /payment/intents/{intentId}/refunds
```

<ParamField body="amount" type="integer" required>
  Amount to refund in **major units** (e.g. `25` = 25.00). Minimum `1`. Must not exceed `refunds_summary.refundable_amount`.
</ParamField>

<ParamField body="reason" type="string" required>
  Reason for the refund. Must be one of the following values:

  | Value                    | Description                                         |
  | ------------------------ | --------------------------------------------------- |
  | `requested_by_customer`  | The customer requested the refund                   |
  | `duplicate`              | The payment was a duplicate charge                  |
  | `fraudulent`             | The payment is suspected fraud                      |
  | `product_not_received`   | The customer did not receive the product or service |
  | `product_unsatisfactory` | The product or service did not meet expectations    |
  | `order_cancelled`        | The order was cancelled                             |
  | `other`                  | Any other reason — use `note` to add details        |
</ParamField>

<ParamField body="note" type="string">
  Free-text explanation. Maximum 500 characters.
</ParamField>

<ParamField body="metadata" type="object">
  Up to 10 key/value pairs stored on the refund.
</ParamField>

<ParamField body="allow_payout" type="boolean">
  When `true`, Orchestrate may process the refund as an outbound payout to the original payer if the payment gateway does not support a direct reversal. Requires the corresponding project setting to be enabled. When this path is taken, the `execution_method` on the refund will be `payout` and the `payout` block will be populated.
</ParamField>

A rejected refund returns `422` with the service's error message — for example, if the amount exceeds what is refundable or the payment is not in a refundable state.

## Refundable amount

Every payment intent carries a `refunds_summary` object:

<ResponseField name="refunded_amount" type="Amount">
  Total already refunded.
</ResponseField>

<ResponseField name="pending_amount" type="Amount">
  Total currently in-flight refunds (created but not yet completed).
</ResponseField>

<ResponseField name="refundable_amount" type="Amount">
  The amount you may safely refund right now. This is authoritative — it already accounts for in-flight refunds. A refund up to this value is guaranteed not to be rejected on balance grounds.
</ResponseField>

<ResponseField name="has_pending_refund" type="boolean">
  Whether at least one refund is currently in the `pending` or `processing` state.
</ResponseField>

Always use `refundable_amount` — not your own arithmetic — before submitting a refund.

## Refund resource

<ResponseField name="id" type="string">
  Refund identifier.
</ResponseField>

<ResponseField name="amount" type="Amount">
  `{ value, formatted, short, currency }` — the refunded amount.
</ResponseField>

<ResponseField name="type" type="string">
  `full` when the refund covers the full intent amount; `partial` otherwise.
</ResponseField>

<ResponseField name="execution_method" type="string">
  How the refund was processed: `gateway` (reversed through the original payment gateway) or `payout` (sent as an outbound payout to the original payer).
</ResponseField>

<ResponseField name="status" type="string">
  One of `pending`, `processing`, `completed`, `failed`.
</ResponseField>

<ResponseField name="reason" type="object">
  `{ value, label }` — the reason enum value and its human-readable label.
</ResponseField>

<ResponseField name="note" type="string">
  The note supplied at creation, if any.
</ResponseField>

<ResponseField name="failure_code" type="string | null">
  Machine-readable failure code when `status` is `failed`.
</ResponseField>

<ResponseField name="failure_message" type="string | null">
  Human-readable failure message when `status` is `failed`.
</ResponseField>

<ResponseField name="metadata" type="object">
  The metadata supplied at creation.
</ResponseField>

<ResponseField name="payout" type="object | null">
  Populated when `execution_method` is `payout`. Contains:

  | Field                    | Description                                               |
  | ------------------------ | --------------------------------------------------------- |
  | `id`                     | Payout identifier                                         |
  | `gateway_code`           | The gateway used to send the payout                       |
  | `method`                 | Payout method identifier                                  |
  | `recipient`              | Payout instrument object describing where funds were sent |
  | `gateway_transaction_id` | Provider transaction identifier                           |
  | `fee_amount`             | Fee charged for the payout                                |
  | `status`                 | Payout status                                             |
  | `initiated_at`           | ISO 8601 timestamp                                        |
  | `completed_at`           | ISO 8601 timestamp                                        |
</ResponseField>

<ResponseField name="completed_at" type="string | null">
  ISO 8601 timestamp when the refund completed.
</ResponseField>

<ResponseField name="failed_at" type="string | null">
  ISO 8601 timestamp when the refund failed.
</ResponseField>

<ResponseField name="created_at" type="string">
  ISO 8601 timestamp when the refund was created.
</ResponseField>

## List and retrieve

**List all refunds for an intent:**

```
GET /payment/intents/{intentId}/refunds
```

Returns a paginated collection. See [API conventions](/api-conventions) for the pagination shape.

**Retrieve a single refund:**

```
GET /payment/intents/{intentId}/refunds/{refundId}
```

## Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.orqex.com/v1/payment/intents/pi_.../refunds \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "amount": 25,
      "reason": "requested_by_customer",
      "note": "Customer changed their mind before delivery."
    }'
  ```

  ```php PHP theme={null}
  use Orqex\Client;

  $client = new Client('sk_live_...');

  // Check refundable amount first
  $intent = $client->paymentIntents->get('pi_...');
  $refundable = $intent->data->refunds_summary->refundable_amount->value;

  if ($refundable >= 25) {
      $refund = $client->refunds->create('pi_...', [
          'amount' => 25,
          'reason' => 'requested_by_customer',
          'note'   => 'Customer changed their mind before delivery.',
      ]);
  }
  ```
</CodeGroup>
