Skip to main content

Ledgers

A ledger is one leg of a transaction — a single asset moving in, out, or paid as a fee. This endpoint queries them directly, across transactions, which is what you want for balance reconciliation and accounting exports.

Base URL: https://api-v2.kryptos.io · Required Permission: transactions:read

EndpointReturns
GET/v1/ledgersFiltered, paginated list
GET/v1/ledgers/{id}One ledger entry

To read the legs of one known transaction, GET /v1/transactions/{id}/ledgers is cheaper.

Like transactions, this domain returns { data, meta } with no success field, and nests errors as { error: { code, message } }.

Request

curl -X GET "https://api-v2.kryptos.io/v1/ledgers?types=outgoing&limit=100" \
-H "Authorization: Bearer ACCESS_TOKEN"

Query Parameters

Comma-separated lists:

ParameterDescription
transactionIdsRestrict to specific transactions
assetIdsKryptos asset ids
typesincoming, outgoing, fee
providersProvider ids, e.g. binance

Filters and paging:

ParameterTypeDefaultDescription
hasMissingPricebooleanLegs with no resolved price
hasMissingAssetbooleanLegs whose asset is unresolved
startTime, endTimenumberUnix milliseconds
ltAfterBalancestringRunning balance strictly less than this
gtAfterBalancestringRunning balance strictly greater than this
sortBystringtimestamptimestamp or createdAt
sortOrderstringdescasc or desc
limitinteger501–200
offsetinteger0Rows to skip

ltAfterBalance and gtAfterBalance are decimal strings, not numbers"0", "-0.000001", "1e3". They are deliberately not coerced to floats so that 18-decimal balances compare exactly. Rows with no running balance are excluded from either filter.

ltAfterBalance=0 is the canonical way to find negative running balances — the signature of missing purchase history.

Response

{
"data": [
{
"id": "led_31c9",
"transactionId": "8f14e45f-ceea-467a-9a3b-1c2f0d7e5a91",
"workspaceId": "ws_12ab",
"type": "outgoing",
"assetId": "a3f1c8e0-9d42-4b17-8c55-6e0b2f7a1d34",
"assetRaw": { "symbol": "USDC" },
"quantity": "3200.000000",
"baseCurrency": "USD",
"price": { "price": 1, "baseCurrency": "USD", "timestamp": 1721088000000, "source": "cmc" },
"value": 3200,
"timestamp": 1721088000000,
"walletId": "int_9f2c",
"syncId": "sync_7712",
"fromAccount": { "provider": "binance", "walletId": "int_9f2c" },
"toAccount": null,
"label": "Sell",
"description": null,
"internalLabel": null,
"isEdited": false,
"beforeBalance": "5000.000000",
"afterBalance": "1800.000000",
"costbasis": "3200.00",
"proceeds": "3200.00",
"profit": "0.00",
"asset": { "symbol": "USDC", "name": "USD Coin", "logoUrl": "https://...", "type": "stablecoin" }
}
],
"meta": { "total": 4821, "limit": 50, "offset": 0 }
}

meta here has no hasMore — unlike /v1/transactions. Page by comparing offset + data.length against meta.total.

Response Fields

FieldTypeDescription
idstringLedger id
transactionIdstringParent transaction
typestringincoming, outgoing or fee
assetIdstring | nullResolved asset; null while unresolved
assetRawobjectAsset as reported by the source
quantitystringDecimal string, up to 18 places
baseCurrencystringCurrency of price and value
priceobject | null{ price, baseCurrency, timestamp, source }
valuenumber | nullquantity × price, derived on read
timestampnumberUnix milliseconds
walletIdstringOwning connected account — the authoritative source for this leg
syncIdstring | nullSync run that produced it
fromAccount, toAccountobject | nullCounterparty accounts
label, description, internalLabelstringAnnotations
isEditedbooleanA user manually edited this leg
beforeBalance, afterBalancestring | nullRunning asset balance around this leg
costbasis, proceeds, profitstring | nullAccounting figures; null until tax processing has run
debitCoaCode, creditCoaCodestring | nullGL codes posted to — enterprise only
isDebitCoaEdited, isCreditCoaEditedbooleanThe code was set manually, so a COA re-run skips it — enterprise only

Every numeric column here is serialized as a decimal string, not a JSON number: quantity, beforeBalance, afterBalance, costbasis, proceeds and profit. That is deliberate — see the precision note on transactions. Only value is a number, because it is an already-rounded fiat amount. The accounting fields are null until the accounting pipeline has run for that period.

One ledger entry

GET /v1/ledgers/{id} returns { data } with a single entry, or 404 { "error": { "code": "NOT_FOUND", "message": "…" } }.

Errors

StatusCodeMeaning
404NOT_FOUNDNo such ledger in this workspace
500INTERNAL_ERRORUnexpected server error