Skip to main content

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

ComponentResponsibility
Your applicationBuild the bulk payload, submit it, store bulk_id, reconcile outcomes
POST /v1/radars/bulkValidates envelope-level shape and queues items
Bulk processorValidates and processes each queued item asynchronously
Your webhook endpointReceives 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"
    }
  ]
}
  1. Submit bulk and store bulk_id.
  2. Process webhook events and persist item outcomes by bulk_id + item_index.
  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.