Create Export

​

Create a CSV export job for filtered entities.

This endpoint kicks off an asynchronous export job that streams the filtered entity set to a CSV file in object storage. Small result sets may complete synchronously; larger sets are dispatched to a background worker via NATS and the client polls the status endpoint.

Args: request: Export configuration including: - filter: FilterRequest used to scope the export (same shape as /filter) - columns: Optional column selection / ordering for the CSV - fileName: Optional filename for the produced CSV user: Authenticated user information (used for audit and ownership)

Returns: ExportJobResponse containing: - jobId: Unique identifier used to poll the export status - status: Current job status (queued, running, completed, failed) - downloadUrl: Populated once the export is ready - expiresAt: When the download URL stops being valid

Note: - Returns HTTP 202 (Accepted) — the response represents a job, not the file - The CSV neutralizes formula prefixes (=, +, -, @, \t, \r) on both headers and cells to prevent spreadsheet injection - FK / array-of-id columns are resolved to display values automatically

Raises: HTTPException: - 401: Authentication required - 403: Account user not found for this tenant - 503: Export pipeline unavailable (no NATS sender) - 500: Internal server error while enqueueing the job

Body·

required
application/json
  • Filter applied to the export, mirroring /filter

    Properties: 6
  • Display labels paired with columns, in the same order. When supplied, the worker writes these verbatim as the CSV header row so the CSV matches what the user sees in the UI; when omitted, the worker falls back to the per-account *_fields.label lookup.

  • Ordered list of field_keys. Defaults to the entity's full output model.

  • Per-column raw-value → display-label maps, supplied by the frontend for columns whose UI renders an enum/int as a human string (e.g. service duration 2 → "1 Year"). Shape: {column_key: {str(raw_value): label}}. The worker writes the mapped label verbatim and falls back to default cell formatting when the column has no map or the raw value isn't in it. Keeping these mappings in the UI avoids duplicating webapp i18n strings in the backend (CRM-129 translations stay in one place).

    Properties: 1
  • Resolve FK references for export rows

  • Sort spec mirroring /filter; worker appends id ASC tiebreaker

    Properties: 1

Responses

  • application/json
  • application/json
Request Example for post/export
curl https://crm.dreamhub.ai/api/v1/users/export \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --data '{
  "filter": {
    "filters": {
      "and": [
        {
          "field": "status",
          "operator": "eq",
          "value": 1
        },
        {
          "field": "deal_value_amount",
          "operator": "gte",
          "value": 50000
        },
        {
          "or": [
            {
              "field": "region",
              "operator": "in",
              "value": [
                "EMEA",
                "NA"
              ]
            },
            {
              "field": "owner_id",
              "operator": "eq",
              "value": "u-abc-123"
            }
          ]
        }
      ]
    },
    "aggregations": {
      "avg_amount": {
        "field": "deal_value_amount",
        "operation": "avg"
      },
      "entity_count": {
        "field": "id",
        "operation": "count"
      },
      "max_amount": {
        "field": "deal_value_amount",
        "operation": "max"
      },
      "total_value": {
        "field": "deal_value_amount",
        "operation": "sum"
      }
    },
    "sort": [
      {
        "direction": "desc",
        "field": "deal_value_amount"
      },
      {
        "direction": "asc",
        "field": "created_at"
      }
    ],
    "search": {
      "case_sensitive": false,
      "fields": [
        "name",
        "description"
      ],
      "operator": "and",
      "term": "enterprise license"
    },
    "comparePeriod": "last30Days",
    "compareCustomStart": ""
  },
  "sort": [
    {
      "additionalProperty": "anything"
    }
  ],
  "columns": [
    ""
  ],
  "columnLabels": [
    ""
  ],
  "columnValueLabels": {
    "additionalProperty": {
      "additionalProperty": ""
    }
  },
  "fullyResolved": true
}'
{
  "id": "string",
  "entityType": "string",
  "status": "queued",
  "attachmentId": "string",
  "rowCount": 1,
  "errorCode": "string",
  "createdAt": "2026-09-29T00:03:31.393Z",
  "completedAt": "2026-09-29T00:03:31.393Z",
  "actions": [
    "string"
  ]
}