Cancel Payment

Cancel a pending or processing payment and close its checkout link.

DELETE/api/v1/payments/:id

When to Use

Use this endpoint when you no longer want a payment you created:

  • Customer cancels their order
  • Cart amount changes (cancel old, create new)

Note: This only works for pending or processing payments. Cancelling a payment in any other status (for example succeeded, expired, or one that is already cancelled) returns 400 with code ALREADY_COMPLETED.

Closes the checkout link: Cancelling also closes the hosted checkout link (paymentUrl), so the customer can no longer pay it.

If the customer already paid: UltraPay checks with the payment processor before cancelling. If the customer has already completed checkout, the payment is not cancelled. It is recorded as succeeded, the request returns 400 with code ALREADY_COMPLETED, and you receive a payment.completed webhook. Fulfill the order as usual.

In rare cases the checkout link cannot be closed at the moment you cancel (for example, during a payment processor outage). The payment is still cancelled, and if the customer pays anyway it becomes succeeded and you receive payment.completed.

Response

json
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "cancelled",
"message": "Payment cancelled successfully"
}
}

cURL Example

bash
curl -X DELETE https://pay.ultrapay.cc/api/v1/payments/550e8400-e29b-41d4-a716-446655440000 \
-H "X-Public-Key: upp_your_public_key" \
-H "X-Secret-Key: ups_your_secret_key"

Handling Cart Changes

If a customer modifies their cart after a payment link has been created, cancel the old payment and create a new one with the updated amount. Cancelling closes the old checkout link, so send the customer to the new paymentUrl.

If the cancel request returns ALREADY_COMPLETED, the old payment is no longer pending or processing. Check its status with GET /api/v1/payments/:id before creating a new payment, because the customer may already have paid. Keep the old payment's ID linked to the order until you know, so its payment.completed webhook can still be matched.

javascript
// Cancel old payment
const cancelResponse = await fetch(`https://pay.ultrapay.cc/api/v1/payments/${oldTransactionId}`, {
method: 'DELETE',
headers: {
'X-Public-Key': 'upp_your_public_key',
'X-Secret-Key': 'ups_your_secret_key',
},
});
if (!cancelResponse.ok) {
const { error } = await cancelResponse.json();
// ALREADY_COMPLETED: the old payment is no longer pending or processing.
// Check its status with GET /api/v1/payments/:id before charging again,
// because the customer may already have paid.
throw new Error(`Could not cancel old payment: ${error.code}`);
}
// Create new payment with updated amount
const response = await fetch('https://pay.ultrapay.cc/api/v1/payments/create', {
method: 'POST',
headers: {
'X-Public-Key': 'upp_your_public_key',
'X-Secret-Key': 'ups_your_secret_key',
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: newAmount,
currency: 'usd',
customerEmail: 'customer@example.com',
successUrl: 'https://yoursite.com/thank-you',
cancelUrl: 'https://yoursite.com/checkout',
}),
});
const { data } = await response.json();
window.location.href = data.paymentUrl;
↑ ↓ navigate↵ select