Events and comments

The append-only order audit trail, operator notes with a visibility flag, and the customer rollup report that hands order facts to the customers app.

An order's history is not derived from its columns. Every action route writes a row, and that row is also the domain event a workflow reacts to — so what a workflow saw and what an operator reads cannot diverge.

The trail

Request
curl "https://api.revenexx.com/v1/orders/{id}/events?limit=50" \
  -H "X-Revenexx-Tenant: <TENANT_SLUG>" \
  -H "X-Revenexx-Api-Key: rvxk_..."

Everything that has ever happened to this order, oldest first, each with the payload the action carried:

text
order.placed              order.requested            order.updated
order.acknowledged        order.shipment.created     order.held
order.payment_status.changed                         order.returned
order.completed           order.cancelled            order.comment.added

This is the trail an operator reads to answer "why is this order in this state".

Detail
Append-onlyRows are written by the action routes. There is no way to add, edit or remove one, and this route is read-only.
PaginatedAn order's trail grows for as long as the order lives. page.hasMore says whether more exists.
FiltersEvery query parameter is an exact match on the column it names.
order_idNot a filter. The route fixes it from the path, so a value sent for it is overwritten rather than honoured.
payloadThe jsonb column is not filterable — the data plane answers 400 for anything that is not a whole JSON document.
Deprecated key. The response repeats the array under events as well as items, for compatibility with the pre-envelope shape. Read items. The alias is removed in the next minor version.

Each row carries name, payload, actor and created_at. actor is free text as the calling client supplied it, and null for a row the app wrote itself.

Comments

Notes are for what the state machine cannot record: what the customer said on the phone, why an exception was made, what the warehouse found in the box.

Request
curl -X POST "https://api.revenexx.com/v1/orders/{id}/comments" \
  -H "X-Revenexx-Tenant: <TENANT_SLUG>" \
  -H "X-Revenexx-Api-Key: rvxk_..." \
  -H "Content-Type: application/json" \
  -d '{
        "body": "Customer asked for delivery after 15 August.",
        "visibility": "internal",
        "author": "desk@merchant.example"
      }'

visibility is internal (for the service desk) or customer (text meant to be shown to the buyer). It defaults to the tenant's default_comment_visibility, which is internal out of the box, so a note is never accidentally customer-facing.

Adding one writes an order.comment.added event, so the trail shows that a note was made and its visibility without copying the text onto the event feed.

It changes nothing about the order, and it sends nothing to anybody: this stores a comment, it does not email the customer.

Request
curl "https://api.revenexx.com/v1/orders/{id}/comments" \
  -H "X-Revenexx-Tenant: <TENANT_SLUG>" \
  -H "X-Revenexx-Api-Key: rvxk_..."

The customer rollup

Request
curl -X POST https://api.revenexx.com/v1/orders/reports/customer-rollup \
  -H "X-Revenexx-Tenant: <TENANT_SLUG>" \
  -H "X-Revenexx-Api-Key: rvxk_..." \
  -H "Content-Type: application/json" \
  -d '{"organization_ids":["…","…"]}'

What each company has bought, as numbers another app can keep: order count, lifetime revenue, first and last order date, and the same count and revenue over the last 30, 90 and 365 days.

This is the hand-over that makes a segment like "bought for more than 100k last year" possible: revenue lives in the orders app, customer segments live in the customers app, and the two may not join across apps. The customers app materialises this answer into a local projection its segment rules query.

Three properties worth knowing:

  • It answers about organizations only. A private or guest order carries none and is counted in orders_without_organization rather than attributed to anybody.
  • It converts nothing. An organization that ordered in two currencies gets both listed and one summed number to read with care.
  • Every number is additive (count, sum, min, max), so partial answers merge. The average order value is deliberately not returned — it is revenue_total / order_count over the merged parts.

Windows are anchored at as_of, which is echoed back so a loop measures one consistent picture.

Where to go next

  • Orders — the actions that write the trail.
  • Returns — the four steps that also appear on it.
  • Segments — what the rollup feeds.
  • Events — the platform event surface these rows are published on.
Was this page helpful?