You set up TAMradar monitoring for a user. Read this file top to bottom before starting. Base URL:
https://api.tamradar.com
Auth header: x-api-key: {TAMRADAR_API_KEY} — required on every request. No Bearer prefix.
Authentication
Check the environment forTAMRADAR_API_KEY. If the variable is unset or empty, ask the user:
“I need your TAMradar API key to proceed. You can find it in your account settings at tamradar.com.”
Never guess or construct the key. Do not proceed without it.
Canonical request format — use this exact pattern for every call:
x-api-key is the auth header. Content-Type: application/json is required on all POST requests.
How this works — overview
Inputs — collect before starting
| Input | Required | Notes |
|---|---|---|
TAMRADAR_API_KEY | MUST have | UUID format — check env first, ask if unset |
| Target list | MUST have | Companies (domain), people (name + LinkedIn URL + company domain), or industry keywords |
webhook_url | Optional | Omit for poll-only. Add it for real-time push delivery. |
Webhook URL — default to polling
webhook_url is optional. Default to polling via GET /v1/updates unless the user explicitly provides a webhook URL.
If no webhook URL provided: omit webhook_url entirely — the radar will be poll-only. Retrieve findings via GET /v1/updates. No need to ask.
If user provides a real webhook URL (Make.com, Clay, Zapier, n8n): include it. Real-time delivery will work automatically.
⚠️ Once set, webhook_url cannot be changed without deactivating and recreating the radar. Avoid ephemeral test URLs like webhook.site for production radars.
Phase 1: Pre-flight — ALWAYS run first
- IF
data.balance_remaining_usd == 0→ STOP. Tell user: “Your TAMradar balance is $0. Add funds at tamradar.com before I can create any radars.” - IF
data.balance_remaining_usd < 5→ WARN. Tell user the balance, ask if they want to continue. - IF
data.balance_remaining_usd >= 5→ Proceed. Report balance to user.
Recommend: balance monitoring cron (to user only — do not auto-install)
Tell the user:“To avoid radars being deactivated unexpectedly, I recommend setting up a daily job that callsOnly suggest this. Do not install cron jobs, crontab entries, or scheduled tasks without explicit instruction.GET /v1/accountand alerts you ifbalance_remaining_usddrops below a threshold (e.g. 0 and sends aradar_failurewebhook — but proactive monitoring is better than reacting after the fact.”
Phase 2: Create radars
Idempotency — check local store first
Before every POST, look up(domain, radar_type) in ./tamradar-radars.jsonl (your local mapping store). If a matching entry exists, skip the POST and use the stored radar_id. This avoids wasteful requests and eliminates a whole class of 409 errors.
Singles vs bulk
- ≤10 targets → create one by one (single POSTs). Simple, easy to debug.
- >10 targets → use
POST /v1/radars/bulk(async queue, max 1000 items per request).
Single radar creation
custom_fields recommendation: always pass your internal IDs here. They echo back in every finding, making it easy to route data back to your CRM, database, or workflow.
Company radar
Contact radar
Industry radar
⚠️ CRITICAL: persist the mapping after every 201
Store immediately to./tamradar-radars.jsonl (append one JSON object per line):
Bulk creation — for >10 targets
Send up to 1000 radars per request.webhook_url is required at the envelope level and applies to all items in the submission.
- Response returns
bulk_idand submission summary only. - Item-level outcomes are asynchronous and arrive via:
- webhook events (
radar_created/radar_failure/bulk_completed) GET /v1/radars/bulk/{bulk_id}polling
- webhook events (
Phase 3: Error handling
MUST handle every error before reporting success.| Code | Meaning | Action |
|---|---|---|
401 | Invalid API key | STOP. Ask user to verify key. |
402 | Insufficient balance | STOP. Tell user to add funds, then retry. |
409 | Radar already exists | NOT an error — it’s already running. Extract radar_id from errors[0].reason. Store it. Move on. |
400 | Validation error | Show errors[].field + errors[].reason verbatim. Ask user to correct. |
429 | Rate limited | Wait, then retry. NEVER retry more than 3 times. |
5xx | Server error | Retry once. If still failing, report error_id to user and STOP. |
Phase 4: Retrieve findings (polling)
GET /v1/updates returns the same data as webhooks. The response uses updates[] — not data[].
Note: findings are retained for 60 days. Data older than 60 days is purged.
Note: radar_failure events are excluded by default. Default update_type is radar_finding only.
Sample response:
Fetch findings for specific radars (max 10 radar_ids per call)
Fetch by signal type
Incremental — only new since last check
discovered_at from the last update you processed. Pass it as since on the next call.
Pagination
IFhas_more: true → fetch next page:
has_more: false.
To include radar failures in polling
Presenting findings to the user
Group bydata.radar_type. Always include discovered_at. Example:
New job at openai.com — Senior Research Engineer, Alignment Detected: 2026-04-29 · View posting
Phase 5: Deactivate radars
- Irreversible. Must create a new radar to resume monitoring.
- No further charges after deactivation.
radar_id from ./tamradar-radars.jsonl and DELETE it.
Phase 6: Retrieving findings
Default: use polling.GET /v1/updates always works regardless of webhook_url. Findings are available immediately after creation and retained for 60 days.
If the user later wants real-time push delivery:
“Your radars are active and I can fetch findings anytime you ask. For real-time delivery into Slack, your CRM, or an automation, connect a tool like Make.com or Clay — it generates a webhook URL you can give me and I’ll update the setup.”
Summary template — ALWAYS present when done
Endpoint reference (machine-readable)
Fetch these as raw markdown for full schema details:- Company radar:
https://docs.tamradar.com/api-reference/create-company-radar.md - Contact radar:
https://docs.tamradar.com/api-reference/create-contact-radar.md - Industry radar:
https://docs.tamradar.com/api-reference/create-industry-radar.md - Poll updates:
https://docs.tamradar.com/api-reference/poll-updates.md - Account:
https://docs.tamradar.com/api-reference/account.md
Radar type reference
Company — POST /v1/radars/companies
Required: domain, radar_type — webhook_url optional (omit for poll-only)
radar_type | What it tracks |
|---|---|
company_job_openings | New job postings |
company_new_hires | People joining the company |
company_promotions | Internal promotions |
company_reviews | Glassdoor/employer reviews |
company_mentions | Web mentions of the company |
company_social_posts | Company LinkedIn/social posts |
company_social_posts_cxo | Executive social posts |
company_social_engagements | Engagements on company posts |
Domain normalization
The API accepts any format — bare domain, URL, or with www/path/port. All are normalized automatically:openai.com✅https://www.openai.com/about✅ → normalized toopenai.comwww.openai.com✅ → normalized toopenai.com
openai.com).
Contact — POST /v1/radars/contacts
Required: radar_type + type-specific identifiers — webhook_url optional (omit for poll-only):
radar_type | Additional required fields |
|---|---|
contact_job_changes | domain + at least one of: email, profile_url, full_name |
contact_social_engagements | profile_url (must contain linkedin.com/in/, x.com/, or twitter.com/) |
contact_social_posts | profile_url (same URL formats) |
Profile URL normalization
Pass the full URL. The API normalizes automatically:https://www.linkedin.com/in/samaltman✅ (preferred)https://linkedin.com/in/samaltman✅ → normalized tohttps://www.linkedin.com/in/samaltmanlinkedin.com/in/samaltman✅ →https://added automatically- Trailing slash stripped automatically
profile_url + radar type — different radar types for the same person ARE allowed.
Industry — POST /v1/radars/industry
Required: radar_type. No domain field — webhook_url optional (omit for poll-only).
radar_type | Additional required fields |
|---|---|
industry_funding_rounds | None |
industry_new_companies | None |
industry_mentions | keyword (min 3 chars) |
industry_job_openings | keyword (min 3 chars) + optional countries[] (max 5) |
Key fields reference
| Field | Found in | Purpose |
|---|---|---|
radar_id | Creation response → data.radar_id | MUST store with input. Used for polling, deactivation. |
update_id | Every finding payload | Deduplicate on this. NEVER process the same update_id twice. |
discovered_at | Every finding payload | Store latest value. Use as since param for incremental polling. |
custom_fields | Request body → echoed in every finding | Your internal IDs. Route findings back to your CRM using these. |
data.radar_type | Every finding payload | Route your processing logic on this. |
content | Every finding payload | The actual finding. Shape varies by radar_type. |
Hard limits
webhook_urlis optional — omit for poll-only radars; include only when real-time push delivery is needed- Rate limit: 100 write requests / 60 seconds, 200 read requests / 60 seconds — need more? contact support@tamradar.com
- Bulk max: 1000 radars per request
- Polling
radar_idfilter: max 10 IDs per call — split into multiple requests if you have more - Polling data retention: 60 days — older data is purged
- One radar per
domain + radar_typeper account — duplicates get409 - Contact uniqueness: per
profile_url + radar_type— different contact radar types for the same person ARE allowed - Persistence: save mappings to
./tamradar-radars.jsonlby default