Changelog
2026-07-13 — place ids, manual FX rates, per-diem overrides, exchange-rate direction
Additive, backward-compatible contract fields plus a new exchange-rate discriminator.
- Place ids on travel entries. Create and update requests accept
departureLocationPlaceIdanddestinationPlaceId(Google Placesplace_id), and the travel-entry response returns them. Echo the stored values back on a full-replace update to preserve place identity when you edit destination text. - Destination country on travel entries. Requests accept an optional
destinationCountryCode(ISO 3166-1 alpha-2). When supplied it is stored directly and the server-side geocoding fallback is skipped. - Manual exchange rates. Expense and per-diem requests accept an optional
manualExchangeRate, and travel-entry requests acceptmanualAdvanceExchangeRatefor the advance. Each is honored only when the FX provider publishes no rate for the referential date; supplying one while an official rate exists is rejected withEXCHANGE_RATE_UNAVAILABLE. - Per-diem overrides. The per-diem request accepts
overrideAmountandoverrideReason, and the per-diem read models return them. To preserve an existing override on a full-replace update, echo the values back; omitting them clears the override and reverts to the statutory payout. - Exchange-rate direction.
GET /api/v1/reference/exchange-ratesnow carries adirectiondiscriminator:ForeignPerBase(HNB / ECB) means divide the rate to convert to the base currency,BasePerForeign(CNB) means multiply.
2026-07-08 — advance-payment date, CZ/SK exchange-rate provider
Two additive, backward-compatible changes.
- Advance-payment date on travel entries. Create and update requests now
accept an optional
advancePaymentDate(yyyy-MM-dd), and the travel-entry response returns it. When omitted on create the server defaults it to the entry date. It sets the FX date for the advance and, for Czech tenants, the per-diem FX referential date. - Exchange-rate provider for CZ/SK.
GET /api/v1/reference/exchange-ratesnow documents the full provider set: HNB for HR, ECB for SI and SK, CNB for CZ. Thesourcefield can be"CNB", andbaseCurrencyis the provider’s native base (EUR for HNB/ECB, CZK for CNB). Behavior is unchanged; the docs now match runtime.
2026-06-11 — per-meal counts, FX provenance, exchange-rate-unavailable code
Three additive surface changes. All are backward compatible: existing payloads keep working unchanged, and the new response fields are additions you can ignore until you need them.
- Per-meal counts on per-diem create/update. Per-diem requests now accept
breakfastsProvided,lunchesProvided, anddinnersProvided(per-meal integer counts) plus an optional per-daymealsProvidedAllocation. They are the canonical write model: the server recomputes the reduction from these counts. The existing v1 aggregatemealsProvidedis still accepted; when the per-meal fields are absent the server maps the aggregate as before, so legacy clients are unaffected. Responses keep returning the derivedmealsProvided(lunch + dinner, the HR Pravilnik shape) alongside the per-meal counts, so read paths are unchanged. - FX provenance on responses. Expense and per-diem responses gain
exchangeRateSource, and the travel-entry response gainsadvancePaymentExchangeRateSource, recording where the applied rate came from: a provider code ("HNB","ECB") for an official rate,"MANUAL"for a user-supplied rate, ornullfor a same-currency row (no conversion) or a legacy row saved before provenance tracking. Read-only; no request change. - New error code
EXCHANGE_RATE_UNAVAILABLE(HTTP 400). Fires when the tenant’s FX provider publishes no rate for a currency on the requested date and no historical rate exists to fall back on. It is a validation-family failure with the standard field-keyederrorsbody, so you can discriminate the FX-unavailable case specifically and prompt for a manual rate. Added to the errors catalog.
2026-05-23 — per-diem itinerary times stored as true UTC (fix)
Per-diem times persisted via
POST /api/v1/travel-entries/{id}/per-diems/from-itinerary are now stored as
true UTC instants. Previously each leg’s departure/arrival was written using its
wall-clock value tagged as UTC without shifting (an 08:00 local leg was stored
as 08:00Z instead of 07:00Z/06:00Z), so itinerary-generated rows disagreed
with manually-added rows by 1–2 hours and displayed late. The request and
response schemas are unchanged, but the departureTime/arrivalTime values
this endpoint returns (and that later reads of the same rows return) now reflect
the corrected UTC instant. The stateless calculator preview still echoes
wall-clock times. Per-diem amounts are unaffected.
2026-05-23 — per-diem calculator + whole-trip persist
The per-diem calculation surface is consolidated and gains whole-trip persist parity with the locco web app.
- New
POST /api/v1/utilities/per-diems/calculate— a stateless calculator. Send an itinerary (one leg = a 2-stop itinerary) and get the computed rows back, with itinerary-level redistribution applied. No entry context, nothing persisted. - New
POST /api/v1/travel-entries/{id}/per-diems/from-itinerary— rebuild a travel entry’s per-diems from an itinerary in one call. The server re-runs its own engine over the stops (submitted amounts are never trusted), applies per-leg meals keyed by(countryCode, departureTime)(the pairs the calculator returns), then atomically replaces the entry’s per-diems. This reproduces itinerary-level redistribution and domestic-unit upgrades that posting rows one at a time cannot. - Removed
POST /api/v1/travel-entries/{id}/per-diems/computeandPOST /api/v1/per-diems/calculate-simple. Both are subsumed byutilities/per-diems/calculate— a single leg is just a 2-stop itinerary. Move integrations to the new calculator.
2026-05-22 — Slovenian market support
Initial support for Slovenian tenants. Update your client from the refreshed
OpenAPI snapshot at /api-reference/:
- Slovenian municipalities — new
GET /api/v1/reference/slovenian-municipalitiesreturns the SURS municipality list for place dropdowns on Slovenian travel forms. Callable from any tenant. - Employee tax residency — employee records gain a
residencyfield (Resident/NonResident) for Slovenian per-diem and payroll-tax reporting. Defaults toResident.
2026-04-28 — v1.0 launching
The first stable release of the locco partner API. Every surface is wired,
typed, and covered by the OpenAPI snapshot at
/api-reference/:
- Travel entries — full CRUD plus the workflow transitions (submit, approve, reject, cancel, request-changes), with atomic creates that accept nested expenses, per-diems, cost-center allocations, and attachments in a single call.
- Attachments — direct upload to a travel entry via
POST /api/v1/travel-entries/{id}/attachments. Multipart, up to 5 files per request. - Webhooks — subscription registration with one-time signing-secret exposure, delivery history per subscription, and retry endpoint for failed or exhausted deliveries.
- Payouts — list ready-for-payout entries, create batches, list history, delete a batch.
- Employees, Departments, Vehicles, Cost centers — CRUD + list, with custom-field values on employees.
- Reference — Croatian municipalities, HNB exchange rates, per-diem rate table, the company’s enabled-country and enabled-currency allow-lists.
- Company — profile read.
Enum values for Status, TravelType, PayoutMethod, and the rest are
documented in the OpenAPI schema as enum: [...] allow-lists, so
generated clients pin against the canonical strings ("PendingApproval",
"BankTransfer", etc.) rather than opaque values.