Refunds
Return all or part of a payment to the customer.
| Endpoint | What it does |
|---|---|
POST /v1/refunds |
Create a refund |
GET /v1/refunds |
List a charge’s refunds |
GET /v1/refunds/{id} |
Retrieve a refund |
Try any of them in the API tester.
Create a refund
Section titled “Create a refund”POST /v1/refunds
Returns money from a succeeded charge to the customer who paid it.
YOUR BALANCE IS DEBITED WHEN THE REFUND IS CREATED, not when the customer receives the money. A refund that returns pending has already taken the funds out of your available balance.
Omit amount to refund everything that is left; pass it to refund part of the charge. Partial refunds may be repeated until the original amount is used up, and a request that would exceed it is refused with refund_exceeds_original rather than partially applied.
PAYSIGNA’S FEE ON THE ORIGINAL CHARGE IS NOT RETURNED TO YOU. amount is the slice of the charge being reversed, debited is what leaves your balance and what the customer receives, and fee_retained is what we kept. On a charge whose fee the CUSTOMER paid, debited is larger than amount, because the customer is refunded what they actually paid.
Requires an Idempotency-Key header. A retry with the same key returns the original response rather than refunding a second time.
If a request times out, READ the refund. Do not resend it. A timeout does not mean the money did not move, and the funds stay reserved — and the amount stays claimed against the original charge — until the partner tells us what happened.
Only a succeeded or partially refunded collection can be refunded. A payout cannot be recalled, a refund cannot itself be refunded, and a charge older than 180 days is outside the window.
Authentication: a secret key (server-side only) with the scope refund.create.
Headers
Section titled “Headers”| Field | Type | Required | Allowed values and limits | What it is |
|---|---|---|---|---|
Idempotency-Key |
string | yes | Unique per operation. Resend the same value to retry safely. A refund resent without it refunds twice, and the second one cannot be recovered from a customer who has already cashed out. |
Request body
Section titled “Request body”| Field | Type | Required | Allowed values and limits | What it is |
|---|---|---|---|---|
amount |
integer | no | min 1 | How much of the original transaction to reverse, in minor units. Omit it to refund everything that is left. This is the ORIGINAL’s amount, not what leaves your balance — see the debited field on the response. |
callback_url |
string (uri) | no | HTTPS only. Defaults to the original transaction’s callback URL. | |
metadata |
object | no | Returned unchanged on every read and webhook. The key “paysigna” is reserved and will be discarded. | |
reason |
string | no | at most 300 characters | Why the refund was issued. Appears on your statement line and on the refund webhook. Not shown to the customer. |
reference |
string | no | at most 100 characters | Your own identifier for this refund. |
transaction_id |
string (uuid) | yes | The charge to refund. Must be a succeeded or partially refunded collection — a payout cannot be recalled, and a refund cannot itself be refunded. |
curl -X POST https://sandbox.paysigna.com/v1/refunds \ -H "Authorization: Bearer sk_test_…" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "transaction_id": "01a1…"}'Response 201
Section titled “Response 201”| Field | Type | What it is |
|---|---|---|
amount |
integer | How much of the original transaction this reverses, in minor units. |
channel |
string | The channel the money is returned on, the same as the original charge. |
completed_at |
string (date-time) | When the refund reached a final state. Absent while it is in flight. |
created_at |
string (date-time) | When the refund was created. |
currency |
string | ISO 4217 code of every amount on this refund, the same as the original charge. |
customer |
object | |
customer.masked |
string | A partial identifier. The full value is never returned. |
customer.name |
string | The customer’s name, when known. |
debited |
integer | What was taken from your balance, and what the customer receives. Larger than the amount field when the customer bore PaySigna’s fee on the original charge, because the customer is refunded what they actually paid. |
failure_code |
string | A machine-readable reason, present when the refund failed. |
failure_message |
string | Present when the refund failed. The funds have been returned to your balance and the amount can be refunded again. |
fee_retained |
integer | The share of PaySigna’s fee on the original charge that is NOT returned to you. A refund does not refund our fee. |
id |
string | The refund’s id. Read it at /v1/refunds/{id}. |
metadata |
object | The metadata you sent, unchanged. |
object |
string | |
reason |
string | The reason you gave. |
reference |
string | PaySigna’s reference. Quote it to support. |
status |
string | pending or processing means in flight — your balance is already debited. Wait for the webhook or read the refund; do not resend it. One of: initiated, pending, processing, succeeded, failed, cancelled, expired |
transaction_id |
string | The charge this reverses. |
your_reference |
string | The reference you sent when creating the refund. |
Errors
Section titled “Errors”400: the request is malformed401: the key is missing, wrong or revoked402: your balance cannot cover it403: the key lacks the scope, or your account may not do this404: no such resource on this account409: it conflicts with the current state, or the idempotency key was used for a different request422: a field is invalid;errorsnames it429: too many requests; wait forRetry-After500: Internal Server Error502: the payment partner refused it503: the payment partner is unreachable; safe to retry504: the partner timed out; read the resource before retrying
Every error is a JSON problem with a stable code. See Errors.
List a charge’s refunds
Section titled “List a charge’s refunds”GET /v1/refunds
Every refund raised against one charge, oldest first.
transaction_id is required. This answers what /v1/transactions cannot: how a charge’s refundable amount was drawn down, and which of those refunds stuck. Use /v1/transactions for an open-ended history — it is keyset-paginated and date-windowed, and this is not.
Authentication: a secret key (server-side only) with the scope refund.read.
Parameters
Section titled “Parameters”| Field | Type | Required | Allowed values and limits | What it is |
|---|---|---|---|---|
transaction_id |
string (uuid) | yes | The charge whose refunds to list. |
Response 200
Section titled “Response 200”| Field | Type | What it is |
|---|---|---|
data |
array | |
object |
string |
Errors
Section titled “Errors”401: the key is missing, wrong or revoked403: the key lacks the scope, or your account may not do this404: no such resource on this account422: a field is invalid;errorsnames it429: too many requests; wait forRetry-After500: Internal Server Error503: the payment partner is unreachable; safe to retry
Every error is a JSON problem with a stable code. See Errors.
Retrieve a refund
Section titled “Retrieve a refund”GET /v1/refunds/{id}
Reads a refund’s current state. This is the authority after a timeout: if a create request did not return, read the refund rather than resending it.
Authentication: a secret key (server-side only) with the scope refund.read.
Parameters
Section titled “Parameters”| Field | Type | Required | Allowed values and limits | What it is |
|---|---|---|---|---|
{id} |
string (uuid) | yes | The refund’s id, as returned when it was created. |
Response 200
Section titled “Response 200”| Field | Type | What it is |
|---|---|---|
amount |
integer | How much of the original transaction this reverses, in minor units. |
channel |
string | The channel the money is returned on, the same as the original charge. |
completed_at |
string (date-time) | When the refund reached a final state. Absent while it is in flight. |
created_at |
string (date-time) | When the refund was created. |
currency |
string | ISO 4217 code of every amount on this refund, the same as the original charge. |
customer |
object | |
customer.masked |
string | A partial identifier. The full value is never returned. |
customer.name |
string | The customer’s name, when known. |
debited |
integer | What was taken from your balance, and what the customer receives. Larger than the amount field when the customer bore PaySigna’s fee on the original charge, because the customer is refunded what they actually paid. |
failure_code |
string | A machine-readable reason, present when the refund failed. |
failure_message |
string | Present when the refund failed. The funds have been returned to your balance and the amount can be refunded again. |
fee_retained |
integer | The share of PaySigna’s fee on the original charge that is NOT returned to you. A refund does not refund our fee. |
id |
string | The refund’s id. Read it at /v1/refunds/{id}. |
metadata |
object | The metadata you sent, unchanged. |
object |
string | |
reason |
string | The reason you gave. |
reference |
string | PaySigna’s reference. Quote it to support. |
status |
string | pending or processing means in flight — your balance is already debited. Wait for the webhook or read the refund; do not resend it. One of: initiated, pending, processing, succeeded, failed, cancelled, expired |
transaction_id |
string | The charge this reverses. |
your_reference |
string | The reference you sent when creating the refund. |
Errors
Section titled “Errors”401: the key is missing, wrong or revoked403: the key lacks the scope, or your account may not do this404: no such resource on this account422: a field is invalid;errorsnames it429: too many requests; wait forRetry-After500: Internal Server Error503: the payment partner is unreachable; safe to retry
Every error is a JSON problem with a stable code. See Errors.

