Skip to content
Last updated

Recipe: Cancels and refunds

When to cancel vs. refund

The correct reversal method depends on whether the transaction has settled.

image

ActionWhenAPI callFunds returned
Cancel (void)Before settlementPOST /v1/transactions/{id}/cancelHold released immediately
Refund (full)After settlementPOST /v1/transactions/{id}/cancel with type: card_refund3–5 business days
Refund (partial)After settlementSame, with amount field3–5 business days

Step 1: Check the transaction state

Before attempting a reversal, confirm the current state.

curl -X GET \
  https://api.dev.paradisegateway.net/v1/transactions/TRANSACTION-01KEW32V6YNV11T33XGDR7TGWC \
  -H "APIKEY: YOUR-API-KEY"

Step 2a: Cancel (before settlement)

Cancel releases the hold immediately. Works for authorized or captured (pre-settlement) transactions.

curl -X POST \
  https://api.dev.paradisegateway.net/v1/transactions/TRANSACTION-01KEW32V6YNV11T33XGDR7TGWC/cancel \
  -H "Content-Type: application/json" \
  -H "APIKEY: YOUR-API-KEY"

Step 2b: Refund (after settlement)

For settled transactions, send a refund. Include type: card_refund and optionally an amount for partial refunds.

Full refund

curl -X POST \
  https://api.dev.paradisegateway.net/v1/transactions/TRANSACTION-01KEW32V6YNV11T33XGDR7TGWC/cancel \
  -H "Content-Type: application/json" \
  -H "APIKEY: YOUR-API-KEY" \
  -d '{ "type": "card_refund" }'

Partial refund

curl -X POST \
  https://api.dev.paradisegateway.net/v1/transactions/TRANSACTION-01KEW32V6YNV11T33XGDR7TGWC/cancel \
  -H "Content-Type: application/json" \
  -H "APIKEY: YOUR-API-KEY" \
  -d '{ "type": "card_refund", "amount": 1500 }'

Decision logic implementation

def reverse_transaction(txn_id: str, partial_amount: int | None = None) -> dict:
    txn = requests.get(f"{BASE}/v1/transactions/{txn_id}", headers=HEADERS).json()
    state = txn["transaction_state"]

    if state in ("authorized", "captured"):
        resp = requests.post(f"{BASE}/v1/transactions/{txn_id}/cancel", headers=HEADERS)
    elif state == "settled":
        payload = {"type": "card_refund"}
        if partial_amount:
            payload["amount"] = partial_amount
        resp = requests.post(
            f"{BASE}/v1/transactions/{txn_id}/cancel",
            headers=HEADERS,
            json=payload,
        )
    else:
        raise ValueError(f"Cannot reverse transaction in state: {state}")

    return resp.json()

Common mistakes

MistakeResultFix
Refunding a pre-settlement transactionError — not settled yetCancel instead
Canceling a settled transactionError — already settledRefund instead
Refunding more than the original amountError — amount exceeds originalCheck original amount first
Not checking state firstUnpredictable errorsAlways GET the transaction before reversing

Further reading