Rate Limits and Metering
The short version
- Billing is usage-based, with no monthly floor. Most API calls bill per record returned. Audience downloads and export runs bill distinct people, not one row per email. Lookups that return no data are free. See What gets billed.
- New organizations start with a usage limit of 50,000 records per meter per month, which grows with your usage. Read your current limits with
GET /api/v1/billing/usage-limits. See Usage limits. - Every intent endpoint and both identity lookups (
/api/v1/lookup,/api/v1/lookup/batch) acceptdry_runto see the exact billable count before a live run. So do the signals people calls (/api/v1/signals/people/lookup,/api/v1/signals/people/batch) and the signals members download. Dry runs bill nothing. - Default rate limit on intent endpoints is 10 requests per second per organization. Most other API routes are limited at 10 requests per second per client.
- The Events API has its own limit: 720 requests per minute per organization (burst of 25).
- Intent batch endpoints take up to 10,000 items per call, so high intent volume rarely needs high request rates.
- Identity batch (
/api/v1/lookup/batch) takes up to 1,000 keys per call. It is limited to 2 requests per second per organization, a ceiling of 2,000 lookups per second./api/v1/contact/queryalso takes up to 1,000 emails per call. - Data Rights Tier 2 (Embedded Use): re-query a record before it goes into new output once 90 days have passed since Delivr last returned it. See Storing and reusing records.
Rate limits
| Surface | Limit | Notes |
|---|---|---|
Intent endpoints (/api/v1/intent/*) | 10 requests/sec per organization | Shared across all intent endpoints. Higher limits are available per contract. Ask your Delivr contact. |
Intent preview endpoints (/api/v1/intent/*/preview) | 5 requests/sec per organization | Previews return capped samples and bill nothing. |
Events API (/api/v1/events*, /api/v1/event_counts*, /api/v2/events*, /api/v2/event_counts, /api/v3/events*) | 720 requests/min per organization, burst of 25 | Shared across all Events API routes and keys in the organization. Higher limits are available per contract. Ask your Delivr contact. |
| Other data endpoints | 10 requests/sec | Per client key. Does not apply to the Events API. |
Going over a rate limit returns 429 with a Retry-After header (in seconds). Wait that long before retrying. If Retry-After is absent, back off exponentially from 1 second.
Intent and the other data endpoints also send X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds) on every response. You can use them to pace requests before hitting the limit. The Events API does not send them.
At 10 requests/sec against the 10,000-item intent batch endpoint, the intent ceiling is 100,000 lookups per second of wall time. So request rate is rarely the constraint for intent. Identity batch is lower: 1,000 keys at 2 requests/sec is 2,000 lookups per second per organization. If either limit constrains you, raise it with your Delivr contact rather than working around it.
Usage limits
Separately from rate limits, Delivr applies a daily and a monthly usage limit per meter. A new organization starts at 50,000 records per meter per month (200,000 for web events). Its daily limit starts at the same figure. So a new organization can use its whole first month in one day.
The limits then grow with your usage. The monthly limit becomes the greater of the starting limit and 3 times your median monthly usage, up to a per-meter ceiling. The daily limit is 10% of the monthly limit, and never below the starting limit.
The median covers your 6 most recent completed months that had usage. Months with no usage are skipped, so the window can reach back further than 6 calendar months.
The figures above are the defaults. Support can set different limits for your account. If you plan a pull larger than your limit, contact support to raise it before you start. An example is a full topic audience sized from a preview count.
A request that would go past a limit is refused with 429 and a body whose error is platform_cap_exceeded, so check error before retrying a 429. Its kind says what to do:
kind | What to do |
|---|---|
limit_reached | The same request succeeds after resets_at: midnight UTC for a daily limit, the 1st of next month (UTC) for a monthly one. Retry-After gives the wait in seconds. |
request_too_large | This request alone is larger than the limit, so retrying cannot succeed. Send a smaller request, or contact support to raise the limit. |
shut_off | Usage is paused for this account. Contact support. |
message says the same in a sentence you can show your users. The API reference shows the full body on every endpoint that can return it.
Read your current limits
GET /api/v1/billing/usage-limits returns each meter's daily and monthly limit, how much of each your organization has used, and when each resets. Read it before a large job, so the job does not stop part-way with a 429. The call is free and needs an organization key. A project key gets 403, because the limits count the whole organization's usage.
curl "https://api.delivr.ai/api/v1/billing/usage-limits" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "X-Api-Secret: YOUR_API_SECRET"{
"organization_id": "3f6c2a1e-8d4b-4c7a-9e2f-1b5d7a9c0e34",
"status": "active",
"limits": [
{
"meter": "intent_signal_scored",
"label": "Intent Signals",
"unit": "records",
"limited": true,
"daily": { "limit": 50000, "used": 1234, "remaining": 48766, "resets_at": "2026-11-08T00:00:00Z" },
"monthly": { "limit": 120000, "used": 7400, "remaining": 112600, "resets_at": "2026-12-01T00:00:00Z" }
},
{
"meter": "web_event",
"label": "Events / Journey",
"unit": "records",
"limited": false,
"daily": null,
"monthly": null
}
]
}limits has one entry per meter, and meter matches the meter of a 429. A request is refused when used plus the records it would bill is more than limit, so compare a dry run's records_to_charge with remaining. limited is false when no limit applies to the meter, and daily and monthly are then null. status is shut_off while usage is paused for the account, and limits is then empty. cause is nonpayment_limit while your limits are lowered because a payment is overdue.
The limits move with your usage, so read them again before each large job instead of storing them. In an agent, the get_usage_limits tool answers the same.
Payment required (402)
A billed request from an organization that cannot be billed is refused with 402 and nothing is billed. Previews and dry_run requests bill nothing, so they work without a payment method: payment_method_required, subscription_inactive and budget_exceeded never refuse them. A dry_run can still be refused with terms_acceptance_required or account_suspended_inactive. Branch on error:
error | What to do |
|---|---|
payment_method_required | No card or bank account is on file. An organization owner or admin adds one in the dashboard under Billing, then retry. |
subscription_inactive | The subscription was canceled. Reactivate the plan in Billing. |
terms_acceptance_required | No agreement is on file. An owner or admin accepts the terms in the dashboard. |
account_suspended_inactive | The account was suspended for inactivity. An owner or admin accepts the current terms in the dashboard. |
budget_exceeded | A monthly budget you set is reached. See Project budgets. |
Retrying does not help until the cause is fixed.
What gets billed
Delivr bills on usage meters. The ones you will meet through the API:
| What you did | What is billed |
|---|---|
| Intent lookup or batch (person or company) | One record per item that returns at least one topic after topic_ids and min_score, on Intent Signals (intent_signal_scored). Items that do not match, or that match but return no topics, are free. |
| Topic-to-people / topic-to-companies queries | Per record returned in the page, on Intent Signals (intent_signal_scored). People rows are persons, one per person. |
Preview endpoints (/preview) | Nothing. Capped at 25 records, built for evaluation. |
Audience sample (GET /api/v1/audiences/{id}/sample) | Nothing. Capped and redacted: no contact fields and no hashed email. |
dry_run on any intent endpoint, identity lookup, signals people call or signals members download | Nothing. Returns the count a live run would bill. |
Identity lookup (/api/v1/lookup, /api/v1/lookup/batch, /api/v1/contact/query) | Per record returned (contact_record). /api/v1/contact/query bills only records that carry a business email. Misses, filtered-out records, and per-key errors are free. The batch route takes up to 1,000 keys per call and is also limited to 2 requests per second per organization. |
| Identity resolution endpoints | Per resolved record, by resolution depth: HEM only (the hashed email), HEM + PTE (the hashed email plus the plaintext email email and UUID/PID stitching identifiers), or full profile (adds contact, company and demographic fields). |
| Events API | Per record returned on a 2xx response, on the meter set by the identity fields in the records. See Events API metering. |
Audience download (GET /api/v1/audiences/{id}/download) | Distinct people in the build, capped by record_limit when it binds. Each build bills once, and re-downloading the same build is free. See When a download is billed again. |
Audience records (GET /api/v1/audiences/{id}/records) | Per record returned. A record read again on the same UTC day is free. In one day, paging a build never costs more than a download of it. See Paging Audience Records. |
| Audience export run | Distinct people the run delivers, not one row per email. Each run bills. An export of another source bills per row delivered. |
Predictive Signals (/api/v1/signals/*) | Per top company, topics row or member returned, and one unit per history call that returns a day, on Predictive Signals (predictive_signal). People lookup and batch bill each distinct person with at least one trend topic. A repeat read of the same answer is free, except history. Dashboard views are free, but the members download bills every caller. See Predictive Signals. |
| Partner data fields in an audience or export | A per-1,000-record rate for each partner dataset used, on top of the base charge. Charged only for datasets you have enabled. See Partner data. |
Usage accrues to your organization and bills through Stripe at the volume rates on your order form. Pricing brackets are on the pricing page.
Three opt-in surfaces bill each person once per project, per meter, per UTC calendar month: GET /api/v3/events/{tier}/visitors/new, GET /api/v1/audiences/{id}/download/new, and export destinations with delivery_mode set to new. A person already delivered to the project on that meter this month is left out and not billed again. A retry that re-delivers its own people bills nothing more. Every other route and export bills as the table above shows.
What "month" means. A month is a calendar month in UTC. It starts at 00:00:00 UTC on the 1st and ends at 00:00:00 UTC on the 1st of the next month. It is the same month your usage and invoices are counted in.
The once-per-person rule lasts only for that month and resets at the boundary. So a person delivered at 23:59 UTC on October 31 is new again, and billed again, at 00:00 UTC on November 1.
The month is set when the delivery starts. For a request, the month is set at its arrival time. For an audience download, it is set when the build is requested. For a scheduled export run, it is set when the run is created, so every retry of that run counts in the same month.
Events API metering
The Events API bills per record returned, on a single meter per response:
| Records contain | Meter |
|---|---|
| Event fields only | Events / Journey |
| Identity or profile columns | The matching Resolution meter: HEM only, HEM + PTE, or Full Profile |
- The highest tier present wins. A response is never billed on two meters.
- On
/api/v3/events/{tier}the route sets the meter. See Events API v3. - A tier route bills every event it returns, whether or not the visitor was identified. Add
filter=resolved:eq:trueto return, and pay for, identified visitors' events only. - Each event is a record, so a visitor with five page views is five records. The
/api/v3/events/{tier}/visitorsroute returns one row per person, and each person it returns is billed once per request. - On other events routes, an explicit
selectsets the meter from the fields you list. Withoutselect, the meter follows the identity columns actually returned. emailis a HEM + PTE column. So aselectofhemandemail, with no other profile column, bills HEM + PTE. Every other email column, such asemailsorpersonal_email, bills Full Profile.- Repeat reads bill again.
- Billing does not depend on how you sign in. A dashboard session is billed like an API key on the routes that return full rows.
- Not billed:
events_schema, scan estimates,event_counts,event_counts_index, the v3/schemaroutes,/api/v3/events/web_event/counts, non-2xxresponses, empty results, and test-environment keys. - Pixel capture (ingest) is not billed.
Storing and reusing records (Tier 2)
If your agreement with Delivr grants Data Rights Tier 2 (Embedded Use), a record can go into new output in your product for 90 days after Delivr last returned it to you, unless your signed agreement states a different Data Freshness Period. After that, re-query the record through Delivr before you use it in new output. A re-query bills like any other query (see What gets billed) and starts a new period. Output your customers already received is not affected, and the period does not limit how long you keep records you have paid for.
To stay inside the period, store the time each record was returned to you and re-query records approaching 90 days before you show them in new output.
Predict cost before you spend: dry_run
Any intent request becomes a free cost preview by adding one field:
curl -X POST "https://api.delivr.ai/api/v1/intent/batch" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "X-Api-Secret: YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{"items": [{"id": "r1", "email": "[email protected]"}], "dry_run": true}'{
"dry_run": true,
"meter": "intent_signal_scored",
"records_to_charge": 1,
"records_fidelity": "exact",
"scope": {},
"note": "Cost preview only: no results were returned and nothing was billed. A live run of this request would charge records_to_charge against the named meter.",
"estimated_cost": {
"amount_cents": 5,
"currency": "usd",
"basis": "graduated_ceiling",
"note": "Estimated at standard rates as if this were your first usage this billing period. With tiered volume pricing, your actual charge will be this or lower."
}
}The request is fully resolved server-side, so records_to_charge is exact, not an estimate. estimated_cost.amount_cents is the most that count costs at standard rates, in cents. It assumes this is your first usage this billing period, so your actual charge is this amount or lower. A recommended pattern for large jobs: dry-run the batch, confirm the count and the cost are what you expect, then re-send without the flag.
Identity lookup works the same way. Add "dry_run": true to a /api/v1/lookup/batch body, or ?dry_run=true to either lookup route:
curl -X POST "https://api.delivr.ai/api/v1/lookup/batch" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "X-Api-Secret: YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{"keys": [{"email": "[email protected]"}, {"email": "[email protected]"}], "dry_run": true}'{
"dry_run": true,
"meter": "contact_record",
"records_to_charge": 1,
"records_fidelity": "exact",
"scope": {},
"note": "exact billable count: one contact record per key that returns a record after filter",
"estimated_cost": {
"amount_cents": 1,
"currency": "usd",
"basis": "graduated_ceiling",
"note": "Estimated at standard rates as if this were your first usage this billing period. With tiered volume pricing, your actual charge will be this or lower."
},
"field_coverage": {
"business_email": 1,
"company_domain": 1,
"company_name": 1,
"direct_phone": 0,
"job_title": 1,
"linkedin_url": 1,
"mobile_phone": 0,
"personal_email": 0,
"postal_address": 0,
"seniority": 1
}
}records_to_charge is the number of records a live call returns, after filter. field_coverage counts how many of those records carry each field, after select. The response has no records and no identifiers. A dry run works without a payment method. With a test key, the sandbox ignores dry_run and returns mock records.
Evaluate for free: previews
The discovery endpoints have preview variants that return real records, capped at 25, with no billing:
POST /api/v1/intent/people/previewPOST /api/v1/intent/companies/previewPOST /api/v1/intent/people/multi/previewPOST /api/v1/intent/companies/multi/preview
Previews return the top of the ranked result plus count, the number of records that match the filters you sent (min_score with min_perc_score for people, or with min_people_count for companies). You can use a preview to judge quality and size before importing anything. The multi-topic previews count only the records they scanned, so their count is not the size of a full pull.
The single-topic people preview counts within the topic's top 10,000 people by perc_score, the only people POST /api/v1/intent/people serves. So the count from POST /api/v1/intent/people/preview never exceeds 10,000. On a large topic, count is a lower bound on how many people show intent, not the topic's size.
The companies preview leaves count out when min_people_count is above 1 and roughly 200,000 or more companies on the topic qualify. Treat count as optional. Previews mask emails, LinkedIn URLs, phones and last names, and identify each person with a ref instead of a hem. Full identifiers come only from the paid endpoints.
Timeouts and retries
429witherrorplatform_cap_exceeded: a usage limit, not a rate limit. Follow itskind(see Usage limits above) instead of retrying.- Any other
429: wait forRetry-After, then retry. If it is absent, back off exponentially from 1 second. 402: fix the cause named byerror(see Payment required above) before retrying.5xx: safe to retry. Lookups are read-only and idempotent.- Client timeouts: allow 60 seconds on full 10,000-item intent batches.
Updated about 19 hours ago
