API Updates - March 2026
Exports
Record Limits for Exports and Audience Downloads
Set a maximum number of records returned when downloading audiences or creating/updating exports. The record_limit field accepts a structured object with a cap and a failure mode. To clear a previously set limit on an existing export, set record_limit to null in the update payload.
POST /api/v1/exports
PUT /api/v1/exports/{id}
GET /audiences/{id}/download
Parameters (Export create/update body):
record_limit(object, optional). Controls max records in export output.maxRecords(int64, 1 to 10,000,000). Maximum records to include.failMode(string). Behavior when the limit is exceeded.
Parameters (Audience download query):
project_id(string, required). Workspace project ID.record_limit(int, optional, 0 to 10,000,000). Max records to return. Pass0to clear.
Example (set a record limit on export creation):
curl -X POST https://apiv3.delivr.ai/api/v1/exports \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Weekly CRM sync",
"record_limit": {
"maxRecords": 50000,
"failMode": "truncate"
}
}'Example (clear a record limit):
curl -X PUT https://apiv3.delivr.ai/api/v1/exports/exp_abc123 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"record_limit": null}'DSP List Name Preservation
When exporting an audience to DelivrDSP, the audience name is automatically used as the DSP list name. Override with a custom name using the list_name field.
POST /api/v1/exports
Parameters (body):
list_name(string, optional). Custom DSP list name. Defaults to the audience name if omitted.
Per-Record Export Error Details
Export run responses now include a breakdown of results by CRM object type. The object_type_results map provides per-object success/failure counts and individual error messages for failed records.
GET /api/v1/exports/{id}/runs
GET /api/v1/exports/{id}/runs/{run_id}
Response fields (on export run objects):
records_total(int64). Total records processed.records_exported(int64). Successfully exported records.records_failed(int64). Failed records.records_duplicated(int64). Duplicate records skipped.object_type_results(map[string]object). Per-object-type breakdown, keyed by object name (e.g.,"Contact","Lead"):object_type(string). CRM object type name.records_created(int64). New records created.records_updated(int64). Existing records updated.records_failed(int64). Records that failed.records_skipped(int64). Records skipped.operation(string). Operation performed.error_message(string). Error detail for failures.
Example response:
{
"run_id": "run_xyz789",
"status": "completed_with_errors",
"records_total": 5000,
"records_exported": 4950,
"records_failed": 50,
"object_type_results": {
"Contact": {
"object_type": "Contact",
"records_created": 3200,
"records_updated": 1700,
"records_failed": 45,
"records_skipped": 5,
"operation": "upsert",
"error_message": "REQUIRED_FIELD_MISSING: Email is required"
}
}
}CRM Field Mapping
Field Constraints and Normalization
CRM exports now validate and normalize field values before pushing to the destination. Each field can have a maximum character length, required flag, allowed picklist values, and type-specific formatting.
Validation error codes:
REQUIRED_FIELD_MISSING. A required field has an empty value.STRING_TOO_LONG. Value exceeds the field'smaxLength(measured in Unicode runes, not bytes).MULTI_VALUE_TOO_LONG. A multi-value/array field exceeds the destination's length limit after flattening. Previously these were silently truncated.INVALID_PICKLIST_VALUE. Value is not in the allowed picklist (case-insensitive comparison).INVALID_EMAIL_FORMAT. Email field missing@or..
Breaking change: Multi-value fields that exceed the destination's character limit now return a MULTI_VALUE_TOO_LONG error instead of being silently truncated. Update your field mappings or reduce the number of values to stay within limits.
Normalization behavior:
- String values are truncated to
maxLengthin a Unicode-safe manner (rune-based, not byte-based). - Configurable default values are applied when a field is empty.
HubSpot Contact Write with Auto-Created Companies
HubSpot exports now automatically create or attach company records when writing contacts. If a contact's company_domain matches an existing HubSpot company, that company is linked. If no match exists, a new company is created.
Pixel activity from Delivr is also written to the contact's HubSpot timeline, surfacing on-site behavior natively in HubSpot's contact view. No additional configuration is required for existing HubSpot integrations. This behavior is enabled automatically on the next sync.
Audiences and Lists
Bulk Delete for List Uploads
Remove multiple list uploads in a single request.
DELETE /api/v1/lists/batch
Request body:
ids(string[], required). Array of list IDs to delete. Maximum 1,000 items per request.
Response:
{
"deleted_count": 3
}Type and Source Filters on List Uploads
Filter list upload results by upload type and originating source.
GET /api/v1/lists
Query parameters:
type(string, optional). Filter by list type.source(string, optional). Filter by originating source.limit(int, optional, default 25, max 1000). Results per page.offset(int, optional). Pagination offset.
Audience Preview Limit
The audience preview endpoint now accepts a limit query parameter to control the maximum number of preview rows returned, useful when previewing very large audiences.
GET /api/v1/audiences/{id}/preview
Query parameters:
limit(int, optional). Maximum number of preview rows to return.
DSP Reporting
Campaign Match Rates
DelivrDSP campaign responses now include match rate data showing how many exported contacts were matched by the DSP.
GET /api/v1/campaigns/{campaign_id}/match-rates
Response:
match_rate(float64). Overall match rate as a decimal (e.g.,0.85for 85%).identifiers_count(int64). Total identifiers sent.matched_count(int64). Identifiers successfully matched.contacts_total(int64). Distinct contacts in the campaign.lists(array). Per-list match breakdown.
Daily Campaign Performance
DelivrDSP campaign performance is now persisted with per-day granularity. Daily delivery, spend, and CPM trends are available through the campaign performance endpoints, alongside the existing cumulative totals.
Privacy and Compliance
UID2 Opt-Out Webhook
A new public webhook endpoint accepts UID2 opt-out notifications. When a user opts out through the UID2 framework, their record is added to a unified privacy opt-out registry with a full audit log. This endpoint does not require JWT authentication.
GET /api/v1/uid2/optout
POST /api/v1/uid2/optout
Both methods are supported to accommodate different UID2 operator configurations.
Query parameters:
user(string, required). UID2 user identifier.optouttime(string, required). ISO 8601 timestamp of the opt-out event.
Response:
204 No Contenton success.
Pixel Collection
Cookieless Mode
Organizations can enable cookieless pixel collection through the organization settings API. When cookies_enabled is set to false, pixels deployed for that organization will not set or read browser cookies. Existing pixels are regenerated automatically to reflect the new mode on the next pixel update cycle.
PUT /api/v1/organizations/{id}/settings
Parameters (body):
cookies_enabled(bool). Set tofalseto enable cookieless mode. Defaults totrue.
Custom Fields in Pixel Events
Pixel event payloads now include source-level custom fields in the event_data object. This allows richer context from pixel sources to flow into downstream processing.
POST /pixel/core/api/send-event
Request body:
pixel_id(string, required). Pixel identifier.organization_id(string, required). Organization ID.event_type(string, required). Event type.event_data(object, optional). Flexible JSON payload. Now includes source-level custom fields alongside standard fields:- Geo:
country,region,city, coordinates. - Device:
type,os,browser. - Content:
title,url,category. - Pricing:
price,currency. - Custom: Any additional key-value pairs defined on the pixel source.
- Geo:
Bug Fixes
-
Export creation with incomplete workspace context. Fixed an issue where export creation could fail with an empty identifier when the workspace context was not fully resolved. The API now returns a
400with a descriptive error. -
Email integration test credential error. Fixed email integration test connections returning a credential decryption error.
-
Audience downloads for export-generated lists. Fixed audience downloads failing for lists that were generated by export runs.
-
Campaign sync account filtering. Fixed campaign sync not filtering results by the correct account.
-
Campaign budget and CPM null values. Fixed campaign
budgetandcpmvalues being stored asnullwhen syncing from DelivrDSP. -
record_countfield type. Fixed therecord_countfield being returned as the wrong type in event ingestion responses. -
Contact database filter casing. Fixed contact database filters using incorrect field name casing.
-
Sync history stuck as RUNNING. Fixed sync history records staying in
RUNNINGstate when the dashboard tab disconnected mid-sync. -
Empty UUID handling. Fixed empty-string UUID fields being treated as valid IDs in handler responses.
For full endpoint details, parameters, and examples, see our developer documentation.