Reports
Reports turn order, payment, Flint billing, balance, payout, and tax history into versioned CSV files. Generation is asynchronous: create a report, wait for it to finish, then download the file.
All report routes are API-key-only. Creating a report requires the reports.write scope; listing, reading, and downloading require reports.read. Reports are scoped to the environment your key belongs to, so a sandbox key generates sandbox reports.
For matching a single deposit to the transactions that funded it, see Reconciliation. For what each processing fee is, see Processing fees.
Create a report#
curl -X POST https://api.withflintpay.com/v1/reports \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 8f2b1c40-payments-2026-01" \
-d '{
"report_type": "payments_itemized_v1",
"interval_start_at": "2026-01-01T05:00:00Z",
"interval_end_at": "2026-02-01T05:00:00Z",
"timezone": "America/New_York",
"currency": "USD"
}'
| Field | Required | Notes |
|---|---|---|
report_type | Yes | One of the types listed under Report Types. |
interval_start_at | Yes | RFC 3339 instant, inclusive. |
interval_end_at | Yes | RFC 3339 instant, exclusive. Cannot be in the future. |
timezone | No | IANA name, defaults to UTC. Controls how timestamp columns are rendered. Payout reports also interpret the interval boundaries as local calendar dates in this timezone. |
currency | Yes | Three-letter ISO 4217 code. A report covers one currency; amounts are never converted. |
A new report comes back 201 with status: pending and a rep_ report ID.
Idempotency-Key is optional, and omitting it makes the call non-idempotent: each request creates a new report. When you do send one, replaying it with the same parameters returns the original report and sets Idempotency-Replayed: true; replaying it with different parameters returns 409 IDEMPOTENCY_KEY_REUSED. A replay is also a 201, but it carries whatever status the original report has now, so treat status as something to read rather than assume.
Wait for completion#
Poll GET /v1/reports/{report_id}, or subscribe to report.succeeded and report.failed. The webhook data is the same report resource REST returns.
A report is in exactly one state:
pending: nodownload, nofailure_reason.succeeded:download.report_download_id,download.url, anddownload.expires_at.failed:failure_reasonofgeneration_failed,data_unavailable, orlimit_exceeded.
data_unavailable means Flint cannot prove that the interval is complete or a record's supporting evidence has not landed yet: provider balance or payout history has not reconciled through the interval, a Flint billing collection is still waiting on its outcome or lacks its balance transaction, a paid payout's allocations have not synced, an order lacks authority-level tax evidence, or a refund lacks tax lineage. Flint fails the report rather than emitting a file with gaps in it.
limit_exceeded means generation crossed the documented row, file-size, duration, or tax-summary grouping limit. Request a smaller interval.
Transient generation failures are retried before the report moves to a terminal state. Wait for report.succeeded or report.failed instead of creating a duplicate report.
Download the CSV#
curl https://api.withflintpay.com/v1/report-downloads/rdl_01J9Z2K7Q4M8XN3B5V6T0R1C2D \
-H "Authorization: Bearer YOUR_API_KEY" \
--location \
--output report.csv
The download is an authenticated Flint API route. After authorization, it redirects to a short-lived private file URL, so HTTP clients must follow redirects. Do not store or share the temporary redirect target. The Flint URL expires 24 hours after the report succeeds, at the exact instant in download.expires_at. After that the route returns 410 REPORT_DOWNLOAD_EXPIRED.
To get a fresh file for the same interval, create the report again with a new Idempotency-Key (or none at all). Replaying the original key returns the original report and its already-expired download.
List your reports#
curl "https://api.withflintpay.com/v1/reports?page_size=20" \
-H "Authorization: Bearer YOUR_API_KEY"
The response uses the standard data[] and opaque next_page_token envelope, ordered by created_at then report_id, newest first. The token is bound to the page_size, merchant, and environment it was issued for, so changing any of them mid-pagination returns INVALID_PAGE_TOKEN. Start a new pass instead.
Report types#
| Report type | One row is | Interval matches |
|---|---|---|
orders_itemized_v1 | A closed order | Order close time |
payments_itemized_v1 | A succeeded payment | Capture time |
merchant_billing_itemized_v1 | One change to what you owe Flint or the credit you hold | Entry occurrence time |
balance_transactions_itemized_v1 | A balance transaction | Transaction time |
payouts_itemized_v1 | One balance transaction allocated to one payout | Payout arrival date |
tax_itemized_v1 | An order tax breakdown | Order close time |
tax_summarized_v1 | A jurisdiction and tax type | Order collection time for sales, refund success time for reversals |
tax_transactions_itemized_v1 | A Quaderno-connected calculation or refund reversal | Order collection time for sales, refund success time for reversals |
Two report types over the same dates do not select matching activity. A payout that arrives on February 1 pays for balance transactions created in January, so payouts_itemized_v1 and balance_transactions_itemized_v1 cover different rows for the same interval by design. Reconcile a payout through its own entries, not by date arithmetic.
Reports use only the authoritative occurrence field for their type. A completed record without that field makes generation fail with data_unavailable; Flint does not move financial activity between periods using a mutable last-updated timestamp.
Type names are versioned. A future incompatible column change ships as a new version rather than editing a published shape.
payments_itemized_v1 and tax_summarized_v1 can cover at most 366 days. Other itemized reports can cover at most 90 days. Each merchant and environment can have up to five pending reports. Generation fails explicitly instead of truncating when a report exceeds 1,000,000 source or output rows, 500 MiB of uncompressed CSV, 25 minutes, or 10,000 tax authority and tax type groups.
Columns#
Money is two columns, an amount in minor units and a currency, matching the Money shape everywhere else in the API. See Money & currency.
orders_itemized_v1
order_id, collection_completed_at, subtotal_money.*, discount_money.*, charge_money.*,
tax_money.*, additive_tax_money.*, inclusive_tax_money.*, requested_tip_money.*,
total_money.*
payments_itemized_v1
payment_intent_id, occurred_at, selected_payment_option, captured_money.*,
processing_fee_money.*, merchant_net_money.*, order_id
merchant_billing_itemized_v1
merchant_billing_entry_id, type, occurred_at, outstanding_effect_money.*,
available_credit_effect_money.*, net_billing_effect_money.*, description,
event_fee_type, payment_intent_id, dispute_id,
merchant_subscription_invoice_id, balance_transaction_id,
related_merchant_billing_entry_id
balance_transactions_itemized_v1
balance_transaction_id, type, status, occurred_at, available_at,
amount_money.*, fee_money.*, net_money.*, payment_intent_id, refund_id,
dispute_id, return_id, payout_id, related_balance_transaction_ids
payouts_itemized_v1
payout_entry_id, payout_id, arrival_date, balance_transaction_id, type,
occurred_at, amount_money.*
tax_itemized_v1
order_id, tax_breakdown_id, collection_completed_at, location_id, jurisdiction.code,
jurisdiction.country, jurisdiction.state, jurisdiction.level,
jurisdiction.name, tax_type, calculation_type, price_mode, percentage,
flat_money.*, taxable_money.*, tax_money.*
tax_summarized_v1
jurisdiction.code, jurisdiction.country, jurisdiction.state,
jurisdiction.level, jurisdiction.name, tax_type, taxable_sales_money.*,
nontaxable_sales_money.*, tax_collected_money.*, tax_refunded_money.*,
tax_payable_money.*
tax_transactions_itemized_v1
record_type, merchant_id, order_id, payment_intent_id, order_line_item_id,
order_charge_id, refund_id, applied_tax_calculation_id,
collection_completed_at, refund_succeeded_at, currency, origin_source,
origin_source_id, origin_revision, seller_origin.line_1,
seller_origin.line_2, seller_origin.city, seller_origin.region,
seller_origin.postal_code, seller_origin.country, buyer_destination.line_1,
buyer_destination.line_2, buyer_destination.city, buyer_destination.region,
buyer_destination.postal_code, buyer_destination.country,
product_description, product_reference, quantity, flint_tax_category,
provider, provider_product_type, provider_tax_code, gross_amount,
discount_amount, taxable_amount, nontaxable_amount, tax_amount, total_amount,
tax_behavior, status, taxable_percentage, primary_tax_name, primary_tax_rate,
additional_tax_name, additional_tax_rate, additional_taxable_percentage,
additional_tax_amount, provider_country, provider_region, provider_county,
provider_city, configuration_generation, effective_settings_fingerprint,
refund_reversed_tax_amount
charge_money on the order report is the order's charges (delivery, service, handling), not a processing fee. Processing fees are on the payment and balance reports.
tax_money is the total tax for the order and equals additive_tax_money + inclusive_tax_money. Reconcile the charged order total with subtotal_money - discount_money + charge_money + additive_tax_money + requested_tip_money = total_money. Inclusive tax is already embedded in the entered prices, so adding it again would overstate the total.
merchant_billing_itemized_v1 is the line-by-line history behind what you owe Flint and the account credit you hold. Each row is one change to that position, and merchant_billing_entry_id (prefix mbe_) identifies the change, so the same row keeps the same ID every time you generate the report.
type names the change:
type | What the row is |
|---|---|
event_fee | A fee for one event on your account, such as a card dispute or a failed ACH payment. |
subscription_invoice | A Flint subscription invoice issued to you for a billing period. |
correction | A finalized correction to a fee Flint already charged you. |
credit_issued | Flint gave you account credit. |
credit_applied | Account credit was put toward what you owe. |
collection | Flint collected what you owe out of your Flint balance. |
collection_reversal | A collection came back, so the amount is owed again. |
write_off | Flint stopped collecting an amount you owed and cleared it. |
event_fee_type is set only on event_fee rows and is one of bank_verification, failed_ach_payment, ach_dispute, or card_dispute.
The two effect columns are signed: a positive outstanding_effect_money increases what you owe, a positive available_credit_effect_money increases the credit you can use, and net_billing_effect_money is outstanding_effect_money minus available_credit_effect_money. Collection and reversal rows carry the matching balance_transaction_id, and related_merchant_billing_entry_id points at the earlier row a credit application, collection, reversal, or write-off acts on. Event fees and finalized fee corrections belong here; the original processing fee stays on the payment and payments_itemized_v1. See Flint billing.
The foreign-key columns on balance_transactions_itemized_v1 are sparse: a row populates the one that matches its source and leaves the rest empty. related_balance_transaction_ids is independent of that and can be set alongside another key, on a refund that points back at the payment it reverses. The value is a JSON array containing every related Flint balance transaction ID.
tax_itemized_v1 covers tax charged on orders. Successful refund executions increase tax_refunded_money and are netted into tax_payable_money on tax_summarized_v1, so use the summarized report when you need the amount owed to a jurisdiction. Pending and failed refund executions do not change either amount.
Use tax_transactions_itemized_v1 for Quaderno-connected automatic tax. record_type is collection for the frozen calculation collected with an order and refund_reversal for a successful reversal. The amount columns are minor units in the row's currency. The report preserves the provider result and its seller origin, buyer destination, product, configuration, and refund evidence for reconciliation or import. It is not a tax return, nexus decision, or filing instruction.
The jurisdiction-based tax_itemized_v1 and tax_summarized_v1 reports require Flint authority breakdowns. They fail with data_unavailable when the interval contains nonzero Quaderno-connected tax because Flint does not invent those breakdowns from a combined provider result. Generate tax_transactions_itemized_v1 for those orders. See Sales tax.
Reconcile fees and payouts#
payments_itemized_v1 gives you the processing fee charged on each succeeded payment alongside merchant_net_money.
balance_transactions_itemized_v1 gives you every movement of your balance and preserves its original report convention: fee charges are negative, fee credits are positive, and net_money = amount_money + fee_money. The report schema is independent of the HTTP API version. At API version 2026-09-07, balance transaction responses use the opposite fee signs and net_money = amount_money - fee_money.
For the transactions in one specific payout, GET /v1/payouts/{payout_id}/entries is authoritative and does not require generating a report. It needs the money_movement.payouts.read scope rather than reports.read, and it can return 503 PAYOUT_ENTRIES_UNAVAILABLE with a Retry-After header for a payout whose allocations have not synced yet. Retry rather than treating that as an empty payout.
Annual payment totals#
For a calendar-year gross payment total, generate payments_itemized_v1 for the full year in your reporting timezone and sum captured_money.amount. That figure is gross: it is not reduced by refunds, processing fees, credits, discounts, or payouts. Pull those from balance_transactions_itemized_v1 and subtract them yourself.
Flint does not expose tax forms through the API. Where Flint is required to file a US information return covering your payment volume, Flint prepares and delivers that form directly. Use these totals as an input to your own books, and confirm anything you file with your accountant.
Errors#
payments_itemized_v1 and tax_summarized_v1.page_size, merchant, or environment changed mid-pagination.TOO_MANY_PENDING_REPORTSRetryableOn GET /v1/payouts/{payout_id}/entries:
Next steps#
- Reconciliation: matching a single deposit to the transactions that funded it.
- Flint billing: what you owe Flint, the credit you hold, and how Flint collects.
- Processing fees: what each fee on the payment and balance reports is.
- Sales tax: what the tax reports are built from.
- Money movement API reference: balances, balance transactions, and payouts.
