# Testing refunds

How to test refund webhooks in the sandbox.

Use the simulation endpoints to test how your integration handles refunds (including SWIFT partial refunds), without initiating real-world financial transactions.

When a transfer’s status becomes `funds_refunded`, Wise sends a `transfers#refund` webhook event to your subscribed endpoint.

Important!
- Even if funding moves the transfer to `processing`, you must still call the `/processing` simulation step.
- Simulation isn’t supported for email transfers.


## Refund behaviour in sandbox

In production, refund amounts can differ by payout method (for example, SWIFT intermediary bank fees may reduce the amount returned). Sandbox simulates this to help you test your webhook handling.

| Transfer payout type | Refund amount |
|  --- | --- |
| Non-SWIFT transfer | Typically the full gross amount the customer paid for the transfer (including Wise fees). |
| SWIFT transfer | A random percentage from 5–15% is deducted from the gross amount to simulate intermediary bank fees. |


## Steps to simulate a refund

### Step 1: Create quote

Create an authenticated quote for the transfer.

- If you want to test **SWIFT partial refunds**, set `payOut` to `SWIFT` when creating the quote. See the [Authenticated quotes](/guides/product/send-money/quotes/authenticated-quote) and [SWIFT network transfers](/guides/product/send-money/swift-network-transfers) guides for details.


#### Example request

### Step 2: Create recipient

Create a recipient account for the transfer.

- For SWIFT, use recipient/account details that route via SWIFT as described in the [SWIFT network transfers guide](/guides/product/send-money/swift-network-transfers).
- If the recipient doesn’t support SWIFT for your currency/route, the quote may be updated to a non-SWIFT payout method when you update it with the recipient.


### Step 3: Create and fund the transfer

Create the transfer using the quote and recipient, then fund it using your normal funding flow.

See the [Send money guide](/guides/product/send-money/use-cases/correspondent/send-money) for instructions.

### Step 4: Create application webhook subscription

Create an [application-level webhook subscription](/api-reference/webhook/webhookapplicationsubscriptioncreate) for `transfers#refund` using a **client credentials token**.

Endpoint: `POST /v3/applications/{clientKey}/subscriptions`

#### Example request

```bash
curl -X POST "https://api.wise-sandbox.com/v3/applications/<CLIENT_KEY>/subscriptions" \
  -H "Authorization: Bearer <CLIENT_CREDENTIALS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sandbox transfers refund subscription",
    "trigger_on": "transfers#refund",
    "delivery": {
      "version": "4.0.0",
      "url": "https://example.com/webhooks/wise"
    }
  }'
```

### Step 5: Simulate transfer into funds_refunded

Use [Simulate transfer state change](/api-reference/simulation/simulationtransferstatechange) to move the transfer through states **in order**:

`processing → funds_converted → outgoing_payment_sent → bounced_back → funds_refunded`

Endpoint: `GET /v1/simulation/transfers/{transferId}/{status}`

#### Example requests

```bash
curl -X GET "https://api.wise-sandbox.com/v1/simulation/transfers/<TRANSFER_ID>/processing" \
  -H "Authorization: Bearer <USER_TOKEN>"
```

```bash
curl -X GET "https://api.wise-sandbox.com/v1/simulation/transfers/<TRANSFER_ID>/funds_converted" \
  -H "Authorization: Bearer <USER_TOKEN>"
```

```bash
curl -X GET "https://api.wise-sandbox.com/v1/simulation/transfers/<TRANSFER_ID>/outgoing_payment_sent" \
  -H "Authorization: Bearer <USER_TOKEN>"
```

```bash
curl -X GET "https://api.wise-sandbox.com/v1/simulation/transfers/<TRANSFER_ID>/bounced_back" \
  -H "Authorization: Bearer <USER_TOKEN>"
```

```bash
curl -X GET "https://api.wise-sandbox.com/v1/simulation/transfers/<TRANSFER_ID>/funds_refunded" \
  -H "Authorization: Bearer <USER_TOKEN>"
```

### Step 6: Receive and verify webhook

After you simulate `funds_refunded`, Wise sends a `transfers#refund` webhook to your subscribed endpoint.

The webhook includes:

- `data.resource.refund_amount` — amount returned to the sender
- `data.resource.refund_currency` — currency of the refund


See the [event type reference guide](/guides/developer/webhooks/event-types#transfer-refund) for details about the `transfers#refund` webhook.

#### Example webhook payload

```json
{
   "data": {
    "resource": {
      "type": "transfer",
      "id": 111,
      "profile_id": 222,
      "account_id": 333,
      "refund_amount": 5000,
      "refund_currency": "EUR"
    },
    "occurred_at": "2024-01-01T12:34:56.789Z"
  },
  "subscription_id": "01234567-89ab-cdef-0123-456789abcdef",
  "event_type": "transfers#refund",
  "schema_version": "4.0.0",
  "sent_at": "2024-01-01T12:34:56.123Z"
}
```

## Sandbox limitations

- **Webhook-only simulation**: the simulated refund amount applies only to the webhook payload.
- **Not suitable for reconciliation**: account balances and the Sandbox UI can reflect different values (for example, a full refund), regardless of payout method. Don’t reconcile Sandbox webhooks to balances/statements.


For details, see the [Simulate transfer state change](/api-reference/simulation/simulationtransferstatechange#sandbox-refund) endpoint.