POST /api/actions/refund-ticket/create-ticket
Authentication: Merchant API Key (server-to-server).
Request body
| Field | Type | Required | Description |
|---|---|---|---|
paymentId | string | Yes | Short ID of the payment to refund, e.g. PAY_6eYCunG3IMmIgcQOnaXdoA |
reason | string | Yes | Free-text reason shown to the customer / dashboard |
requestedAmount.amount | string | Yes | Refund amount in display format (e.g. "10.50"), must be > 0 and ≤ payment.amount |
requestedAmount.currency | string | Yes | ISO 4217 code, must match the payment currency |
refundTicketMerchantExternalId | string | No | Your business-side refund-ticket reference (max 128 chars). |
Success response (200)
{
"data": {
"ticket": {
"id": "TKT_3bVzrkD0FJjFdZNLk8Ualx",
"status": "processing",
"subjectId": "PAY_6eYCunG3IMmIgcQOnaXdoA",
"refundTicketMerchantExternalId": "REF-2026-00891"
}
}
}
processing.
Errors
Retry policy: Never retry 4xx — fix the request and resubmit. Retry 5xx with exponential backoff (start 5s, max 3 attempts).
| Status | errors[0].message | What it means | Recommended handling |
|---|---|---|---|
| 400 | Missing required field: <name> | Required field missing (paymentId, reason, requestedAmount.amount, requestedAmount.currency) | Fix the body, resubmit |
| 400 | Expected format: PAY_xxx, got "..." | paymentId Short ID could not be decoded | Fix paymentId format, resubmit |
| 400 | Invalid requestedAmount.amount format | Amount string could not be parsed | Use a display string like "10.50" (not minor units) |
| 400 | refundTicketMerchantExternalId must be at most 128 characters | Value exceeds 128 chars | Shorten to 128 chars or less |
| 401 | Unauthorized | Invalid API Key signature | Verify auth headers |
| 404 | Payment not found | Payment doesn’t exist or doesn’t belong to your store | Verify paymentId |
| 409 | Payment status is X, must be succeeded | Original payment is not in succeeded state | Do not retry — the payment never succeeded |
| 409 | Payment is not yet fully processed by PSP, please retry later | PSP confirmation hasn’t been written back yet | Retry after 5–30 seconds (transient) |
| 409 | Refund period expired (X days, max 14) | Past the 14-day window | Do not retry — refunds are no longer allowed |
| 409 | Requested amount must be greater than 0 | Amount is ≤ 0 | Fix the amount, resubmit |
| 409 | Requested amount exceeds payment amount | Amount > payment.amount | Fix the amount, resubmit |
| 409 | Currency mismatch: requested X, payment Y | Currency must match the original payment | Use the payment’s currency |
| 409 | A refund record already exists for this payment | A previous refund already succeeded against this payment | Do not retry — query existing refunds via GraphQL |
| 409 | A refund ticket already exists for this payment | Another in-flight ticket is blocking | Wait for the existing ticket to terminate, then resubmit if still needed |
| 500 | Internal server error | Unexpected server-side failure | Retry with exponential backoff (start 5s, max 3 attempts) |
Use GraphQL to query the created ticket and the executed refund record. Filter executed refunds by the ticket reference using
refunds(filter: { refundTicketMerchantExternalId: ... }).