Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.unifygtm.com/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Use the Bulk API to request large datasets from Unify without waiting for a long-running HTTP request to finish. The Bulk API is asynchronous: you create a query job, poll the job until it is finished, and then page through the materialized results. Use the Bulk API when you need to export or sync many records. For small operational reads, use the standard API for the resource instead.
The Bulk API is currently in preview. Endpoint behavior, filters, and response shapes may change before general availability.The Bulk API is for requesting data from Unify. To create or update records in Unify, see Send records via API.

Supported resources

The Bulk API currently supports these resources:
ResourceCreate a query jobFetch results
Sequence enrollmentsPOST /sequences/v1/enrollments/jobs/queryGET /sequences/v1/enrollments/jobs/{job_id}/results
Sequence enrollment stepsPOST /sequences/v1/enrollment-steps/jobs/queryGET /sequences/v1/enrollment-steps/jobs/{job_id}/results
You can also list and inspect jobs for each resource:
GET /sequences/v1/{resource}/jobs
GET /sequences/v1/{resource}/jobs/{job_id}
In these paths, {resource} is either enrollments or enrollment-steps.

Authentication

The Bulk API requires a user-backed API key. Generate an API key in Settings → Developers and include it with each request:
X-Api-Key: <YOUR_API_KEY>
All examples use main unify API base URL:
https://api.unifygtm.com

How the Bulk API works

1

Create a query job

Submit a query job for the resource you want to export. The request body is optional and defaults to an empty filter.
curl -X POST 'https://api.unifygtm.com/sequences/v1/enrollments/jobs/query' \
  -H 'X-Api-Key: ${UNIFY_API_KEY}' \
  -H 'Content-Type: application/json' \
The response includes the job_id, current status, and expires_at time:
{
  "job_id": "<string>",
  "status": "IN_PROGRESS",
  "expires_at": "2026-05-13T12:00:00Z"
}
2

Poll job metadata

Poll the job metadata endpoint until the job reaches a terminal status. Avoid tight polling loops; use a steady interval or exponential backoff. Most Jobs should finish within a few seconds.
curl 'https://api.unifygtm.com/sequences/v1/enrollments/jobs/<string>' \
  -H 'X-Api-Key: ${UNIFY_API_KEY}'
A finished job includes total_rows:
{
  "job_id": "<string>",
  "status": "FINISHED",
  "total_rows": 123,
  "error_code": null,
  "created_at": "2026-05-12T12:00:00Z",
  "expires_at": "2026-05-13T12:00:00Z",
  "canceled_at": null
}
3

Fetch results

After the job status is FINISHED, fetch results by page. Results are immutable for a finished job, so each page is stable for that job.
curl 'https://api.unifygtm.com/sequences/v1/enrollments/jobs/<string>/results?page=1&page_size=1000' \
  -H 'X-Api-Key: ${UNIFY_API_KEY}' \
  -H 'Accept: application/json'
{
  "total": 123,
  "page": 1,
  "page_size": 1000,
  "data": [
    {
      "id": "<string>",
      "updated_at": "2026-05-12T11:58:00Z"
    }
  ]
}
4

Store a checkpoint

For recurring syncs, store a checkpoint such as the newest updated_at value you processed. Use that checkpoint in the next query job so you only request new or changed records.

Create a query job

Create-job endpoints are resource-specific:
POST /sequences/v1/enrollments/jobs/query
POST /sequences/v1/enrollment-steps/jobs/query
Use filters to narrow the dataset. For example, you can scope a request to exclude specific set of IDs:
{
  "filter": {
    "id": { "not_in": ["<string>", "<string>"] }
  }
}

Filter fields

Available filter fields depend on the resource. Common filters include:
FilterDescription
updated_atFilter by the time records were last updated.
personFilter by person.
companyFilter by company.
id.inInclude only specific record IDs.
id.not_inExclude specific record IDs.
Bulk API endpoints also support endpoint-specific filters.

Job statuses

A job can have one of the following statuses:
StatusMeaning
IN_PROGRESSThe job has been created and results are still being prepared.
FINISHEDThe job completed successfully and results are available.
FAILEDThe job failed. Check error_code on the job metadata.
CANCELEDThe job was canceled before completion.
EXPIREDThe job or its results are no longer available.
Jobs and results are available until expires_at, which is currently 24 hours after job creation. Download all required result pages before that time.

List jobs

List jobs for a resource:
GET /sequences/v1/{resource}/jobs
Query parameters:
ParameterDescription
limitNumber of jobs to return. Defaults to 100; maximum is 100.
cursorOpaque pagination cursor from the previous response.
statusOptional job status filter.
Example request:
curl 'https://api.unifygtm.com/sequences/v1/enrollments/jobs?limit=100&status=FINISHED' \
  -H 'X-Api-Key: ${UNIFY_API_KEY}'
Example response:
{
  "jobs": [
    {
      "job_id": "<string>",
      "status": "FINISHED",
      "total_rows": 123,
      "error_code": null,
      "created_at": "2026-05-12T12:00:00Z",
      "expires_at": "2026-05-13T12:00:00Z",
      "canceled_at": null
    }
  ],
  "next_cursor": null
}

Fetch results

Fetch results for a finished job:
GET /sequences/v1/{resource}/jobs/{job_id}/results?page=1&page_size=1000
Result pagination is page-based. Rows are ordered by most recently updated first with a stable tie-breaker, so pages remain stable for a finished job.

JSON results

JSON is the default response format:
Accept: application/json
JSON limits:
LimitValue
Default page_size1000
Maximum page_size2000
Maximum raw payload size8 MiB
If a JSON page is too large, request a smaller page_size or use NDJSON.

NDJSON results

Use NDJSON for larger streamed pages by providing the following header in your request.
Accept: application/x-ndjson
Example request:
curl -N 'https://api.unifygtm.com/sequences/v1/enrollments/jobs/<string>/results?page=1&page_size=10000' \
  -H 'X-Api-Key: ${UNIFY_API_KEY}' \
  -H 'Accept: application/x-ndjson'
NDJSON responses return one JSON object per line, streaming one line at a time. Pagination metadata is returned in response headers instead of a JSON envelope:
x-total: 123
x-page: 1
x-page-size: 10000
The maximum NDJSON page_size is 10000.

Job states

The results endpoint validates the job state before returning data:
Job stateHTTP statusError code
IN_PROGRESS409results_not_ready
FAILED409results_failed
CANCELED409results_canceled
Expired410results_expired
Only fetch results after the job status is FINISHED.

Rate limiting

Bulk API rate limits are applied by operation type. Query job creation is limited to roughly 100 jobs per day, so create jobs only when you need a new snapshot and use filters or checkpoints to keep each job focused.
OperationRate limit
Create query jobs~100 jobs per day
query/list job status~10 requests per second
list/stream job results~5 requests per second
cancel in flight jobs~1 request per second
Treat other job management requests, such as checking job status, listing jobs, and canceling jobs, as low-frequency control-plane calls. When polling job status, use a steady interval or exponential backoff instead of a tight loop. Status checks are intended for roughly 5 requests per second, and most jobs finish quickly enough that slower polling is usually sufficient. When fetching results, page through data with bounded concurrency. If you receive 429 Too Many Requests, wait before retrying, honor the Retry-After header to avoid additional rate limiting.

Best practices

  • Request only the data you need. Use filters to keep result sets small and exports fast.
  • Prefer incremental syncs. Use checkpoints such as updated_at so recurring jobs only request new or changed records.
  • Design for retries. Store the job_id, job status, and processing checkpoint in your system.
  • Process results idempotently. Use stable record IDs so retrying a page does not create duplicate downstream records.
  • Use NDJSON for large pages. NDJSON streams results and supports larger pages than JSON.
  • Download before expiration. Jobs expire at expires_at; create a new job if you need the data again after expiration.

What’s next

Data API reference

Review the Data API for object, attribute, and record operations.

Send records via API

Learn how to create and update records in Unify.