---
title: "Create data_export"
method: POST
path: "/data-exports"
tags: ["data-exports"]
---

# Create data_export

`POST /data-exports`

## Request

- Base URL: `https://api.cogram.com/v1`
- URL: `https://api.cogram.com/v1/data-exports`
- Auth: HTTP bearer

Create a new data_export in PENDING and enqueue the build worker.

Pass ``project_ids`` to scope the export to those projects (list
candidates via ``GET /v1/projects``); omit it for an org-wide export,
which is capped at a 6-month range. Any project the API key's org
doesn't own returns 404 — same as an unknown one, and the whole
request is rejected rather than exporting the subset that resolved.

The build is asynchronous — poll ``GET /v1/data-exports/{id}`` for status
and (once ``status == "completed"``) freshly-signed download URLs
for each part.

## Request body

- DataExportCreateRequest: Body for ``POST /data_exports`` (both UI and external API). Cap rule is **not** enforced by Pydantic — call ``validate_cap_rule()`` explicitly from the service so the structured ``CapRuleViolation`` can propagate cleanly to the router (Pydantic would otherwise wrap it in a ``ValidationError`` and surface a 422 with the wrong shape).
  - `project_ids` string[], nullable: Project KSUIDs to scope the data_export to. Omit for an org-wide data_export, which carries the 6-month cap. Duplicates are collapsed.
  - `project_id` string, nullable: Deprecated single-project form of `project_ids`.
  - `time_filter` union, required: Discriminated-union wrapper so the JSONB column can use ``PydanticJsonbType``. Stored shape mirrors ``root`` directly (``RootModel`` serializes without a wrapping field), e.g. ``{"mode": "range", "start": ..., "end": ...}``.
    - TimeRangeFilter: Closed time range. Both bounds timezone-aware; ``end`` must be >= ``start``.
      - `mode` 'range'
      - `start` string, date-time, required: Inclusive. Must be timezone-aware.
      - `end` string, date-time, required: Inclusive. Must be timezone-aware.
    - AllTimeFilter: All available data, no time bound. Only valid for project-scoped data_exports (one or more ``project_ids``).
      - `mode` 'all_time'
  - `document_formats` string[]: Rendered document formats to emit per field report and observation, alongside the JSON. Empty (the default) ships metadata and raw blobs only. Does not affect `meeting.docx`, which every export includes. Rendering makes a build slower and its zip larger.

## Response `201`

Successful Response

- DataExportResponse: Full read shape returned by ``GET /data_exports`` and ``GET /data_exports/{id}``. ``parts`` is empty until the data_export reaches ``COMPLETED``. Even after ``EXPIRED``, the row remains as an audit record — clients distinguish "downloadable" from "audit-only" via the ``status`` field.
  - `id` string, required
  - `organization_id` string, required
  - `source` 'ui' | 'api', required
  - `requester_user_id` string, nullable, required: `ui` source only.
  - `requester_api_key_id` string, nullable, required: `api` source only.
  - `requester_api_key_name` string, nullable, required: `api` source only. Prefer this over parsing `requester_display`.
  - `requester_forwarded_user` string, nullable, required: `X-Forwarded-User` header value at create time.
  - `requester_display` string, required: Human-readable attribution: the user's name (their email if the name is empty), `API key '<name>'`, or `<forwarded_user> (via API key '<name>')`. Degrades to `<forwarded_user> (via deleted API key)` or `unknown` when the linked user or key row was deleted after the export was created.
  - `project_ids` string[], required: Scope as requested — empty for org-wide exports. Retains ids of projects deleted after the export was created, so `projects` may be shorter.
  - `projects` DataExportProjectRef[]: Scope projects that still exist, in `project_ids` order.
    - `id` string, required
    - `name` string, required
    - `customer_project_id` string, nullable, required: Customer's own project label. Not unique — use `id` for identity.
  - `project_id` string, nullable, required: Set only for single-project exports; null otherwise.
  - `project_name` string, nullable: Set only when `project_id` is set.
  - `project_customer_id` string, nullable: Customer's own project label. Not unique — use `project_id` for identity.
  - `time_filter` union, required: Discriminated-union wrapper so the JSONB column can use ``PydanticJsonbType``. Stored shape mirrors ``root`` directly (``RootModel`` serializes without a wrapping field), e.g. ``{"mode": "range", "start": ..., "end": ...}``.
    - TimeRangeFilter: Closed time range. Both bounds timezone-aware; ``end`` must be >= ``start``.
      - `mode` 'range'
      - `start` string, date-time, required: Inclusive. Must be timezone-aware.
      - `end` string, date-time, required: Inclusive. Must be timezone-aware.
    - AllTimeFilter: All available data, no time bound. Only valid for project-scoped data_exports (one or more ``project_ids``).
      - `mode` 'all_time'
  - `document_formats` string[], required: Echo of the request. Typed loosely so a row written by a newer deployment, carrying a format this one does not know, still serializes instead of failing the whole listing.
  - `status` 'pending' | 'running' | 'cancelling' | 'cancelled' | 'completed' | 'failed' | 'expired', required
  - `error` string, nullable, required: Set when `status` is `failed`.
  - `requested_at` string, date-time, required
  - `started_at` string, date-time, nullable, required
  - `completed_at` string, date-time, nullable, required: Also set on failure and cancellation.
  - `expires_at` string, date-time, nullable, required: Parts are deleted at this time, 7 days after completion.
  - `parts` DataExportPartResponse[]: Zip parts with signed URLs. Empty until `status` is `completed`.
    - `id` string, required
    - `part_index` integer, required: Zero-indexed.
    - `size_bytes` integer, required: Compressed size.
    - `signed_url` string, required: Pre-signed, valid 1 hour. Re-fetch on each read, never cache.

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `404`: Not found
- `409`: Conflict
- `422`: Validation error
- `429`: Rate limit exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/cogram/apis/cogram-api.md) · [All operations](https://skmtc.dev/cogram/apis/cogram-api/llms.txt) · [OpenAPI document](https://skmtc.dev/cogram/apis/cogram-api/revisions/5a3c9c40fca5?raw)
