A valid request URL is required to generate request examples{
"items": [
{
"ticketId": "tkt-2026-0142",
"ticketNumber": "T-2026-0142",
"storeId": "store-paris-11",
"recordedAt": "2026-07-14T10:32:05.000Z",
"skuId": "2f0a30932a471a86d885382399c476bc17fde6e613c42a73e2cf6a760fe4f774",
"quantity": 2,
"unitPriceCents": 1800,
"lineTotalCents": 3600
}
],
"total": 1,
"page": 1,
"pageSize": 20,
"pageCount": 1
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123,
"fieldErrors": [
{
"field": "<string>",
"message": "<string>"
}
]
}
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123
}
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123
}
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123
}
}Get a customer's purchase history
Returns ONE PAGE of the customer’s line-item purchase history — one row per priced ticket line, newest ticket first — projected from the sales read model. Reach for this to answer ‘what has this customer bought’; use listSales instead for store-wide reporting. Pass ?store=<id> to restrict to one store. Amounts are integer cents, VAT-inclusive. An unknown customer (or one who never bought) returns EMPTY items, not a 404.
The history grows with every ticket a loyal customer ever settles, so it is paged (page/pageSize, max 100). total counts the matching lines across ALL pages: to answer ‘everything this customer bought’ keep requesting pages until page reaches pageCount, or narrow with store — reading page 1 and stopping under-reports a customer’s lifetime history without looking like it did.
A valid request URL is required to generate request examples{
"items": [
{
"ticketId": "tkt-2026-0142",
"ticketNumber": "T-2026-0142",
"storeId": "store-paris-11",
"recordedAt": "2026-07-14T10:32:05.000Z",
"skuId": "2f0a30932a471a86d885382399c476bc17fde6e613c42a73e2cf6a760fe4f774",
"quantity": 2,
"unitPriceCents": 1800,
"lineTotalCents": 3600
}
],
"total": 1,
"page": 1,
"pageSize": 20,
"pageCount": 1
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123,
"fieldErrors": [
{
"field": "<string>",
"message": "<string>"
}
]
}
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123
}
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123
}
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123
}
}Authorizations
Authorization: Bearer <token>. Accepts EITHER a Keycloak access token (scopes-in-token) OR an opaque POS session token; both resolve to the same pos.* scope vocabulary the route guards enforce.
Path Parameters
The customer id to act on, e.g. cust-1 (client Customer.id).
1Query Parameters
1-based page index to return. Defaults to 1.
1 <= x <= 9007199254740991Rows per page, 1..100. Defaults to 20.
1 <= x <= 100Restrict the history to one store id; omit for all stores.
1Response
A page of the customer's priced purchase lines, newest ticket first, with the whole-history totals.
A page of the customer's priced purchase lines, newest ticket first, with the whole-history totals.
The rows on this page, in the query's sort order.
Show child attributes
Show child attributes
Total rows matching the filter across ALL pages, not just this one.
0 <= x <= 9007199254740991The 1-based page number served.
0 < x <= 9007199254740991Rows requested per page.
0 < x <= 9007199254740991Total number of pages; stop walking when page reaches it.
0 <= x <= 9007199254740991
