Introduction
CapyScout turns an email address into a scored, source-backed decision - a classification, fit/risk/confidence scores, a recommended action and route, a suggested reply, and company + person enrichment. There are three ways to call it, all sharing one API key, one billing model, and the same result:
- REST API - call from your backend, signup flow, or CRM webhook.
- MCP server - let an AI agent (Claude, Cursor, Windsurf) call CapyScout as a tool.
- Clay - enrich a whole table with the HTTP API block, no code.
Authentication
Every request needs an account API key. Create one in Settings → Integrations. Keys are shown once - store the secret securely. Send it as a Bearer token (or the X-Api-Key header). The account is resolved from the key, so request bodies never carry an account id.
Authorization: Bearer cs_live_xxxxxxxxxxxxxxxxxxxxxxxx
Base URL
Production base URL is https://app.capyscout.com (local dev: http://localhost:8080). All REST endpoints are versioned under /api/v1. The MCP server is at /mcp.
Enrich an email
POST /api/v1/enrich/email
Synchronous. Returns the full Intelligence Card. Warm lookups (cached domain/identity) return in well under a second; cold lookups run a live crawl + model pass and take longer.
Request
curl -X POST https://app.capyscout.com/api/v1/enrich/email \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"email": "jane@acme.com",
"domain": "acme.com", // optional override
"source": "signup", // optional
"message": "Looking for a demo", // optional
"scenario": "signup_triage" // optional, defaults to signup_triage
}'
Response 200
{
"object": "enrichment",
"id": "enr_9aZ2xQ1p",
"status": "complete",
"cached": false,
"latency_ms": 8421,
"data": {
"email": "jane@acme.com",
"classification": "high_fit_lead",
"classificationLabel": "High-fit lead",
"fitScore": 88, "riskScore": 12, "confidence": 91,
"recommendedAction": "Route to sales - high-priority follow-up",
"fullName": "Jane Chen", "jobTitle": "VP of Engineering",
"company": { "name": "Acme", "domain": "acme.com", "industry": "B2B SaaS" },
"signals": ["Work email verified", "Hiring engineers", "Has pricing page"],
"suggestedReply": "Hi Jane - thanks for signing up...",
"evidence": [ ... ], "uncertain": [ ... ]
}
}
Flat response (Clay, Zapier, Make)
POST /api/v1/enrich/email/flat
Same enrichment, but the card is flattened to a single-level snake_case object so no-code tools can map each field straight to a column. This is the endpoint to use in a Clay HTTP API block. Same auth, billing, quotas, and cutoffs as the standard endpoint.
curl -X POST https://app.capyscout.com/api/v1/enrich/email/flat \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "email": "jane@acme.com" }'
Response 200
{
"id": "enr_9aZ2xQ1p",
"cached": false,
"latency_ms": 8421,
"email": "jane@acme.com",
"scenario": "signup_triage",
"classification": "high_fit_lead",
"classification_label": "High-fit lead",
"fit_score": 88,
"risk_score": 12,
"confidence": 91,
"recommended_action": "Route to sales - high-priority follow-up",
"recommended_route": "Sales / founder",
"full_name": "Jane Chen",
"job_title": "VP of Engineering",
"seniority": "Exec",
"person_linkedin": "https://linkedin.com/in/janechen",
"person_location": "San Francisco, US",
"identity_verified": true,
"company_name": "Acme",
"company_domain": "acme.com",
"company_industry": "B2B SaaS",
"company_size": "51-200",
"company_category": "B2B SaaS",
"website_reachable": true,
"suggested_reply": "Hi Jane - thanks for signing up...",
"why_it_matters": "VP-level buyer at a growing SaaS...",
"signals": "Work email verified; Hiring engineers; Has pricing page"
}
signals is a single semicolon-joined string so it drops cleanly into one column. Errors keep the standard error envelope (see below), so map error.message too.
Enrich a company
POST /api/v1/enrich/company
Domain in, firmographics out - company name, description, tech stack, pricing/careers signals, domain age, LinkedIn, and a free SEC EDGAR funding signal (US). Company-only, no person layer.
curl -X POST https://app.capyscout.com/api/v1/enrich/company \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "domain": "stripe.com" }'
Response 200
{
"id": null, "cached": false, "latency_ms": 1240,
"data": {
"domain": "stripe.com",
"name": "Stripe",
"description": "Financial infrastructure for the internet",
"websiteReachable": true,
"hasPricingPage": true,
"hasCareersPage": true,
"techStack": ["HubSpot", "Segment"],
"domainAgeDays": 5487,
"linkedinUrl": "https://linkedin.com/company/stripe",
"secFundingFiling": true,
"secFundingDate": "2024-04-01",
"secFilingCount": 12
}
}
Discover companies
POST /api/v1/discover
Describe who to find in plain English and get merged company results from competitor, technology, and local sources. Searching is free - it costs no credits, only your per-plan monthly search cap; enriching the results is what spends credits. The API is available on Lite and up.
curl -X POST https://app.capyscout.com/api/v1/discover \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "query": "Shopify stores in Austin with 4.5+ stars" }'
Response 200
{
"object": "discovery",
"interpretation": "Shopify stores in Austin, TX with 4.5+ stars",
"count": 24,
"results": [
{ "name": "Acme Goods", "domain": "acmegoods.com", "reason": "Runs Shopify",
"rating": 4.7, "reviews": 212, "match_score": 88, "location": "Austin, TX" }
],
"searches_remaining": 476
}
A query that is too vague returns count: 0 with a clarification question instead of spending a search.
Verify an email (1 credit)
POST /api/v1/verify/email
Authoritative mailbox deliverability (valid / invalid / catch-all) plus quality flags. Costs one credit per completed verification. For a free syntax/MX/quality verdict, use /api/v1/check/email below.
curl -X POST https://app.capyscout.com/api/v1/verify/email \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "email": "jane@acme.com" }'
Response 200
{
"email": "jane@acme.com", "domain": "acme.com",
"deliverable": true, "verification_status": "valid",
"has_mx": true, "is_disposable": false, "is_role_account": false,
"is_free_email": false, "is_work_email": true
}
Recent events (free)
GET /api/v1/feed?limit=20
Your most recent enrichment and signal events, newest first. Read-only and consumes no credits; limit is clamped to 1-100.
curl -H "Authorization: Bearer cs_live_xxx" \ "https://app.capyscout.com/api/v1/feed?limit=20"
Response 200
{
"object": "list",
"count": 20,
"data": [
{ "id": "enr_9aZ2xQ1p", "created_at": "2026-07-18T14:03:00", "data": { ... } }
]
}
Check an email (free, rate-limited)
POST /api/v1/check/email
No credits consumed. Returns syntax, MX deliverability, free/disposable/role flags, and a 0-100 quality score with a plain verdict (business, personal, role_account, disposable, undeliverable, invalid). Great for gating a signup form or filtering a batch before sending to /enrich/email.
Rate limit: 200 checks/hour per API key (configurable on enterprise plans). Returns 429 with a Retry-After epoch when exceeded.
curl -X POST https://app.capyscout.com/api/v1/check/email \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "email": "jane@acme.com" }'
Response 200
{
"email": "jane@acme.com",
"domain": "acme.com",
"syntax_valid": true,
"deliverable": true,
"has_mx": true,
"mx_provider": "Google Workspace",
"is_free_email": false,
"is_disposable": false,
"is_role_account": false,
"is_work_email": true,
"quality_score": 92,
"verdict": "business"
}
Find competitors
POST /api/v1/intel/competitors
Domain in, a scored list of rival companies out. Each competitor carries a website, a reason (product_overlap, market_overlap, keyword_overlap), and a 0-100 threat score. Built from public search + reasoning.
curl -X POST https://app.capyscout.com/api/v1/intel/competitors \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{ "domain": "stripe.com" }'
Response 200
{
"id": null, "cached": false, "latency_ms": 3120,
"data": {
"domain": "stripe.com",
"companyName": "Stripe",
"competitors": [
{ "name": "Adyen", "website": "adyen.com", "reason": "product_overlap", "threatScore": 88 },
{ "name": "Square", "website": "squareup.com", "reason": "product_overlap", "threatScore": 74 },
{ "name": "Checkout.com", "website": "checkout.com", "reason": "keyword_overlap", "threatScore": 61 }
]
}
}
Fetch a prior enrichment
GET /api/v1/enrich/{id}
curl https://app.capyscout.com/api/v1/enrich/enr_9aZ2xQ1p \ -H "Authorization: Bearer cs_live_xxx"
Returns a compact summary of the stored decision. Scoped to your account; unknown ids return 404.
Monitoring: watchlist & signals
Read and manage the companies you monitor and the signals you track - the same data the app shows. Writes respect your plan limits (watchlist size and signal count); over-limit items are skipped and reported in the response.
GET /api/v1/companies - watched companies with score and Why Now
curl https://app.capyscout.com/api/v1/companies \
-H "Authorization: Bearer cs_live_xxx"
→ { "object": "list", "data": [
{ "domain": "acme.com", "name": "Acme Corp", "score": 42,
"why_now": "New CRO, hiring 5 AEs...", "last_scan": "2026-07-14T08:00" } ] }
POST /api/v1/companies - add domains to the watchlist
curl -X POST https://app.capyscout.com/api/v1/companies \
-H "Authorization: Bearer cs_live_xxx" -H "Content-Type: application/json" \
-d '{ "domains": ["acme.com", "beta.io"], "tags": "Q3 targets" }'
→ { "object": "add_result", "added": 2, "already_monitored": 0,
"capped_out": 0, "watchlist": "My Watchlist" }
GET /api/v1/companies/{domain}/signals - signals that fired on a company
curl https://app.capyscout.com/api/v1/companies/acme.com/signals \ -H "Authorization: Bearer cs_live_xxx"
GET /api/v1/signals - list your custom signals
POST /api/v1/signals - add a signal (plain English)
curl -X POST https://app.capyscout.com/api/v1/signals \
-H "Authorization: Bearer cs_live_xxx" -H "Content-Type: application/json" \
-d '{ "question": "Did they hire a new CRO?", "name": "New CRO", "rank": "High" }'
→ { "object": "add_result", "added": 1, "watchlist": "My Watchlist" }
If added is 0, your plan's signal limit is reached - upgrade to add more. New signals fire to your configured webhook (Slack, Teams, Clay, or any URL) as they are detected.
Idempotency
Safely retry POSTs without double-charging. Send an Idempotency-Key header; a repeat with the same key returns the original result and is not billed again.
-H "Idempotency-Key: 6f1c8b2e-...-a7"
Response schema
Key fields on the enrichment (nested data / flat response):
| Field | Type | Description |
|---|---|---|
| classification | string | e.g. high_fit_lead, low_intent, risky_signup |
| fit_score | int 0-100 | How well the lead fits your ICP |
| risk_score | int 0-100 | Abuse / fraud / bad-fit risk |
| confidence | int 0-100 | Confidence in the decision |
| recommended_action | string | The one next step to take |
| full_name / job_title | string | Verified identity (when available) |
| company_* | string | name, domain, industry, size, category |
| suggested_reply | string | Ready-to-send opener |
Errors, rate limits & cutoffs
Errors use a consistent envelope. No internal details are ever leaked.
{ "error": { "type": "quota_exceeded", "code": "plan_limit_reached",
"message": "Your plan's enrichment quota has been reached." } }
| Status | Meaning |
|---|---|
| 400 | Invalid or missing email. |
| 401 | Missing / invalid / revoked API key. |
| 402 | Plan enrichment quota reached (no overage). |
| 429 | Rate limit or system cutoff. Check Retry-After. |
| 500 | Transient enrichment error - safe to retry. |
Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. A 120 requests/minute per-key burst limit applies by default.
MCP server
CapyScout ships a Model Context Protocol server at POST /mcp (JSON-RPC 2.0, Streamable-HTTP). Point any MCP-capable agent at it with your API key. Tools are metered and plan-limited exactly like REST.
Tools: enrich_email, get_enrichment, check_email, list_competitors, list_watchlist, add_to_watchlist, list_signals, add_signal, get_company_signals.
Client config
{
"mcpServers": {
"capyscout": {
"url": "https://app.capyscout.com/mcp",
"headers": { "Authorization": "Bearer cs_live_xxx" }
}
}
}
Call a tool (raw JSON-RPC)
curl -X POST https://app.capyscout.com/mcp \
-H "Authorization: Bearer cs_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0", "id": 1,
"method": "tools/call",
"params": {
"name": "enrich_email",
"arguments": { "email": "jane@acme.com" }
}
}'
The tool returns a compact, token-efficient card (classification, scores, recommended action, key signals, suggested reply) as both text and structuredContent.
Connect over OAuth (Claude.ai, no key)
MCP clients that speak OAuth - like Claude.ai Custom Connectors - can connect to /mcp without a pasted key. Add CapyScout as a connector, sign in, and approve; the client discovers everything automatically (PKCE + Dynamic Client Registration).
- Claude.ai → Settings → Connectors → Add custom connector.
- Paste
https://app.capyscout.com/mcpas the connector URL. - Click Connect, sign in, and approve. Manage or revoke under Settings → Integrations → Connected apps.
GET /.well-known/oauth-protected-resource # RFC 9728 GET /.well-known/oauth-authorization-server # RFC 8414 POST /oauth/register # RFC 7591 dynamic client registration GET /oauth/authorize # user sign-in + consent (PKCE, S256) POST /oauth/token # authorization_code + refresh_token grants
Clay integration
Enrich a whole Clay table with CapyScout using the built-in HTTP API enrichment block - no code. Every row's email becomes a scored decision with company + person fields as columns.
- In a Clay table with an email column, add a column → HTTP API.
- Method:
POST. URL:https://app.capyscout.com/api/v1/enrich/email/flat - Headers:
Authorization: Bearer cs_live_xxxandContent-Type: application/json - Body:
{ "email": "{{email}}" }(map{{email}}to your column) - Run the column, then map response fields (
fit_score,classification,company_name, ...) to new columns.
Use the flat endpoint so each field maps to one column. For agentic, one-off enrichment inside Claygent, point Clay's MCP block at /mcp instead.
Delivery destinations
Beyond calling CapyScout, you can have CapyScout call you. In Workflows, an IF/THEN rule fires an action whenever a decision matches your conditions (for example classification = high_fit_lead or risk_score > 70). Each action delivers to one destination. All HTTP destinations are outbound POSTs from CapyScout - you never open an inbound port.
You configure the destination in the workflow action; there is no separate API call. The table below shows what each destination expects and the exact payload CapyScout sends.
| Destination | You provide | Payload shape |
|---|---|---|
| Slack | Incoming webhook URL | Slack { "text": ... } message |
| Microsoft Teams | Incoming webhook URL | Teams MessageCard |
| Zapier | Catch Hook URL | Flat Brief JSON |
| HubSpot | Workflow / webhook URL | Flat Brief JSON |
| Custom webhook | Any HTTPS URL | Flat Brief JSON |
| Recipient address | Plain-text summary email | |
| Tag | Tag name | Internal - no outbound call |
Every workflow has a Test button that fires a synthetic sample event (jane@acme.com, classification high_fit_lead, fit 88) at your configured destination right now. You can verify Slack messages arrive, check your webhook receives the payload, and confirm email delivery — without touching production traffic.
- Go to Workflows and open or create a rule.
- Configure the action (Slack URL, webhook endpoint, email address, etc.).
- Click the Test button on the rule row — CapyScout fires the sample event immediately.
- Check the Last run status badge; it turns green on a
2xxresponse and shows the HTTP code on failure.
Slack
Posts a formatted message to a channel via a Slack incoming webhook.
- In Slack, open Apps and add Incoming Webhooks (or create a Slack app with the Incoming Webhooks feature enabled).
- Choose the channel to post to and copy the webhook URL (looks like
https://hooks.slack.com/services/T000/B000/XXXX). - In CapyScout → Workflows, add an action, pick Slack, and paste the webhook URL.
Payload CapyScout POSTs to the webhook URL
{
"text": "*CapyScout* - High-fit leads triggered\n>*Email:* jane@acme.com\n>*Classification:* high_fit_lead\n>*Fit:* 88 | *Risk:* 8\n>*Action:* Route to sales and follow up within 15 minutes."
}
Microsoft Teams
Posts a card to a Teams channel via an incoming webhook connector.
- In Teams, open the channel → Manage channel → Connectors → add Incoming Webhook.
- Name it
CapyScout, optionally add an icon, and copy the generated URL. - In CapyScout → Workflows, add an action, pick Microsoft Teams, and paste the webhook URL.
Payload CapyScout POSTs to the webhook URL
{
"@type": "MessageCard",
"@context": "https://schema.org/extensions",
"summary": "jane@acme.com - high_fit_lead (fit: 88, risk: 8)",
"themeColor": "7c3ff7",
"title": "CapyScout - high_fit_lead",
"text": "jane@acme.com - high_fit_lead (fit: 88, risk: 8)"
}
Zapier
Sends the full Brief JSON to a Zapier Catch Hook, so you can fan out to thousands of downstream apps (Sheets, Salesforce, Notion, SMS, and more).
- In Zapier, create a Zap with the Webhooks by Zapier trigger → Catch Hook.
- Copy the custom webhook URL Zapier generates.
- In CapyScout → Workflows, add an action, pick Zapier, and paste the URL. Map fields in later Zap steps.
Payload CapyScout POSTs to the Catch Hook
{
"id": 1234,
"email": "jane@acme.com",
"domain": "acme.com",
"scenario": "signup_triage",
"classification": "high_fit_lead",
"fitScore": 88,
"riskScore": 8,
"confidence": 82,
"recommendedAction": "Route to sales and follow up within 15 minutes.",
"source": "signup_form",
"accountId": 42
}
HubSpot
Sends the same flat Brief JSON to a HubSpot webhook so you can create or update contacts and enroll them in workflows. HubSpot webhook actions are part of workflow automation (Operations Hub) or a custom integration endpoint.
- In HubSpot, create a workflow with a Send a webhook action (or use a custom endpoint that accepts JSON).
- Set the method to
POSTand copy the target URL. - In CapyScout → Workflows, add an action, pick HubSpot, and paste the URL. Map
email,companyName, and scores to HubSpot properties.
Payload CapyScout POSTs to the HubSpot endpoint
{
"id": 1234,
"email": "jane@acme.com",
"domain": "acme.com",
"scenario": "signup_triage",
"classification": "high_fit_lead",
"fitScore": 88,
"riskScore": 8,
"confidence": 82,
"recommendedAction": "Route to sales and follow up within 15 minutes.",
"source": "signup_form",
"accountId": 42
}
Custom webhook
Sends the flat Brief JSON to any HTTPS endpoint you control - your backend, a queue consumer, or an internal service. This is the same payload used by the Zapier and HubSpot destinations; only the label differs.
- Expose an HTTPS endpoint that accepts
POSTwith a JSON body. - In CapyScout → Workflows, add an action, pick Webhook, and paste your URL.
- Read the fields you need; respond
2xxto mark delivery successful.
POST https://your-service.com/hook
Content-Type: application/json
{
"id": 1234,
"email": "jane@acme.com",
"domain": "acme.com",
"scenario": "signup_triage",
"classification": "high_fit_lead",
"fitScore": 88,
"riskScore": 8,
"confidence": 82,
"recommendedAction": "Route to sales and follow up within 15 minutes.",
"source": "signup_form",
"accountId": 42
}
Delivery is best-effort and logged to the workflow run history. Non-2xx responses are recorded as failed so you can spot broken endpoints in the Workflows UI.
Sends a plain-text summary email to any address. Messages are sent from notifications@capyscout.com - no inbound setup required, just enter the recipient.
- In CapyScout → Workflows, add an action, pick Email, and enter the recipient address.
- Add
notifications@capyscout.comto your allowlist if your mail server filters aggressively.
Message CapyScout sends
From: notifications@capyscout.com Subject: CapyScout: high_fit_lead - jane@acme.com Workflow "High-fit leads" fired. Email: jane@acme.com Company: Acme Inc Scenario: signup_triage Classification: high_fit_lead Fit / Risk: 88 / 8 Recommended: Route to sales and follow up within 15 minutes.
Tag
An internal action that labels the matching Brief for later filtering. It makes no outbound HTTP call and needs no setup beyond choosing a tag name in the workflow action.