Skip to content
SeekOutDevelopers

Concepts

Rate limits

Rate limits protect the API and your own spend. They are separate from credits: a limit says how much work can run at once, not whether you can afford it.

Default limits

These limits apply to every organization unless SeekOut or one of your organization admins has set a lower one for it. Every key and workspace in an organization shares them.

Default limits for each organization
LimitDefaultWhat is countedWhen it is reached
Request rate25 requests per secondEvery authenticated /v1 request from the organization429 rate_limited
Requests in flight25 at onceRequests that have started and not yet finished429 rate_limited
Running contact-retrieval jobs2Jobs that have been accepted and have not finished429 contact_job_concurrency_cap
Webhook replays10 per endpoint per hourReplays of one endpoint's dead-lettered deliveries429 webhook_replay_cap

The request rate is a strict one-second window with no burst allowance on top: at most 25 requests are admitted in any one second, and a request that is refused does not use up part of the window. Each key, key family and application is held to the same 25 per second inside the organization's total, so spreading calls across more keys does not raise the rate.

What a 429 means

429 is raised on admission, before useful work happens. Honor the Retry-After header and retry the same request. For unlock, reuse the same idempotency key — no credits were spent.

HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 1
X-Request-Id: 00000000-0000-4000-8000-000000000000
Cache-Control: private, no-store

{
  "type": "urn:seekout:developer-api:problem:rate_limited",
  "title": "Rate limited",
  "status": 429,
  "code": "rate_limited",
  "instance": "urn:seekout:developer-api:request:00000000-0000-4000-8000-000000000000",
  "request_id": "00000000-0000-4000-8000-000000000000"
}

Refusals specific to contacts and webhooks

Contact retrieval, batch job creation, the Jobs API reads and the cancel, and every webhook route each carry their own request rate limit, and two of them refuse for a reason worth handling separately.

429 codes that mean something specific
CodeWhat happenedWhat to do
contact_job_concurrency_capYour organization already has two contact-retrieval jobs running. This is a concurrency cap, not a rate: waiting a moment is not enough if the running jobs are long. Retry-After is 30Wait for Retry-After, or for a running job to finish, then create the job again
webhook_replay_capMore than 10 replays of one endpoint's dead-lettered deliveries in the last hourFix the receiver first, then replay. Wait for Retry-After

Neither is a charge and neither leaves state behind. A job that was refused at the cap never existed, so there is nothing to cancel and nothing to reconcile.

Search quotas

Search also limits bulk extraction with three further 429 codes: preview_quota_exceeded, distinct_query_cap and delivery_quota_exceeded. They count unique people or distinct queries rather than requests per second, and each response carries Retry-After: 1. If one persists after a retry, contact support with the X-Request-Id.

Read your limits

Limits in the console and GET /v1/operational-limits (scope limits.v1:read) report the limits that are enforced for your organization, for each operation and for each application, key family and key. An organization that has set no limit of its own is held to the defaults in the table above, so every entry reports those until a limit is set.

What a limit entry reports
FieldWhat it is
requests_per_secondRequests admitted per second, in the strict one-second window. 25 unless a lower organization-wide rate has been set, which the api.request_baseline.v1 entry for the organization reports.
requests_per_minuteAn exact cap on requests in any trailing minute, or null when no per-minute cap applies. An organization that has set no limit has none, so this is null; only a custom limit makes it a number.
max_concurrencyRequests in flight at once. 25 by default; a custom limit sets its own.
lease_ttl_secondsHow long an in-flight request holds its slot if it is never released. A Retry-After on an in-flight refusal can be this long.
statusactive, or denied when SeekOut has blocked the operation. A denied entry reports no figures.
sourceoverride while a custom limit is in force: a per-minute cap, a block, or an organization-wide rate below 25 per second. inherited and cleared both mean the defaults apply.

Each entry describes one operation on its own. Every request is also held to the api.request_baseline.v1 entry, so the limit a request meets is the stricter of its operation's entry and the baseline entry for the same organization, application, key family or key. An operation's entry can read 25 per second with no per-minute cap while the baseline entry holds a cap, a lower organization-wide rate or a block; read both.

Organization admins can lower a limit from the console by setting a per-minute cap on an operation, for one key, one key family, one application or the whole organization. A cap must be below standard_requests_per_minute, and it is the only thing that sets requests_per_minute. The standard, maximum_requests_per_minute, suggested_requests_per_minute and inherited_ceiling_ref describe the ceilings a cap is measured against. They are not limits in force. A cap can only be lowered here; raising the request rate or the in-flight limit is a conversation with SeekOut.

Not the same as 402429 means wait; 402 means the work is not funded. Adding credits does not raise a rate limit, and lowering a rate limit does not change what an operation costs.