export_ ID
immediately; Retrieve export tells you
when it is ready and returns a signed download URL.
Both operations require API access: Manage and Reports: View. The key
selects the company. Any currently authorized teammate may retrieve an API
export in that company. Generating an export does not edit your books.
Choose the report
All four examples below usePOST /api/v1/reports/exports. Send a different
Idempotency-Key for each new job.
Income statement:
Fields and options
group_by is an object; omitted members take their defaults. Quarter/year
columns follow the company’s existing calendar/fiscal report settings. First
and last columns can be partial periods. There is no date_type override.
Balance sheets need a range, too. Each displayed period shows cumulative
balances through its cutoff, retaining activity before start_date.
Department rows work only for income_statement and require the departments
feature. Without it, the request returns 403 feature_disabled.
Ranges are limited to 120 calendar months, counting both boundary months,
regardless of format or grouping. PDF exports additionally support 13 displayed
periods, using the company’s calendar/fiscal report settings. For more columns,
use a shorter range, coarser grouping, CSV or XLSX. Oversized ranges return
400 invalid_date_range with param: "end_date" before creating or queuing a job.
Unknown fields are rejected, including
email_on_completion, grouped_by, a single date, or a company selector.
Company, actor and filename are inferred by Finta.
Submit an export
201 Created, with Location pointing to
the retrieval path and Cache-Control: no-store.
status; HTTP 201 does not guarantee that the job is new or still pending.
Poll for completion
200 OK for every recognized job state:
Stop polling at success or failure. Every poll consumes the ordinary
API allowance, so use bounded backoff rather than
a tight loop. There is no guaranteed generation time, completion webhook,
email notification or MCP event subscription in this flow.
The worker reads the books when it generates the file; POST does not freeze a
financial snapshot. Completed files are retained results. To regenerate against
updated books, submit a new job with a new key.
Download the file
Onlysucceeded responses expose a file object:
size is bytes and expires_at
is Unix seconds. CSV uses text/csv; XLSX uses
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.
The client or agent fetches the returned URL with its own HTTP/file tools:
completed_at (2,592,000 seconds).
At or after that cutoff, GET and idempotent POST replays still return
status: "succeeded", but file and error are null. The export record and stored
file are retained. To generate another report from the current books, submit a
new export with a new key.
Within that window, successful retrieval requests a fresh link with expiry seven days from
retrieval, not from job creation or when the link is opened. Signing credentials
or storage policies can invalidate a link sooner. If it expires,
retrieve the export again before its 30-day cutoff. Already-issued links keep
their original expiry and can remain valid beyond the regeneration cutoff.
A download started before expiry can finish afterward;
restarting or requesting additional byte ranges afterward needs a fresh link.
Links are bearer credentials: anyone with one can download until it expires,
even if API permissions change in the meantime. Retrieval itself checks current
access. Link expiry does not delete the file; export records and files have no
automatic age-based cleanup policy in the application.
Idempotency and retries
POST requires a nonblank, case-sensitiveIdempotency-Key of 1–255 characters.
It is scoped to the company, submitting user and operation, across that user’s
API keys. Identical normalized inputs replay the same export and current state,
including failures. Different inputs with that key return
409 idempotency_key_conflict.
Keys remain reserved for the lifetime of the record.
- After a timeout or
503 report_export_failed, retry the same body/key. A job may already be queued; same-key retry repairs an interrupted dispatch without creating another record. The retained job stays pending rather than becoming a terminal enqueue failure. - After a terminal failed job, fix the cause and use a new key to retry. The old key continues to replay that failure.
- For intentionally new work, including refreshing the same dates after the books change, use a new key.
Export capacity
A company may have at most five unfinished API exports, across all submitters. New submissions above that limit return429 report_export_limit_exceeded
without creating or enqueueing a job. Existing-key replays and GET polling
remain available, subject to ordinary API limits. A terminal success or failure
releases its slot.
This capacity error has no Retry-After: the finish time is unknown. Poll
existing jobs with backoff and retry the rejected submission after one finishes.
It is separate from burst/monthly quotas. For ordinary rate_limit_exceeded,
honor Retry-After; for monthly_limit_exceeded, stop short-term retries.
Headers
Standard
X-RateLimit-* headers describe API requests, not export slots. Their
availability and reset behavior are documented under
Usage Limits.
Failures and metrics
An HTTP 200 withstatus: "failed" contains a job error with code/message,
not the HTTP error envelope’s type/doc_url fields:
access_revoked: the submitter lost required access before generation finished.generation_failed: generation could not finish after retries.enqueue_failed: a compatibility value in the declared job-error schema. New dispatch uncertainty returns HTTP 503 with a pending job, rather than recording this terminal code.
started_at is the first generation-attempt timestamp and can remain null when
access is revoked before generation. completed_at is terminal
completion, for success or failure. Both are Unix seconds and nullable before
their events. generation_duration_ms is nullable until an attempt finishes,
then accumulates generation/render/upload attempt time, including failed attempts
but excluding queue and retry waits. It is not total time since submission.
Finta records export ID, status and whether a download link was issued in its
API request logs. Pending/failed responses and HEAD probes do not count as link
issuance. Issuing a link does not prove its bytes were downloaded; actual S3
downloads and download duration are not tracked.
Unknown or other-company IDs, browser-created exports and raw database IDs
return 404 resource_missing. Department exports also require the feature on
retrieval. There is no export list, cancel or delete operation.
Use recognized schema values and inspect status before file/error. Treat an
unknown future state as unrecognized, rather than assuming success. File exports
use the export_ resource; they are separate from transaction job_ resources.
The JSON income-statement endpoint keeps its scalar group_by=category|department;
this new export body uses group_by: {period, rows}.