Skip to main content

Update Booking

Update an existing booking. Confirmed and PickedUp bookings can be updated, including ones that have already been paid; pass reconciliation_method to settle any price delta in the same call.

Bookings in cancelled, checked_in, returned, completed or no_show status cannot be updated. A no_show booking still takes a change of status on its own; see A booking marked as a no-show.

PATCH /v1/bookings/{id}

Authenticationโ€‹

Requires a valid API key with bookings:write scope.

Path Parametersโ€‹

ParameterTypeDescription
idintegerBooking ID

Request Bodyโ€‹

All fields are optional. Only include fields you want to update.

FieldTypeDescription
customer_idintegerChange the customer
customerobjectEdit the booking's customer: first_name, last_name, email, phone, phone_country_code. Other keys are ignored. Needs the customers:write scope (a phone app sign-in needs Edit customers), or the request returns 403.
start_datedateNew start date (YYYY-MM-DD)
end_datedateNew end date (YYYY-MM-DD), must be after start_date
statusstringChange status: draft, confirmed, picked_up, checked_in, returned, completed or no_show. Setting a draft to confirmed works like Confirm Booking with both emails on. Any other change runs the same checks as the matching action, including the checklist gates, and returns 422 with code status_transition_failed when the move is not allowed. no_show works like Mark a No Show. To cancel, use Cancel Booking
email_customerbooleanWith status: no_show only. Send the customer the We missed you email. Default true
overridebooleanWith a status change only. Skip a checklist that blocks it, as on the pickup and check-in actions. Needs the bookings.checklist_override permission
override_reasonstringWhy the checklist was skipped, up to 500 characters
holds_datesbooleanDrafts only. Turn the draft's hold on or off. Returns 409 with code HOLD_FAILED if the dates are no longer free.
hold_untilstringDrafts only. Last day to hold the dates (YYYY-MM-DD), or null for no end date.
sourcestringUpdate source label
discountbooleanEnable/disable discount
discount_typestringpercentage or flat
discount_valuenumberDiscount amount
security_depositbooleanEnable/disable security deposit
security_deposit_amountnumberDeposit amount
pickup_location_idintegerPickup location ID (see Locations). If the product prices by location, moving the booking re-prices its lines and totals at the new location.
return_location_idintegerReturn location ID (see Locations). Does not affect pricing.
add_bundlesarrayBundles to add (rental bookings only)
remove_bundle_idsarrayBundle line IDs to remove
experiencesarrayEdit experience lines already on the booking. Each item needs the line id (from Get Booking experiences[].id). Send start_time (local HH:MM, or null for the window's opening) to change when an open-window line starts on its day; the booking's start_date and end_date follow. A line moved to another day with schedule_id keeps its start time when the new day's window allows it
attributionobjectEdit marketing attribution. Same shape as Create Booking โ†’ Attribution Object. Send a key with an empty string to clear it; omit a key to leave it unchanged.
reconciliation_methodstringSettle a price delta on a paid / partially-paid booking. One of: send_payment_link, refund_to_card, skip. See Reconciling a paid booking below
Delivery is set when the booking is created

delivery is not a field here. Changing where a booking goes re-prices the journey, which moves the subtotal, the tax and what is owed on a booking that may already be paid - so it needs its own endpoint rather than a field on the general update. Send delivery to this endpoint and it is refused with delivery_not_updatable (422) rather than accepted and ignored. Set the address on Create Booking.

Add Bundles Arrayโ€‹

FieldTypeRequiredDescription
bundle_idintegerYesProduct bundle ID
quantityintegerNoBundle quantity (default: 1)

Request Exampleโ€‹

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"status": "confirmed",
"start_date": "2026-01-20",
"end_date": "2026-01-22"
}'

Responseโ€‹

Returns 200 OK with the updated booking details.

{
"data": {
"id": 123,
"type": "rental",
"status": "confirmed",
"payment_status": "unpaid",
"source": "API",
"start_date": "2026-01-20T00:00:00+00:00",
"end_date": "2026-01-22T00:00:00+00:00",
"currency": "USD",
"pricing": {
"subtotal": 150.00,
"discount": {
"enabled": false,
"type": null,
"value": null,
"amount": 0
},
"promo_code": null,
"voucher": null,
"taxes": [],
"custom_charges": [],
"security_deposit": 0,
"total": 150.00
},
"pickup_location": {
"id": 1,
"name": "Main Store",
"address": "123 Beach Road, Bondi NSW 2026, AU"
},
"return_location": null,
"customer": {
"id": 456,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1234567890"
},
"products": [],
"experiences": [],
"bundles": [],
"payments": [],
"tags": [],
"notes": [],
"created_at": "2026-01-10T14:30:00+00:00",
"updated_at": "2026-01-15T09:00:00+00:00"
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-01-15T09:00:00+00:00"
}
}

Confirm a Bookingโ€‹

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"status": "confirmed"}'

Add Discountโ€‹

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"discount": true,
"discount_type": "flat",
"discount_value": 25
}'

Change Customerโ€‹

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"customer_id": 789}'

Add Bundlesโ€‹

Add product bundles to a rental booking:

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"add_bundles": [
{"bundle_id": 5, "quantity": 1},
{"bundle_id": 8, "quantity": 2, "extras": [{"extra_id": 12, "quantity": 1}]}
]
}'

Each add_bundles entry accepts the same fields as bundles[] on Create booking, including extras[] and the selection keys (choices, durations, participants, schedules, variations, content_variations). Kit part picks use { "<bundle_item_id>": { "<template_item_id>": <variation_id> } }.

An extra charged once can only be added once. Sending a larger quantity for one returns a field-named 422 under add_bundles.{i}.extras.{j}.quantity, and nothing is changed. A booking that already carries two of one from before keeps them.

Remove Bundlesโ€‹

Remove bundles by their line item IDs (found in the booking's bundles array):

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"remove_bundle_ids": [45, 46]
}'
note

The remove_bundle_ids are the id values from the booking's bundles array (the bundle line item IDs), not the bundle's product ID.

Reconciling a paid bookingโ€‹

When you update a booking that has already been paid (or partially paid) and the price changes, the response includes a reconciliation block under meta describing what action was taken. If you don't pass reconciliation_method, no payment action is taken โ€” the booking just reflects the new totals and the response asks you to settle the difference.

Methodsโ€‹

MethodWhen to useEffect
send_payment_linkNew total > old totalCreates a payment link for the delta and emails it to the customer. The link is paid through the business's own gateway (Stripe, Paystack, Rapyd or Authorize.net). Booking flips to partial. Customer must have an email on file
refund_to_cardNew total < old totalRefunds the delta to the original payment method using the existing booking-level refund pipeline (Stripe or Paystack).
skipEither directionNo payment action. For a price increase the booking is marked partial so the imbalance shows up in the UI. Settle later via POST /bookings/{id}/payments or by sending a payment link manually

Charge exampleโ€‹

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"add_bundles": [{"bundle_id": 8, "quantity": 1}],
"reconciliation_method": "send_payment_link"
}'

Response (excerpt):

{
"data": { "id": 123, "...": "..." },
"meta": {
"reconciliation": {
"old_total": 180.00,
"new_total": 245.00,
"delta": 65.00,
"action": "payment_link_sent",
"amount": 65.00
}
}
}

Refund exampleโ€‹

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"remove_bundle_ids": [45],
"reconciliation_method": "refund_to_card"
}'

The reconciliation.action will be refunded on success.

Validationโ€‹

  • Passing send_payment_link when the new total decreased returns 422 with code: reconciliation_invalid. Use refund_to_card.
  • Passing refund_to_card when the new total increased returns 422 with code: reconciliation_invalid. Use send_payment_link.
  • A failed Stripe / Paystack refund returns 422 with code: reconciliation_failed โ€” the booking changes still persist; you can retry the refund separately.

A booking marked as a no-showโ€‹

A booking whose status is no_show is locked like a completed one, with one exception: a request that sends only status (with email_customer, override or override_reason if you need them) still goes through.

status sentResult
confirmedUndoes the no-show, the same as revert-no-show
checked_in or picked_upRecords a late arrival and clears the no-show

Any other field on a no_show booking returns 409 Conflict.

curl -X PATCH "https://app.equipdash.com/api/v1/bookings/123" \
-H "Authorization: Bearer eqd_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"status": "checked_in"}'

Error Responsesโ€‹

StatusCodeDescription
401authentication_requiredMissing or invalid API key
403insufficient_scopeAPI key lacks bookings:write scope
403forbiddenBooking belongs to another supplier
404resource_not_foundBooking not found
409conflictCannot update a cancelled, checked-in, returned, completed or no-show booking
422status_transition_failedThe booking cannot move to that status. The message says why
422validation_errorInvalid request data
422reconciliation_invalidreconciliation_method doesn't match the direction of the price change
422reconciliation_failedThe refund or payment-link call failed downstream (booking changes still persist)

Conflict Error Exampleโ€‹

{
"error": {
"code": "conflict",
"message": "Cannot update a booking that is cancelled."
},
"meta": {
"request_id": "req_abc123"
}
}

Notesโ€‹

  • Cancelled, checked-in, returned, completed and no-show bookings cannot be updated. Use the Cancel Booking endpoint for cancellation.
  • The customer must belong to your supplier account.
  • Changing dates will automatically:
    • Check availability for all products with the new dates
    • Recalculate prices based on new rental duration
    • Recalculate taxes and totals
    • Return an error if any products are unavailable for the new dates
  • Bundles can only be added to or removed from rental bookings.
  • Prices are automatically recalculated when bundles are added or removed.

Bundle rate countsโ€‹

For a bundle using prices by rate type, include rate_counts on each add_bundles[] entry. This maps offered rate category IDs to counts and replaces per-experience participant counts for that bundle. Keep the existing departure, choice, duration, and variation maps. The booking saves its rate labels, counts, and sold prices so later catalog changes do not reprice it.