Refunds

Created by Kalin Ivanov, Modified on Tue, 23 Jun at 8:39 AM by Kalin Ivanov

Refunds return funds from a successful payment back to the customer. SwissPay supports full and partial refunds, and a single payment can be refunded multiple times up to its captured amount.

The Refund object

{
  "id": "re_01HABCXYZ...",
  "payment": "pay_01HABCXYZ...",
  "amount": 1000,
  "currency": "CHF",
  "status": "pending",
  "reason": null,
  "metadata": { "order_note": "wrong size" },
  "created_at": "2026-05-20T12:00:00Z"
}
Field Type Notes
id string Stable, prefixed with re_.
payment string The pay_... ID being refunded.
amount integer Minor units.
currency string ISO 4217. Always matches the original payment.
status string The refund's current state. See Refund lifecycle below.
reason string | null Optional free-text reason you supplied on creation.
metadata object Up to 50 string keys, values ⤠500 bytes. Echoed back on read.
created_at string ISO 8601 UTC.

Create a refund

POST /api/v1/payments/{payment_id}/refunds

Required headers

Authorization: Bearer sk_test_...
Content-Type: application/json
Idempotency-Key: <unique-per-attempt>

Idempotency-Key is required â refunds move money and must be safe to retry. See Idempotency.

Body fields

All fields are optional. An empty body refunds the full remaining refundable amount of the payment.

Field Type Notes
amount integer Minor units. Must be ⤠the payment's remaining refundable amount. Omit for a full refund.
reason string Free-text reason. Stored on the refund and returned on read.
metadata object Up to 50 keys, values ⤠500 bytes. Stored verbatim and echoed back on read.

Example â full refund

curl -X POST https://app.swisspay.ai/api/v1/payments/pay_01HABCXYZ/refunds \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'

Example â partial refund with metadata

{
  "amount": 1000,
  "reason": "Item returned",
  "metadata": { "order_note": "wrong size" }
}

Multiple partial refunds

A payment can be refunded more than once as long as the sum of refund amounts does not exceed the captured amount. Each call returns its own Refund object with its own id.

Refund lifecycle

A refund is created in pending while SwissPay forwards the request to the upstream processor. Once the processor confirms, the refund transitions to a terminal state. The refund's id is stable across the transition â poll GET /api/v1/refunds/{id} (or list refunds on the payment) to observe the final state.


Retrieve a refund

GET /api/v1/refunds/{id}
curl https://app.swisspay.ai/api/v1/refunds/re_01HABCXYZ \
  -H "Authorization: Bearer sk_test_..."

Unknown IDs â including IDs that belong to another merchant â return 404 Not Found with no body.


List refunds for a payment

GET /api/v1/payments/{payment_id}/refunds?page=1&per_page=20
Query param Default Max
page 1 â
per_page 20 100
curl 'https://app.swisspay.ai/api/v1/payments/pay_01HABCXYZ/refunds' \
  -H "Authorization: Bearer sk_test_..."

Response:

{
  "data": [ /* refund objects */ ],
  "page": 1,
  "per_page": 20,
  "total_count": 2,
  "has_more": false
}

See also

  • Payments â the resource refunds operate on.
  • Idempotency â pick the right Idempotency-Key.
  • Errors â every error code we return.

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article