Submit a booking (pending reservation)
const url = 'https://demo.yourapp.com/api/v1/bookings';const options = { method: 'POST', headers: { 'Idempotency-Key': 'example', Authorization: 'Bearer <token>', 'Content-Type': 'application/json' }, body: '{"quoteId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","customer":{"firstName":"example","lastName":"example","email":"hello@example.com","phone":"example"},"pickupLocation":"example","dropoffLocation":"example","notes":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://demo.yourapp.com/api/v1/bookings \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: example' \ --data '{ "quoteId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "customer": { "firstName": "example", "lastName": "example", "email": "hello@example.com", "phone": "example" }, "pickupLocation": "example", "dropoffLocation": "example", "notes": "example" }'Creates a pending reservation from an unexpired quote. Staff
confirm or reject it in the dashboard; poll GET /bookings/{id}.
Always send a unique Idempotency-Key per booking attempt. Retries
with the same key replay the original response — success or business
rejection alike — instead of creating a duplicate. A quote can be
used exactly once (enforced by a database constraint, so concurrent
submissions cannot double-book a quote). Requires bookings:create.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”Required when the request carries an Origin header (browser channel)
Unique value per booking attempt (e.g. a UUID)
Request Bodyrequired
Section titled “Request Bodyrequired”object
object
Examplegenerated
{ "quoteId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "customer": { "firstName": "example", "lastName": "example", "email": "hello@example.com", "phone": "example" }, "pickupLocation": "example", "dropoffLocation": "example", "notes": "example"}Responses
Section titled “Responses”Booking accepted for staff review
object
object
Pending until staff confirm or reject
Example
{ "data": { "status": "pending" }}Request validation failed (VALIDATION_ERROR)
object
object
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "path": "example", "message": "example" } ] }}Missing/invalid/revoked/expired API key (API_KEY_REQUIRED, API_KEY_INVALID, API_KEY_REVOKED, API_KEY_EXPIRED) or missing/invalid session token on the browser channel (SESSION_REQUIRED, SESSION_INVALID, SESSION_EXPIRED).
object
object
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "path": "example", "message": "example" } ] }}Quote belongs to a different session (QUOTE_SESSION_MISMATCH)
object
object
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "path": "example", "message": "example" } ] }}Quote not found for this key (QUOTE_NOT_FOUND)
object
object
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "path": "example", "message": "example" } ] }}QUOTE_EXPIRED — request a new quote. QUOTE_ALREADY_USED — a booking already exists for this quote. REQUEST_IN_PROGRESS — same Idempotency-Key currently processing. If the original request failed before a response was recorded (e.g. a 5xx), the key becomes retryable within ~2 minutes.
object
object
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "path": "example", "message": "example" } ] }}Rate limit exceeded (RATE_LIMITED)
object
object
object
Examplegenerated
{ "error": { "code": "example", "message": "example", "details": [ { "path": "example", "message": "example" } ] }}Headers
Section titled “Headers”Seconds until the window resets
Unix timestamp (seconds) of the window reset