Skip to main content
Use this guide when you want to create many radars at once using POST /v1/radars/bulk. To deactivate multiple existing radars, use the separate synchronous DELETE /v1/radars/bulk endpoint. It returns final per-item results immediately and does not use bulk status polling. Bulk creation is asynchronous:
  • The submission request returns 202 Accepted with a bulk_id.
  • Item-level outcomes are produced later as radar_created or radar_failure.
  • A final bulk_completed event indicates that all items are done.
Two delivery modes are supported:
  • With webhook_url — per-item and final results are pushed to your endpoint, with GET /v1/radars/bulk/{bulk_id} available as a reliability fallback.
  • Without webhook_url (poll-only) — omit the field entirely; track the batch with GET /v1/radars/bulk/{bulk_id}. See Polling without a webhook.
For request and response schemas, use:

Bulk flow and responsibilities

Step 1: Prepare your webhook consumer (skip for poll-only)

webhook_url is optional. If you omit it, skip this step and use Polling without a webhook instead. If you provide one, point it to an HTTPS endpoint that:
  • accepts POST
  • returns 2xx quickly
  • processes payloads asynchronously in your own worker queue
You should handle these update types:
  • radar_created
  • radar_failure
  • bulk_completed
See Webhook Payloads for payload details and examples.

Step 2: Build a valid bulk request

The top-level body:
  • radars (required): array of radar payloads
  • webhook_url (optional): single callback URL for all items in this bulk submission
To disable webhooks, omit webhook_url entirely. An explicit "webhook_url": null is rejected with 400 — the field accepts a valid URL or no key at all, never null.
Each item in radars[] uses the same field structure as the corresponding single-radar endpoint. Before building a bulk payload, make sure you’re familiar with the per-type schemas:
Each item may also provide its own updates_since. Use it when you need historical findings or want to enforce a specific earliest event date. The value must be an RFC 3339 timestamp with a timezone and must represent now or a past instant. Omit it to use that radar’s creation time. A five-second server tolerance exists only for clock skew and cannot be used to schedule a future start. We recommend adding custom_fields to every item. If you skip it, you can still reconcile with item_index, but item-level tracing in downstream systems is harder.

Step 3: Submit and persist bulk_id

On success, the API returns 202 with a bulk_id and summary. Persist bulk_id immediately. It is your primary key for reconciliation and polling.
Typical immediate failure cases:
  • 400: invalid JSON or invalid envelope (webhook_url, radars[])
  • 401: missing or invalid API key
  • 429: bulk rate limit exceeded
  • 500: queueing failed
For error format details, see Error Handling. 400 example:
429 example:
For async bulk, reason is always minute because this endpoint enforces a dedicated per-minute bulk bucket.

Step 4: Process per-item events

Items do not complete at the same time. You can receive outcomes in any order. radar_created means the item created successfully. radar_failure means that item failed (validation, conflict, billing, or processing error). The code, message, and errors[] fields are identical to what the sync single-create endpoint would return for the same failure — so any error handling you already have for the sync API works here without changes. Use item_index, bulk_id, and custom_fields to map each event back to the original request item. For successful items, data matches the same data shape returned by single-create endpoints: Create Company Radar, Create Contact Radar, and Create Industry Radar. radar_created example:
When an item omits updates_since, successful radar_created and bulk-status results return "updates_since": null. The effective cutoff is that radar’s created_at. radar_failure example:
discovered_at is included for backwards compatibility and equals completed_at. Prefer completed_atdiscovered_at will be removed in a future version.

Possible failure codes

The code, message, and errors[] below are spread directly into the radar_failure envelope above — identical to what the sync single-create endpoint returns for the same failure. Your existing sync error handling works for bulk without changes.
Returned when a field is missing, invalid, or the radar type is not supported. errors[] may contain multiple entries, one per failing field.
Returned when your account does not have enough credits to create the radar. The item is not created and no credits are deducted.
Returned when a radar with the same configuration already exists on your account. Always includes conflicting_radar_id so you can look it up directly.The field name varies by radar type:
  • Company radars → domain
  • Contact radars → identifiers.email when email matched, or identifiers.profile_url when the profile URL matched
  • Industry radars → keyword (for industry_mentions / industry_job_openings) or radar_type (for other industry types)
Rare. Indicates a transient infrastructure failure. The item will be retried automatically — no action needed on your side. If a radar_failure with code: 500 is delivered, it means all retries were exhausted.

Step 5: Finalize on bulk_completed

When all items reach terminal state, you receive one bulk_completed event. Use it to:
  • mark the bulk job complete in your system
  • compare final counts (created, failed) with your local ledger
  • trigger any retry workflow for failed items
bulk_completed carries the full per-item result array. At 1,000 items with rich custom_fields or filter data, the payload can approach 1–2 MB — ensure your receiver can handle it. Alternatively, use GET /v1/radars/bulk/{bulk_id} to fetch results on demand instead of relying on this webhook.
bulk_completed.radars[] contains per-item results for the submission. Each radars[] entry is identical to the per-item webhook payload already delivered for that item (radar_created or radar_failure).

Step 6: Add polling as a reliability path

If webhook delivery is delayed or your consumer is unavailable, poll: GET /v1/radars/bulk/{bulk_id} The response status is:
  • processing: at least one item is still in flight
  • completed: all items are terminal
Poll until completed, then stop. Both polling responses include radars[]:
  • In processing, in-flight items appear as { item_index, status: "processing", custom_fields }.
  • In completed, each item is the full terminal payload (same shape as per-item webhook delivery).
processing example:
completed example:

Polling without a webhook

Omit webhook_url to run the whole batch in poll-only mode — no HTTP callback is attempted, and GET /v1/radars/bulk/{bulk_id} is your single tracking surface for every outcome, including failures.
The 202 response is the same as webhook mode, except the message directs you to polling only:
Poll-only workflow:
  1. Submit without webhook_url and store bulk_id.
  2. Poll GET /v1/radars/bulk/{bulk_id} until status is completed (see Step 6 for both response shapes).
  3. Read every terminal item from radars[] — successes carry the created radar’s data, failures carry the same code/message/errors[] shown in Step 4.
  4. Retry only failed items with a new bulk request.
Remember: omit the key entirely — "webhook_url": null returns 400.
  1. Submit bulk and store bulk_id.
  2. Process webhook events and persist item outcomes by bulk_id + item_index (webhook mode), or rely on the status endpoint alone (poll-only mode).
  3. Poll status endpoint on a fallback interval until completed.
  4. Reconcile webhook-driven and poll-driven outcomes.
  5. Retry only failed items with a new bulk request.
This gives you real-time processing through webhooks and deterministic recovery through polling — or, without a webhook, a single deterministic polling surface.