Start Entity Export Run
Starts an export run: a background job that produces the FULL filtered
result set of one entity type as a CSV file, however large it is. Returns
immediately with a runId — poll
GET /entities/{entityType}/export-runs/{runId} until the run succeeds,
then fetch the file from
GET /entities/{entityType}/export-runs/{runId}/download.
A run streams rows into a stored CSV in the background and lets you download the finished file without holding the full result set in request memory.
The request body is OPTIONAL
The body is the export request:
fields— the export columns, in CSV column order. Omit it (or send no body at all) to export the type’s full default column set: the systemid/createdAt/updatedAtcolumns followed by every configured column of the type’s export surface.filters/filterText— the same generic filters the List Entities endpoint accepts.sortBy/sortDirection— row order.asOf— point-in-time lens (YYYY-MM-DD): for Policy it resolves each policy to the segment in effect on that date, for Event it bounds the financial export columns.
A body that arrives and cannot be read as JSON is a 400
(UNREADABLE_REQUEST_BODY) — it is never treated as an omitted body, because
that would export different columns and rows than the ones asked for.
The run snapshots the request AND the company’s current configuration version when it starts, so what a queued export produces cannot drift: a configuration import landing mid-run does not change the file.
Duplicate starts collapse onto the run already in flight
If a run is already in flight (queued or running) producing this exact
export — same request, same configuration version — this endpoint does not
start a second one: it returns 200 with that run’s id and
outcome: "duplicate". That is a normal, successful answer, not an error.
Pass ?force=true to start a new run anyway. A run that already
finished is never deduplicated onto — re-asking for the same export is
how you refresh the file.
At most 3 runs in flight per company
A company may have 3 export runs in flight at once. A 4th distinct
request is refused with a 429 whose body carries inFlightRunIds — poll
those instead of retrying blind. ?force=true does not lift this limit.
Required permission: company.{entity}:list — the exact key varies by
type (Policy uses company.policy:export). See
Permissions.
Authorizations
User-principal OAuth 2.0 Bearer authentication. Send a user-scoped Auth0 access token (audience = the app API audience) as Authorization: Bearer <jwt>. The request resolves to the user's identity and is authorized by their Role on the {companyId} in the path — the same role-based permissions the web app enforces. This is the path the MCP connector uses to act on a user's behalf; endpoints that accept it list both BearerAuth and ApiKeyAuth.
Path Parameters
Company identifier
Field Model V1 EXPORTABLE entity type (lowercase kebab-case URL slug): the six
CRUD entity types plus policy. Unlike the CRUD entity routes, policy IS
valid here — a Policy export reads the segment in effect on the asOf date
(defaulting to today).
event, exposure, quote, submission, person, organization, policy Query Parameters
When true, start a new run even if a run is already in flight producing
this exact export — i.e. skip the duplicate check and always mint a fresh
run. Any value other than the literal true (including omission) is
treated as false. This does not raise the limit of 3 runs in flight
per company.
Body
OPTIONAL. The export request; omit it entirely (or send {}) to export the
type's full default column set with no filters. A body that cannot be read
as JSON is a 400, never a silent default export.
Explicit export columns, in CSV column order. Omit to export the type's full default column set (system columns + every configured column of the type's export surface).
Filters applied to the export snapshot with AND semantics.
Tenant filters must use fieldType: "declared" and a key from
the entity surface's listFilters. Explicit systemUser,
systemDate, and systemId forms remain supported.
Implicit field-derived forms fail at admission with HTTP 400
and code implicit-filters-disabled; no run is persisted or
enqueued.
A filter accepted by FMV1 external list, version, and export endpoints.
Tenant-field filters must use fieldType: declared and the key of a
listFilters definition on the surface being queried. The definition supplies
the SQL expression, result type, and permitted operators; the request supplies
only its key, an exposed operator, and an operand of that operator's shape.
The fixed systemUser, systemDate, and systemId forms remain explicit.
Implicit field-derived forms such as text, number, optionSet, or join
are rejected with 400 and code implicit-filters-disabled.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
Free-text filter over the type's search fields
asc, desc Point-in-time lens (YYYY-MM-DD); see the endpoint description.
Response
The run to poll. outcome: "enqueued" means a new export was started;
outcome: "duplicate" means runId is a run already in flight producing
this exact export and no second one was started.
The run to poll after starting an export run. outcome is a policy verdict
delivered as a successful 200, not an error: duplicate means a run
producing this exact export (same request, same configuration version) was
already in flight, so runId is that run and no second export was started.
The run to poll via the start endpoint's GET .../export-runs/{runId} sibling
enqueued when a new export was started; duplicate when a run already in flight was producing this exact export (pass ?force=true to start a new run anyway)
enqueued, duplicate 