Data semantics
The reference tells you the shape of every response. This page tells you what the values mean. Everything here is a place where a technically successful request can still give you a number you did not intend to use, so it is worth reading once before you write the integration rather than after.
1. Books do not start at the beginning of time
Section titled “1. Books do not start at the beginning of time”Every entity has a books_start_date — the earliest date its books cover — and it is
returned on every record from GET /business_entities.
Requested ranges are clamped to it. If you ask for a trailing twelve months and the
entity’s books begin four months ago, you get four months of data, and the response tells
you so: start_date and end_date in the payload are the effective range we reported
on, not the range you asked for.
This is not an edge case. An entity typically arrives on Flychain part-way through its
financial year, and its books begin when we start keeping them, so a short window is the
normal early state of a new entity rather than a fault. The failure to design against is
treating those months as missing or as zero revenue: a partial year of books is “the books
start here”, and a per-month figure of zero for a month before books_start_date would be
a fabrication, not a fact.
Two consequences worth building in:
- Compare the returned range against the range you asked for, and record which one the figure covers. Any downstream calculation that assumes twelve months because it asked for twelve months will be wrong for months at a time.
- A range entirely before
books_start_dateis a400, not an empty statement. We would rather fail your request than hand you a zero that looks like a real measurement. The same applies to a range entirely in the future.
end_date is also capped at today, which is the ordinary case for a job that asks for the
current month every day.
2. is_closed and is_complete are different questions
Section titled “2. is_closed and is_complete are different questions”Both flags appear on every period of a monthly response; is_closed also appears on the
single-range endpoints and on whole_period.
| Flag | Question it answers |
|---|---|
is_complete |
Has this period’s end date passed? false for a period ending today or later — in practice, the month in progress. |
is_closed |
Has a Flychain bookkeeper finalized the books through this period’s end date? |
is_complete is a calendar fact. is_closed is an accounting fact, and it is the one that
tells you whether a figure can still move.
A note on is_complete: it is about the period, not the calendar month. If your
requested range starts or ends mid-month, the first and last periods are clipped to your
range (see §5), and a clipped period reads is_complete: true once its end date has
passed even though the calendar month it is labelled with is not fully covered.
3. Trust is_closed, not the calendar
Section titled “3. Trust is_closed, not the calendar”Our bookkeepers aim to close each month within the first couple of weeks of the following month. Treat that as a target, not a guarantee — a close can land later, and a process that assumes a fixed date will occasionally read provisional figures as final. We are telling you this rather than promising a date we might miss, because you are invoicing on these numbers.
is_closed is the authoritative signal, and it is why the flag exists. Before a close,
figures are provisional: categorization is largely automated, so revenue is usually close
to final well before the books close, but as in any accounting system the item most likely
to move a figure is a large non-revenue deposit — a loan, say — that has not yet been
reconciled. That can make revenue read high and then settle lower.
The pattern that handles this deterministically:
- Re-pull trailing months on a schedule (the monthly endpoints make this one request).
- Treat every period with
is_closed: trueas settled, and stop re-pulling it. - Treat every period with
is_closed: falseas provisional, and expect it to change. - If a figure you have already acted on changes after close, true it up from the closed value.
If you would rather only ever act on final figures, wait for is_closed: true on the
period before using it. That is a choice on your side; nothing changes on ours.
4. Accounting basis belongs to the entity
Section titled “4. Accounting basis belongs to the entity”Each entity’s basis — CASH or ACCRUAL — is recorded against its books and is the basis
its financials are prepared and reviewed on. We return accounting_basis on every entity
record and every report, so a figure is never ambiguous about which basis it is on.
There is no per-request basis switch, and adding one would be misleading rather than helpful: a report is produced on the basis the underlying books are kept on, and re-expressing cash-basis books on an accrual basis is a bookkeeping exercise, not a query parameter. Where an entity needs to change basis, that is a decision made with them and the field will reflect it — it will not change without notice.
Practically: an entity’s basis is stable, but do not assume every entity in your relationship shares one. Store the basis alongside any figure you keep.
5. Dates, ranges and periods
Section titled “5. Dates, ranges and periods”- All dates are
YYYY-MM-DD, zero-padded.2026-7-1is rejected, as is a date that does not exist (2026-02-31). Both are400 INVALID_REQUEST. - Ranges are inclusive of both endpoints.
start_date=2026-07-01&end_date=2026-07-31is the whole of July. - Report windows are evaluated in UTC. Do not send a local-timezone-adjusted date; a shifted window can pull a transaction from the neighbouring day into the wrong period.
generated_atis ISO 8601 UTC. Reports are computed on request, so it is also the as-of time of the figures. There is no caching delay to work around: an on-demand pull reflects the current state of the books.- Monthly periods are clipped, not extended. A range from the 15th to the 14th yields a
first period starting on the 15th and a last period ending on the 14th. The
label(“July 2026”) is derived from the period’s start date, so use the dates, not the label, to know what a period covers. Align your ranges to month boundaries if you want whole calendar months. whole_periodis computed independently, over the full range, rather than summed from the per-month figures. The two agree; a discrepancy would indicate an upstream inconsistency rather than rounding.
6. Entities that are not reportable, and entities that are gone
Section titled “6. Entities that are not reportable, and entities that are gone”Two distinct situations, reported differently on purpose.
Not yet reportable, or no longer reportable. GET /business_entities lists the entity
with reporting_available: false. This covers both directions: an entity still being
onboarded, and one that has been deactivated. A report request for it returns
409 BOOKS_NOT_AVAILABLE. Skip these rather than recording a zero — an entity mid-onboarding
would otherwise read as a business with no revenue.
Outside your relationship. The entity or provider stops appearing in the discovery
endpoints, and a report request returns 403, with a code (PROVIDER_NOT_IN_PARTNER_SCOPE
or BUSINESS_ENTITY_NOT_IN_PARTNER_SCOPE) distinct from the 404 you get for an id that
never existed. That distinction is deliberate: a provider leaving the relationship is a
thing your platform should be able to detect and flag, rather than discovering it as a
silent absence.
So: PROVIDER_NOT_IN_PARTNER_SCOPE and BUSINESS_ENTITY_NOT_IN_PARTNER_SCOPE mean “this
existed and is no longer yours — stop querying it and tell someone”. 404 means “this id
is wrong”.
Match on the code, not on the status. 403 also carries PARTNER_API_NOT_ENABLED, which
means the opposite: your organization is not enrolled in the API programme, every id you
hold is still valid, and nothing has left your relationship. Treating that one as a
departure would flag your whole roster as churned.
7. Amounts
Section titled “7. Amounts”Every monetary value is a signed integer in cents, USD. We hold monetary values in cents internally to avoid floating-point rounding in financial calculations, and expose them the same way so no precision is lost in transit. Expense categories are positive magnitudes, as they appear on a statement.
In the full statement, read total_amount_cents for a category or account total — it
includes every account beneath that node. amount_cents is only what is posted directly at
that node, which for a category root is usually zero but is not guaranteed to be. Reading
amount_cents on a category is the single easiest way to under-report a figure.