Skip to main content

Customer API

Your finance and data systems can read the ledger directly — no Salesforce session involved. The API is read-only JSON over HTTPS.

Base URL: https://txh.edge.production.kaptioapis.com/customer/v1/{tenantId}

Auth: a per-tenant API key issued by Kaptio, sent as the x-txh-key header. Keys are tenant-bound — a key can never read another tenant's ledger. Rate limit: 120 requests per minute.

EndpointReturns
GET /transactionsEvent list — paginated, filterable
GET /transactions/summaryNet amounts by TR code, segment, and currency
GET /trial-balanceDebit/credit totals per GL account and currency
GET /itineraries/changed?since=Bookings with financial activity since a timestamp

Events for one booking

itineraryId accepts either the booking number or the Salesforce id:

curl -H "x-txh-key: $KEY" \
"https://txh.edge.production.kaptioapis.com/customer/v1/meridian/transactions?itineraryId=2001471&limit=100"
{
"transactions": [
{
"id": "5f0c9a4e-2f6b-4d0e-9a1c-7d2f8c3b1e90",
"trCode": "CCR",
"trSegment": "PAYREC",
"trIndicator": "A",
"eventType": "CC_PAYMENT_RECEIVED",
"amount": "2000.00",
"currencyCode": "USD",
"itineraryId": "a2wDEM000000101YAA",
"itineraryName": "2001471",
"itineraryTitle": "Canadian Rockies by Rail",
"recordId": "a2vDEM000000104YAA",
"recordName": "PM-100241",
"occurredAt": "2026-08-18T14:20:00.000Z",
"source": "sync"
}
],
"total": 5,
"limit": 100,
"offset": 0
}

Other filters: from / to (ISO datetimes against occurredAt), trCode, trSegment, limit (max 1000), offset.

The change feed

"Which bookings had financial activity since 06:00?" — the polling pattern for downstream sync:

curl -H "x-txh-key: $KEY" \
"https://txh.edge.production.kaptioapis.com/customer/v1/meridian/itineraries/changed?since=2026-08-31T06:00:00Z"
{
"since": "2026-08-31T06:00:00.000Z",
"itineraries": [
{
"itineraryId": "a2wDEM000000101YAA",
"itineraryName": "2001471",
"itineraryTitle": "Canadian Rockies by Rail",
"eventCount": 5,
"lastEventAt": "2026-08-31T06:41:12.000Z",
"trCodes": ["CCR", "CST", "GPP", "OPT"]
}
]
}

The feed is keyed on the time Edge captured the event, not the source timestamp — so a Salesforce transaction that commits late is still picked up by a later poll. To poll robustly, overlap your windows rather than chaining exact request times: use the maximum lastEventAt from your previous response minus a few minutes as the next since. Treat each entry as an idempotent upsert keyed by itineraryId — a booking re-seen from window overlap carries the same lastEventAt and is a no-op, while the same booking with a newer lastEventAt is a genuine new change to consume. Never skip a booking just because you have processed its id before.

If your org runs the real-time capture stack, the same question is answerable inside Salesforce via the Last Financial Change datetime field — see Capturing events.

Summary and trial balance

curl -H "x-txh-key: $KEY" \
"https://txh.edge.production.kaptioapis.com/customer/v1/meridian/transactions/summary?from=2026-08-01T00:00:00Z"
{
"summary": [
{ "trCode": "CCR", "trSegment": "PAYREC", "currencyCode": "USD",
"netAmount": "21518.00", "addCount": 5, "cancelCount": 0 },
{ "trCode": "CST", "trSegment": "COST", "currencyCode": "USD",
"netAmount": "23440.00", "addCount": 4, "cancelCount": 0 }
]
}
curl -H "x-txh-key: $KEY" \
"https://txh.edge.production.kaptioapis.com/customer/v1/meridian/trial-balance"
{
"trialBalance": [
{ "glAccountCode": "1010", "glAccountName": "Card Clearing",
"currencyCode": "USD", "totalDebit": "21518.00",
"totalCredit": "830.00", "entryCount": 6 }
]
}

Contract notes

  • Responses always carry both the technical identity (itineraryId, recordId) and the human reference (itineraryName = booking number, itineraryTitle, recordName). Fields are additive over time; integrations keyed on ids are stable.
  • itineraryName is null when a booking has no booking number — it never falls back to the trip title.
  • Amounts are strings with two decimals, signed; currency is per row (ISO 4217).
  • Errors are structured: { "error": "machine_code", "message": "human readable" } with conventional HTTP statuses (401, 429 with Retry-After, 400 with field details).