> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fitsociety.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Async exports

> Create, monitor, retry, cancel, and download asynchronous company exports through the FITsociety Public API.

Public API exports use the same asynchronous export pipeline as the FITsociety
software. A client queues an export request, polls the request status, and reads
a temporary `downloadUrl` when the request is completed. Export types can expose
`xlsx`, `csv`, or `zip` formats.

The authenticated company and Public API client are always derived from the
Bearer token. Public API clients can only see export requests that they created
themselves. Software-created export requests, requests created by other Public
API clients, raw params, metadata, internal actor fields, provider payloads, and
internal error details are not exposed.

Legacy direct XLSX routes and coach export templates are not part of the Public
API.

## Scopes

| Scope           | Allows                                                                                                               |
| :-------------- | :------------------------------------------------------------------------------------------------------------------- |
| `exports:read`  | Read available export types, list export requests, inspect one export request, and read temporary download metadata. |
| `exports:write` | Create, cancel, retry, and delete export requests.                                                                   |

Integrations that create an export and later poll for status or download
metadata need both scopes.

## Workflow

1. Use `GET /public/v1/exports/types` to discover active export types for the
   authenticated company.
2. Queue an export with `POST /public/v1/exports/requests`.
3. Poll `GET /public/v1/exports/requests/{exportRequestId}` until `status` is
   `completed`, `failed`, `canceled`, `expired`, or `deleted`.
4. Download the file through the signed
   `data.exportRequest.file.downloadUrl` while it is present and before
   `file.expiresAt`.
5. Optionally retry failed or completed jobs, cancel queued or running jobs, or
   delete terminal jobs to clear their public file URL.

## List export types

```http theme={null}
GET /public/v1/exports/types
Authorization: Bearer <access_token>
```

Required scope: `exports:read`

The response contains only export types that are active for the authenticated
company, have an async handler, and support one of their configured formats.

Response fields:

| Field                              | Type      | Description                                                 |
| :--------------------------------- | :-------- | :---------------------------------------------------------- |
| `data.exportTypes[].typeId`        | string    | Stable export type identifier used when creating a request. |
| `data.exportTypes[].label`         | string    | Localized display label.                                    |
| `data.exportTypes[].description`   | string    | Localized export description.                               |
| `data.exportTypes[].filters`       | object    | Public filter metadata for building request params.         |
| `data.exportTypes[].formats`       | string\[] | Allowed formats, such as `xlsx`, `csv`, or `zip`.           |
| `data.exportTypes[].defaultFormat` | string    | Default format when the request does not specify one.       |
| `data.exportTypes[].capabilities`  | string\[] | Public export capabilities.                                 |

<CodeGroup>
  ```bash cURL theme={null}
  curl -H "Authorization: Bearer $FITSOCIETY_ACCESS_TOKEN" \
    "https://api.fitsociety.io/public/v1/exports/types"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.fitsociety.io/public/v1/exports/types", {
    headers: {
      Authorization: `Bearer ${process.env.FITSOCIETY_ACCESS_TOKEN}`,
    },
  });

  const body = await response.json();
  console.log(body.data.exportTypes);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.get(
      "https://api.fitsociety.io/public/v1/exports/types",
      headers={"Authorization": f"Bearer {os.environ['FITSOCIETY_ACCESS_TOKEN']}"},
  )
  response.raise_for_status()

  body = response.json()
  print(body["data"]["exportTypes"])
  ```
</CodeGroup>

## Create an export request

```http theme={null}
POST /public/v1/exports/requests
Authorization: Bearer <access_token>
Idempotency-Key: <stable_request_key>
Content-Type: application/json
```

Required scope: `exports:write`

Request body:

| Field              | Type      | Required | Rule                                                                                      |
| :----------------- | :-------- | :------- | :---------------------------------------------------------------------------------------- |
| `typeId`           | string    | yes      | Must match an export type returned by `GET /public/v1/exports/types`.                     |
| `params`           | object    | no       | Export-specific filters. Date ranges use `YYYY-MM-DD` values and may not exceed 366 days. |
| `params.fields`    | string\[] | no       | Selected fields when the export type exposes a public field catalog.                      |
| `options.format`   | string    | no       | Must be one of the export type's `formats`, for example `xlsx` or `csv`.                  |
| `options.language` | string    | no       | Optional response and export label language.                                              |

When a single-sheet export is requested as `csv`, the download is a `.csv`
file. When a multi-sheet export is requested as `csv`, the download is a `.zip`
file containing one CSV file per worksheet so no worksheet data is dropped.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.fitsociety.io/public/v1/exports/requests" \
    -H "Authorization: Bearer $FITSOCIETY_ACCESS_TOKEN" \
    -H "Idempotency-Key: export-clients-20260714" \
    -H "Content-Type: application/json" \
    -d '{
      "typeId": "company-clients-xlsx",
      "params": {
        "fields": ["firstName", "lastName", "email"]
      },
      "options": {
        "format": "csv",
        "language": "en"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.fitsociety.io/public/v1/exports/requests", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.FITSOCIETY_ACCESS_TOKEN}`,
      "Content-Type": "application/json",
      "Idempotency-Key": "export-clients-20260714",
    },
    body: JSON.stringify({
      typeId: "company-clients-xlsx",
      params: {
        fields: ["firstName", "lastName", "email"],
      },
      options: {
        format: "csv",
        language: "en",
      },
    }),
  });

  const body = await response.json();
  console.log(body.data.exportRequestId);
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.post(
      "https://api.fitsociety.io/public/v1/exports/requests",
      headers={
          "Authorization": f"Bearer {os.environ['FITSOCIETY_ACCESS_TOKEN']}",
          "Idempotency-Key": "export-clients-20260714",
      },
      json={
          "typeId": "company-clients-xlsx",
          "params": {"fields": ["firstName", "lastName", "email"]},
          "options": {"format": "csv", "language": "en"},
      },
  )
  response.raise_for_status()

  body = response.json()
  print(body["data"]["exportRequestId"])
  ```
</CodeGroup>

Response:

```json theme={null}
{
  "data": {
    "exportRequestId": "66f7b8b1e13c8d25f4d3d90a",
    "status": "queued"
  },
  "meta": {
    "requestId": "req_0123456789abcdef",
    "rateLimit": { "limit": 10, "remaining": 9, "resetSeconds": 1 }
  }
}
```

## List export requests

```http theme={null}
GET /public/v1/exports/requests?status=completed,failed&limit=25
Authorization: Bearer <access_token>
```

Required scope: `exports:read`

Query parameters:

| Parameter  | Type    | Required | Rule                                                           |
| :--------- | :------ | :------- | :------------------------------------------------------------- |
| `limit`    | integer | no       | Minimum `1`, maximum `100`.                                    |
| `cursor`   | string  | no       | Use the previous response `nextCursor` to fetch the next page. |
| `status`   | string  | no       | Comma-separated statuses or `in(completed,failed)`.            |
| `typeId`   | string  | no       | Restrict results to one export type.                           |
| `language` | string  | no       | Optional response label language.                              |

Only requests created by the authenticated Public API client are returned.

## Export request fields

`GET /public/v1/exports/requests` returns `data.exportRequests[]`.
`GET /public/v1/exports/requests/{exportRequestId}` returns
`data.exportRequest`.

| Field                     | Type    | Nullable | Description                                                                                                                                                                                       |
| :------------------------ | :------ | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `exportRequestId`         | string  | no       | Export request ID.                                                                                                                                                                                |
| `typeId`                  | string  | no       | Export type identifier.                                                                                                                                                                           |
| `typeLabel`               | string  | no       | Localized export type label.                                                                                                                                                                      |
| `status`                  | string  | no       | `queued`, `running`, `completed`, `failed`, `canceled`, `expired`, or `deleted`.                                                                                                                  |
| `progress`                | number  | yes      | Percent progress when available.                                                                                                                                                                  |
| `rowCount`                | integer | yes      | Number of exported rows when available.                                                                                                                                                           |
| `format`                  | string  | no       | Requested format: `xlsx`, `csv`, `zip`, or an empty string before a format is known.                                                                                                              |
| `paramsSummary`           | string  | no       | Human-readable filter summary. Raw `params` are not exposed.                                                                                                                                      |
| `file.downloadUrl`        | string  | yes      | Signed temporary download URL when the export is completed and the file has not expired or been deleted. Fetch the request again to receive a fresh URL while the export file is still available. |
| `file.format`             | string  | yes      | Download file format. This can be `zip` for multi-sheet CSV requests.                                                                                                                             |
| `file.sizeBytes`          | integer | yes      | File size when known.                                                                                                                                                                             |
| `file.expiresAt`          | string  | yes      | Export file and returned download URL expiry timestamp.                                                                                                                                           |
| `error.code`              | string  | yes      | Public export error code when failed.                                                                                                                                                             |
| `error.message`           | string  | yes      | Generic public failure message. Internal error details are not exposed.                                                                                                                           |
| `createdAt`               | string  | yes      | Creation timestamp.                                                                                                                                                                               |
| `startedAt`               | string  | yes      | Processing start timestamp.                                                                                                                                                                       |
| `completedAt`             | string  | yes      | Terminal timestamp.                                                                                                                                                                               |
| `updatedAt`               | string  | yes      | Last update timestamp.                                                                                                                                                                            |
| `previousExportRequestId` | string  | yes      | Source request when this request was created by retry.                                                                                                                                            |

Example completed request:

```json theme={null}
{
  "data": {
    "exportRequest": {
      "exportRequestId": "66f7b8b1e13c8d25f4d3d90a",
      "typeId": "company-clients-xlsx",
      "typeLabel": "Client List (XLSX)",
      "status": "completed",
      "progress": 100,
      "rowCount": 128,
      "format": "xlsx",
      "paramsSummary": "Fields: 3 selected",
      "file": {
        "downloadUrl": "https://api.fitsociety.io/downloads/exports/example.xlsx",
        "format": "xlsx",
        "sizeBytes": 24576,
        "expiresAt": "2026-07-15T10:00:00.000Z"
      },
      "error": null,
      "createdAt": "2026-07-14T10:00:00.000Z",
      "startedAt": "2026-07-14T10:00:03.000Z",
      "completedAt": "2026-07-14T10:00:15.000Z",
      "updatedAt": "2026-07-14T10:00:15.000Z",
      "previousExportRequestId": null
    }
  },
  "meta": {
    "requestId": "req_0123456789abcdef",
    "rateLimit": { "limit": 10, "remaining": 8, "resetSeconds": 1 }
  }
}
```

## Cancel, retry, and delete

All write actions require `exports:write` and an `Idempotency-Key` header.
Empty request bodies are accepted.

| Endpoint                                                    | Behavior                                                                                                                             |
| :---------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------- |
| `POST /public/v1/exports/requests/{exportRequestId}/cancel` | Cancels a queued or running request created by the authenticated Public API client.                                                  |
| `POST /public/v1/exports/requests/{exportRequestId}/retry`  | Queues a new request with the same params and options. The response returns the new `exportRequestId` and `previousExportRequestId`. |
| `DELETE /public/v1/exports/requests/{exportRequestId}`      | Marks a terminal request as deleted and removes its public file URL. Running requests must be canceled first.                        |

Software-created requests and requests from another Public API client are
returned as not found for these actions.
