Documentation Index
Fetch the complete documentation index at: https://docs.tamradar.com/llms.txt
Use this file to discover all available pages before exploring further.
Use this guide when you want to create many radars at once using POST /v1/radars/bulk.
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.
For request and response schemas, use:
Bulk flow and responsibilities
| Component | Responsibility |
|---|
| Your application | Build the bulk payload, submit it, store bulk_id, reconcile outcomes |
POST /v1/radars/bulk | Validates envelope-level shape and queues items |
| Bulk processor | Validates and processes each queued item asynchronously |
| Your webhook endpoint | Receives per-item radar_created / radar_failure, then bulk_completed |
GET /v1/radars/bulk/{bulk_id} | Polls live status and per-item results |
Step 1: Prepare your webhook consumer
webhook_url is required for async bulk. 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 requires:
webhook_url: single callback URL for all items in this bulk submission
radars: array of radar payloads
Each item in radars[] should use the same structure you would send to a single create endpoint (/v1/radars/companies, /contacts, or /industry).
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.
{
"webhook_url": "https://your-domain.com/webhooks/tamradar",
"radars": [
{
"radar_type": "company_job_openings",
"domain": "stripe.com",
"custom_fields": { "crm_account_id": "acc_001" }
},
{
"radar_type": "contact_job_changes",
"domain": "openai.com",
"profile_url": "https://www.linkedin.com/in/example",
"custom_fields": { "owner": "sdr_team" }
}
]
}
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.
curl -X POST https://api.tamradar.com/v1/radars/bulk \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://your-domain.com/webhooks/tamradar",
"radars": [
{
"radar_type": "company_job_openings",
"domain": "stripe.com",
"custom_fields": { "crm_account_id": "acc_001" }
},
{
"radar_type": "industry_funding_rounds",
"custom_fields": { "segment": "fintech" }
}
]
}'
{
"status": "success",
"code": 202,
"message": "Bulk submission accepted - 2 radars queued for processing. Poll GET /v1/radars/bulk/5f9da22e-4778-427c-b7e4-dab2a8d9d709 for status or wait for the bulk_completed webhook.",
"bulk_id": "5f9da22e-4778-427c-b7e4-dab2a8d9d709",
"summary": {
"total": 2
},
"timestamp": "2026-05-25T11:17:12Z"
}
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:
{
"status": "error",
"code": 400,
"message": "Invalid request body",
"errors": [
{
"field": "webhook_url",
"reason": "Invalid webhook URL format"
}
],
"timestamp": "2026-05-25T11:18:10Z",
"error_id": "245df4c2-3ab8-4c96-a60d-42f6fc59f9b8"
}
429 example:
{
"status": "error",
"code": 429,
"message": "Rate limit exceeded — wait and retry.",
"errors": [
{
"field": "rate_limit",
"reason": "minute"
}
],
"timestamp": "2026-05-25T11:18:44Z",
"error_id": "29a4ff58-f4a8-4ebe-8b2d-1544ee43a99c"
}
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).
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:
{
"update_id": "efbf7c77-c1ae-4a0d-85b6-116674e9e0b1",
"update_type": "radar_created",
"completed_at": "2026-05-25T11:17:20Z",
"bulk_id": "5f9da22e-4778-427c-b7e4-dab2a8d9d709",
"item_index": 0,
"custom_fields": { "crm_account_id": "acc_001" },
"status": "success",
"data": {
"radar_id": "2ffb1a07-ac95-4a6d-bc34-39f479f1c856",
"radar_type": "company_job_openings",
"domain": "stripe.com",
"radar_status": "active"
}
}
radar_failure example:
{
"update_id": "a1b2c3d4-0001-4000-b000-000000000001",
"update_type": "radar_failure",
"completed_at": "2026-05-25T11:17:26Z",
"discovered_at": "2026-05-25T11:17:26Z",
"bulk_id": "5f9da22e-4778-427c-b7e4-dab2a8d9d709",
"item_index": 1,
"custom_fields": { "segment": "fintech" },
"status": "error",
"code": 409,
"message": "Conflict: Radar already exists",
"errors": [
{
"field": "domain",
"reason": "A radar with this domain and type already exists for your account. Conflicting radar_id: 3f1d8e8a-39c4-47e8-a4b4-f7db6a2e50f0. You can view it using GET /radars/{radar_id}",
"conflicting_radar_id": "3f1d8e8a-39c4-47e8-a4b4-f7db6a2e50f0"
}
],
"timestamp": "2026-05-25T11:17:26Z",
"error_id": "45ed35e5-986c-4496-afd8-9a84f6baa410"
}
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).
{
"update_id": "9a2f0f77-5c8b-4b3e-b636-3ad539f4de65",
"update_type": "bulk_completed",
"bulk_id": "5f9da22e-4778-427c-b7e4-dab2a8d9d709",
"completed_at": "2026-05-25T11:17:33Z",
"summary": {
"total": 2,
"created": 1,
"failed": 1
},
"radars": [
{
"update_type": "radar_created",
"item_index": 0,
"...": "same fields as radar_created (including custom_fields and data)"
},
{
"update_type": "radar_failure",
"item_index": 1,
"...": "same fields as radar_failure (including code, errors, error_id, timestamp)"
}
]
}
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).
curl https://api.tamradar.com/v1/radars/bulk/5f9da22e-4778-427c-b7e4-dab2a8d9d709 \
-H "x-api-key: YOUR_API_KEY"
processing example:
{
"status": "processing",
"code": 200,
"timestamp": "2026-05-25T12:19:17Z",
"message": "Bulk submission is being processed",
"bulk_id": "5d089cd9-239d-4de4-af1d-8d19da889d00",
"summary": {
"total": 3,
"processing": 3,
"created": 0,
"failed": 0
},
"radars": [
{
"item_index": 0,
"status": "processing",
"custom_fields": {}
},
{
"item_index": 1,
"status": "processing",
"custom_fields": {}
},
{
"item_index": 2,
"status": "processing",
"custom_fields": {}
}
]
}
completed example:
{
"status": "completed",
"code": 200,
"timestamp": "2026-05-25T12:19:46Z",
"message": "Bulk submission completed",
"bulk_id": "5d089cd9-239d-4de4-af1d-8d19da889d00",
"summary": {
"total": 3,
"processing": 0,
"created": 0,
"failed": 3
},
"radars": [
{
"item_index": 0,
"custom_fields": {},
"code": 409,
"errors": [
{
"field": "domain",
"reason": "A radar with this domain and type already exists for your account. Conflicting radar_id: 351d5644-3d75-416e-b8a5-eb0e1b16b602. You can view it using GET /radars/{radar_id}",
"conflicting_radar_id": "351d5644-3d75-416e-b8a5-eb0e1b16b602"
}
],
"status": "error",
"message": "Conflict: Radar already exists",
"error_id": "f9ab0e2d-8246-4465-868f-922add7fbeab",
"timestamp": "2026-05-25T12:19:45.783Z"
},
{
"...": "additional items with the same terminal shape"
}
]
}
Recommended production pattern
- Submit bulk and store
bulk_id.
- Process webhook events and persist item outcomes by
bulk_id + item_index.
- 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.
This gives you real-time processing through webhooks and deterministic recovery through polling.