Add check payment
const url = 'https://api.aerandil.com/v1/actions/hospitality.action.add_check_payment/apply';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"branch":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","params":{"amount":{"amount":"example","currency":"example"},"authorised_by":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","credential_token":"example","external_ref":"example","folio_id":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","guest_id":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","override_reason":"example","paid_at":"2026-04-15T12:00:00Z","poiid":"example","psp_reference":"example","reservation_id":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","tender":"room_charge","tendered":{"amount":"example","currency":"example"},"terminal_transaction_id":"example","tip":{"amount":"example","currency":"example"}},"return_modified":false,"target":{"id":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","object_type":"hospitality.guest_check"}}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.aerandil.com/v1/actions/hospitality.action.add_check_payment/apply \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "branch": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "params": { "amount": { "amount": "example", "currency": "example" }, "authorised_by": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "credential_token": "example", "external_ref": "example", "folio_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "guest_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "override_reason": "example", "paid_at": "2026-04-15T12:00:00Z", "poiid": "example", "psp_reference": "example", "reservation_id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "tender": "room_charge", "tendered": { "amount": "example", "currency": "example" }, "terminal_transaction_id": "example", "tip": { "amount": "example", "currency": "example" } }, "return_modified": false, "target": { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "object_type": "hospitality.guest_check" } }'Take one tender against an open check — the kernel is the system of record for a check’s payments. amount is what the payment applies to the check and may not exceed balance_due, except in cash: cash tendered (default amount) above the balance applies the balance and gives the rest back as change_given. A tip rides only on card, room_charge and charge_to_key and stays out of paid_total. A card payment carries the terminal’s references (psp_reference, terminal_transaction_id, poiid), never card data. A folio tender is bound server-side, the same on every path: room_charge requires folio_id and reservation_id, and the folio must be an open guest window of that booking’s in-house stay at the check’s own property (a house, master or company account, another booking’s bill or another hotel’s is refused); charge_to_key requires credential_token, the tapped key, resolved as post_charge_by_credential resolves it — its in-house stay names the folio and the reservation (a client folio_id or reservation_id that is not the key’s is refused) and its per-charge and daily caps bound the payment and its tip; a tap is live, so a paid_at more than five minutes from the kernel’s clock is refused and its postings are dated when the kernel records them, the clock the daily cap counts by. guest_id, the guest the server confirmed, must be the reservation’s guest (a sharer signs on their own booking); it is recorded on the payment and on each folio charge as signed_by. They post to that open folio as the payment is taken: one charge per revenue category on the check (bucket = the outlet’s usali_department, charge_at_outlet, revenue_category, its share of the VAT as tax applications), apportioned by largest remainder so the parts sum to the payment exactly, and the tip as a separate gratuity charge — a pass-through, never revenue — each emitting charge.posted.recorded, the payment linked to the charges and the check to the folio. The stay’s package allowance is consumed with no prompt and no other tender: when the folio’s in-house stay holds a live package component with a daypart — the check’s own meal period, else an all_day credit — due on the check’s business date (a breakfast the morning after its night), eaten at this outlet (an alternate outlet, or any when it names none) and with something left, it covers the payment’s food and soft-drink shares up to what is left (never alcohol, never the tip): that part is recorded as the payment’s allowance_applied and as a package_component_consumption (allowance and consumed both the amount, consumed, with the check’s covers) through the one package write, linked to the payment (consumption_for_check_payment), whose balance-neutral package line on the folio is one of the payment’s postings — and only the rest posts as the charges the guest owes, the covered shares shrunk with their VAT. One component per payment. Every payment records its share of each category and its VAT (allocation) over what earlier payments left, so a check paid in parts sums exactly. The payment that brings balance_due to zero settles the check — every line must be fulfilled, voided or comped by then — stamping settled_at (= paid_at), marking a seated table dirty and emitting fnb.check_settled with the per-tender breakdown. Business time: paid_at defaults to now. A present external_ref routes the create through the check_payment_external_ref business key, so a replayed payment is a no-op rather than a second payment. A room charge or charge-to-key is held to the stay’s posting rules (set_posting_rules): a no-post stay refuses it (no_post: …), and so does one whose credit — the greater of its credit limit and its live card holds, less its bills’ balance and the room still due — the posting and its tip would pass (no_credit: …). An override (override_reason) taken under a manager’s own session lets the refusal through — an override is proven by who is signed in, not by who is named: the authoriser recorded on the payment (override_kind, authorised_by, override_reason) and emitted as fnb.posting_override is the session’s staff member, and a body authorised_by must be that same one (override_not_authenticated: …). An override with nothing to override is refused (nothing_to_override: …), as is one under a session that is no manager’s (not_a_manager: …) or none at all (override_not_authenticated: …). Emits fnb.payment_added.
Effects: create hospitality.check_payment; link hospitality.link.check_payment_on_check; link hospitality.link.check_payment_to_folio; modify hospitality.guest_check; create hospitality.charge; create hospitality.tax_application; link hospitality.link.folio_has_charge; link hospitality.link.charge_at_outlet; link hospitality.link.charge_has_tax_application; link hospitality.link.check_payment_posted_charge; link hospitality.link.check_settled_to_folio; link hospitality.link.charge_via_credential; modify hospitality.folio; modify hospitality.service_table; create hospitality.check_receipt; link hospitality.link.receipt_for_check; create hospitality.package_component_consumption; modify hospitality.package_sale; link hospitality.link.package_sale_has_consumption; link hospitality.link.consumption_for_charge; link hospitality.link.charge_attributed_to_package_sale; link hospitality.link.charge_attributed_to_package_component; link hospitality.link.consumption_for_check_payment.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Apply against an open branch’s overlay view instead of the canonical (main) plane. The action’s writes land in the branch’s copy-on-first-write overlay, its events in the branch’s own stream, and the invocation is journaled for merge-by-replay. Branch writes are action-only, so this is the write-side entry point to a branch (POST /v1/branches forks one).
object
object
object
object
When true, the response carries modified_objects and modified_links projections — the engine reads the event log inside the same transaction so the projection observes the handler’s own writes.
object
Responses
Section titled “Responses”Action applied. modified_objects and modified_links populated when return_modified: true was supplied.
Envelope returned by the Aerandil action engine. correlation_id ties every event emitted by this invocation; modified_objects and modified_links project the events the handler emitted (per the action’s declared effects); warnings carries any non-blocking soft-validator observations.
object
Per-invocation correlation id; matches events.correlation_id for every event this action appended.
Links established or removed by this invocation. Empty when the caller did not request return_modified.
object
Objects created, modified, or soft-deleted by this invocation. Empty when the caller did not request return_modified.
object
Non-blocking soft-validator observations emitted during this invocation (e.g. comp-authority over-limit, recipe pour-cost over sell-price). Absent when no warnings were emitted.
object
Human-readable summary, suitable for logging or operator-UI surfacing.
Object type the warning was raised against.
Property the warning anchors to, when a single field is the locus. Absent for multi-field rules.
Stable kebab-case rule identifier (e.g. comp-authority-over-limit).
Example
{ "modified_links": [ { "kind": "linked", "link_type": "hospitality.link.check_payment_on_check" } ], "modified_objects": [ { "kind": "created", "object_type": "hospitality.check_payment" } ]}Conflict — concurrent modification or unique constraint violation.
Validation error — parameter validation or business-rule violation.