API reference

Rules

How transactions are filed: written rules first, then the model.

Guides: Automate filing with rules

List the categorization rules

GET/v1/rules

client.rules.list()

Every rule these books file by, newest first.

Parameters

NameTypeDescription
limitQueryinteger

Page size, 1–200.

Default 50
cursorQuerystring or null

The next_cursor of the previous page.

originQuerystring or null

Only rules a person wrote, only learned ones, or only those written from an answer.

One of manual, learned, answer
source_question_idQuerystring or null

An id that starts with qst_.

is_activeQueryboolean or null

Only rules that are on, or only paused ones.

counterparty_idQuerystring or null

An id that starts with party_.

category_account_idQuerystring or null

An id that starts with gla_.

Response

200RulePage

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl "https://api.ledgerit.ai/v1/rules" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN"

Write a categorization rule

POST/v1/rules· Idempotent

client.rules.create()

Write a rule. The category is validated now, not when it first fires.

A rule matching exactly what another already matches is refused with rule_conflict; edit that one instead.

Request body

NewRule

Response

201RuleOut

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl -X POST "https://api.ledgerit.ai/v1/rules" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"category_account_id":"…","name":"…","pattern":"…"}'

Get how often people agreed with the model

GET/v1/rules/model_quality

client.rules.modelQuality()

Of the model's proposals a person has since filed themselves, how many they filed where the model said. Null until one has been judged.

Response

200ModelQualityOut

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl "https://api.ledgerit.ai/v1/rules/model_quality" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN"

See what a rule would match before saving it

GET/v1/rules/preview

client.rules.preview()

What a rule with these terms would match, before it is saved.

Looks through the newest transactions with the same matching the feed uses and answers with how many match and the newest of them. Nothing is written and nothing is filed: a saved rule files what arrives after it, and what is already filed stays where it is. Terms that could never match are refused as saving them would be (rule_invalid).

Parameters

NameTypeDescription
patternQuery · Requiredstring

What the rule would look for.

match_onQuerystring

Which text it is compared to.

One of description, source_description, counterpartyDefault description
match_typeQuerystring

How it is compared.

One of contains, equals, starts_withDefault contains
account_idQuerystring or null

An id that starts with gla_.

event_typeQuerystring or null

Only transactions of this event type.

One of expense, income, transfer, fee, interest, refund, sales_refund
amount_minQuerynumber | string or null

Only transactions at least this size.

amount_maxQuerynumber | string or null

Only transactions at most this size.

memo_patternQuerystring or null

Only transactions whose memo — the description the ledger shows, or the line the bank printed — holds these words. Compared as pattern is: case-insensitively, processor noise removed. Null when the rule does not look at the memo.

document_kindQuerystring or null

Only transactions with this paper behind them: an invoice or a receipt linked as evidence, or none for one with no paper at all. Null when the rule does not care.

One of invoice, receipt, none

Response

200RulePreviewOut

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl "https://api.ledgerit.ai/v1/rules/preview" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN"

File undecided transactions by rule, then by model

POST/v1/rules/run

client.rules.run()

Decide what every undecided transaction is for: rules, then a model.

Categorizes; does not post. Posting stays a separate decision, so a run that produces something surprising can be looked at first.

A run that may call the model counts against the entity's model budget (MODEL_RUNS); a rules-only run spends nothing and is not counted.

Request body

CategorizeRequest

Response

200CategorizeResponse

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl -X POST "https://api.ledgerit.ai/v1/rules/run" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'

Get a rule

GET/v1/rules/{rule_id}

client.rules.get()

One rule, with how often it has fired.

Parameters

NameTypeDescription
rule_idPath · Requiredstring

An id that starts with rule_.

Response

200RuleOut

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl "https://api.ledgerit.ai/v1/rules/{rule_id}" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN"

Change or pause a rule

PATCH/v1/rules/{rule_id}· Idempotent

client.rules.update()

Change a rule, or pause it with is_active: false.

Held to the same checks as writing one. Transactions it already filed stay as they are: they are in the books, and changing a rule is not a reason to restate them.

Parameters

NameTypeDescription
rule_idPath · Requiredstring

An id that starts with rule_.

Request body

RuleChanges

Response

200RuleOut

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl -X PATCH "https://api.ledgerit.ai/v1/rules/{rule_id}" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'

Delete a rule

DELETE/v1/rules/{rule_id}

client.rules.delete()

Remove a rule. Transactions it already filed are untouched — they are in the books, and changing a rule is not a reason to restate them. Pausing it (is_active: false) keeps it on the record instead.

Parameters

NameTypeDescription
rule_idPath · Requiredstring

An id that starts with rule_.

Response

204No content

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl -X DELETE "https://api.ledgerit.ai/v1/rules/{rule_id}" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN"

Count what a rule filed that names no department yet

GET/v1/rules/{rule_id}/unnamed

client.rules.unnamed()

How many transactions a rule already filed do not name its department, or any other dimension value it names.

A rule that names a department, or learns one, gives it to what it files from then on; what it filed before stays unnamed until it is given the values. A transaction naming another value of the dimension is not counted: a person chose it.

Parameters

NameTypeDescription
rule_idPath · Requiredstring

An id that starts with rule_.

Response

200RuleUnnamedOut

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl "https://api.ledgerit.ai/v1/rules/{rule_id}/unnamed" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN"

Give what a rule already filed its department

POST/v1/rules/{rule_id}/unnamed/name· Idempotent

client.rules.nameUnnamed()

Give the transactions a rule already filed the department, and any other dimension value, it names.

Each takes the rule's value for every dimension it does not name yet, as filing it today would; a value a person chose stands. One already in the books is reversed and posted again with them, so the change is on the record and spend by department counts it. Ones in a locked month, and ones spread over months, are left as they are. A batch a request, oldest first; unnamed.to_name says how many are still to name.

Parameters

NameTypeDescription
rule_idPath · Requiredstring

An id that starts with rule_.

Response

200RuleNamedOut

Errors

400
The request was malformed or a parameter is invalid.
401
No valid credential was sent.
403
The credential or the member's role does not allow this.
404
No such resource in this ledger.
409
A conflicting request, e.g. one with the same Idempotency-Key still running.
422
A well-formed request a business rule refused.
429
Too many requests; retry after the Retry-After header.
500
Something failed on our side; the request_id identifies it.

Example

curl
curl -X POST "https://api.ledgerit.ai/v1/rules/{rule_id}/unnamed/name" \
  -H "Authorization: Bearer $LEDGERIT_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)"

Objects

The objects these operations take and return.

RulePage

NameTypeDescription
dataRequiredarray of RuleOut
has_moreRequiredboolean
next_cursorRequiredstring or null

NewRule

NameTypeDescription
account_idstring or null

An id that starts with gla_.

amount_maxnumber | string or null
amount_minnumber | string or null
category_account_idRequiredstring

An id that starts with gla_.

dimensionsarray of LineDimensionIn

The department, and the value of any other dimension, a matching transaction is to name, at most one per dimension. Refused with dimension_invalid when a value is not of the dimension named.

document_kindstring or null

Only transactions with this paper behind them: an invoice or a receipt linked as evidence, or none for one with no paper at all. Null when the rule does not care.

One of invoice, receipt, none
event_typestring or nullOne of expense, income, transfer, fee, interest, refund, sales_refund
match_onstringOne of description, source_description, counterpartyDefault description
match_typestringOne of contains, equals, starts_withDefault contains
memo_patternstring or null

Only transactions whose memo — the description the ledger shows, or the line the bank printed — holds these words. Compared as pattern is: case-insensitively, processor noise removed. Null when the rule does not look at the memo.

nameRequiredstring
patternRequiredstring
priorityintegerDefault 0

RuleOut

NameTypeDescription
account_idRequiredstring or null

An id that starts with gla_.

amount_maxRequiredstring or null
amount_minRequiredstring or null
category_account_idRequiredstring

An id that starts with gla_.

category_codeRequiredstring
category_nameRequiredstring
counterparty_idstring or null

An id that starts with party_.

created_atRequiredstring (date-time)
dimensionsarray of LineDimensionOut

The department, and the value of any other dimension, a matching transaction names: each one it does not already name, so its lines to category_account_id carry it. A learned rule takes them once three of its merchant's transactions name the same values. Empty when the rule names none.

document_kindstring or null

Only transactions with this paper behind them: an invoice or a receipt linked as evidence, or none for one with no paper at all. Null when the rule does not care.

One of invoice, receipt, none
event_typeRequiredstring or nullOne of expense, income, transfer, fee, interest, refund, sales_refund
idRequiredstring

An id that starts with rule_.

is_activeRequiredboolean
last_applied_atRequiredstring (date-time) or null
match_onRequiredstringOne of description, source_description, counterparty
match_typeRequiredstringOne of contains, equals, starts_with
memo_patternstring or null

Only transactions whose memo — the description the ledger shows, or the line the bank printed — holds these words. Compared as pattern is: case-insensitively, processor noise removed. Null when the rule does not look at the memo.

nameRequiredstring
originRequiredstring

manual: a person wrote it. learned: the product wrote it from three consistent human decisions about one merchant. answer: written from a person's answer to a question, when they asked for it to be done every time.

One of manual, learned, answer
patternRequiredstring
priorityRequiredinteger
source_question_idstring or null

An id that starts with qst_.

source_transaction_idstring or null

An id that starts with txn_.

times_appliedRequiredinteger

ModelQualityOut

How often a person agreed with the model, out of how many they judged.

Reported rather than assumed. A product that files transactions with a model and cannot say how often it is right is asking to be trusted rather than earning it.

NameTypeDescription
agreedRequiredinteger
agreement_rateRequirednumber or null
judgedRequiredinteger

RulePreviewOut

NameTypeDescription
matchedRequiredinteger

How many of the transactions looked at the terms match.

sampleRequiredarray of RulePreviewMatch

The newest matches.

scannedRequiredinteger

How many transactions were looked at, newest first.

truncatedRequiredboolean

True when the books hold more transactions than were looked at.

CategorizeRequest

NameTypeDescription
event_idsarray of string or null
use_modelbooleanDefault true

CategorizeResponse

NameTypeDescription
by_modelRequiredinteger
by_ruleRequiredinteger
consideredRequiredinteger
errorsRequiredarray of string
model_needs_reviewRequiredinteger
model_unavailableRequiredboolean
to_suspenseRequiredinteger

RuleChanges

Only the fields sent change. The narrowing fields (account_id, event_type, amount_min, amount_max) are cleared by sending null; the rest cannot be: they are typed without null, and default to None only so that leaving one out means "unchanged" (hence the ignores).

NameTypeDescription
account_idstring or null

An id that starts with gla_.

amount_maxnumber | string or null
amount_minnumber | string or null
category_account_idstring

An id that starts with gla_.

dimensionsarray of LineDimensionIn

Every value a matching transaction is to name; the ones left out are taken off, and an empty list clears them. Transactions it already filed keep theirs; POST /rules/{rule_id}/unnamed/name gives them the rule's values.

document_kindstring or null

Only transactions with this paper behind them: an invoice or a receipt linked as evidence, or none for one with no paper at all. Null when the rule does not care.

One of invoice, receipt, none
event_typestring or nullOne of expense, income, transfer, fee, interest, refund, sales_refund
is_activeboolean
match_onstringOne of description, source_description, counterparty
match_typestringOne of contains, equals, starts_with
memo_patternstring or null

Only transactions whose memo — the description the ledger shows, or the line the bank printed — holds these words. Compared as pattern is: case-insensitively, processor noise removed. Null when the rule does not look at the memo.

namestring
patternstring
priorityinteger

RuleUnnamedOut

NameTypeDescription
lockedRequiredinteger

Ones in the books in a locked month: left as they are, since naming them would change a closed month. Reopen the month to include them.

locked_monthsRequiredarray of string (date)

The first day of each month those are in, oldest first.

spreadRequiredinteger

Ones spread over months by a schedule, which takes each month's share out with the values the transaction names: left as they are.

to_nameRequiredinteger

Transactions the rule filed, whose filing still stands, that do not name a dimension the rule names and can be given its values now (POST /rules/{rule_id}/unnamed/name). Zero when the rule names no dimension values.

RuleNamedOut

NameTypeDescription
namedRequiredinteger

Transactions given the rule's values by this request.

refusedRequiredinteger

Transactions left as they were because posting them again was refused: an account each is filed to now requires a value neither it nor the rule names.

unnamedRequiredRuleUnnamedOut

What is still unnamed afterwards. to_name is above zero when there were more than 200 to name: send the request again.

LineDimensionIn

NameTypeDescription
dimension_idRequiredstring

An id that starts with dim_.

value_idRequiredstring

A value of that dimension.

LineDimensionOut

NameTypeDescription
dimension_idRequiredstring

An id that starts with dim_.

dimension_keyRequiredstring

The dimension's key, e.g. department.

dimension_nameRequiredstring
value_codeRequiredstring
value_idRequiredstring

An id that starts with dimv_.

value_nameRequiredstring

RulePreviewMatch

NameTypeDescription
amountRequiredstring
category_account_idRequiredstring or null

An id that starts with gla_.

category_namestring or null
currencyRequiredstring
descriptionRequiredstring
event_dateRequiredstring (date)
event_typeRequiredstring
idRequiredstring

An id that starts with txn_.

statusRequiredstring