Export an Audience to S3, Email, or Slack

Use Case

  • Deliver a saved audience to your own S3 bucket on a schedule (e.g. daily)
  • Send the same file to teammates by email or to a Slack channel instead
  • Control the record type, file format, and exact columns in the output

A scheduled export has two parts: an integration (the destination, set up once) and an export (what to send and when, pointed at that integration). This recipe creates an S3 integration, then a daily export to it, then shows the email and Slack variants.

Prerequisites

  • Organization API key + secret pair (Authentication). Create one at https://app.delivr.ai/{org_id}/settings/api-keys.
  • A project id (the workspace the export lives in).
  • An audience id to export (Intent Audiences API).
  • For S3: a bucket and an IAM access key with write access to it.

Steps

1. Create the S3 Integration

Create the destination once. The organization comes from your key; pass the project as project_id. Credentials are write-only: they are stored encrypted and never returned.

curl -X POST "https://api.delivr.ai/api/v1/integrations?project_id=YOUR_PROJECT_ID" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Api-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "s3",
    "name": "Warehouse bucket",
    "region": "us-west-2",
    "bucket_name": "my-company-exports",
    "access_key_id": "AKIAEXAMPLE0123456789",
    "secret_access_key": "your-aws-secret-access-key",
    "prefix": "delivr/audiences",
    "path_format": "date",
    "file_format": "csv"
  }'

The response is the created integration. Note its id; the export references it.

{
  "id": "b7c4e2a1-9f3d-4c8e-a1b2-3c4d5e6f7a8b",
  "organization_id": "0a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "project_id": "YOUR_PROJECT_ID",
  "type": "s3",
  "name": "Warehouse bucket",
  "config": { "settings": { "bucket_name": "my-company-exports", "region": "us-west-2", "prefix": "delivr/audiences", "path_format": "date", "file_format": "csv" } },
  "has_credentials": true,
  "enabled": true,
  "created_at": "2026-06-25T18:00:00Z",
  "updated_at": "2026-06-25T18:00:00Z"
}

2. Create the Export

Create a daily export that draws from your audience and delivers to the integration from step 1. The query selects what to send; the destination says where and in what shape.

curl -X POST "https://api.delivr.ai/api/v1/exports" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Api-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "YOUR_PROJECT_ID",
    "name": "Daily warehouse drop",
    "query": {
      "sourceType": "audience",
      "sourceId": "YOUR_AUDIENCE_ID"
    },
    "schedule": "daily",
    "run_time": "09:00",
    "destination": {
      "type": "s3",
      "integration_id": "b7c4e2a1-9f3d-4c8e-a1b2-3c4d5e6f7a8b",
      "record_type": "contacts_only",
      "file_format": "csv",
      "fields": ["first_name", "last_name", "email", "company_domain"],
      "array_transform": "comma",
      "combine_output": true
    }
  }'

The response contains both the created export and its destination:

{
  "export": {
    "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
    "name": "Daily warehouse drop",
    "schedule": "daily",
    "run_time": "09:00",
    "status": "active",
    "enabled": true,
    "created_at": "2026-06-25T18:01:00Z",
    "updated_at": "2026-06-25T18:01:00Z"
  },
  "destination": {
    "id": "d4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f80",
    "export_id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
    "type": "s3",
    "status": "active",
    "enabled": true
  }
}

The export now runs every day at 09:00 UTC and writes a CSV to s3://my-company-exports/delivr/audiences/<date>/.


Destination Config Reference

All file-delivery destinations (s3, email, slack) share these fields:

FieldWhat it does
record_typeWhat each output record encodes: hem, uid2, raw_events, raw_logs, contacts_only, ip, domain, or maid. The value valid for a given export depends on its source (here, contacts_only for an audience export; raw_events for a pixel / DSP event export).
file_formatcsv, json, jsonl, or parquet.
fieldsOutput column allow-list. Omit to use the default set for the record type.
array_transformHow to render a multi-value field in one cell: first, comma, pipe, semicolon, json, or count. Defaults to first.
filename_templateOverride the generated filename.

S3 and email add two file-write options (not available on Slack):

FieldWhat it does
combine_outputCombine a multi-window run into one file. Not allowed with parquet.
emit_empty_fileDeliver a file even when there are zero records.

S3 also adds prefix and path_format (flat, date, or project).


Variations

Email the File

Use an email integration (recipients are configured on the integration in the dashboard). Same delivery fields, plus an optional subject_template:

"destination": {
  "type": "email",
  "integration_id": "YOUR_EMAIL_INTEGRATION_ID",
  "record_type": "contacts_only",
  "file_format": "csv",
  "fields": ["first_name", "last_name", "email", "company_domain"],
  "subject_template": "Daily audience export"
}

Post to Slack

Use a slack integration (the channel is configured on the integration):

"destination": {
  "type": "slack",
  "integration_id": "YOUR_SLACK_INTEGRATION_ID",
  "record_type": "contacts_only",
  "file_format": "csv"
}

Weekly Instead of Daily

Set schedule to weekly and add run_day_of_week (0 = Sunday … 6 = Saturday):

"schedule": "weekly",
"run_day_of_week": 1,
"run_time": "09:00"

Cap the Row Count

Add a top-level record_limit to the export (max 10,000,000):

"record_limit": { "maxRecords": 50000, "failMode": "soft" }

failMode decides what happens when the export has more records than the cap:

ValueBehavior
soft (default)Deliver up to the limit and mark the run partial.
hardCheck the count first and abort if it is over the limit, delivering nothing.

Use hard when a truncated file is worse than no file, for example when the recipient treats each delivery as a complete list.

Send One Export to Several Destinations

An export can deliver to up to 5 destinations at once, for example the S3 bucket above plus a Slack channel for the team. Add the rest at create time with additional_destinations (same shape as destination, one saved integration each):

{
  "project_id": "YOUR_PROJECT_ID",
  "name": "Daily warehouse drop",
  "query": { "sourceType": "audience", "sourceId": "YOUR_AUDIENCE_ID" },
  "schedule": "daily",
  "run_time": "09:00",
  "destination": {
    "type": "s3",
    "integration_id": "b7c4e2a1-9f3d-4c8e-a1b2-3c4d5e6f7a8b",
    "record_type": "contacts_only",
    "file_format": "csv"
  },
  "additional_destinations": [
    {
      "type": "slack",
      "integration_id": "YOUR_SLACK_INTEGRATION_ID",
      "record_type": "contacts_only",
      "file_format": "csv"
    }
  ]
}

The response's destination is the S3 row (the primary, "primary": true); additional_destinations holds the rest.

To add a destination to an export that already exists, call POST /api/v1/exports/{id}/destinations with one destination instead of resending the whole export:

curl -X POST "https://api.delivr.ai/api/v1/exports/YOUR_EXPORT_ID/destinations" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Api-Secret: YOUR_API_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "slack",
    "integration_id": "YOUR_SLACK_INTEGRATION_ID",
    "record_type": "contacts_only",
    "file_format": "csv"
  }'

Every destination on an export is delivered as part of the same run, and the run is billed once for the data, not once per destination. When the destinations use different products, the run is billed at the highest-priced one, for the largest record count any billable destination received. DelivrDSP destinations are never billed as data.

additional_destinations is only accepted alongside destination on create; use POST /api/v1/exports/{id}/destinations to add to an export afterward. An export can have at most 5 destinations, each on a different connection. A marketplace destination cannot be combined with any other destination, and a DelivrDSP destination can only be an export's first destination.


Notes

  • One call creates both the export and its destination, so you never get an export with nowhere to deliver. Create the integration first; the export references it by integration_id.
  • Credentials (access_key_id, secret_access_key) are write-only. List and get responses return has_credentials: true instead of the secret.
  • Export names are unique within a project; a duplicate returns 409.
  • An export's first destination is its "primary" ("primary": true in responses).
  • The project_id and the destination's integration_id must both belong to your key's organization, or the call returns 400.
  • Email (recipients) and Slack (OAuth) integrations are set up in the dashboard; S3 and DelivrDSP authenticate with credentials and can be created via the Integrations API.

Next Steps


Did this page help you?