A valid request URL is required to generate request examples{
"id": "txn-ok",
"registerId": "reg-1",
"transaction": {
"id": "txn-ok",
"number": "T-100",
"storeId": "store-1",
"sellerId": "user-camille",
"customerId": "cust-1",
"status": "completed",
"type": "sale",
"lines": [
{
"skuId": "72474f561163443c1d5c6702bf47b7f83de910cf3cc94212be19a0f882f6da20",
"quantity": 1,
"unitPrice": 1800
},
{
"skuId": "07ae28fbd784733d76896d29b542c41882dea56eb1fa3249d4b861f161d0817c",
"quantity": 1,
"unitPrice": 500
}
],
"totals": {
"subtotal": 2300,
"total": 2120,
"itemCount": 2,
"lineCount": 2
}
},
"ticket": {
"number": "T-100",
"storeId": "store-1",
"sellerId": "user-camille",
"customerId": "cust-1",
"subtotalCents": 2300,
"totalCents": 2120,
"itemCount": 2,
"tenders": [
{
"method": "card",
"appliedCents": 2120
}
],
"changeCents": 0
},
"loyalty": {
"customerId": "cust-1",
"pointsEarned": 21
},
"stockMovements": [
{
"skuId": "72474f561163443c1d5c6702bf47b7f83de910cf3cc94212be19a0f882f6da20",
"deltaQuantity": -1
}
],
"coupon": {
"code": "WELCOME10",
"basketCents": 2120,
"discountAmountCents": 0
},
"emittedAt": "2026-07-28T10:00:00.000Z"
}{
"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
}
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123
}
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "<string>",
"statusCode": 123
}
}Finalize a settled sale (encaissement)
Commits an encaissement: turns a settled cart plus its tenders into one idempotent sale event (vente), booked against the register session, and produces the ticket de caisse / reçu (201). This is the ONLY way to commit a sale. The submitted cart prices are ADVISORY — the server re-prices every catalog line from its own reference authority (plus any declaredDiscounts, automatic promotions and a presented couponCode) and refuses a cart it prices differently. Idempotent by transactionId: replaying the same id with the same content is a no-op. Reach for it to ring up a customer at the till. Gotchas: mark a self-priced line (Article libre / gift card) with custom: true so it is trusted instead of re-priced; a registerId keys the NF525 fiscal chain per till. Side-effects: this operation is IRREVERSIBLE and money-in — a single call decrements on-hand stock for every sold unit, accrues loyalty points for an identified customer, and appends an inalterable entry to the per-register NF525 fiscal signature chain (the ticket de caisse is fiscally sealed and cannot be un-issued). There is no un-finalize: a mistake is corrected by processing a return / avoir, never by deleting the sale. This is why the operation is tier avoid — an agent must not trigger it unprompted. Failure conditions: 400 on a malformed body OR on a storeId the provisioned store network does not carry (field error on storeId; a network with NO store yet abstains and the sale proceeds); 403 for a declared discount the principal may not grant (needs price:override, or a single-use x-elevation-token); 409 when the same transactionId was already finalized with DIFFERENT content; 422 on an empty cart, a price/settlement mismatch (beyond the deployment’s cash-rounding tolerance) or a SKU the price authority does not carry.
A valid request URL is required to generate request examples{
"id": "txn-ok",
"registerId": "reg-1",
"transaction": {
"id": "txn-ok",
"number": "T-100",
"storeId": "store-1",
"sellerId": "user-camille",
"customerId": "cust-1",
"status": "completed",
"type": "sale",
"lines": [
{
"skuId": "72474f561163443c1d5c6702bf47b7f83de910cf3cc94212be19a0f882f6da20",
"quantity": 1,
"unitPrice": 1800
},
{
"skuId": "07ae28fbd784733d76896d29b542c41882dea56eb1fa3249d4b861f161d0817c",
"quantity": 1,
"unitPrice": 500
}
],
"totals": {
"subtotal": 2300,
"total": 2120,
"itemCount": 2,
"lineCount": 2
}
},
"ticket": {
"number": "T-100",
"storeId": "store-1",
"sellerId": "user-camille",
"customerId": "cust-1",
"subtotalCents": 2300,
"totalCents": 2120,
"itemCount": 2,
"tenders": [
{
"method": "card",
"appliedCents": 2120
}
],
"changeCents": 0
},
"loyalty": {
"customerId": "cust-1",
"pointsEarned": 21
},
"stockMovements": [
{
"skuId": "72474f561163443c1d5c6702bf47b7f83de910cf3cc94212be19a0f882f6da20",
"deltaQuantity": -1
}
],
"coupon": {
"code": "WELCOME10",
"basketCents": 2120,
"discountAmountCents": 0
},
"emittedAt": "2026-07-28T10:00:00.000Z"
}{
"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
}
}{
"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.
Body
111111Show child attributes
Show child attributes
Show child attributes
Show child attributes
1sale, rental, repair, return - Option 1
- Option 2
- Option 3
Show child attributes
Show child attributes
1^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$Response
The committed sale event: its transaction, ticket, loyalty, and stock movements.
The committed sale event: its transaction, ticket, loyalty, and stock movements.

