Skip to main content

Charge for Missing Parts

When a product tracks its contents and parts come back unticked at return, the unticked parts that carry a replacement cost are "missing". This endpoint sums those costs and adds them to the booking's bill as a single itemised custom charge โ€” raising the booking's total and amount due โ€” so the missing parts are then collected through the normal payment flow (terminal, card, cash, bank transfer, or a payment link), exactly like the rest of the booking.

There is one amount due: whatever settles it (a payment link or an in-store payment) settles it once. The endpoint never charges the customer automatically โ€” it only adds the line to the bill; you take payment with the existing Add Payment endpoint.

POST /api/v1/mobile/bookings/{id}/missing-parts-charge

Authenticationโ€‹

Mobile-authenticated endpoint. The user's role must include both the bookings.fulfillment and bookings.payments permissions. The booking must belong to the requesting supplier.

Path Parametersโ€‹

ParameterTypeDescription
idintegerBooking ID

Request Bodyโ€‹

FieldTypeDefaultDescription
sendbooleantruefalse returns a preview (the itemised summary only, nothing written). true adds the missing-parts line to the booking's bill.

What counts as "missing"โ€‹

A return-checklist part is included only when all of these hold:

  1. It was not ticked back in at return (is_completed = false).
  2. It carries a replacement cost (unpriced parts are tracked but never billed).
  3. If the product's contents were checked at pickup, the part was ticked out then โ€” a part never handed over can't be missing.

Responseโ€‹

200 OK. summary is always returned; custom_charge is the line that was added (or null in preview mode).

{
"data": {
"summary": {
"lines": [
{
"line_id": 64,
"product_name": "4-Person Tent",
"items": [
{ "label": "Footprint", "quantity": 1, "unit_cents": 4000, "line_cents": 4000 },
{ "label": "Stakes", "quantity": 8, "unit_cents": 200, "line_cents": 1600 }
],
"total_cents": 5600
}
],
"total_cents": 5600
},
"custom_charge": {
"id": 812,
"description": "Missing parts: Footprint, Stakes ร—8",
"amount": 56.00
}
},
"meta": { "request_id": "...", "timestamp": "..." }
}
FieldTypeDescription
summary.lines[]arrayOne entry per booking line that has missing priced parts.
summary.lines[].items[]arraylabel, quantity, unit_cents, line_cents (unit_cents ร— quantity).
summary.parts_centsintegerWhat the missing parts cost across the booking, in cents.
summary.deposit_centsintegerHow much of that a deposit kept at return already paid.
summary.total_centsintegerWhat is left to charge: parts_cents less deposit_cents, in cents.
custom_chargeobject|nullThe bill line that was added. null in preview mode (send: false) and when nothing new was added (see Idempotency).
custom_charge.amountnumberCharge amount in the booking's currency (dollars).

After a successful call the amount appears as a Missing parts line in the booking's custom charges, and the booking's total / amount due rise by summary.total_cents / 100. The charge is added untaxed (it's a replacement-cost recovery, not a sale).

Idempotencyโ€‹

A return never marks the missing parts as returned, so they stay "missing". To prevent double-billing, the endpoint adds at most one missing-parts charge per booking: if a Missing parts: custom charge already exists, the call is a safe no-op โ€” it returns 200 with the current summary but custom_charge: null. Check custom_charge !== null to know whether a new line was written.

Errorsโ€‹

StatusCodeWhen
403forbiddenThe booking belongs to another supplier, or the user lacks bookings.payments.
404not_foundNo booking with that id.
422nothing_to_chargeNo priced parts are missing, or a deposit kept at return already paid for them (the message says which).

Notesโ€‹

  • This replaces the earlier behaviour where the endpoint emailed a standalone payment link. The charge now folds into the booking's bill, so it's collected the same way as everything else and there is never a separate balance to reconcile.
  • To preview the total before committing, call with { "send": false } first.
  • When a return keeps part of the deposit (deposit: keep), that money pays for the missing parts first. Only the rest is charged, and the line's description names what the deposit paid.