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

# Refunds

A refund returns money to the payer against a payment that has already succeeded. This is different from a [payout](/essentials/payments-guide/payouts), which sends money to a recipient rather than reversing an existing payment.

## Request

Send a `POST` request to `/refunds`. Only `payment_id` is required — omit `amount` for a full refund.

<CodeGroup>
  ```bash curl theme={"system"}
  curl --request POST \
    --url https://api.sandbox.pesaswap.io/refunds \
    --header "api-key: {{api_key}}" \
    --header "Content-Type: application/json" \
    --data '{
      "payment_id": "{{payment_id}}",
      "amount": 100,
      "reason": "Customer cancelled the order"
    }'
  ```

  ```javascript Node.js theme={"system"}
  const response = await fetch("https://api.sandbox.pesaswap.io/refunds", {
    method: "POST",
    headers: {
      "api-key": "{{api_key}}",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      payment_id: "{{payment_id}}",
      amount: 100,
      reason: "Customer cancelled the order",
    }),
  });

  const refund = await response.json();
  console.log(refund);
  ```

  ```python Python theme={"system"}
  import requests

  response = requests.post(
      "https://api.sandbox.pesaswap.io/refunds",
      headers={
          "api-key": "{{api_key}}",
          "Content-Type": "application/json",
      },
      json={
          "payment_id": "{{payment_id}}",
          "amount": 100,
          "reason": "Customer cancelled the order",
      },
  )

  refund = response.json()
  print(refund)
  ```

  ```php PHP theme={"system"}
  <?php
  $curl = curl_init();

  curl_setopt_array($curl, [
      CURLOPT_URL => "https://api.sandbox.pesaswap.io/refunds",
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_CUSTOMREQUEST => "POST",
      CURLOPT_HTTPHEADER => [
          "api-key: {{api_key}}",
          "Content-Type: application/json",
      ],
      CURLOPT_POSTFIELDS => json_encode([
          "payment_id" => "{{payment_id}}",
          "amount" => 100,
          "reason" => "Customer cancelled the order",
      ]),
  ]);

  $response = curl_exec($curl);
  curl_close($curl);

  echo $response;
  ```
</CodeGroup>

| Field         | Required | Notes                                                             |
| ------------- | -------- | ----------------------------------------------------------------- |
| `payment_id`  | yes      | The payment to refund                                             |
| `amount`      | no       | Omit for a full refund. Pass a smaller value for a partial refund |
| `reason`      | no       | Free text, shown in the dashboard                                 |
| `refund_type` | no       | `instant` or `scheduled`                                          |
| `refund_id`   | no       | Your own identifier, useful for idempotency                       |
| `metadata`    | no       | Arbitrary key/value data you want stored with the refund          |

## Response

A successful call returns a `200` with a refund object. The fields that matter right now:

```json theme={"system"}
{
  "refund_id": "{{refund_id}}",
  "payment_id": "{{payment_id}}",
  "amount": 100,
  "status": "pending"
}
```

## What to do next

A refund does not settle synchronously. Poll `GET /refunds/{refund_id}` until the status settles.

<CodeGroup>
  ```bash curl theme={"system"}
  curl --request GET \
    --url "https://api.sandbox.pesaswap.io/refunds/{{refund_id}}" \
    --header "api-key: {{api_key}}"
  ```

  ```javascript Node.js theme={"system"}
  const response = await fetch(
    `https://api.sandbox.pesaswap.io/refunds/${refundId}`,
    {
      method: "GET",
      headers: {
        "api-key": "{{api_key}}",
      },
    }
  );

  const refund = await response.json();
  console.log(refund);
  ```

  ```python Python theme={"system"}
  import requests

  response = requests.get(
      f"https://api.sandbox.pesaswap.io/refunds/{refund_id}",
      headers={"api-key": "{{api_key}}"},
  )

  refund = response.json()
  print(refund)
  ```

  ```php PHP theme={"system"}
  <?php
  $curl = curl_init();

  curl_setopt_array($curl, [
      CURLOPT_URL => "https://api.sandbox.pesaswap.io/refunds/{$refundId}",
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_CUSTOMREQUEST => "GET",
      CURLOPT_HTTPHEADER => [
          "api-key: {{api_key}}",
      ],
  ]);

  $response = curl_exec($curl);
  curl_close($curl);

  echo $response;
  ```
</CodeGroup>

## Status reference

| Status      | What it means                      | What to do      |
| ----------- | ---------------------------------- | --------------- |
| `pending`   | Submitted, not yet settled.        | Keep polling.   |
| `succeeded` | The money has been returned.       | Stop — settled. |
| `failed`    | The connector rejected the refund. | Stop — failed.  |
| `review`    | Held for manual review.            | Keep polling.   |

## Common errors

<AccordionGroup>
  <Accordion title="Payment not in succeeded status">
    Refunding a payment that is not in `succeeded` status.
  </Accordion>

  <Accordion title="Amount exceeds captured total">
    Refunding more than the captured amount.
  </Accordion>

  <Accordion title="Mistaking pending for a failure">
    Assuming `pending` means the refund failed — it means it is still in progress.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Payouts" icon="banknote" href="/essentials/payments-guide/payouts">
    Send money to a recipient instead of reversing a payment.
  </Card>

  <Card title="Quickstart" icon="rocket" href="/essentials/payments-guide/quickstart">
    Create and confirm your first payment.
  </Card>

  <Card title="Mandates and recurring" icon="repeat" href="/essentials/payments-guide/mandates-and-recurring">
    Set up recurring charges against a stored mandate.
  </Card>

  <Card title="Wallet payments" icon="wallet" href="/essentials/payments-guide/wallet-payments">
    M-Pesa, Airtel, and MTN MoMo payments.
  </Card>
</CardGroup>
