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.

👤 For humans Give this to your agent and it will set up TAMradar monitoring for you — create radars, check balance, retrieve findings. Give this link to your agent: https://tamradar.readme.io/reference/tamradar-agentmd.md

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 for TAMRADAR_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:
curl -s -X POST "https://api.tamradar.com/v1/radars/companies" \
  -H "x-api-key: $TAMRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "openai.com", "radar_type": "company_job_openings" }'
x-api-key is the auth header. Content-Type: application/json is required on all POST requests.

How this works — overview

1. PRE-FLIGHT     GET  /v1/account              → check balance, block if $0
2. CREATE         POST /v1/radars/companies      → company signals
                  POST /v1/radars/contacts       → person signals
                  POST /v1/radars/industry       → industry-wide signals
                  POST /v1/radars/bulk           → >10 targets: async queue (max 1000 items per request)
3. RETRIEVE       GET  /v1/updates               → poll for findings (always available)
                  [webhook]                      → push delivery (faster, if webhook_url set)
4. MANAGE         DELETE /v1/radars/:id          → stop monitoring a target
Detailed breakdown follows.

Inputs — collect before starting

InputRequiredNotes
TAMRADAR_API_KEYMUST haveUUID format — check env first, ask if unset
Target listMUST haveCompanies (domain), people (name + LinkedIn URL + company domain), or industry keywords
webhook_urlOptionalOmit 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

GET /v1/account
Sample response:
{
  "status": "success",
  "code": 200,
  "data": {
    "balance_remaining_usd": 42.50,
    "account": {
      "active_radars": 12,
      "inactive_radars": 2,
      "failed_radars": 0,
      "total_radars": 14,
      "total_updates_found": 3847
    },
    "usage": {
      "month": "2026-05",
      "radars_activated": 3,
      "radars_deactivated": 0,
      "radars_failed": 0,
      "balance_used_usd": 7.50,
      "updates_found": 142
    }
  }
}
Balance gate — enforce strictly:
  • IF data.balance_remaining_usd == 0STOP. Tell user: “Your TAMradar balance is $0. Add funds at tamradar.com before I can create any radars.”
  • IF data.balance_remaining_usd < 5WARN. 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 calls GET /v1/account and alerts you if balance_remaining_usd drops below a threshold (e.g. 10).TAMradarautodeactivatesradarswhenbalancehits10). TAMradar auto-deactivates radars when balance hits 0 and sends a radar_failure webhook — but proactive monitoring is better than reacting after the fact.”
Only suggest this. Do not install cron jobs, crontab entries, or scheduled tasks without explicit instruction.

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.
"custom_fields": {
  "crm_account_id": "0011U00000TFV7MQAX",
  "owner": "alice@yourcompany.com",
  "label": "enterprise-tier"
}

Company radar

curl -s -X POST "https://api.tamradar.com/v1/radars/companies" \
  -H "x-api-key: $TAMRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "openai.com",
    "radar_type": "company_job_openings",
    "webhook_url": "https://hook.make.com/your-scenario-url",
    "departments": ["Engineering", "Research"],
    "seniorities": ["Senior", "Director", "Vice President", "CXO"],
    "custom_fields": { "crm_account_id": "0011U00000TFV7MQAX" }
  }'

Contact radar

curl -s -X POST "https://api.tamradar.com/v1/radars/contacts" \
  -H "x-api-key: $TAMRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "radar_type": "contact_job_changes",
    "domain": "openai.com",
    "profile_url": "https://www.linkedin.com/in/samaltman",
    "full_name": "Sam Altman",
    "webhook_url": "https://hook.make.com/your-scenario-url",
    "custom_fields": { "crm_contact_id": "003Dn00000AHtLQIA1" }
  }'

Industry radar

curl -s -X POST "https://api.tamradar.com/v1/radars/industry" \
  -H "x-api-key: $TAMRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "radar_type": "industry_funding_rounds",
    "webhook_url": "https://hook.make.com/your-scenario-url",
    "custom_fields": { "label": "ai-funding-watch" }
  }'

⚠️ CRITICAL: persist the mapping after every 201

Store immediately to ./tamradar-radars.jsonl (append one JSON object per line):
{ "input_domain": "openai.com", "input_radar_type": "company_job_openings", "radar_id": "c70813b3-7e87-4ca7-90fd-8c64574d911b", "created_at": "2026-05-01T09:05:00Z" }
This file IS your monitoring state. Without it you cannot poll by specific radar, deactivate targets, or check idempotency before creating.

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.
curl -s -X POST "https://api.tamradar.com/v1/radars/bulk" \
  -H "x-api-key: $TAMRADAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://hook.make.com/your-scenario-url",
    "radars": [
      { "domain": "openai.com", "radar_type": "company_job_openings", "custom_fields": { "crm_account_id": "001" } },
      { "domain": "anthropic.com", "radar_type": "company_new_hires", "custom_fields": { "crm_account_id": "002" } }
    ]
  }'
Bulk submission response — HTTP 202 accepted:
  • Response returns bulk_id and 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

Phase 3: Error handling

MUST handle every error before reporting success.
CodeMeaningAction
401Invalid API keySTOP. Ask user to verify key.
402Insufficient balanceSTOP. Tell user to add funds, then retry.
409Radar already existsNOT an error — it’s already running. Extract radar_id from errors[0].reason. Store it. Move on.
400Validation errorShow errors[].field + errors[].reason verbatim. Ask user to correct.
429Rate limitedWait, then retry. NEVER retry more than 3 times.
5xxServer errorRetry 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:
{
  "status": "success",
  "code": 200,
  "updates": [
    {
      "update_id": "550e8400-e29b-41d4-a716-446655440000",
      "update_type": "radar_finding",
      "discovered_at": "2026-05-01T08:30:00Z",
      "data": {
        "radar_id": "c70813b3-7e87-4ca7-90fd-8c64574d911b",
        "radar_type": "company_job_openings",
        "domain": "openai.com",
        "custom_fields": { "crm_account_id": "001" }
      },
      "content": { }
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Fetch findings for specific radars (max 10 radar_ids per call)

GET /v1/updates?radar_id={id1},{id2}&limit=50
If you have more than 10 radars, split into multiple calls of up to 10 IDs each.

Fetch by signal type

GET /v1/updates?radar_type=company_job_openings,company_new_hires&limit=50

Incremental — only new since last check

GET /v1/updates?since={last_discovered_at}&limit=100
ALWAYS store discovered_at from the last update you processed. Pass it as since on the next call.

Pagination

IF has_more: true → fetch next page:
GET /v1/updates?cursor={next_cursor}
Repeat until has_more: false.

To include radar failures in polling

GET /v1/updates?update_type=radar_finding,radar_failure

Presenting findings to the user

Group by data.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

curl -s -X DELETE "https://api.tamradar.com/v1/radars/{radar_id}" \
  -H "x-api-key: $TAMRADAR_API_KEY"
  • Irreversible. Must create a new radar to resume monitoring.
  • No further charges after deactivation.
IF user says “stop monitoring openai.com for job openings” → look up 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

TAMradar setup complete.

Balance: $42.50 remaining

Radars active:
  company_job_openings     · openai.com     · c70813b3-7e87-4ca7-90fd-8c64574d911b
  contact_job_changes      · Sam Altman     · a4f28c91-3b12-4e70-9d55-7e3dda58f100  (already existed — skipped POST)
  industry_funding_rounds  · —              · f9d01c55-82ba-4f3e-b461-2a9e7c11d830

Failures:
  None

Mapping saved to:
  ./tamradar-radars.jsonl

To fetch findings now:
  GET /v1/updates?radar_id=c70813b3-...,a4f28c91-...&limit=50
  (max 10 IDs per call — split into multiple requests if needed)

Findings retained for 60 days.

Webhook: Make.com scenario (https://hook.make.com/...) ✓
  — OR —
Polling only. Ask me anytime to check for new findings.

Radar type reference

Company — POST /v1/radars/companies

Required: domain, radar_typewebhook_url optional (omit for poll-only)
radar_typeWhat it tracksFilterable?
company_job_openingsNew job postingsYes
company_new_hiresPeople joining the companyYes
company_promotionsInternal promotionsYes
company_reviewsGlassdoor/employer reviewsNo
company_mentionsWeb mentions of the companyNo
company_social_postsCompany LinkedIn/social postsNo
company_social_posts_cxoExecutive social postsYes
company_social_engagementsEngagements on company postsNo

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 to openai.com
  • www.openai.com ✅ → normalized to openai.com
Best practice: pass the bare domain (openai.com).

Filters for filterable types

departments[] — OR within the array. Omit to match any department. Do not send an empty array (400 error). seniorities[] — OR within the array. Omit to match any seniority. Do not send an empty array (400 error). When both are provided, findings must match the department filter AND the seniority filter. Valid departments: Accounting, Administrative, Business Development, Consulting, Customer Success, Design, Education, Engineering, Finance, Human Resources, Information Technology, Legal, Manufacturing, Marketing, Media and Communication, Operations, Product Management, Project Management, Purchasing, Quality Assurance, Real Estate, Research, Sales, Support Valid seniorities: Owner, CXO, Vice President, Director, Manager, Senior, Entry, Training, Partner NEVER invent department or seniority values. Use ONLY the values listed above or you will get a 400 error.

job_titles — boolean expression string (optional, overrides departments + seniorities)

When job_titles is set, it replaces departments and seniorities — you cannot combine them. Supported operators: OR, AND, NOT. Multi-word terms must be double-quoted.
"CEO OR CTO"
"VP Engineering OR VP Sales"
"(CEO OR CTO) AND NOT Manager"
"\"Head of Engineering\" OR \"VP of Engineering\""

Contact — POST /v1/radars/contacts

Required: radar_type + type-specific identifiers — webhook_url optional (omit for poll-only):
radar_typeAdditional required fields
contact_job_changesdomain + at least one of: email, profile_url, full_name
contact_social_engagementsprofile_url (must contain linkedin.com/in/, x.com/, or twitter.com/)
contact_social_postsprofile_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 to https://www.linkedin.com/in/samaltman
  • linkedin.com/in/samaltman ✅ → https:// added automatically
  • Trailing slash stripped automatically
Uniqueness for contacts is keyed on 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_typeAdditional required fields
industry_funding_roundsNone
industry_new_companiesNone
industry_mentionskeyword (min 3 chars)
industry_job_openingskeyword (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_url is optional — omit for poll-only radars; include only when real-time push delivery is needed
  • Rate limit: 100 requests / 60 seconds — need more? contact support@tamradar.com
  • Bulk max: 100 radars per request
  • Polling radar_id filter: 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_type per account — duplicates get 409
  • Contact uniqueness: per profile_url + radar_type — different contact radar types for the same person ARE allowed
  • Persistence: save mappings to ./tamradar-radars.jsonl by default