Skip to main content

Capturing events from your org

The ledger fills from your Salesforce org through one of two ingestion modes, configured per tenant. Both feed the same event store; the difference is what lives in your org and how quickly changes appear.

Real-time capture (outbox mode)

A small trigger stack in your org classifies every financial save as it happens and writes one row per event to an outbox object (LedgerEvent__c). The Edge service polls the outbox every 30 seconds on a watermark and ingests new rows.

  • Captures inserts and mutations — including cancellations, which produce C-indicator events at the moment they happen.
  • The outbox is a queue, not a history: rows can be purged after ingestion. The ledger holds the history.
  • Classification runs in the trigger using the same mapping documented in your txh/event-definitions.yaml, so what the org publishes and what the ledger expects stay in lockstep.
  • Each outbox row carries the human references (booking number, trip title, record label), the row-level currency, and a source-context payload.

The trigger stack is deliberately thin: classify, write outbox row, done. It never blocks the user's save — a publisher failure is logged, not thrown. A companion pattern stamps a Last Financial Change datetime field on the booking on every financial save, giving your org an indexed, SOQL-queryable answer to "what changed in the last N hours" without touching the API.

Read-only sync (transaction_sync mode)

For tenants that have not deployed (or cannot yet deploy) the trigger stack, the Edge service polls the source records themselves — payments and items — on a created-date watermark and classifies them on ingestion.

  • Requires no metadata in your org — read-only API access only.
  • Captures inserts only: a record mutated after capture is not re-read, so cancellations modelled as record updates are out of scope until the outbox phase.
  • Typically used during evaluation and migration; tenants graduate to outbox mode for real-time, mutation-aware capture. The switch is a one-line configuration change on the Edge side — no redeploy.

Historical backfill

Either mode starts capturing from "now". History is loaded explicitly through a windowed, idempotent backfill that scans the org's existing records, classifies them with the same maps, and dedupes against anything already captured — safe to re-run, safe to overlap with live capture. Backfills are operated by Kaptio and always dry-run first, reporting per-code counts for sign-off before any write.

Classification is configuration

The payment-method and item-type maps live in your tenant configuration (txh/event-definitions.yaml), reviewed like any other config change:

payment_method_map:
Card: { positive: { tr_code: CCR, event_type: CC_PAYMENT_RECEIVED },
negative: { tr_code: REC, event_type: CC_REFUND_ISSUED } }
Bank Transfer: { positive: { tr_code: CSH, event_type: CASH_PAYMENT_RECEIVED },
negative: { tr_code: REF, event_type: CASH_REFUND_ISSUED } }

item_record_type_map:
Package_Item: { tr_code: CST, event_type_add: TOUR_COST_ADDED,
event_type_cancel: TOUR_COST_OFFSET }
Excursion: { tr_code: OPT, event_type_add: OPTION_ADDED,
event_type_cancel: OPTION_REMOVED }

A method missing from the map does not lose data — it produces an UNK suspense event, and extending the map plus replaying the GL rules brings the history into line.