Changelog
Every change to the API, newest first. The newest version number here is the version in the OpenAPI document.
Versions
The current version is 1.13.0. It is the info.version of the OpenAPI document and the version that GET /health returns.
1.13.0
- `GET /empties-movements` `type` adds `received_from_supplier` and `returned_to_supplier` (a supplier's empties: no customer or trip) and `bought_back` (empties an outlet had paid for and handed back; not part of what it owes).
1.12.0
- `GET /trips/{id}/settlement` adds `cashExpenses`: crew lunch allowances and receipted purchases paid out of the trip cash (never fuel). `cashExpectedFromSales`, `cashExpected` and `variance` already net it.
1.11.0
- DMS documents: `route_settlement` (cash handed in, credit, closing van stock, the day's documents) closes the salesman's day, and `daily_totals` (count and value per document type, optionally the documents) is the DMS's own account of the day. Both now have typed bodies.
- A salesman's DMS day is recorded as a read-only trip (`GET /trips`, `GET /trips/{id}/settlement`): the day's invoices, receipts, returns and van loads and unloads count in its settlement, and the route settlement closes it.
- `dms.reconciliation.completed` carries the daily reconciliation per salesman: per-type totals and every difference (a document the DMS lists that never arrived, one that did not post, cash, credit and stock differences, a day with no route settlement).
1.10.0
- `TruncatedRecord.summary` strings are cut at 1 KB and end with `…`; the new optional `summaryTruncated: true` says a string was cut or a header field left out, so the record always fits one delivery.
1.9.0
- Resource webhooks: customer.created/updated, product.created/updated, order.created/status_changed, invoice.created/updated/voided, credit_note.created, payment.created/reversed, stock.movement.created (one per inventory document), trip.closed and settlement.closed. Each event's `data.object` is the resource's GET representation without `customers:pii` fields, read when the event is sent (usually within seconds of the change), and carries `updatedAt`; delivery order is not guaranteed.
- The OpenAPI document's `webhooks` section lists each event with its envelope and object schema. A record deleted by the time its event is sent arrives as a `DeletedRecord` tombstone; one too large to send whole (over 256 KB, or too many reads to build) arrives as a `TruncatedRecord` with its header fields and the GET endpoint to fetch it; a stock document keeps the movements that fit and sets `movementsTruncated`.
1.8.0
- Sales writes: POST /invoices creates and posts an invoice through the Go van-sale core; with a van as `locationId` it is a van sale that needs the salesperson's in-transit trip with that van (422 no_open_trip). POST /invoices/{id}/void voids one.
- POST /credit-notes issues and posts a credit note; POST /credit-notes/{id}/cancel voids it. POST /returns records and processes a customer return against its invoice (credit note at the invoice's price, goods back in stock, empties collected).
- Stock writes: POST /stock-adjustments and POST /stock-transfers, posted at once through Mikono's stock cores.
- Invoices follow Go's credit rule (422 credit_limit_exceeded) and a van sale needs the Field sales modules (422 field_sales_disabled). Credits against a trip's invoice count in its settlement; a return's credit note posts to QuickBooks as Go's stop return does.
- New error codes: no_open_trip, insufficient_stock, credit_limit_exceeded, field_sales_disabled, currency_not_supported; these writes also raise period_closed and invoice_not_found (1.7.0). Credit notes and returns accept base-currency invoices only; a stock removal never takes a caller unitCost.
1.7.0
- Writes: POST /customers and PATCH /customers/{id} (TIN, GPS and contacts need customers:pii), POST /orders and POST /orders/{id}/cancel, POST /payments and POST /payments/{id}/reverse. Each runs the core the Mikono app runs and writes an audit row with source Integration.
- POST /orders takes the customer and products by id or DMS code, `case`/`bottle`/`piece` units, and defaults prices from the customer's price group. POST /payments records one receipt per allocation, as Mikono Go does, each queued for QuickBooks; it returns `{ payments: [...] }`.
- New error codes: invoice_not_found, over_allocation, unallocated_amount, currency_mismatch and period_closed.
- PUT /customers/by-code/{system}/{code} now refuses taxId, location.gps and contact without customers:pii (403 insufficient_scope), the rule POST and PATCH follow.
1.6.0
- Every operation in this document now has a response example, and every request body an example, drawn from the sandbox organisation Kampala Beverage Distributors (Demo).
- The Errors page lists every code the API can return; each problem `type` links to its row.
- Sandbox request logs now also redact `contact`, `photoUrls` and `photoUrl`, so no field that needs `customers:pii` is stored.
1.5.0
- Sales documents (read): GET /orders, /invoices, /returns, /credit-notes and /payments, each by id; orders, invoices, credit notes and payments also by external code. `updatedSince` change feeds on every list.
- Invoices carry lines (`selling`, `free_issue`, `empties`), `balanceDue`, EFRIS `fiscal` (FDN) and QuickBooks `posting`; credit notes carry `remainingAmount` and `applications`; payments carry `allocations` and `cheque`.
- Each document has `linesTruncated` (more than 500 lines); list pages stop early within a read budget and resume from `nextCursor`. A payment's allocations are in their invoice's currency and `unallocated` in the payment's.
- Every change feed (`updatedSince`, and `since` on stock movements and trip locations) orders records by `updatedAt` and pages by a keyset cursor that only moves forward. A write can become visible a few seconds after its `updatedAt`, so a record changed during your read can appear after you have paged past its time: to never miss a change, start each poll from your last checkpoint minus an overlap of 5 minutes and skip records whose id and updatedAt you have already processed. Records can therefore repeat. For real-time changes, subscribe to webhooks. A feed cursor issued before this version is refused with 400 invalid_field; restart from the first page. On GET /returns, externalCode cannot be combined with updatedSince (400 invalid_field).
1.4.0
- POST /dms/{system}/files: send a DMS file as application/xml or multipart/form-data (one file, at most 5 MB, Idempotency-Key required). Files are deduplicated by SHA-256 and read in the background; 413 payload_too_large and 415 unsupported_media_type are new error codes.
- GET /dms/{system}/files/{batchId}/flags: the file's flags as an XML flag file.
1.3.0
- Stock (read-only): GET /stock-levels (a snapshot, no updatedSince), GET /stock-movements with `since` as the stock change feed (unitCost only with payments:read) and GET /empties-movements.
- Trips and settlements (read-only): GET /trips, GET /trips/{id} with crew, stop counts, Goods Issued Notes and returns, GET /trips/{id}/settlement and GET /settlements (at most 5 full sheets per page), whose figures are the depot settlement screen's; 403 module_disabled when the Delivery module is off. A filter id from another organisation is 404 not_found.
- Field activity (read-only): GET /visits (planned, visited and missed), GET /outlet-activities, GET /competitor-observations and GET /trips/{id}/locations. Photos and GPS need customers:pii.
1.2.0
- Master data: customers, products, prices, routes, journey plans, salespeople and locations, with GET by id and by external code, `updatedSince` change feeds and `PUT …/by-code/{system}/{code}` upserts.
- PUT /prices upserts prices by product code, price group and unit; PUT /journey-plans replaces a route's plan in the DMS shape; PUT /routes/{id}/outlets replaces a route's outlets.
1.1.0
- POST /dms/{system}/documents: send up to 500 canonical DMS documents (50 in sync mode) and get a Received or Rejected flag per document.
- GET /dms/{system}/flags: read update flags (received, posted, rejected, superseded) with reason codes R01 to R09, oldest change first.
- The dms.document.flagged webhook carries the same Flag on every change; connections can also have flags called back to their own URL.
1.0.0
- First version: GET /health, GET /me and GET /openapi.json.
- Per-key rate limits (RateLimit-* headers, 429 rate_limited) and Idempotency-Key on creates; GET /me returns the key's rate limits.
How versions change
- Every path is under
/api/v1. - New fields, new endpoints and new event types are added within v1 and raise the minor version, for example from 1.0.0 to 1.1.0. Your client must ignore response fields it does not know.
- A change that would break a working client goes into
/api/v2. v1 stays up for at least 12 months after v2 is released.