# Book a ticket with a specific Product
Workflow
## 1. Let's find a product
Let's say we use the catalog ID `0194abdc-3a71-72b0-a9b9-89d4be0cd73e`.
To obtain a list of catalog's products you can use
the [/v1/ticketing/catalogs/{id}/products](/openapi/ticketingproduct/api_v1ticketingcatalogs_catalogidproducts_get_collection)
endpoint:
### Request
```bash
curl --request GET \
--url https://api.korusticket.com/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/products\?page\=1\&itemsPerPage\=2 \
-H 'accept: application/ld+json' \
-H 'Authorization: Bearer {{YOUR_JWT_TOKEN}}' \
-H 'Accept-Language: fr'
```
### Response
```json
{
"@context": "/contexts/TicketingProduct",
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/products",
"@type": "Collection",
"totalItems": 65,
"member": [
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/products/0194abfe-1bdb-7b12-af59-ad81ae443689",
"@type": "TicketingProduct",
"id": "0194abfe-1bdb-7b12-af59-ad81ae443689",
"name": "Puy du Fou 1 jour Adulte",
"description": "Le tarif « Sur réservation » s’applique jusqu’à 72 heures avant la date de visite indiquée lors de la réservation, dans la limite des places disponibles. Les billets sont valables uniquement aux dates de visite réservées. Adulte à partir de 14 ans.
"
},
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/products/0194abfe-1c04-7ade-9bc3-dbcfefb12652",
"@type": "TicketingProduct",
"id": "0194abfe-1c04-7ade-9bc3-dbcfefb12652",
"name": "Puy du Fou 1 jour Adulte + Cinéscénie Argent",
"description": "Les tarifs \" Puy du Fou + Cinéscénie \" s'appliquent uniquement sur réservation, dans la limite des places disponibles. Les billets sont valables uniquement à la date de visite réservée. Adulte à partir de 14 ans."
}
],
"view": {
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/products?itemsPerPage=2&page=1",
"@type": "PartialCollectionView"
}
}
```
We can see in the response that there is 65 products (`"totalItems": 65`) in the catalog.
You can use the pagination parameters to iterate through the list.
If you need more information about pagination, refer to [this page](/using-the-api/pagination)
Let’s choose the product with ID `0194abfe-1c04-7ade-9bc3-dbcfefb12652`.
## 2. Choose a product Offer at a specific Date
To find an offer corresponding to our chosen product for the specific date 2025-06-07 we can use
the [GET /v1/ticketing/catalogs/{catalogId}/offers](/openapi/ticketingoffer/api_v1ticketingcatalogs_catalogidoffers_get_collection)
endpoint as follows:
### Request
```bash
curl --request GET \
--url https://api.korusticket.com/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers\?product=0194abfe-1c04-7ade-9bc3-dbcfefb12652\&date=2025-06-07\&page\=1\&itemsPerPage\=2 \
-H 'accept: application/ld+json' \
-H 'Authorization: Bearer {{YOUR_JWT_TOKEN}}' \
-H 'Accept-Language: fr'
```
### Response
```json
{
"@context": "/contexts/TicketingOffer",
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers",
"@type": "Collection",
"totalItems": 1,
"member": [
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894",
"@type": "TicketingOffer",
"id": "0194ac40-fda7-78c1-8fcb-26fc2df25894",
"date": "2025-06-07",
"availableQuantity": 1500,
"realtimePriceRequired": false,
"price": {
"@type": "TicketingOfferPrice",
"@id": "/.well-known/genid/7a820a778b28cb765bc6",
"amountInclTax": "87.00",
"originalAmountInclTax": "87.00",
"currency": "EUR",
"syncAt": "2025-01-28T09:32:07+00:00"
},
"product": {
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/products/0194abfe-1c04-7ade-9bc3-dbcfefb12652",
"@type": "TicketingProduct",
"id": "0194abfe-1c04-7ade-9bc3-dbcfefb12652",
"name": "Puy du Fou 1 jour Adulte + Cinéscénie Argent",
"description": "Les tarifs \" Puy du Fou + Cinéscénie \" s'appliquent uniquement sur réservation, dans la limite des places disponibles. Les billets sont valables uniquement à la date de visite réservée. Adulte à partir de 14 ans."
},
"tickets": [
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/0194ac40-fda7-78c1-8fcb-26fc2e2612d4",
"@type": "TicketingOfferTicket",
"id": "0194ac40-fda7-78c1-8fcb-26fc2e2612d4",
"name": "Puy du Fou Adulte",
"description": ""
},
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/0194ac40-fda8-739e-8d03-57f30adf4660",
"@type": "TicketingOfferTicket",
"id": "0194ac40-fda8-739e-8d03-57f30adf4660",
"name": "Cinéscénie Adulte - Argent",
"description": ""
}
]
}
],
"view": {
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers?date=2025-06-07&order%5Bdate%5D=asc&product=0194abfe-1c04-7ade-9bc3-dbcfefb12652",
"@type": "PartialCollectionView"
},
"search": {
"@type": "IriTemplate",
"template": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers{?date,product}",
"variableRepresentation": "BasicRepresentation",
"mapping": [
{
"@type": "IriTemplateMapping",
"variable": "date",
"property": "date",
"required": false
},
{
"@type": "IriTemplateMapping",
"variable": "product",
"property": "product",
"required": false
}
]
}
}
```
In this response we have the following information:
- there is only one offer
- this offer contains two tickets
- the field `"availableQuantity"=1500` indicates that the offer has a limited capacity. Offers with unlimited
have availableQuantity=null. You can check the offer's real-time availability before calling
the reservation. Read [this section](/how-to/availability-checks#check-offer-availability) for more details.
- the field `“realtimePriceRequired"=false` indicates that the price returned will not change. For realtime price, refer
to [this section](/how-to/real-time-price#realtime-price) for more details.
## 3. Select a session for each ticket
Each offer's ticket must be associated with a session in order to create a reservation.
To list the sessions available for each ticket, use
the [GET /v1/ticketing/catalogs/{catalogId}/offers/{offerId}/tickets](/openapi/ticketingofferticket/api_v1ticketingcatalogs_catalogidoffers_offeridtickets_get_collection)
endpoint.
### Request
```bash
curl --request GET \
--url https://api.korusticket.com/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets \
-H 'accept: application/ld+json' \
-H 'Authorization: Bearer {{YOUR_JWT_TOKEN}}' \
-H 'Accept-Language: fr'
```
### Response
```json
{
"@context": "/contexts/TicketingOfferTicket",
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets",
"@type": "Collection",
"totalItems": 2,
"member": [
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/0194ac40-fda7-78c1-8fcb-26fc2e2612d4",
"@type": "TicketingOfferTicket",
"id": "0194ac40-fda7-78c1-8fcb-26fc2e2612d4",
"name": "Puy du Fou Adulte",
"description": "",
"dateAccess": true,
"sessions": []
},
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/7522b8de-37a2-458d-b099-6d515b0739be",
"@type": "TicketingOfferTicket",
"id": "7522b8de-37a2-458d-b099-6d515b0739be",
"name": "Cinéscénie Adulte - Argent",
"description": "",
"dateAccess": false,
"sessions": [
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/events/2aa6ca51-5193-47db-9e27-0aeefdc0d381/sessions/ff23a5a2-a53f-43b9-a530-d84a61386449",
"@type": "TicketingSession",
"id": "ff23a5a2-a53f-43b9-a530-d84a61386449",
"occursAt": "2025-06-07T17:00:00+02:00",
"duration": null,
"availableQuantity": 24,
"event": {
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/events/2aa6ca51-5193-47db-9e27-0aeefdc0d381",
"@type": "TicketingEvent",
"id": "2aa6ca51-5193-47db-9e27-0aeefdc0d381",
"name": "Cinéscénie Adulte - Argent",
"description": ""
}
},
{
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/events/2aa6ca51-5193-47db-9e27-0aeefdc0d381/sessions/337177bc-e513-444f-bcee-49a3e25b48a3",
"@type": "TicketingSession",
"id": "337177bc-e513-444f-bcee-49a3e25b48a3",
"occursAt": "2025-06-07T20:00:00+02:00",
"duration": null,
"availableQuantity": 56,
"event": {
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/events/2aa6ca51-5193-47db-9e27-0aeefdc0d381",
"@type": "TicketingEvent",
"id": "2aa6ca51-5193-47db-9e27-0aeefdc0d381",
"name": "Cinéscénie Adulte - Argent",
"description": ""
}
}
]
}
],
"view": {
"@id": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets",
"@type": "PartialCollectionView"
}
}
```
In this response we have the following information:
- the ticket of id `0194ac40-fda7-78c1-8fcb-26fc2e2612d4` grants full-day access.
- the ticket of id `7522b8de-37a2-458d-b099-6d515b0739be` that gives access to the Event `Cinéscénie Adulte - Argent`
has two sessions available. You will need to choose one to create the reservation.
- Additionally, every session have a non-null `"availableQuantity"` value, meaning that sessions have a limited
capacity. Session with unlimited capacity have `"availableQuantity"=null`. If you want you can check the real-time
availability value before making a reservation. Refer
to [this section](/how-to/availability-checks#check-session-availability) for more details.
## 4. Create the reservation
Creating a reservation temporarily holds an offer, guaranteeing its availability and price for a limited time.
### Request Body - Ticket/Session association
To create the reservation you can use
the [POST /v1/booking/reservations/_bulk](/openapi/bookingreservation/api_v1bookingreservations_bulk_post)
endpoint by passing the following JSON body:
```json
{
"items": [
{
"quantity": 1,
"offer": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894",
"ticketSessions": [
{
"ticket": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/0194ac40-fda7-78c1-8fcb-26fc2e2612d4"
},
{
"ticket": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/7522b8de-37a2-458d-b099-6d515b0739be",
"session": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/events/2aa6ca51-5193-47db-9e27-0aeefdc0d381/sessions/337177bc-e513-444f-bcee-49a3e25b48a3"
}
]
}
]
}
```
For the first ticket there is no session to choose we just need to pass the ticket iri.
For the second ticket we choose the session that occurs at `2025-06-07T20:00:00+02:00`.
### Request
```bash
curl --request POST \
--url https://api.korusticket.com/v1/booking/reservations/_bulk \
-H 'accept: application/ld+json' \
-H 'Authorization: Bearer {{YOUR_JWT_TOKEN}}' \
-H 'Accept-Language: fr' \
-d '{"items":[{"quantity":1,"offer":"/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894","ticketSessions":[{"ticket":"/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/0194ac40-fda7-78c1-8fcb-26fc2e2612d4"},{"ticket":"/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/7522b8de-37a2-458d-b099-6d515b0739be","session":"/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/events/2aa6ca51-5193-47db-9e27-0aeefdc0d381/sessions/337177bc-e513-444f-bcee-49a3e25b48a3"}]}]}'
```
### Response
```json
{
"@context": {
"@vocab": "https://api.demo.korusticket.com/docs.jsonld#",
"hydra": "http://www.w3.org/ns/hydra/core#",
"reservations": "CreateReservationBulkOutput/reservations",
"failedReservations": "CreateReservationBulkOutput/failedReservations"
},
"@type": "CreateReservationBulkOutput",
"@id": "/.well-known/genid/78651cc4640b9253b7c0",
"reservations": [
{
"@id": "/v1/booking/reservations/35e72d9b-0fdc-44e3-869c-e1781c14418e",
"@type": "BookingReservation",
"expired": false,
"id": "35e72d9b-0fdc-44e3-869c-e1781c14418e",
"createdAt": "2025-01-29T07:55:53+00:00",
"totalAmountInclTax": "80.00",
"totalAmountExclTax": null,
"expiresAt": "2025-01-29T08:10:53+00:00",
"items": [
{
"@type": "ReservationItem",
"@id": "/.well-known/genid/dbb1fda993fdc977bbab",
"unitAmountInclTax": "42.32",
"unitAmountExclTax": null,
"quantity": 1,
"totalAmountInclTax": "42.32",
"totalAmountExclTax": null,
"offer": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894",
"product": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/products/0194abfe-1c04-7ade-9bc3-dbcfefb12652",
"offerTickets": [
{
"@type": "ReservationItemOfferTicket",
"@id": "/.well-known/genid/6fef51eaef68c943a2de",
"ticket": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/0194ac40-fda7-78c1-8fcb-26fc2e2612d4"
},
{
"@type": "ReservationItemOfferTicket",
"@id": "/.well-known/genid/567f51eaef68c943aaa",
"ticket": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/offers/0194ac40-fda7-78c1-8fcb-26fc2df25894/tickets/7522b8de-37a2-458d-b099-6d515b0739be",
"session": "/v1/ticketing/catalogs/0194abdc-3a71-72b0-a9b9-89d4be0cd73e/events/2aa6ca51-5193-47db-9e27-0aeefdc0d381/sessions/337177bc-e513-444f-bcee-49a3e25b48a3"
}
]
}
],
"organization": "/v1/ticketing/organizations/0194abdc-3a79-7ec3-b1b9-a1f291de587d",
"order": null
}
],
"failedReservations": []
}
```
The response contains two arrays :
- the `“reservations”` array contains the successful reservations
- the `"failedReservations"` array contains offers that failed to be reserved
The `"expiresAt"` indicates when the reservation expires. After this timestamp, the offer will be released and the
reservation will become invalid for booking.
## 5. Create the Order
To finalize the booking, call the [POST /v1/booking/orders/_bulk](/openapi/bookingorder/api_v1bookingorders_bulk_post)
endpoint. This converts reservations into actual bookings in
the ticket issuer's system. Make this call only after confirming that the customer's payment was successful.
To create the order, call the endpoint with the previously created reservation IDs and customer information. You must
also include your own reference ID in the optional `"externalReference"` field (max length 255 characters).
```json
{
"reservations": [
"/v1/booking/reservations/0194b10f-3ddd-70a5-a96a-d1026cd42746"
],
"customer": {
"firstname": "John",
"lastname": "Doe",
"email": "john.doe@gmail.com",
"phone": "0612345678",
"country": "FR",
"language": "fr"
},
"externalReference": "CUSTOM_BOOKING_REF_NUMBER_003"
}
```
### Request
Execute the request as follows:
```bash
url --request POST \
--url https://api.korusticket.com/v1/booking/orders/_bulk? \
-H 'accept: application/ld+json' \
-H 'Authorization: Bearer {{YOUR_JWT_TOKEN}}' \
-d '{"reservations":["/v1/booking/reservations/0194b10f-3ddd-70a5-a96a-d1026cd42746"],"customer":{"firstname":"John","lastname":"Doe","email":"john.doe@gmail.com","phone":"0612345678","country":"FR","language":"fr"}}'
```
### Response
```json
{
"@context": {
"@vocab": "https://api.demo.korusticket.com/docs.jsonld#",
"hydra": "http://www.w3.org/ns/hydra/core#",
"orders": "CreateOrderBulkOutput/orders"
},
"@type": "CreateOrderBulkOutput",
"@id": "/.well-known/genid/ca4347e0ca0909425dee",
"orders": [
{
"@id": "/v1/booking/orders/0194b132-448c-7d1b-bb13-f8e09ae5c18f",
"@type": "BookingOrder",
"id": "0194b132-448c-7d1b-bb13-f8e09ae5c18f",
"createdAt": "2025-01-29T08:34:09+00:00",
"organization": "/v1/organizations/0194abdc-3a79-7ec3-b1b9-a1f291de587d",
"reference": "KT-ORD-6799E80128885",
"externalReference": "CUSTOM_BOOKING_REF_NUMBER_003",
"totalAmountInclTax": "42.32",
"totalAmountExclTax": "40.11",
"reservation": "/v1/booking/reservations/0194b10f-3ddd-70a5-a96a-d1026cd42746",
"customer": [],
"items": [
{
"@type": "OrderItem",
"@id": "/.well-known/genid/fc26307a17a3ad7720bc",
"unitAmountInclTax": "42.32",
"unitAmountExclTax": "40.11",
"quantity": 1,
"totalAmountInclTax": "42.32",
"totalAmountExclTax": "40.11",
"offer": "/v1/ticketing/catalogs/0194d07e-aa37-7171-820c-712e91552451/offers/0194ac3f-7bdd-7175-a275-30c865618283",
"product": "/v1/ticketing/catalogs/0194d07e-aa37-7171-820c-712e91552451/products/0194abfe-1bdb-7b12-af59-ad81ae443689",
"offerTickets": [
{
"@type": "OrderItemOfferTicket",
"@id": "/.well-known/genid/2c89a04ae411eae8a3af",
"ticket": "/v1/ticketing/catalogs/0194d07e-aa37-7171-820c-712e91552451/offers/0194ac3f-7bdd-7175-a275-30c865618283/tickets/0194ac3f-7be0-7f34-aa3f-7f22e2aa6285",
"session": "/v1/ticketing/catalogs/0194d07e-aa37-7171-820c-712e91552451/events/0195f1a2-6de6-78bc-aef4-d6dca86cd207/sessions/0195f1a2-6de9-716f-b9f5-f908391de21c"
}
]
}
],
"documents": [
"/v1/booking/orders/0194b132-448c-7d1b-bb13-f8e09ae5c18f/documents/0194b132-449c-79cd-9da1-50be439b6e9d"
]
}
]
}
```
In the response you can see the following fields:
- `"reference"` is the Korus Ticket API internal order reference
- `“externalReference”` is your own order reference. You can call
the [POST v1/booking/orders/_bulk](/openapi/bookingorder/api_v1bookingorders_bulk_post) endpoint multiple times with
the same value in the `“externalReference”` field to group all orders in the same booking.
- `"items”` contains the detail of reserved products and their prices as well as tickets and associated sessions
- `“documents”` lists the available order documents. These are typically the customer's tickets for the Event. You will
need to call
the [PATCH /v1/booking/orders/{orderId}/documents](/openapi/bookingorderdocument/api_v1bookingorders_orderiddocuments_id_patch)
endpoint to get the document's public URL.
## 6. Expired Reservation error
If one or more reservations passed to
the [POST v1/booking/orders/_bulk](/openapi/bookingorder/api_v1bookingorders_bulk_post) endpoint is expired you will get
an HTTP 422 response
with the following violations:
```json
{
"@context": "/contexts/ConstraintViolationList",
"@id": "/validation_errors/d53a91b0-def3-426a-83d7-269da7ab4200",
"@type": "ConstraintViolationList",
"status": 422,
"violations": [
{
"propertyPath": "reservations[0].expired",
"message": "La réservation a expiré",
"code": "d53a91b0-def3-426a-83d7-269da7ab4200"
}
],
"detail": "reservations[0].expired: La réservation a expiré",
"description": "reservations[0].expired: La réservation a expiré",
"type": "/validation_errors/d53a91b0-def3-426a-83d7-269da7ab4200",
"title": "An error occurred"
}
```
## 7. Get an `OrderDocument` download Url
To access orders documents, including events tickets, please refer to [this section](/how-to/get-order-documents).