Skip to main content

Release Notes

Follow new updates and improvements to Delivr.ai.

API Updates - August 2026

Audiences

Audience definitions and downloads picked up several changes this month that affect how you build, poll, and read them over the API.

AND/OR grouping across list filters

List-based filters in an audience definition now carry real boolean grouping. The condition marker on a list group is read when the definition is transformed, so you can express combinations such as two lists matched with OR and a third required with AND in a single audience. Send it on POST /api/v1/audiences or PUT /api/v1/audiences/{id}, and read it back from GET /api/v1/audiences/{id}.

Download preparation stages and progress

GET /api/v1/audiences/{id}/download now reports normalized preparation stages and job progress for an audience that is still being built, and treats active build states as pollable rather than terminal. Terminal failure reasons are preserved, so a client polling the endpoint can distinguish "still preparing, here is how far along" from "this run failed, and here is why." Requested full-download intent is persisted, so preparation continues even if the requesting client disconnects.

Company counts on company-grain audiences

An audience built at company grain now populates account_count, the number of companies it contains, alongside the existing size field. Audience reads previously carried this field without a producer ever writing it, so integrators rendering a company audience no longer have to infer the unit from the audience type.

contact is the audience type value

The audience type formerly written as elixir is now stored and returned as contact. Both spellings are accepted on write, so existing integrations keep working unchanged, and readers should treat contact as the canonical value on GET /api/v1/audiences and GET /api/v1/audiences/{id}. This rolled out across the platform, so the value is consistent wherever an audience type appears.

Spend Controls

The monthly spend ceiling an organization configures for itself now applies to the two largest sources of metered spend, and refuses over budget with a documented response instead of serving the request.

Budget enforcement on audience downloads

GET /api/v1/audiences/{id}/download consults the organization's configured monthly budget before serving a download. A request over the ceiling is refused with 402 and a body naming the reason and the limits that applied, matching the refusal shape the API key and export surfaces already return.

Budget enforcement on metered data endpoints

The metered data endpoints, including GET /api/v1/lookup and the event tier reads under GET /api/v3/events/web_event, now consult the same budget decision and answer 402 with the shared refusal body when the ceiling is reached. If you meter your own consumption against a configured ceiling, expect 402 on these routes rather than a successful response once the ceiling is hit.

Bug Fixes

  • The events API now honors project-level membership on JWT authentication. A user with membership only at project scope receives data from GET /api/v3/events/web_event and the other tier reads instead of 401.

  • record_limit on an audience is applied once at the end of the build rather than being dropped, so GET /api/v1/audiences/{id}/download returns the top records up to the limit instead of the full record set.

  • A download whose underlying build was cancelled now triggers a rebuild instead of polling indefinitely against a prefix that will never produce output.

  • Soft-deleted lists no longer appear as attached in GET /api/v1/campaigns/{id}/lists.

  • An export run refused for exceeding a configured spend limit now returns the budget refusal, with its reason code and limits intact, instead of collapsing into a generic server error.

For full endpoint details, parameters, and examples, see our developer documentation.

API

API Updates - May 2026

Audiences

Audience responses now carry richer reach and signal data for developers reading them programmatically.

Distinct profile count on audience responses

Audience responses now include a distinct_profile_count field reporting the number of unique resolved profiles, separate from the raw record count (which can be larger because a profile may carry multiple records). Both GET /api/v1/audiences and GET /api/v1/audiences/{id} return it, so you can report true reach without post-processing the download.

Intent frequency and impression count on audience samples

The audience sample endpoint now returns two additional per-contact fields: intent_frequency (how many times a profile appeared in the audience over the lookback window) and impression_count (ad impressions served to that profile over the same window). These are available on GET /api/v1/audiences/{id}/sample for intent and persona audiences, giving a graded signal rather than a binary match.

Authentication

Two changes tighten credential handling. Review them before your next integration build.

API key and secret pair validation

API key authentication now validates the key and its secret together. Send the secret in the X-Api-Secret header alongside X-Api-Key. For clients with secret enforcement enabled, a request presenting a valid key without the matching secret is now rejected. If you have only been sending the key, add the secret you saved at creation time.

Application client secrets are no longer returned in plaintext

Application credential reads through GET /api/app/get and GET /api/app/retrieve/{app_id} no longer return the raw client secret. Credential validation now compares a hash of the secret you supply, so store the secret issued at creation time; it cannot be read back from the API.

Behavior Changes

Refreshing a paused audience returns 409

POST /api/v1/audiences/{id}/refresh against a paused audience now returns a 409 with a structured reason, instead of reporting success without actually queuing a rebuild. Resume the audience before requesting a refresh.

Bug Fixes

  • Intent audience downloads via GET /api/v1/audiences/{id}/download no longer return a spurious 400 when upstream data lands late for an otherwise-ready audience.
  • GET /api/v1/audiences no longer returns 500 for projects in certain organization hierarchies.
  • Audience filters using range operators (such as greater-than or less-than on bucketed fields like company employee-count ranges) now return only records that actually fall within the requested range.

For full endpoint details, parameters, and examples, see our developer documentation.

API

API Updates - April 2026

Authentication

API Key Auth on Lists and Campaigns

The lists and campaigns endpoints now accept API-key authentication. Previous scope gates have been removed: API-key callers reach the same surface as session callers.

GET /v1/lists
GET /v1/lists/{list_id}
POST /v1/lists
GET /v1/campaigns
GET /v1/campaigns/{campaign_id}

Authentication:

  • Authorization: Bearer <api_key> - Standard API-key header. No additional scope is required.

Example:

curl https://api.delivr.ai/api/v1/lists \
  -H "Authorization: Bearer $API_KEY"

Events

Query DSP Events by Campaign ID

Developer tokens can query DSP events filtered by campaign_id against the v2 events API. The proxy translates the v2 source parameter to the upstream contract.

GET /v2/events

Parameters:

  • source (string) - delivrdsp

  • campaign_id (string) - Campaign to filter events by.

  • start_time (string, ISO 8601) - Inclusive lower bound.

  • end_time (string, ISO 8601) - Inclusive upper bound.

Example:

curl "https://apiv3.delivr.ai/api/v2/events?source=delivrdsp&campaign_id=cmp_abc123&start_time=...&end_time=..." \
  -H "Authorization: Bearer $API_KEY"

Project-Scoped DSP Queries

The events API supports project-scoped DSP queries, returning events for all DSP campaigns under a given project.

Parameters:

  • project_id (string) - Restrict results to events belonging to this project.

Audiences

Configurable Intent Lookback

Audiences accept an intent_window_days value on create and edit. Bucket counts scale to match the selected window.

POST /v1/audiences
PATCH /v1/audiences/{audience_id}

Parameters:

  • intent_window_days (integer) - Number of days of intent history to consider when building the audience.

Response:

  • audience.intent_window_days (integer) - The configured window.

  • audience.bucket_counts (object) - Counts scaled to the configured window.

Rate Limiting

Rate limits on the data API are now applied per organization rather than globally. Each organization receives 25 requests per second with a burst capacity of 50. Integrators making concurrent requests across many organizations are no longer constrained by a shared global limit.

Response headers:

  • X-RateLimit-Limit (integer) - 25

  • X-RateLimit-Remaining (integer) - Tokens remaining in the current second.

  • X-RateLimit-Burst (integer) - 50

  • Retry-After (integer, on 429) - Seconds to wait before retrying.

Migration note: Clients previously throttled by the global limit will see additional headroom. Clients running heavy traffic against a single organization should still implement exponential backoff on 429 responses.

Bug Fixes

  • DSP exports no longer fail with pixel not found when source and campaign ID are not threaded into the event query.

  • Empty audience exports complete with zero records instead of failing the run.

  • Fixed an end_date boundary mismatch between SQL and application code in export queries; the boundary is now consistent across the stack.

  • Fixed a race where an export run could continue executing after the export was disabled.

  • Audience filters with very large inline value lists now spill values to S3 instead of failing the count worker with E2BIG.

  • The contains filter no longer splits multi-word values on commas.

  • Audience download presigned URLs are re-signed on every download call, eliminating expired-URL errors on retry.

  • Email subject templates are interpolated on every export send path, including batched, streamed, and multi-file exports.

  • The email export windowed path now defaults the S3 bucket instead of erroring with s3_bucket is required.

  • S3 exports fail fast with a clear error when integration credentials are empty or partially populated, instead of erroring deep in the run.

For full endpoint details, parameters, and examples, see our developer documentation.

API