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 Acceptedwith abulk_id. - Item-level outcomes are produced later as
radar_createdorradar_failure. - A final
bulk_completedevent indicates that all items are done.
- With
webhook_url— per-item and final results are pushed to your endpoint, withGET /v1/radars/bulk/{bulk_id}available as a reliability fallback. - Without
webhook_url(poll-only) — omit the field entirely; track the batch withGET /v1/radars/bulk/{bulk_id}. See Polling without a webhook.
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
2xxquickly - processes payloads asynchronously in your own worker queue
radar_createdradar_failurebulk_completed
Step 2: Build a valid bulk request
The top-level body:radars(required): array of radar payloadswebhook_url(optional): single callback URL for all items in this bulk submission
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:- Create Company Radar —
domain,radar_type, optional filters - Create Contact Radar —
profile_url,radar_type,domain - Create Industry Radar —
radar_type, optionalkeyword
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.
400: invalid JSON or invalid envelope (webhook_url,radars[])401: missing or invalid API key429: bulk rate limit exceeded500: queueing failed
400 example:
429 example:
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:
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_at — discovered_at will be removed in a future version.Possible failure codes
Thecode, 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.
400 — Validation error
400 — Validation error
Returned when a field is missing, invalid, or the radar type is not supported.
errors[] may contain multiple entries, one per failing field.402 — Insufficient balance
402 — Insufficient balance
Returned when your account does not have enough credits to create the radar. The item is not created and no credits are deducted.
409 — Conflict (radar already exists)
409 — Conflict (radar already exists)
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.emailwhen email matched, oridentifiers.profile_urlwhen the profile URL matched - Industry radars →
keyword(forindustry_mentions/industry_job_openings) orradar_type(for other industry types)
500 — Internal server error
500 — Internal server error
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.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 flightcompleted: all items are terminal
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
Omitwebhook_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.
202 response is the same as webhook mode, except the message directs you
to polling only:
- Submit without
webhook_urland storebulk_id. - Poll
GET /v1/radars/bulk/{bulk_id}untilstatusiscompleted(see Step 6 for both response shapes). - Read every terminal item from
radars[]— successes carry the created radar’sdata, failures carry the samecode/message/errors[]shown in Step 4. - Retry only failed items with a new bulk request.
"webhook_url": null returns 400.
Recommended production pattern
- Submit bulk and store
bulk_id. - Process webhook events and persist item outcomes by
bulk_id + item_index(webhook mode), or rely on the status endpoint alone (poll-only mode). - Poll status endpoint on a fallback interval until completed.
- Reconcile webhook-driven and poll-driven outcomes.
- Retry only failed items with a new bulk request.