WarpLink
API Reference

Exports

Exports endpoints to start a click export for an organization or one link, poll its status, and download the identical CSV file as often as you need.

A click export is a background job. You start it with one request, watch its status, and download the finished file when it is complete, so a large export never times out a request. Every export is a snapshot: it holds the clicks that were committed when the job was cut, minus any click deleted before its page was read. A click that arrives later is never in it. Running the same request again creates a new job with a new snapshot, and its file can differ.

Authentication and Permissions

Exports use an API key with the analytics:read or links:read scope. SDK keys are refused with 403 KEY_TYPE_FORBIDDEN, and an SDK key tied to one app is refused the same way it is on every other route. A member sees the organization's export jobs by default. Free organizations can export even when analytics is gated.

Start an Export

POST/exports

Start a click export

Starts a background job that exports click rows for the organization, or for one link. The export is a snapshot: it holds the clicks committed when the job was cut. Requires an API key with the analytics:read or links:read scope. SDK keys are refused. Poll the job with GET /exports/{id}, then download the file.

Request Body

FieldTypeDescription
since*stringStart of the window, inclusive.
until*stringEnd of the window, exclusive. Must be after since.
link_idstringExport the clicks of one link. Omit to export the whole organization.
job_idstringA job id you generate. Repeating the request with the same id and body returns the same job.

Responses

202The job was created
FieldTypeDescription
job*objectA click export job and its manifest. The same object is returned when the job is created, while it runs, and after it completes.
400Invalid request, including a body that is not valid JSON
FieldTypeDescription
error*object
401Unauthorized
FieldTypeDescription
error*object
403Forbidden
FieldTypeDescription
error*object
404Not found
FieldTypeDescription
error*object
409The job_id was already used for a different request (code EXPORT_JOB_ID_CONFLICT), the organization already has an export running (code EXPORT_IN_PROGRESS), or its stored exports are at their size limit (code EXPORT_QUOTA_EXCEEDED)
FieldTypeDescription
error*object
422No part of the requested window is within your plan's data retention (code RETENTION_WINDOW_UNAVAILABLE). No job is created.
FieldTypeDescription
error*object
503Exports are not available yet (code EXPORTS_UNAVAILABLE). Retry later.
FieldTypeDescription
error*object

The window is clipped once to your plan's data retention, and the response shows the window that was actually exported in window_from and window_to. A window that lies wholly before your plan's retention has nothing to export: the request returns 422 RETENTION_WINDOW_UNAVAILABLE and creates no job. Send your own job_id to make the request safe to repeat: the same id with the same body returns the same job, and the same id with a different body returns 409 EXPORT_JOB_ID_CONFLICT.

An organization has one export in flight at a time. While a job is created, cut or running, starting another returns 409 EXPORT_IN_PROGRESS; start the next one after the first is complete or failed. An organization whose unexpired exports already hold 10 GB of stored files gets 409 EXPORT_QUOTA_EXCEEDED until older exports expire. Neither refusal creates a job.

Get an Export

GET/exports/{id}

Get an export job

Returns the job status and manifest. A job that does not exist and a job in another organization both return 404.

Parameters

NameTypeInDescription
id*stringpath

Responses

200The export job
FieldTypeDescription
job*objectA click export job and its manifest. The same object is returned when the job is created, while it runs, and after it completes.
400Invalid ID
FieldTypeDescription
error*object
401Unauthorized
FieldTypeDescription
error*object
403Forbidden
FieldTypeDescription
error*object
404Not found
FieldTypeDescription
error*object
503Exports are not available yet (code EXPORTS_UNAVAILABLE). Retry later.
FieldTypeDescription
error*object

A job moves through created, cut, running, and then complete or failed. There is no expired status: a job is expired once expires_at has passed. A job that does not exist and a job in another organization both return 404.

Download an Export

GET/exports/{id}/download

Download an export file

Streams the CSV file of a complete export. Every download returns identical bytes. The error body of a refusal carries the manifest in details.manifest. A job past its expires_at returns 410 whatever its status.

Parameters

NameTypeInDescription
id*stringpath

Responses

200The CSV file
400Invalid ID
FieldTypeDescription
error*object
401Unauthorized
FieldTypeDescription
error*object
403Forbidden
FieldTypeDescription
error*object
404Not found
FieldTypeDescription
error*object
409The export failed (code export_failed) or is not ready yet (code export_not_ready)
FieldTypeDescription
error*object
410The export has expired (code export_expired)
FieldTypeDescription
error*object
503The stored file is temporarily unavailable, or exports are not available yet (code EXPORTS_UNAVAILABLE). Retry.
FieldTypeDescription
error*object

Downloads follow one rule, checked in this order:

ConditionResponse
expires_at has passed, whatever the status410 export_expired with the manifest
The job failed409 export_failed with the manifest
The job is not complete yet409 export_not_ready
The job is complete and unexpired200 with the CSV file

Every download of a complete job returns identical bytes. The ETag header and the manifest sha256 are the SHA-256 of the whole file.

Worked Example

Poll GET /v1/exports/{id} until status is complete, then save the file:

On this page