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.
| Endpoint | Returns |
|---|---|
GET /transactions | Event list — paginated, filterable |
GET /transactions/summary | Net amounts by TR code, segment, and currency |
GET /trial-balance | Debit/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. itineraryNameis 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,429withRetry-After,400with field details).