Skip to content
Last updated

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 URL.

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, resulting in a partial refund. The sandbox simulates this to help you test your webhook handling.

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

Simulate a refund

To simulate a refund, you'll go throught the following steps in the sandbox environment (described in the sections below):

  1. Create a quote.
  2. Create a recipient.
  3. Create and fund the transfer using your normal flow.
  4. Subscribe to the transfers#refund event.
  5. Simulate the transfer state changes. The change of transfer state to funds_refunded triggers the webhook event notification.

Step 1: Create quote

Create an athenticated quote for the transfer.

Example request

curl -i -X POST \
  https://api.wise.com/2026Q3/profiles/101/quotes \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'Content-Type: application/json' \
  -H 'X-External-Correlation-Id: f47ac10b-58cc-4372-a567-0e02b2c3d479' \
  -d '{
    "sourceCurrency": "GBP",
    "targetCurrency": "USD",
    "sourceAmount": 100,
    "targetAmount": null,
    "targetAccount": 12345,
    "payOut": null,
    "preferredPayIn": null,
    "paymentMetadata": {
      "transferNature": "MOVING_MONEY_BETWEEN_OWN_ACCOUNTS"
    },
    "pricingConfiguration": {
      "fee": {
        "type": "OVERRIDE",
        "variable": 0.011,
        "fixed": 15.42
      }
    }
  }'

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.
  • If the recipient doesn’t support Swift for your currency/route, the quote changes to a non-Swift payout method when you update it with the recipient.

Step 3: Create and fund transfer

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

See the Send money guide for instructions on creating transfers.

Step 4: Create application webhook subscription

Create an application webhook subscription for transfers#refund using a client credentials token.

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

Example request

curl -i -X POST \
  'https://api.wise.com/2026Q3/applications/{clientKey}/subscriptions' \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'Content-Type: application/json' \
  -H 'X-External-Correlation-Id: f47ac10b-58cc-4372-a567-0e02b2c3d479' \
  -d '{
    "name": "Webhook Subscription #1",
    "trigger_on": "transfers#state-change",
    "delivery": {
      "version": "4.0.0",
      "url": "https://your.webhook.url/12345"
    }
  }'

Step 5: Simulate transfer state changes

Use Simulate transfer state change to move the transfer through states in this order:

processing → funds_converted → outgoing_payment_sent → bounced_back → funds_refunded

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

Example requests

Processing:

curl
curl -i -X GET \
  'https://api.wise.com/2026Q3/simulation/transfers/{transferId}/{status}' \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'X-External-Correlation-Id: f47ac10b-58cc-4372-a567-0e02b2c3d479'

Funds converted:

curl
curl -i -X GET \
  'https://api.wise.com/2026Q3/simulation/transfers/{transferId}/{status}' \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'X-External-Correlation-Id: f47ac10b-58cc-4372-a567-0e02b2c3d479'

Outgoing payment sent:

curl
curl -i -X GET \
  'https://api.wise.com/2026Q3/simulation/transfers/{transferId}/{status}' \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'X-External-Correlation-Id: f47ac10b-58cc-4372-a567-0e02b2c3d479'

Bounced back:

curl
curl -i -X GET \
  'https://api.wise.com/2026Q3/simulation/transfers/{transferId}/{status}' \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'X-External-Correlation-Id: f47ac10b-58cc-4372-a567-0e02b2c3d479'

Fund refunded:

curl
curl -i -X GET \
  'https://api.wise.com/2026Q3/simulation/transfers/{transferId}/{status}' \
  -H 'Authorization: Bearer <YOUR_JWT_HERE>' \
  -H 'X-External-Correlation-Id: f47ac10b-58cc-4372-a567-0e02b2c3d479'

Step 6: Receive and verify webhook

After you simulate funds_refunded, Wise sends a transfers#refund webhook payload 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 transfers#refund api reference for more details about the event.

Example webhook payload

Payload
{ "schema_version": "4.0.0", "subscription_id": "01234567-89ab-cdef-0123-456789abcdef", "event_type": "transfers#refund", "sent_at": "2024-01-01T12:34:56.123Z", "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" } }

See the event type reference for more details about the transfers#refund webhook.

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 more details, see the Simulate transfer state change endpoint.