Skip to main content

Preview Cancellation Refund

Preview the refund a customer would receive if a booking were cancelled right now. Returns the matched policy tier, refund amount, non-refundable fee, and a can_cancel flag โ€” exactly the same numbers the supplier portal Cancel modal renders.

This is a read-only endpoint. It runs no side effects (no refund, no booking update, no email). Use it to drive a confirm screen before calling DELETE /v1/bookings/{id}.

GET /v1/bookings/{id}/refund-preview

Authenticationโ€‹

Requires a valid API key with bookings:read scope.

Path Parametersโ€‹

ParameterTypeDescription
idintegerBooking ID

Request Exampleโ€‹

curl -X GET "https://app.equipdash.com/api/v1/bookings/123/refund-preview" \
-H "Authorization: Bearer eqd_live_your_api_key"

Response (200 OK)โ€‹

{
"data": {
"booking_id": 123,
"booking_reference": "RB-1042",
"can_cancel": true,
"cannot_cancel_reason": null,
"refund_note": null,
"policy": {
"id": 1,
"name": "Flexible",
"description": "Full refund up to 7 days before, 50% up to 24h before.",
"applies_to": "all-experiences",
"allow_cancellations": true,
"allow_reschedule": true,
"tiers": [
{ "id": 11, "applies_after_hours": 168, "human_threshold": "1 week", "refund_percentage": 100.0, "refund_method": "original_payment" },
{ "id": 12, "applies_after_hours": 24, "human_threshold": "1 day", "refund_percentage": 50.0, "refund_method": "original_payment" },
{ "id": 13, "applies_after_hours": 0, "human_threshold": "Within window", "refund_percentage": 0.0, "refund_method": "original_payment" }
],
"non_refundable_fee": 5.00,
"refund_method": "original_payment",
"currency": "USD"
},
"preview": {
"total_paid": 200.00,
"refund_percentage": 50.0,
"refund_amount": 95.00,
"non_refundable_fee": 5.00,
"refund_method": "original_payment",
"policy_has_tiers": true,
"matched_tier": {
"id": 12,
"applies_after_hours": 24,
"human_threshold": "1 day",
"refund_percentage": 50.0,
"refund_method": "original_payment"
}
}
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-04-22T11:00:00+00:00"
}
}

Response Fieldsโ€‹

FieldTypeDescription
booking_idintegerThe booking ID
booking_referencestring|nullCustomer-facing booking reference
can_cancelbooleantrue when the booking's status is cancellable. The policy decides the refund, not whether staff may cancel. Start time is not a factor - see below.
cannot_cancel_reasonstring|nullHuman-readable reason when can_cancel is false
refund_notestring|nullSet when nothing is refunded automatically: no policy covers the booking, or its policy takes no cancellations. Show it beside the Cancel button.
policyobject|nullThe applicable policy (full shape โ€” same as GET /v1/settings/policies/{id}). null if no policy applies.
preview.total_paidnumberTotal amount paid against the booking
preview.refund_percentagenumberThe refund % that will run (matched tier % OR 0 when no tier matches OR legacy single % when policy has no tiers)
preview.refund_amountnumberNet refund: total_paid ร— refund_percentage โˆ’ non_refundable_fee, floored at 0
preview.non_refundable_feenumberPer-policy fixed fee that will be deducted
preview.refund_methodstringoriginal_payment or store_credit
preview.policy_has_tiersbooleantrue when the policy has at least one tier configured
preview.matched_tierobject|nullThe tier that ran. null when policy has no tiers OR cancellation missed every tier

Cannot-cancel casesโ€‹

can_cancel: false returns alongside:

  • "Cannot cancel a {status} booking" - booking is already cancelled / completed / returned
Changed

A booking no policy covers, or whose policy takes no cancellations, used to return can_cancel: false. It now returns can_cancel: true with a refund_note, and DELETE /v1/bookings/{id} cancels it with no automatic refund. Give money back afterwards with a refund if you want to.

The endpoint always returns 200 OK even when can_cancel is false โ€” it's an informational endpoint. Hit DELETE only when can_cancel: true.

Bookings that have already startedโ€‹

A booking whose start time has passed still reports can_cancel: true, because DELETE /v1/bookings/{id} accepts it. An API key is a staff credential, and staff have to be able to close off a late call-in. A customer who never came is marked with Mark a No Show instead, which keeps the payment. The preview simply shows what that costs: the cancellation falls past every tier, so refund_percentage is 0, matched_tier is null, and refund_amount is 0 unless the policy is configured otherwise.

Changed

Start time used to force can_cancel: false with the reason "This booking has already started and can no longer be cancelled." It no longer does. If you disable a Cancel button on that reason string, the button now stays live.

Error Responsesโ€‹

StatusCodeDescription
401authentication_requiredMissing or invalid API key
403insufficient_scopeAPI key lacks bookings:read scope
403forbiddenBooking belongs to another supplier
404resource_not_foundBooking not found