Outstanding scheduled occurrences for one or more accounts
const url = 'https://api.tovarifinancial.com/bills/scheduled?includeMirrors=true';const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://api.tovarifinancial.com/bills/scheduled?includeMirrors=true' \ --header 'Authorization: Bearer <token>'Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”A single account id. MUTUALLY EXCLUSIVE with accountIds — exactly one of the two must be present; neither is a 400 and both is a 400. This path is unchanged in every particular, including its 404 when the account does not resolve and its deliberate lack of any is_active or account-type filter (a CLOSED account answers 200).
Comma-separated account UUIDs — the multi-account scope (KAN-2913). MUTUALLY EXCLUSIVE with accountId. At most 10 ids; an over-cap list is a 400 whose field error is DISTINCT from the malformed-id error, so a client can say “too many accounts selected”. workingBalanceCents is the SUM of the resolved accounts’ balances and the occurrences of all of them are merged into one list sorted by effective date, then income before outflow on the same date (KAN-3160), then bill id. A foreign or non-existent id is silently dropped — it contributes zero and is simply absent from the accountIds echo, with no error or status distinguishing the two, because doing so would be an existence oracle. A list that resolves to nothing is a 200 with accountIds: [] and no occurrences, NEVER a 404. No account-type filter is applied: the endpoint honours the ids it is given.
Calendar date, ‘YYYY-MM-DD’
Window start ‘YYYY-MM-DD’. Honoured ONLY on a purely-past window (a to earlier than today). On every forward-looking window it is ignored and the lower bound stays each bill’s own settle-through cursor, which is what keeps the OVERDUE backlog on screen.
Calendar date, ‘YYYY-MM-DD’
Window end ‘YYYY-MM-DD’. INERT on a forward-looking window — it is neither obeyed, nor extended on, nor validated there: whatever it says, the far edge stays the end of the current month unless forwardTo moves it. This is deliberate. to is the REGISTER’s ledger filter, an unbounded date input whose value two shipped presets resolve to TODAY and which means “ledger rows up to”; obeying it would delete the rest of the month from the caller’s Scheduled Bills section, extending on it would silently pull months of occurrences and a far-edge projection into that section, and refusing an out-of-range value would make the section disappear behind a 400. A value EARLIER than today is a purely-past window and keeps its existing [from, to] behaviour. Use forwardTo to widen the forward window; whatever is resolved is reported back in windowEndIso.
Calendar date, ‘YYYY-MM-DD’
The explicit forward bound ‘YYYY-MM-DD’ (opt-in; no shipped client sends it). EXTENSION-ONLY: the far edge is max(forwardTo, end of the current month), so it can push the window OUT but can never shorten it below end-of-month — narrowing this section would need its own param and its own review. Supplying it makes the request forward-looking even alongside a purely-past to. A value beyond the forward bound — end of the month MAX_FUTURE_MONTHS ahead, the same bound /reports/cash-flow uses — is a 400 on forwardTo naming the bound; so is a malformed date. Neither is ever clamped, and neither message echoes the value sent. Knock-ons of a far edge LATER than end-of-month, all documented and all deliberate: the top-level projectedBalanceCents becomes the balance at that far edge, totalDueCents grows, and the occurrence list grows with it (the statement count does not — this is one account). The overdue backlog is unaffected: windowStartIso stays null on every forward window.
Optional free-text term. It narrows the RETURNED occurrences (and totalDueCents) to bills whose name, memo, payee name, any occurrence note, or amount magnitude (only when the term contains a digit) matches — per BILL, so every occurrence of a matching bill is returned. The projected balance walk, the bank-match assignment, workingBalanceCents and projectedBalanceCents all run over the FULL outstanding set before the filter, so a searched request never changes the balance line. The term is never echoed or logged.
Opt-in (KAN-3398; sent by the web account register only). ‘1’ appends each active bill’s NEXT outstanding occurrence when it falls after windowEndIso — at most one row per bill, after every in-window row, in effective-date order (income before outflow, then bill id). It applies on every window, including a purely-past one. Those rows carry beyondWindow: true, are never bank-matched (pendingMatch/outOfBandMatch null, ambiguousMatches empty), step the projected balance by ZERO (their projectedBalanceCents is the last in-window running balance) and are EXCLUDED from totalDueCents; their outflow total ships separately as beyondWindowDueCents. Every other field keeps exactly its unflagged value. Absent, ‘’ or ‘0’ leaves it off and the body is unchanged (no beyondWindow, no beyondWindowDueCents). Any other value is a 400 VALIDATION_ERROR with fieldErrors.includeNextOutstanding = [‘includeNextOutstanding must be 1 or 0’], refused before a connection is opened and never echoing the value. It adds no database statement.
Opt-in (KAN-3670). ‘true’ also returns, on each scoped account a bill’s destination names (any account type since KAN-3683 — a card or loan it pays, a checking or savings account it transfers into), the READ-ONLY MIRROR of every outstanding occurrence of an active bill scheduled FROM an account outside the scope whose destination account is that account: accountId is the destination, amountCents and effectiveAmountCents are the source occurrence’s figures negated, direction is flipped, and mirrorOf names the bill and its source account. A mirror steps projectedBalanceCents by the money arriving (a card or loan toward zero, a savings or checking balance up; by zero when the source occurrence is skipped), is never bank-matched, and is excluded from totalDueCents, truncatedDueCents and beyondWindowDueCents. Source-side exceptions (skip, amount, moved or declared date) show on the mirror. When the scope holds BOTH the source account and the destination, the occurrence appears ONCE, on the source, with no mirror. With ‘true’ every own occurrence carries mirrorOf: null. Absent, ‘’ or ‘false’ leaves it off: the body and every database statement are unchanged and no occurrence carries mirrorOf. Any other value is a 400 VALIDATION_ERROR with fieldErrors.includeMirrors = [‘includeMirrors must be true or false’], refused before a connection is opened and never echoing the value. It adds ONE database statement whenever the scope resolves to at least one account, of any type.
Responses
Section titled “Responses”Scheduled occurrences + projection
object
object
The single account this request scoped to, or NULL on the accountIds path. The key is never omitted, so a client reading it unconditionally still parses.
The accounts the request ACTUALLY resolved to, derived from the rows the balance read returned — never echoed back from the parsed query string, which would confirm the existence of an id the caller merely guessed. A one-element array on the accountId path; possibly EMPTY on the accountIds path, which is a normal 200.
Integer minor units (cents)
The working balance walked forward through every in-window occurrence — the balance at windowEndIso. MEANINGFUL IN accountId MODE ONLY: on the accountIds path it is seeded from the SUM of mixed-sign balances (a checking balance plus a negative card balance), which is no single account’s balance, so a client must not render it (nor the per-occurrence projectedBalanceCents) in all-accounts mode. GET /accounts/{id}/balance-projection draws the same walk as a daily line for one account (KAN-3658).
Sum of the OUTFLOW magnitudes of the occurrences ACTUALLY RETURNED in occurrences — a footer total describes the rows beneath it. It therefore follows BOTH narrowings: the search filter and the overdue-backlog slice below. projectedBalanceCents does NOT — that is an account forecast over the full outstanding set. Income occurrences are not “due” and contribute nothing, and neither does a skipped occurrence (KAN-2913) — it is returned in the list but excluded from this figure.
object
Which account this occurrence belongs to. ALWAYS emitted, including on the single-account path where it is a constant — a merged multi-account list is otherwise unrenderable.
KAN-3661. The bill’s destination account (bills.destination_account_id), or null when it has none. ALWAYS emitted, on in-window, beyond-window and mirror rows alike. On a mirror row it is still the bill’s destination (the mirror’s own accountId), so a client reads a row’s other side as mirrorOf?.sourceAccountId ?? destinationAccountId.
KAN-3748. The occurrence’s bill’s Auto-enter setting (a mirror row carries its source bill’s). ask_first means a payment found for this occurrence is offered and never entered unattended. ALWAYS emitted.
Calendar date, ‘YYYY-MM-DD’
Integer minor units (cents)
The running balance after this occurrence, walked in display order (effective date, income before outflow, bill id). An occurrence already in the register (registerReflection non-null, KAN-3762) or skipped steps by ZERO; every other occurrence — overdue, due today, future, marked scheduled — steps once (projectionStepCents). Meaningful in accountId mode only (see the top-level field).
PRESENT ONLY in accountIds mode — then on every in-window occurrence (KAN-3761). The projected balance of this occurrence’s OWN account (accountId) after it: that account’s opening balance walked through its own rows by the same rule as projectedBalanceCents, plus the money arriving from a scheduled transfer out of another account in the scope. It equals the projectedBalanceCents that account’s own accountId read (with includeMirrors=true) returns for the same row. Absent in accountId mode and on beyondWindow rows.
TIER 1. ALWAYS emitted — null when no pending bank row covers this occurrence. pendingMatch !== null is exactly occurrenceStatus === 'payment_pending'.
object
SIGNED ledger cents, passed through exactly as stored.
Calendar date, ‘YYYY-MM-DD’
The register’s display text — transactions.description, never bank_description.
TIER 2. ALWAYS emitted — null when there is none. Non-null implies pendingMatch is null (the tiers are mutually exclusive by construction). It does NOT widen occurrenceStatus: a row carrying only this still renders as upcoming/overdue.
object
SIGNED ledger cents, passed through exactly as stored.
Calendar date, ‘YYYY-MM-DD’
The register’s display text — transactions.description, never bank_description.
The bank row’s own status, so a confirmed Enter claims the row with the value it was offered under.
WHICH ROUTE offered the row. Always emitted by the server, but deliberately NOT required: a client that does not recognise the value must keep rendering its existing copy rather than discarding the match.
TIER 3. ALWAYS emitted — an EMPTY array (never null, never absent) when the occurrence is not ambiguous. Non-empty implies occurrenceStatus === 'match_ambiguous' and that both other tiers are empty.
object
SIGNED ledger cents, passed through exactly as stored.
Calendar date, ‘YYYY-MM-DD’
The register’s display text — transactions.description, never bank_description.
The bank row’s own status, so a confirmed Enter claims the row with the value it was offered under.
KAN-3762 — WHY this occurrence is already in the register, or null. pending_match: the tier-1 pending bank row (pendingMatch). payment_found: any other assigned bank row — a cleared “Payment found” not yet settled, or a pending row only the attended ask admitted. tied_cover: a tie the server would not break, with enough unclaimed tied rows to cover this occurrence one-for-one (the earliest occurrences first). manual_entry: a hand-typed register row at exactly this occurrence’s amount, inside the attended date window, on or after the cursor, nearest to this occurrence. A reflected occurrence’s money is already in workingBalanceCents, so it steps the projected balance by ZERO. ALWAYS emitted by this server (explicit null when none), always null on a mirror row. It never changes occurrenceStatus (payment_pending ⇔ pendingMatch !== null still holds) or totalDueCents, and nothing is settled or claimed on the strength of it. Older servers omit the key; a client must tolerate an unknown future member.
KAN-3762 — EXACTLY the delta the projected-balance walk added for this row: 0 for a skipped or reflected row and for every beyondWindow row, otherwise effectiveAmountCents. On a single-account read it equals this row’s projectedBalanceCents minus the previous row’s (the first row’s previous is workingBalanceCents). Clients render it; they never re-derive it.
KAN-3764 — the HAND-TYPED register row covering this occurrence, non-null EXACTLY when registerReflection === 'manual_entry'; explicit null otherwise and always null on a mirror row. Ids and signed cents only — no description, payee or memo. POST /bills/{id}/enter on such an occurrence answers 409 BILL_MANUAL_ENTRY_UNCONFIRMED until the caller names this row in settleAgainstTransactionId or sends postWithoutSettling: true, so a client can open that confirm before the click. Older servers omit the key; read a missing key as null.
object
Calendar date, ‘YYYY-MM-DD’
SIGNED ledger cents, exactly as stored.
KAN-3762 — the earliest EARLIER original date of this bill in [cursor, dueDate) still outstanding and not exception-skipped — the occurrence to Enter or Skip first — or null when none (always null for a NULL-cursor bill and on a mirror row). The SAME rule POST /bills/{id}/enter and POST /bills/{id}/skip refuse with 400 BILL_EARLIER_OCCURRENCE_OUTSTANDING.
The render discriminator, ALWAYS emitted. payment_pending ⇔ pendingMatch !== null, else match_ambiguous ⇔ ambiguousMatches is non-empty, else marked_scheduled ⇔ scheduledMark !== null, else overdue ⇔ isOverdue and not skipped (KAN-3365 — a skipped occurrence is never rendered late; isOverdue keeps its date meaning), else upcoming.
object
Calendar date, ‘YYYY-MM-DD’
Integer minor units (cents)
The occurrence’s effective date, resolved server-side as declaration → forecast → schedule (KAN-2926): scheduledMark ? its scheduledPaymentDate : forecastDate ?? this row’s own dueDate. dueDate keeps its own meaning and value.
SIGNED (income +, expense −), server-computed as declaration → forecast → schedule (KAN-2926). Equals the schedule’s own signed amount when no override is present. Never re-derive a sign on the client.
The household’s own free text on THIS occurrence, or null (KAN-2913). ALWAYS emitted. A SIBLING of scheduledMark, never a member of it: a note asserts nothing about a payment. Spelled identically on GET /bills/scheduled and GET /bills/due; /bills/projection omits it, having no consumer that renders free text.
“Do not count this one” (KAN-2913). ALWAYS emitted. The row STAYS in the list and keeps its own amountCents and effectiveAmountCents; what changes is that it contributes a ZERO delta to projectedBalanceCents and is excluded from totalDueCents. It is not POST /bills/{id}/skip — no cursor moves and no payment history is written.
The FORECAST-ONLY date override on this occurrence, or null (KAN-2926). ALWAYS emitted. Outranked by scheduledMark when both are present. It moves presentation and the projected step only — never month bucketing, window membership or Safe to Spend.
The FORECAST-ONLY amount override, as the POSITIVE MAGNITUDE it is stored as, or null (KAN-2926). ALWAYS emitted. The signed figure is effectiveAmountCents; never re-sign this on the client. Outranked by scheduledMark when both are present.
PRESENT ONLY when includeNextOutstanding=1 — then on EVERY occurrence (KAN-3398). false for an in-window row; true for an appended next-outstanding row past windowEndIso (see the includeNextOutstanding parameter).
PRESENT ONLY when includeMirrors=true (KAN-3670) — then on EVERY occurrence: null on an own occurrence, and on a read-only mirror the bill and the account it is scheduled from. A mirror appears on each scoped account a bill’s destination names, of any account type (KAN-3683). A mirror is display-only: Enter, Skip and Mark-scheduled act on the bill from its source account.
object
The mirrored bill — scheduled on the source account, not this one.
The account the bill is scheduled from.
How many OVERDUE occurrences (dueDate < today) the server dropped from occurrences (KAN-80), 0 when none. A bill whose first payment is far in the past is capped to the most recent MAX_OVERDUE_OCCURRENCES overdue rows nearest today; occurrences due today or later are never truncated. projectedBalanceCents is computed over the full outstanding set and does not move when rows are dropped; totalDueCents DOES follow the returned rows, with the dropped remainder reported as truncatedDueCents.
Sum of the OUTFLOW magnitudes of the occurrences the overdue-backlog slice dropped, 0 when none. Emitted on EVERY response, so totalDueCents + truncatedDueCents always equals the total over the un-truncated set — that identity is what lets a client show “plus $X in N older hidden bills” without recomputing anything. Do not add it into the section total; the server has already excluded it.
The due date of the earliest RETURNED occurrence when the overdue backlog was truncated, else null.
The lower bound actually applied, or null for “no lower bound beyond each bill’s own settle-through cursor”. NULL on every forward-looking window — including one widened by forwardTo — so the overdue backlog always surfaces; non-null only on a purely-past window, where it is the from that was sent.
The upper bound actually applied, emitted on EVERY 200 including the default unqueried path. This is what makes the window rule observable: a caller whose forwardTo was floored to end-of-month — or one that sent only the inert to — reads exactly what it got rather than inferring it. On the default path it is the last day of the current month.
PRESENT ONLY when includeNextOutstanding=1 (KAN-3398). The OUTFLOW magnitude of the beyondWindow: true occurrences (skipped ones excluded), summed by the same rule as totalDueCents, which those rows are excluded from. 0 when there are none.
Example
{ "data": { "occurrences": [ { "autoEnterMode": "automatic", "direction": "expense", "frequency": "once", "outOfBandMatch": { "status": "cleared", "reason": "amount_differs" }, "ambiguousMatches": [ { "status": "cleared" } ], "registerReflection": "pending_match", "occurrenceStatus": "upcoming" } ] }}Validation failed — see errorCode / fieldErrors
object
Machine-readable error code (AUTH_ERROR_CODES).
Optional field-level validation errors, keyed by field name.
object
Example
{ "errorCode": "INVALID_EMAIL_FORMAT"}Missing, invalid, or expired bearer token
object
Machine-readable error code (AUTH_ERROR_CODES).
Optional field-level validation errors, keyed by field name.
object
Example
{ "errorCode": "INVALID_EMAIL_FORMAT"}Authenticated, but the tenant gate refuses the request until the caller resolves a precondition. errorCode is one of EMAIL_NOT_VERIFIED, POLICY_ACCEPTANCE_REQUIRED, or SUBSCRIPTION_REQUIRED, evaluated in exactly that order (contract term CCR-1: email verification first, then policy acceptance, then subscription — so a subscriber who has merely not re-accepted the current policies always sees POLICY_ACCEPTANCE_REQUIRED). A POLICY_ACCEPTANCE_REQUIRED body additionally carries details.outstanding (the policy versions still to accept) and details.firstAcceptance. The SUBSCRIPTION_REQUIRED arm is INERT unless the server-side BILLING_ENABLED flag is exactly the string true; while it is off, only the first two codes are reachable. Not retryable as sent — resolve the named condition, then resend.
object
Which precondition refused the request. Evaluated in this order (CCR-1); SUBSCRIPTION_REQUIRED is unreachable while BILLING_ENABLED is not exactly true.
object
Active policy versions the user has not yet accepted.
object
True when the user has accepted no policy before — the client renders the new-signup screen rather than the re-acceptance one.
Example
{ "errorCode": "EMAIL_NOT_VERIFIED"}Internal error (no internal detail leaked)
object
Machine-readable error code (AUTH_ERROR_CODES).
Optional field-level validation errors, keyed by field name.
object
Example
{ "errorCode": "INVALID_EMAIL_FORMAT"}Service temporarily unavailable — errorCode is SERVICE_UNAVAILABLE. A TRANSIENT, RETRYABLE condition rather than a defect in the request: a query that exceeded its time budget, a lost or refused database connection, a saturated connection pool, or an outage at an upstream provider the request depends on (the authentication provider, or the bank data provider on a bank-connection operation). The identical request may succeed on retry — back off briefly and, on a write, resend the same X-Idempotency-Key where the operation accepts one.
object
Machine-readable error code (AUTH_ERROR_CODES).
Optional field-level validation errors, keyed by field name.
object
Example
{ "errorCode": "INVALID_EMAIL_FORMAT"}