Bookings API
A booking is a calculation made permanent — the immutable record you reconcile against and the thing an invoice is issued from. Create, list, get, adjust, void, and refund it from code.
Create a booking
POST /v1/bookings runs the calculation server-side (same engine as /v1/tax/calculate), freezes the request and response snapshots, and returns the booking record. Wrap the calculation payload in a calculation object and add booking-level fields alongside it. Bookings are org-scoped — the organization comes from your credential and can't be set by the caller.
| Field | Type | Description |
|---|---|---|
| calculationrequired | object | A full TaxCalculationRequest. Also accepts buyer_name / buyer_address for a PEPPOL-valid invoice (these don't affect the tax). |
| idempotency_key | string | Client-generated key (≤ 200 chars). Re-POSTing with the same key + body returns the existing booking with 200; a different body returns 409. See Errors & idempotency. |
| property_id | integer | Managed property to inherit jurisdiction, tax drivers, and default issuers from. See Properties. |
| external_reference | string | Your internal booking ID (≤ 200 chars) for list filters and reconciliation. |
| buyer_reference | string | EN 16931 BT-10 buyer reference (PO number, XRechnung Leitweg-ID, French B2G reference; ≤ 200 chars). Invoice metadata — can also be set later via PATCH /v1/bookings/{id}/invoice-details. |
| buyer_endpoint_id | string | BT-49 buyer electronic address (PEPPOL routing id; ≤ 200 chars) — needed for a transmission-ready B2B PEPPOL invoice. Can also be set later via PATCH /v1/bookings/{id}/invoice-details. |
| buyer_endpoint_scheme | string | EAS/ICD scheme code for buyer_endpoint_id (e.g. 9930; ≤ 20 chars). Can also be set later via PATCH /v1/bookings/{id}/invoice-details. |
| payment_terms | string | BT-20 payment terms text (≤ 300 chars); defaults to 'Due on receipt' when omitted. Can also be set later via PATCH /v1/bookings/{id}/invoice-details. |
| legal_issuer_id / supplier_legal_issuer_id | integer | The invoice seller (and, for self-billed 389, the supplier). Explicit value wins, then the property default, then the org default. |
| is_test | boolean | Mark as a TEST booking so its invoices issue against an isolated TEST fiscal series. See Test vs live. |
curl -X POST https://api.taxlens.getdynamiq.ai/v1/bookings \
-H "X-API-Key: $TAXLENS_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_reference": "PMS-2026-00482",
"idempotency_key": "pms-2026-00482-v1",
"property_id": 42,
"calculation": {
"jurisdiction_code": "US-NY-NYC",
"stay_date": "2026-06-15",
"checkout_date": "2026-06-18",
"nightly_rate": 250,
"currency": "USD",
"nights": 3,
"number_of_guests": 2,
"property_type": "hotel"
}
}'{
"id": 4821,
"org_id": 17,
"external_reference": "PMS-2026-00482",
"idempotency_key": "pms-2026-00482-v1",
"status": "confirmed",
"total_tax": "87.37",
"total_with_tax": "837.37",
"currency": "USD",
"request": { "jurisdiction_code": "US-NY-NYC", "nightly_rate": 250.0, "nights": 3, "...": "..." },
"response": { "calculation_id": "calc_97d7…", "tax_breakdown": { "...": "..." } },
"metadata": {},
"created_at": "2026-05-21T10:29:52.943980Z",
"voided_at": null
}List & get
GET /v1/bookings returns your org's bookings, newest first, with cursor-based pagination — pass the previous next_cursor back to page on, and stop when it's null. Filter by status (confirmed, adjusted, voided, refund), external_reference, and a from_date/to_date creation range. GET /v1/bookings/{id} fetches one, including the frozen request snapshot and the persisted calculation. Bookings from another org return 404, never 403.
curl "https://api.taxlens.getdynamiq.ai/v1/bookings?status=confirmed&from_date=2026-05-01T00:00:00Z&limit=25" \
-H "X-API-Key: $TAXLENS_KEY"
curl https://api.taxlens.getdynamiq.ai/v1/bookings/4821 \
-H "X-API-Key: $TAXLENS_KEY"List your organization's recent bookings (read-only).
Sign in to run this against the live API. Read-only — nothing is saved.
Adjust (re-runs the engine)
When a tax-affecting input changes — dates, jurisdiction, nightly price, guest count, property type, buyer context — PATCH /v1/bookings/{id} re-runs the engine. Send a complete replacement calculation, not just the changed fields. The same row stays, status becomes adjusted, totals and snapshots are replaced, and the prior calculation is appended to metadata.adjustment_history.
curl -X PATCH https://api.taxlens.getdynamiq.ai/v1/bookings/4821 \
-H "X-API-Key: $TAXLENS_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "nightly rate corrected after PMS sync",
"calculation": {
"jurisdiction_code": "US-NY-NYC",
"stay_date": "2026-06-15",
"checkout_date": "2026-06-18",
"nightly_rate": 275,
"currency": "USD",
"nights": 3,
"number_of_guests": 2,
"property_type": "hotel"
}
}'Edit invoice details (no re-calc)
To set or correct invoice-only metadata — buyer name and address, buyer reference, PEPPOL endpoint, payment terms, or the attached legal issuer — use PATCH /v1/bookings/{id}/invoice-details. This does not re-run the engine and does not append to adjustment_history; it's distinct from adjust. Use it to make a booking send-ready before issuing.
curl -X PATCH https://api.taxlens.getdynamiq.ai/v1/bookings/4821/invoice-details \
-H "X-API-Key: $TAXLENS_KEY" \
-H "Content-Type: application/json" \
-d '{
"buyer_name": "ACME GmbH",
"buyer_address": { "line1": "Hauptstrasse 1", "city": "Berlin", "postal_code": "10115", "country_code": "DE" },
"buyer_endpoint_id": "DE123456789",
"buyer_endpoint_scheme": "9930"
}'Void & refund
DELETE /v1/bookings/{id} voids a booking. Voids are sticky and idempotent — the row isn't deleted, status flips to voided and voided_at is set, and a second DELETE is a no-op (returns 204).
POST /v1/bookings/{id}/refund processes a partial or full refund and returns a per-jurisdiction tax_delta — the proportional fraction of the originally-collected tax to return. It's idempotent via refund_idempotency_key. A full refund (refund_amount ≥ total_with_tax) flips status to refund; a partial refund preserves the prior status.
| Field | Type | Description |
|---|---|---|
| refund_amountrequired | decimal | In booking currency, > 0 and ≤ total_with_tax. |
| refund_currencyrequired | string | ISO 4217. Must match the booking currency. |
| refund_reasonrequired | string | guest_cancel | courtesy | no_show | duplicate_charge | downgrade | other. |
| refund_idempotency_key | string | Re-POSTing with the same key returns the prior tax delta (≤ 200 chars). |
curl -X POST https://api.taxlens.getdynamiq.ai/v1/bookings/4821/refund \
-H "X-API-Key: $TAXLENS_KEY" \
-H "Content-Type: application/json" \
-d '{
"refund_amount": 100.00,
"refund_currency": "USD",
"refund_reason": "guest_cancel",
"refund_idempotency_key": "refund-4821-v1"
}'adjust, void, refund, and invoice-details all return 409. Corrections then go through a credit note. See E-invoicing API and Numbering & immutability.Next
Turn a send-ready booking into a fiscal document in E-invoicing API, and see how the dashboard surfaces the same lifecycle in Bookings.