OpheliaDocs
Search docs⌘K
DashboardCreate an account
Booking lifecycle

Booking lifecycle

The states a booking moves through from creation to confirmation or cancellation.

A booking always carries a status. When it is requires_action, the next_action object describes what to submit: requirements lists the fields to send to /continue, and expires_at is when the provider stops waiting.

json
{
"id": "bkg_12345678",
"object": "booking",
"status": "requires_action",
"vertical": "fitness",
"venue_id": "ven_87654321",
"provider": "mindbody",
"next_action": {
"type": "otp",
"message": "Mindbody sent a 6-digit verification code to jane.smith.diner@gmail.com. ...",
"requirements": [
{ "field": "otp_code", "label": "Verification Code", "type": "string", "required": true }
],
"expires_at": "2026-11-14T15:05:00Z"
}
}

Once the required action is submitted (or if none was needed), the booking reaches a terminal status. confirmed carries a provider_booking_id and a confirmation object with the provider's own confirmation_code:

json
{
"id": "bkg_12345678",
"object": "booking",
"status": "confirmed",
"vertical": "fitness",
"venue_id": "ven_87654321",
"provider": "mindbody",
"provider_booking_id": "mb_9f21c8a0",
"confirmation": {
"confirmation_code": "MB-9F21C8A0",
"message": "You're booked. Bring a mat — the studio doesn't rent them."
},
"confirmed_at": "2026-11-14T15:02:41Z"
}

For a restaurant booking (OpenTable, Resy), confirmation.terms holds what the guest agreed to: the card hold or deposit, the cancellation fee and deadline, and the restaurant's own policies in its own words. See Restaurant terms.

failed means the provider could not complete the booking. error_code is stable and safe to branch on; error_message explains it in words. For example, when Mindbody's own sign-in breaks:

json
{
"id": "bkg_12345678",
"object": "booking",
"status": "failed",
"vertical": "fitness",
"venue_id": "ven_87654321",
"provider": "mindbody",
"error_code": "mindbody_signin_error",
"error_message": "Mindbody's sign-in answered \"Something went wrong, please try again later.\""
}

A booking also carries datetime, party_size, customer, metadata (card fields removed), created_at and updated_at, plus end_user and session when it ran signed in as a person (see Sessions) and last_modification once it has been modified.

processingWork is underway. Create and continue are held server-side for up to 150 seconds until the booking reaches its next step (a final status or requires_action) and return it inline with 200, so you rarely observe this state; if the hold ends first you get 202 with this status. Poll GET /v1/bookings/{id}.
requires_actionAn end-user action is needed; see next_action. For dining this is an OTP (SMS); for fitness (Mindbody), a code emailed to the member; for entertainment an emailed code, then card details; for travel (hotels), card details directly, charged on submission, no OTP. With AgentCard it is a payment_authorization. Submit each to /continue before next_action.expires_at.
confirmedBooking is complete. See confirmation.confirmation_code for the provider's code.
failedThe provider could not complete the booking. error_code and error_message say why.
cancelledBooking was cancelled via /cancel. A confirmed booking is cancelled at the venue only on OpenTable; elsewhere it stays confirmed with error_code cancellation_unsupported.
expiredThe action window (e.g. OTP entry) elapsed before completion: a booking left in requires_action for more than 20 minutes becomes expired, with error_code action_expired. Nothing was booked.

Retries and Idempotency-Key

Send a unique Idempotency-Key header on POST /v1/bookings. The key belongs to your organization and does not expire. Sending the same key again returns the booking that key first created, in its current state, and starts nothing new; the request body is not compared, so a changed body under an old key still gets the old booking. Use a new key for each booking you intend to make. A request refused for a missing or invalid field created no booking, so fixing it and retrying under the same key is safe.

Cancelling and modifying

POST /v1/bookings/{id}/cancel cancels a booking that has not finished. A confirmed booking is cancelled at the venue only on OpenTable today; on other providers the call returns 200 with the booking still confirmed and error_code: "cancellation_unsupported", and the guest must cancel with the venue directly. If the venue refuses, the booking also stays confirmed and error_code says why. Cancelling a booking that is already cancelled, failed or expired changes nothing.

POST /v1/bookings/{id}/modify moves a confirmed booking; send any of datetime, party_size, seating_preference. It is supported on OpenTable only; other providers answer 422 modify_unsupported. A booking that is not confirmed is 409. If the venue refuses the change the answer is 422 with the provider's code and the unchanged booking, which is still confirmed at its original time; last_modification records the outcome.