TriportRPC

List balance ledger entries

GEThttps://api.triport.io/v1/balance/entries?limit=50

Returns a cursor-paginated, newest-first slice of your account's balance ledger (every credit and debit).

GET /v1/balance/entries reads your account's balance journal — the append-only ledger of every change to your balance. Each row records a single credit or debit, its source, and when it was applied. Use it to render an account-activity / billing-history view, to reconcile invoices against payments, or to audit adjustments and refunds.

Entries are returned newest-first and are cursor-paginated on the id of the last (oldest) entry in the current page. A balance entry is immutable once written, so a cursor walk is stable: re-fetching the same after_id always yields the same following rows.

All amounts are expressed in micro-USD (1 USD = 1_000_000 micro). A positive delta_micro is a credit to your balance; a negative value is a debit. The server is authoritative for these values — do not derive a running balance on the client by summing deltas; read the snapshot from GET /v1/balance or the balance event stream instead.

This endpoint requires an authenticated Console session (sent as a cookie). A brand-new account with no activity returns an empty entries array with HTTP 200, not a 404.

Parameters

All parameters are optional query-string values.

limitintegeroptional
Maximum number of entries to return in this page. If omitted or non-numeric, the server applies its own default page size.
after_idintegeroptional
Cursor: the id of the last entry you have already seen. Returns entries older than this id. Omit on the first request; on subsequent requests pass the previous response's next_cursor.

Response

Response fields

FieldTypeDescription
entriesarrayThe page of ledger entries, newest-first. Empty array when the account has no (further) activity.
entries[].idintegerMonotonic ledger entry id. Use the id of the last entry as the next page's after_id.
entries[].delta_microintegerSigned balance change in micro-USD. Positive = credit, negative = debit.
entries[].kindstringWhat produced the row: payment_credit, invoice_debit, refund, or adjust.
entries[].ref_invoice_idstring | nullThe invoice this entry relates to, if any (e.g. for invoice_debit). Absent/null otherwise.
entries[].ref_payment_idinteger | nullThe payment this entry relates to, if any (e.g. for payment_credit). Absent/null otherwise.
entries[].reasonstringHuman-readable note describing the entry. May be empty.
entries[].created_atintegerWhen the entry was written, in Unix seconds. Multiply by 1000 for a JavaScript Date.
next_cursorinteger | nullThe id of the last (oldest) entry in this page, to be passed as the next request's after_id. Absent/null only when entries is empty.

Errors

Errors use the shared envelope { "error": "<message>" } — see errors.md for the full contract.

CodeMeaningWhen it happens
401auth requiredNo valid Console session cookie was presented.
500internal: <detail>Unexpected server-side failure while reading the ledger.
503session resolver not configuredAuthentication is temporarily unavailable on this node; retry shortly.

Examples

JavaScript (fetch)

async function listBalanceEntries({ limit, afterId } = {}) {
  const q = new URLSearchParams();
  if (limit != null) q.set('limit', String(limit));
  if (afterId != null) q.set('after_id', String(afterId));
  const qs = q.toString();


  const res = await fetch(
    `https://api.triport.io/v1/balance/entries${qs ? `?${qs}` : ''}`,
    { credentials: 'include', headers: { 'Content-Type': 'application/json' } },
  );
  if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error ?? `HTTP ${res.status}`);
  return res.json(); // { entries, next_cursor }
}


// Walk the whole journal, newest-first.
async function* allEntries() {
  let afterId;
  for (;;) {
    const { entries, next_cursor } = await listBalanceEntries({ limit: 100, afterId });
    if (entries.length === 0) return;
    yield* entries;
    if (next_cursor == null) return;
    afterId = next_cursor;
  }
}

TypeScript SDK (@triport/sdk)

import { Triport } from '@triport/sdk';


const triport = new Triport({ session: process.env.TRIPORT_SESSION! });


const page = await triport.balance.listEntries({ limit: 50 });
for (const e of page.entries) {
  const sign = e.delta_micro >= 0 ? '+' : '-';
  console.log(`#${e.id} ${e.kind} ${sign}${Math.abs(e.delta_micro) / 1_000_000} USD`);
}


if (page.next_cursor != null) {
  const next = await triport.balance.listEntries({ limit: 50, after_id: page.next_cursor });
  // ...
}

Python (triport-sdk)

import os
from triport import Triport


triport = Triport(session=os.environ["TRIPORT_SESSION"])


after_id = None
while True:
    page = triport.balance.list_entries(limit=100, after_id=after_id)
    for e in page["entries"]:
        usd = e["delta_micro"] / 1_000_000
        print(f'#{e["id"]} {e["kind"]} {usd:+.6f} USD')
    if not page["entries"] or page.get("next_cursor") is None:
        break
    after_id = page["next_cursor"]

Notes

  • Pagination terminates on an empty page. next_cursor is the id of the last entry returned and is present on every non-empty page — including the final one. Don't treat "next_cursor is set" as "more data exists." Instead, keep passing after_id=next_cursor until a request returns entries: [] (at which point next_cursor is absent/null).
  • No kind filter. This endpoint does not filter by entry kind; filtering by payment_credit / invoice_debit / refund / adjust is done client-side.
  • Timestamps are Unix seconds, not milliseconds — multiply by 1000 before constructing a JS Date.
  • Related: GET /v1/balance for the current balance snapshot, and the balance event stream for live credit/debit pushes.