Both operations go to POST /v1/transactions/{id}/cancel. The body decides which one you get.
| Void | Refund | |
|---|---|---|
| Use it when | The transaction has not settled | The transaction has settled |
| Body | {"type": "VOID"} | {"type": "REFUND", "amount": …} |
| Amount | Always the full original | Full or partial |
| The cardholder sees | Usually nothing, or a hold disappearing | A credit on their statement |
| Settles | Never. The transaction leaves the batch | As a separate credit |
Void when you can, refund when you must. A void removes the transaction before it ever reaches the cardholder's statement, which means no charge and no credit to explain. A refund is two visible entries and takes days to reach them.
Read is_settled on the transaction.
false— it has not settled. Void it.true— it has settled. Refund it.
Sending a void for a settled transaction fails, and sending a refund for an unsettled one is not the operation you want. When in doubt, read the transaction first with GET /v1/transactions/{id}.
A void takes only type. There is no amount field, because a void is always for the full original amount — you cannot void part of a transaction.
The void record. type comes back as CANCEL, which is the type returned on void and refund response records, and reference_transaction_id points at the sale that was voided. expiry and cvv_result_code are null because neither is re-checked on a void.
{ "id": "TRANSACTION-01KEW38F2RT6N4Z1AJGV5MPQ82", "reference_transaction_id": "TRANSACTION-01KEW32V6YNV11T33XGDR7TGWC", "type": "CANCEL", "result": "APPROVED", "client_id": "CLIENT-01KFDKXMQ637EKEAY410MSQSXB", "client_dba": "Acme Jewelry", "integrations": [ "TSYS" ], "response_code": "00", "response_description": "Approved", "batch_id": "BATCH-01KEW32V6YNV11T33XGDR7TGWC", "is_settled": false, "time_created": "2026-07-15T17:30:44Z", "amount": 10000, "tip": 0, "currency": "USD", "payment_method": { "type": "CARD", "truncated_pan": "****-****-****-5439", "payment_token": "PAYMENT_TOKEN-01KFDKXMQ637EKEAY410MSQSXB", "expiry": null, "first_name": "John", "last_name": "Doe", "entry_method": "keyed", "auth_code": "123456", "retrieval_reference_number": "000000603076", "card_type": "UNKNOWN", "card_brand": "Visa", "cvv_result_code": null }, "initiator": "CUSTOMER", "network_transaction_id": "MCC1234567890", "metadata": { "order_id": "ORD-10432", "sales_channel": "web", "customer_reference": "cust-8891" } }
The result is a new transaction with a type of CANCEL. Note the word: you send VOID and you read CANCEL. Its reference_transaction_id points at the transaction it voided.
amount is required, and it may be less than the original — that example refunds 25.00 of a 100.00 sale. It may not be more.
The refund record. amount is the refunded amount, not the original sale amount. type comes back as CANCEL, and reference_transaction_id points at the sale that was refunded. The refund lands in the next open batch, so its own batch_id is not yet assigned.
{ "id": "TRANSACTION-01KEW3B7XKC9P5W2DMHY6NRS13", "reference_transaction_id": "TRANSACTION-01KEW32V6YNV11T33XGDR7TGWC", "type": "REFUND", "result": "APPROVED", "client_id": "CLIENT-01KFDKXMQ637EKEAY410MSQSXB", "client_dba": "Acme Jewelry", "integrations": [ "TSYS" ], "response_code": "00", "response_description": "Approved", "batch_id": null, "is_settled": false, "time_created": "2026-07-16T10:12:58Z", "amount": 2500, "tip": 0, "currency": "USD", "payment_method": { "type": "CARD", "truncated_pan": "****-****-****-5439", "payment_token": "PAYMENT_TOKEN-01KFDKXMQ637EKEAY410MSQSXB", "expiry": null, "first_name": "John", "last_name": "Doe", "entry_method": "keyed", "auth_code": "123456", "retrieval_reference_number": "000000603076", "card_type": "UNKNOWN", "card_brand": "Visa", "cvv_result_code": null }, "initiator": "CUSTOMER", "network_transaction_id": "MCC1234567890", "metadata": { "order_id": "ORD-10432", "sales_channel": "web", "customer_reference": "cust-8891" } }
A refund is its own transaction with a type of REFUND, and it settles in a batch like any other. The money reaches the cardholder when that batch settles, not when you make the call.
Send the amount you are returning. To refund in several parts, call the endpoint again with the next amount; each call is a separate REFUND transaction against the same original.
The gateway does not stop you from refunding more in total than the original transaction, so track the running total yourself if you issue partial refunds. Reading the original back and summing the refunds that reference it is the reliable way to do that.
An authorization you never capture is a hold on someone's funds. Void it rather than leaving it to expire — the issuer decides when that happens, and it is usually days.
Authorize and capture covers the flow that leads here.