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

# Export a one-off audience to CSV without saving a segment

> Download the contacts matching an ad-hoc filter as a CSV — no segment row, no scheduled refresh — and know when a saved segment export is the better tool.

# Ad-hoc audience CSV export

A saved segment is the right home for an audience you target repeatedly. But sometimes you need the rows behind a filter exactly once — a compliance spot-check, a partner handoff, an analyst's exploratory pull — and creating a segment purely to hold a transient membership is noise. The ad-hoc export endpoint resolves your filter live against your contacts and hands you the CSV directly: nothing is persisted, nothing waits on a refresh schedule.

## Ad-hoc vs. saved segment export

Two CSV export surfaces exist; pick by how long the audience needs to live.

|                      | Ad-hoc export                              | Saved segment export                              |
| -------------------- | ------------------------------------------ | ------------------------------------------------- |
| Endpoint             | `POST /api/v1/segments/export.csv`         | `GET /api/v1/contacts/segments/:id/export.csv`    |
| Audience source      | Filter AST in the request body             | A persisted segment's materialized membership     |
| Wait before download | None — the filter resolves at request time | First export waits on the segment's refresh cycle |
| Row ceiling          | 50,000                                     | 500,000 (streamed)                                |
| Audit record         | One entry per download                     | One entry per download                            |

Rule of thumb: if you would delete the segment right after downloading, use the ad-hoc export.

## Authentication and permissions

PII bulk pulls are privileged, and this endpoint gates exactly like the saved export:

* The caller must hold an **owner, admin, or developer** role.
* The API key must carry the **`contacts:write`** scope. Viewer roles and `contacts:read`-only keys are rejected with a 403.
* Exports are rate-limited to **5 requests per minute**, and every download — row counts included — is written to your audit log (`segment.audience_exported`).

## Request shape

The body carries the same Filter AST the segment builder and `POST /api/v1/segments/auto-suggest` produce — fields come from the segment filter allowlist, and groups nest up to three levels deep.

```bash theme={null}
curl -X POST https://api.orbit.devotel.io/api/v1/segments/export.csv \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -o enterprise-no-consent.csv \
  -d '{
    "filters": {
      "and": [
        { "field": "custom_attribute.plan_tier", "op": "equals", "value": "enterprise" },
        { "field": "sms_optin", "op": "equals", "value": false }
      ]
    },
    "limit": 10000,
    "filename": "enterprise-no-consent"
  }'
```

| Field      | Required | Description                                                                                                                                                              |
| ---------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `filters`  | yes      | The audience definition — the Filter AST shape documented under [build a segment](/guides/cdp-segments).                                                                 |
| `limit`    | no       | Row cap below the 50,000 ceiling (`1`–`50,000`), clamped server-side. Useful for a quick sample.                                                                         |
| `filename` | no       | Filename stem for the download (sanitized, truncated at 80 characters). A date suffix is appended, so the example above lands as `enterprise-no-consent-2026-08-26.csv`. |

### Row cap and truncation

A single ad-hoc export resolves at most **50,000 rows** (unlike the saved export, which streams up to 500,000). If the filter reaches the cap, the response still succeeds with the first 50,000 rows and sets the **`X-Export-Truncated: true`** response header — check that header whenever the row count matters. To pull more than the cap, persist the audience as a segment and use the saved export path.

## CSV columns and PII visibility

One row per matched contact, with this header row:

```
contact_id,first_name,last_name,email,phone,country_code,lifecycle_stage,tags,created_at
```

Every row passes through the same PII visibility rules as the saved export and the dashboard: **the `phone` and `email` columns are masked or revealed to match what the caller's role and reveal context would see in the UI.** An owner with an active reveal gets full values; a caller without one gets masked values. A CSV pulled by two different callers can differ in exactly those columns — never assume a second pull by another teammate will match byte-for-byte.

## Use cases

* **GDPR ingest verification.** After a bulk import, export "contacts created in the last hour with missing consent fields" and confirm the ingest mapped them before anything downstream picks them up.
* **Partner handoff.** A partner asks for a segment of your audience once. Send the filter, get the CSV, delete nothing because you never created anything.
* **Exploratory analysis.** An analyst iterating on a filter — preview the size with `POST /api/v1/contacts/segments/preview`, then pull the rows to a spreadsheet the moment the definition is right.

## When to save the segment instead

Materialize a real segment — `POST /api/v1/contacts/segments` — when the audience has a future, because several downstream surfaces only read saved segments:

* **Scheduled refresh.** `auto_refresh` keeps membership current on a schedule (12 hours up to monthly), so exports and campaigns track a moving population without re-sending the filter.
* **Campaigns and flows.** Targeting, enroll-on-entry, and suppression all reference a segment id; a one-shot export cannot.
* **Ad-network activation.** Audience sync to Meta, Google, TikTok, and the other supported platforms pushes a saved segment.
* **Above-cap or repeat downloads.** The saved export streams over the 50,000-row ad-hoc ceiling, and re-downloading a saved segment skips re-resolving the filter.

Anything else — once, exploratory, or throwaway — belongs on the ad-hoc path.

## See also

* [CDP audiences](/guides/cdp-segments) — build and save segments, computed traits, and ad-network activation
* [Segments API reference](/api-reference/segments) — full endpoint list for segments, exports, and overlap
* [Import contacts](/guides/import-contacts) — the ingest side of the GDPR verification flow above
