# 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; `voucher` is 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

```json
{
  "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](../guides/error-handling) for the full business-code table.
