Quote and Book V2 API
POST /api/v2/quote¶
Create a quote for a specific package. This generates a booking package ID that can be used for the final booking.
Quote is the prebook step — call it only on user intent
The Quote step is effectively the prebook step: it confirms the exact price (totalPrice) and terms that the partner will be charged. It MUST NOT be called for every rate returned by search — call it only when the end user initiates booking a specific package.
Final, partner-payable price
totalPrice in the Quote response is the final net amount payable by the partner — there is no need to separately combine room price, meal price, service fees, promos, or commissions. Taxes and mandatory fees are returned in taxesAndFees, each with an isIncludedInPrice flag indicating whether it is already part of totalPrice.
Rates can change between search and quote
Because the quote re-confirms the rate, details may differ from what was shown at search. Any differences are reported in the room.package.changes array (see Change Types). Both, the isRefundable flag and refundability dates may change.
Authentication: Required (X-Api-Key)
Request Body Schema:
| Field | Type | Required | Description |
|---|---|---|---|
packageId | string | Yes |
Responses:
- 200 OK: Quote created successfully
- 400 Bad Request: Invalid request body
- 401 Unauthorized: Invalid/missing API key
- 404 Not Found: Package not found
- 429 Too Many Requests: Rate limit exceeded
- 502 Bad Gateway: Upstream service failure
Response Schema (200 OK):
| Field | Type | Description |
|---|---|---|
packageBookingId | string | |
property | object | Basic property information |
property.id | string | DEPRECATED, use evocativeId instead. This value will be removed in future API updates. |
property.evocativeId | string | Unique property identifier. |
property.name | string | Property name |
room | object | |
room.id | string | Room identifier |
room.name | string | Room name |
room.package | object | |
room.package.boardType | string | Board/meal plan. See Board Types table |
room.package.totalPrice | object | |
room.package.totalPrice.amount | number | Total amount |
room.package.totalPrice.currency | string | |
room.package.taxesAndFees | array | Taxes and mandatory fees |
room.package.taxesAndFees[].currency | string | Currency code |
room.package.taxesAndFees[].title | string | Fee or tax name |
room.package.taxesAndFees[].isIncludedInPrice | boolean | Whether the amount is included in totalPrice |
room.package.taxesAndFees[].isMandatory | boolean | |
room.package.taxesAndFees[].value | number | Amount of the tax/fee |
room.package.cancellationPolicy | object | Cancellation summary |
room.package.cancellationPolicy.isRefundable | boolean | Indicates whether the package is refundable |
room.package.cancellationPolicy.fullRefundability | object/null | Window for full refund (if refundable) |
room.package.cancellationPolicy.fullRefundability.from | string | Earliest date/time for full refund |
room.package.cancellationPolicy.fullRefundability.to | string | Last date/time for full refund |
room.package.changes | string[] | Array of changes between the searched package and quoted. See Change Types table for possible values. |
bookingRemarks | string/null | Free-form supplier remarks for this package, or null. See Booking Remarks. |
Booking Remarks
bookingRemarks carries free-form text the supplier attaches to the quoted package, for the partner's own reference. It describes additional requirements that come with the reservation — check-in instructions, contact requirements, or charges the property collects locally.
bookingRemarks is opaque, unstructured text
The field is optional and unstructured. Availability, wording, language and formatting are decided by each supplier and vary between them — some send a single paragraph, others a concatenated list, many send nothing at all. The value is not translated and has no guaranteed length or layout.
null is normal, and the key is always present
Most packages have no supplier remarks. In that case the response contains "bookingRemarks": null — the key is always returned, never omitted.
Change Types
| Change Type | Description |
|---|---|
| PriceChanged | Price and/or taxes have changed |
| CancellationPolicyChanged | Cancellation policy have changed. Both, isRefundable flag and refundability dates may be changed. |
Example request body
Example response body (200)
{
"packageBookingId": "0f1...f52",
"property": {
"id": "12345",
"evocativeId": "R:54321",
"name": "Grand Hotel Paris"
},
"room": {
"id": "room-001",
"name": "Deluxe Room",
"package": {
"boardType": "Breakfast",
"totalPrice": {
"amount": 512.35,
"currency": "USD"
},
"taxesAndFees": [
{
"currency": "USD",
"title": "City tax",
"isIncludedInPrice": false,
"isMandatory": true,
"value": 12.5
}
],
"cancellationPolicy": {
"isRefundable": true,
"fullRefundability": {
"from": "2025-10-01T00:00:00Z",
"to": "2025-10-04T23:59:59Z"
}
},
"changes": ["PriceChanged"]
}
},
"bookingRemarks": "Check-in from 15:00. Guests arriving after 22:00 must contact the property at least 24 hours in advance."
}
POST /api/v2/book¶
Complete a booking using a quote ID. This endpoint creates a confirmed reservation.
Authentication: Required (X-Api-Key)
Request Body Schema:
| Field | Type | Required | Description |
|---|---|---|---|
packageBookingId | string | Yes | |
customerOrderId | string | No | Optional idempotency key. A string that must be unique or null. There is no fixed length restriction, but use a collision-proof value such as a prefix + GUID (e.g. <company_prefix>_<guid>). Returned as booking.customerOrderId, it can be used to look up the booking later and is shown as the Reference Number in the Evocative Ops portal. |
customer | object | Yes | |
customer.firstName | string | Yes | |
customer.lastName | string | Yes | |
customer.email | string | Yes | |
customer.phoneCountryCode | string | Yes | |
customer.phoneNumber | string | Yes | |
customer.residency | string | Yes | Residency country code (ISO-3166-1 alpha-2). Example: FR |
rooms | array | Yes | |
rooms[].primaryGuest | object | Yes | |
rooms[].primaryGuest.firstName | string | Yes | |
rooms[].primaryGuest.lastName | string | Yes | |
rooms[].occupancy | object | Yes | |
rooms[].occupancy.adultCount | integer | Yes | |
rooms[].occupancy.childrenAges | array | No | |
rooms[].specialRequest | string | No |
Guest names must use Latin characters only
Guest names must not contain non-English / non-Latin characters (e.g. ć, ę, ü, ø, æ). Requests with such characters are rejected (OCCUPANCY_INVALID_NAME).
No identity documents required
The book request requires only the customer and primary-guest names, contact details, residency, and occupancy. No passport number or other official identity data is collected.
Booking request has no fixed timeout
The booking request has no specific timeout (it cannot be capped to, e.g., 60 seconds). The connection is held open until a response is received from the downstream entity. Size your client read-timeout accordingly.
Responses:
- 200 OK: Booking completed successfully
- 400 Bad Request: Invalid request body or validation error (see error codes below)
- 401 Unauthorized: Invalid/missing API key
- 404 Not Found: Package booking not found
- 429 Too Many Requests: Rate limit exceeded
- 502 Bad Gateway: Upstream service failure
Response Schema (200 OK):
| Field | Type | Description |
|---|---|---|
property | object | |
property.id | string | DEPRECATED, use evocativeId instead. This value will be removed in future API updates. |
property.evocativeId | string | Unique property identifier |
property.name | string | Property name |
booking | object | |
booking.id | string | |
booking.customerOrderId | string | |
booking.referenceNumber | string | Internal reference number |
booking.supplierReferenceNumber | string | Reference number that should be used by the guest during the check-in. |
booking.boardType | string | Board/meal plan. See Board Types table |
booking.status | string | Current status of the booking. See the Booking Statuses table below for possible values. |
booking.totalPrice | object | |
booking.totalPrice.amount | number | Total amount |
booking.totalPrice.currency | string | |
booking.rooms | array | |
booking.rooms[].primaryGuest | object | |
booking.rooms[].primaryGuest.firstName | string | |
booking.rooms[].primaryGuest.lastName | string | |
booking.rooms[].occupancy | object | |
booking.rooms[].occupancy.adultCount | integer | |
booking.rooms[].occupancy.childrenAges | array | |
booking.rooms[].specialRequest | string | |
booking.taxesAndFees | array | Taxes and mandatory fees |
booking.taxesAndFees[].currency | string | Currency code |
booking.taxesAndFees[].title | string | Fee or tax name |
booking.taxesAndFees[].isIncludedInPrice | boolean | Whether the amount is included in totalPrice |
booking.taxesAndFees[].isMandatory | boolean | |
booking.taxesAndFees[].value | number | Amount of the tax/fee |
booking.cancellationPolicy | object | Cancellation summary |
booking.cancellationPolicy.isRefundable | boolean | Indicates whether the package is refundable |
booking.cancellationPolicy.fullRefundability | object/null | Window for full refund (if refundable) |
booking.cancellationPolicy.fullRefundability.from | string | Earliest date/time for full refund |
booking.cancellationPolicy.fullRefundability.to | string | Last date/time for full refund |
booking.bookingRemarks | string/null | Free-form supplier remarks captured at quote time, or null. See Booking Remarks. |
Booking Statuses
The booking.status field of a successful (200 OK) response can take one of the following values:
| Status | Meaning |
|---|---|
Completed | The booking has been successfully confirmed with the supplier/hotel. The reservation is valid. |
Cancelled | The booking has been cancelled or refunded. |
Booking failure is returned as an error, not in the 200 body
If the booking could not be completed because of an issue on the supplier/property side, the request returns a 409 Conflict with the BOOKING_FAILED error code instead of a 200 response. No confirmed reservation is created.
Example request body
{
"packageBookingId": "0f1...f52",
"customerOrderId": "7d6344ba02eeddf11743",
"customer": {
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@gmail.com",
"phoneCountryCode": "+1",
"phoneNumber": "1111111111",
"residency": "US"
},
"rooms": [
{
"primaryGuest": {
"firstName": "John",
"lastName": "Doe"
},
"occupancy": {
"adultCount": 2,
"childrenAges": [3]
},
"specialRequest": null
},
{
"primaryGuest": {
"firstName": "Jane",
"lastName": "Smith"
},
"occupancy": {
"adultCount": 2,
"childrenAges": null
},
"specialRequest": "Extra soft pillows"
}
]
}
Example response body (200)
{
"property": {
"id": "12345",
"evocativeId": "R:54321",
"name": "Grand Hotel Paris"
},
"booking": {
"id": "2bf503af-703f-4bc6-8b28-fe029076d6cc",
"customerOrderId": "7d6344ba02eeddf11743",
"referenceNumber": "4523673",
"supplierReferenceNumber": "1976925772",
"boardType": "Breakfast",
"status": "Completed",
"totalPrice": {
"amount": 512.35,
"currency": "USD"
},
"rooms": [
{
"primaryGuest": {
"firstName": "John",
"lastName": "Doe"
},
"occupancy": {
"adultCount": 2,
"childrenAges": [3]
},
"specialRequest": null
},
{
"primaryGuest": {
"firstName": "Jane",
"lastName": "Smith"
},
"occupancy": {
"adultCount": 2,
"childrenAges": null
},
"specialRequest": "Extra soft pillows"
}
],
"taxesAndFees": [
{
"currency": "EUR",
"title": "City tax",
"isIncludedInPrice": false,
"isMandatory": true,
"value": 12.5
}
],
"cancellationPolicy": {
"isRefundable": true,
"fullRefundability": {
"from": "2025-10-01T00:00:00Z",
"to": "2025-10-04T23:59:59Z"
}
},
"bookingRemarks": "Check-in from 15:00. Guests arriving after 22:00 must contact the property at least 24 hours in advance."
}
}
Example error response
Error Codes:
| Field | Description |
|---|---|
ROOM_SOLD_OUT | Room package is no longer available |
BOOKING_FAILED | The booking could not be completed due to an issue on the supplier/property's side. No confirmed reservation is created. |
DUPLICATE_CUSTOMER_ORDER_ID | Order with given customerOrderId already exists |
PROPERTY_NOT_FOUND | Property not found |
OCCUPANCY_MISMATCH | Total number of rooms or occupancies does not match one specified during the search |
OCCUPANCY_DUPLICATE | One person was given as primary guest for multiple rooms (in multi-room booking request) |
OCCUPANCY_INVALID_NAME | One of the guest's name is invalid or missing |