3. API Reference
OrderVoucher
POST /api/trade/orderVoucher
Retrieves the hotel voucher for an order you placed — the travel document your guest presents at the hotel desk.
The voucher is produced by the platform when the supplier confirms the booking, so
it is not available the instant Book returns. This endpoint always reports a
status; the voucher block is present only when that status is GENERATED.
A booking that is genuinely yours but whose voucher has not been issued yet is a
200 with status: NOT_GENERATED, not an error — poll it the same way you poll
QueryOrders.
Identifying the order
Supply at least one of customerReferenceNo (your own reference, sent on Book),
platformReferenceNo (our order number) or supplierReferenceNo. If a reference
matches more than one order the call is refused with 100001008 rather than
guessing — supply platformReferenceNo, which is unique.
Getting the bytes
voucher.downloadUrl is a time-limited object URL; voucher.expiresIn is how many
seconds it remains valid. Set includeDocument: true to receive the PDF inline as
base64 in voucher.content instead of following the link — intended for
integrations that cannot reach an object-storage URL from where they run. Documents
above 8 MB are never inlined; that request is refused with 100001005.
Checking the document is the one we issued
Every voucher is signed at the moment it is rendered. voucher.signature.digest is
the SHA-256 of the exact bytes we issued, in lowercase hex. Hash whatever you
received and compare — if the two differ, the file has been altered since issue and
must not be given to a traveller. signature.signature is a detached HMAC only we
can verify; it is returned so the claim is auditable, not so you can check it
yourself. A voucher rendered before document signing was introduced has no
signature block at all, rather than a fabricated one.
voucher.verifyUrl is the same public verification page the voucher's QR code
opens, which reports whether the document is still valid and whether it is
unaltered.
Access
The calling key must be scoped booking:read, and the order must belong to you. An
order that is not yours answers 100000404 not found — the same answer as a
reference that never existed, so the endpoint cannot be used to probe another
seller's order book.
Status values
GENERATED— issued and current;voucheris present.NOT_GENERATED— no voucher has been issued for this order yet.PENDING— a voucher number is reserved and the document is being produced.FAILED— generation was attempted and did not complete; contact support.CANCELLED— the booking is cancelled. The document is deliberately withheld: a reissued voucher for a cancelled stay is stamped "not valid for check-in" and must not be handed to a traveller by an automated pipeline.
Request headers
| Header | Required | Description |
|---|---|---|
Client-Request-Timestamp |
No | Client-side send time for this request, expressed as a unix timestamp. |
IP |
No | Caller IP address; both IPv4 and IPv6 are accepted. |
Language |
No | IETF BCP 47 language tag (see https://masonreview.com/posts/ietf-bcp-47-language-tags/), for example "en" or "en-US". Falls back to "en-US" when omitted. |
Market |
No | Point-of-sale market for this call, as an ISO 3166-1 alpha-2 country code. Required only when your account carries a market restriction: an allow-list cannot admit a market you have not stated, so such an account refuses calls that omit it. |
Request-Id |
No | Identifier for this individual request; values must not repeat. |
Trace-Id |
No | Identifier used to correlate a group of related requests. |
User-Ref |
No | Your own identifier for the person on whose behalf this call is made. Required only once named users have been authorised on your account, after which every call must identify one and is authorised against that user's scopes as well as the key's. |
Authorization |
Yes | Bearer credential — the value must be prefixed with "Bearer ". Obtain the token from the Ticket response. The Ticket call itself does not require this header. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
customerReferenceNo |
string | No | Your own reference, as sent on Book. |
platformReferenceNo |
string | No | Our order number, as returned by Book and QueryOrders. |
supplierReferenceNo |
string | No | The supplier's reference, as returned by Book. |
includeDocument |
boolean | No | Return the PDF inline as base64 in voucher.content as well as the link. Refused with 100001005 for documents above 8 MB. |
Example request
{
"customerReferenceNo": "9d1f4b2a-7c60-4f3e-9a58-1b0c2d3e4f50"
}Response
Successful calls return the standard envelope. code is 0 on success — check it rather than the HTTP status alone, because some business failures are delivered with HTTP 200.
| Field | Type | Required | Description |
|---|---|---|---|
code |
integer | No | |
msg |
string | No | |
data |
hotel.trade.protocol.OrderVoucherResp | No | |
data.customerReferenceNo |
string | No | |
data.platformReferenceNo |
string | Yes | |
data.supplierReferenceNo |
string | No | |
data.status |
enum | Yes | GENERATED is the only status that carries a document. CANCELLED withholds it deliberately: a reissued voucher for a cancelled stay is stamped "not valid for check-in". Allowed: GENERATED, NOT_GENERATED, PENDING, FAILED, CANCELLED. |
data.voucher |
OrderVoucherDocument | No | Present only when status is GENERATED. |
data.voucher.voucherNumber |
string | Yes | |
data.voucher.version |
integer | Yes | 1-based. A regenerated voucher supersedes the previous version. |
data.voucher.issuedAt |
string | Yes | |
data.voucher.contentType |
string | Yes | |
data.voucher.byteSize |
integer | Yes | |
data.voucher.verifyUrl |
string | Yes | The public verification page this voucher's QR code opens. |
data.voucher.downloadUrl |
string | Yes | Time-limited object URL for the PDF. |
data.voucher.expiresIn |
integer | Yes | Seconds downloadUrl remains valid. |
data.voucher.signature |
DocumentSignature | No | Absent for a voucher rendered before document signing was introduced. Omitted rather than fabricated. |
data.voucher.signature.alg |
string | Yes | |
data.voucher.signature.keyId |
string | Yes | Which platform key signed it. |
data.voucher.signature.digest |
string | Yes | Lowercase hex SHA-256 of the document bytes, as issued. |
data.voucher.signature.signature |
string | Yes | The detached signature over the manifest. |
data.voucher.signature.signedAt |
string | Yes | |
data.voucher.content |
object | No | Present only when includeDocument was requested. |
data.voucher.content.contentType |
string | Yes | |
data.voucher.content.byteSize |
integer | Yes | |
data.voucher.content.base64 |
string | Yes |
Failure responses
| HTTP | Meaning |
|---|---|
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden — this key is not scoped for booking:read |
| 404 | Order not found, or not yours |
| 429 | Too Many Requests |
Every failure uses the { code, msg } envelope. See Error handling for the full business-code table.
Code samples
curl -X POST https://api-test.ttdbooking.com/api/trade/orderVoucher \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TICKET" \
-H "Request-Id: $(uuidgen)" \
-d '{
"customerReferenceNo": "9d1f4b2a-7c60-4f3e-9a58-1b0c2d3e4f50"
}'Try it
Try it
POST /api/trade/orderVoucher
