# API Reference
Source: https://docs.thehog.ai/api-reference
API endpoints for search, enrichment, research, monitors, scrapers, and operations.
The Hog API is organized around a small set of public resources. All requests use the production base URL:
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
https://developer.thehog.ai
```
Every endpoint is prefixed with `/api`.
Search for companies by firmographics, technographics, and buying signals.
Search for people by role, seniority, company, and natural-language criteria.
Enrich contacts with verified emails, phone numbers, profile data, and signals.
Run LLM-powered research jobs that return data matching your JSON Schema.
Set up recurring monitors and poll detected events.
Submit async searches across web and social sources.
Search LinkedIn posts and retrieve company, profile, post, reaction, and comment data.
Retrieve public profiles, posts, post details, comments, followers, and following lists.
Fetch public profile details and recent videos for TikTok accounts.
Retrieve public post, video, reel, photo, and page content.
Retrieve public video and channel content from YouTube URLs.
Search, scrape, batch scrape, and crawl public web pages through normalized schemas.
Analyze images for signs of face manipulation.
Poll async operations returned by long-running endpoints.
# Search companies
Source: https://docs.thehog.ai/api/companies/company-search
api-reference/openapi.json POST /api/v1/companies/search
Async company discovery. Returns operationId; poll GET /api/operations/:id.
# POST /api/v1/companies/search
> Search for companies by firmographics, technographics, and signals. Async.
Search for companies by industry, headcount, revenue, technology, hiring signals, and more. This is an async endpoint -- returns `202 Accepted` with a poll URL.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/companies/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"query": "Series B SaaS companies in the US with 50-200 employees", "limit": 10}'
```
# Start deep research
Source: https://docs.thehog.ai/api/deep-research
api-reference/openapi.json POST /api/deep-research
Start a deep research job with a prompt and JSON Schema. The response includes an operation ID and poll URL for retrieving the structured result.
# POST /api/deep-research
> Start an async LLM research job with a prompt and JSON Schema.
Kicks off an LLM-powered research job that browses the web and returns structured data conforming to your JSON Schema. Always async -- returns `202 Accepted` with an operation ID.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/deep-research \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"prompt": "Research AI CRM competitors", "schema": {"type": "object", "properties": {"competitors": {"type": "array"}}}}'
```
# Get enrichment
Source: https://docs.thehog.ai/api/enrichments/get-enrichment
api-reference/openapi.json GET /api/enrichments/{id}
Check the status of an enrichment request and retrieve the result once it completes.
# GET /api/enrichments/:id
> Poll status and result of an async enrichment.
Poll for status and results of an enrichment that returned `202`.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/enrichments/op_01HZXYZ789 \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# Submit enrichment
Source: https://docs.thehog.ai/api/enrichments/submit-enrichment
api-reference/openapi.json POST /api/enrichments
Enrich one contact or a batch of contacts with requested fields such as verified email, phone, and signals. Small contact-only requests can complete immediately; larger requests return an operation to poll.
# POST /api/enrichments
> Schema-driven person enrichment. Returns 200 sync or 202 async.
Performs schema-driven person enrichment. Provide an identifier and requested fields.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/enrichments \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"identifier": {"linkedin_url": "https://linkedin.com/in/johndoe"}, "fields": ["contact.email", "profile"]}'
```
# Create monitor
Source: https://docs.thehog.ai/api/monitors/create
api-reference/openapi.json POST /api/v1/monitors
Create a recurring monitor that runs on a schedule and stores matching events for later review.
# POST /api/v1/monitors
> Create a recurring monitor to track keywords, profiles, or posts.
Create a monitor that runs on a schedule to track keywords, profiles, or posts across LinkedIn, X, Reddit, TikTok, Instagram, and the web.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/monitors \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"name": "Competitor mentions", "type": "reddit_keyword", "config": {"query": "acme"}, "cadence_minutes": 60, "max_results": 10}'
```
# Delete monitor
Source: https://docs.thehog.ai/api/monitors/delete
api-reference/openapi.json DELETE /api/v1/monitors/{id}
Delete a monitor by ID.
# DELETE /api/v1/monitors/:id
> Permanently delete a monitor.
Permanently delete a monitor. Historical events are retained.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X DELETE https://developer.thehog.ai/api/v1/monitors/mon_01HZXYZ \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# List monitor events
Source: https://docs.thehog.ai/api/monitors/events
api-reference/openapi.json GET /api/v1/monitors/{id}/events
List events found by a monitor.
# GET /api/v1/monitors/:id/events
> List events detected by a monitor.
Retrieve events (posts, mentions, profile changes) detected by a monitor.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/v1/monitors/mon_01HZXYZ/events?limit=10 \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# Get monitor
Source: https://docs.thehog.ai/api/monitors/get
api-reference/openapi.json GET /api/v1/monitors/{id}
Retrieve a monitor by ID.
# GET /api/v1/monitors/:id
> Retrieve a monitor by ID.
Fetch a single monitor's configuration, status, cadence, and next run time.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/v1/monitors/mon_01HZXYZ \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# List monitors
Source: https://docs.thehog.ai/api/monitors/list
api-reference/openapi.json GET /api/v1/monitors
List monitors for your organization.
# GET /api/v1/monitors
> List all monitors for your organization.
List all monitors with pagination and optional status filtering.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/v1/monitors?status=active \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# Run monitor now
Source: https://docs.thehog.ai/api/monitors/run-now
api-reference/openapi.json POST /api/v1/monitors/{id}/run-now
Trigger a monitor run immediately instead of waiting for its next scheduled time.
# POST /api/v1/monitors/:id/run-now
> Trigger an immediate run of a monitor.
Trigger an immediate execution outside the regular cadence.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/monitors/mon_01HZXYZ/run-now \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# Update monitor
Source: https://docs.thehog.ai/api/monitors/update
api-reference/openapi.json PATCH /api/v1/monitors/{id}
Update a monitor configuration, schedule, or status.
# PATCH /api/v1/monitors/:id
> Update a monitor's configuration or cadence.
Update any mutable field on an existing monitor.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X PATCH https://developer.thehog.ai/api/v1/monitors/mon_01HZXYZ \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"cadence_minutes": 120}'
```
# Get operation
Source: https://docs.thehog.ai/api/operations/get-operation
api-reference/openapi.json GET /api/operations/{id}
Check the status of a background operation and retrieve its result once it completes.
# GET /api/operations/:id
> Poll the status of any async operation.
Poll the status of any async operation (enrichment, deep research, search, etc.).
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/operations/op_01HZXYZ \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# Search people
Source: https://docs.thehog.ai/api/people/people-search
api-reference/openapi.json POST /api/v1/people/search
Async people discovery. Returns operationId; poll GET /api/operations/:id.
# POST /api/v1/people/search
> Search for people by role, seniority, company, and more. Async.
Discover people matching your ICP using natural-language queries or structured filters. This is an async endpoint -- returns `202 Accepted` with a poll URL.
Use `POST /api/v1/people/search/estimate` before queueing the search to inspect
the conservative preflight credit ceiling, especially when requesting
`includeContacts`. If you pass `maxCredits` to this endpoint and it is below the
preflight ceiling, the request fails with `402 Payment Required` before paid
people or contact enrichment work starts.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "VP of Engineering at fintech startups in NYC",
"limit": 10,
"maxCredits": 1250
}'
```
# Estimate people search
Source: https://docs.thehog.ai/api/people/people-search-estimate
api-reference/openapi.json POST /api/v1/people/search/estimate
Pre-flight conservative credit estimate for POST /api/v1/people/search. Includes contact enrichment assumptions when includeContacts is true.
# POST /api/v1/people/search/estimate
> Estimate credits for async people search before queueing paid enrichment work.
Use this endpoint before `POST /api/v1/people/search` when you want to set
`maxCredits` or show users the credit risk of requesting contact enrichment.
The estimate is a conservative preflight ceiling. Actual settled credits are
based on measured usage and can be lower. Discovery risk scales with requested
result pages, so higher `limit` values can require a larger preflight ceiling
even when `includeContacts` is false.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search/estimate \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "VP Engineering at B2B SaaS companies",
"limit": 10,
"includeContacts": true,
"contactFields": ["email"]
}'
```
The response includes the standard estimate fields plus a breakdown. The base
people-search portion assumes one discovery charge per provider-result page
currently modeled as up to 25 people. When `includeContacts` is true, omitted
`contactFields` means both email and phone, matching the search endpoint.
# Get Facebook page
Source: https://docs.thehog.ai/api/scrapers/facebook-page
api-reference/openapi.json POST /api/v1/platform/scrapers/facebook/page
Fetch public page content for a Facebook page URL.
# POST /api/v1/platform/scrapers/facebook/page
> Get public Facebook page content.
Retrieve public page content for a Facebook page URL.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/facebook/page \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.facebook.com/openai"}'
```
# Get Facebook post
Source: https://docs.thehog.ai/api/scrapers/facebook-post
api-reference/openapi.json POST /api/v1/platform/scrapers/facebook/post
Fetch public page content for a Facebook post URL.
# POST /api/v1/platform/scrapers/facebook/post
> Get public Facebook post content.
Retrieve public post content for a Facebook post, video, reel, or photo URL.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/facebook/post \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.facebook.com/openai/posts/1234567890"}'
```
# Detect image deepfakes
Source: https://docs.thehog.ai/api/scrapers/image-deepfake-detection
api-reference/openapi.json POST /api/v1/platform/scrapers/image/deepfake-detection
Analyze an image for signs of face manipulation. Submit either a public image URL or a multipart image file.
# POST /api/v1/platform/scrapers/image/deepfake-detection
> Analyze an image for signs of face manipulation.
Submit either a public image URL or a multipart image file. The response returns
a normalized verdict, score, and supporting signals. Signals that are not part
of this endpoint's analysis are returned with `score: null`.
## JSON Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/image/deepfake-detection \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/image.jpg"}'
```
## Multipart Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/image/deepfake-detection \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-F "image=@./image.jpg"
```
The `status` field is `inconclusive` when analysis could not complete within
the request deadline.
# List Instagram followers
Source: https://docs.thehog.ai/api/scrapers/instagram-followers
api-reference/openapi.json POST /api/v1/platform/scrapers/instagram/followers
Fetch followers for an Instagram username.
# POST /api/v1/platform/scrapers/instagram/followers
> Get followers for an Instagram account.
Retrieve followers of a public Instagram account.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/instagram/followers \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"username": "instagram", "maxFollowers": 100}'
```
# List Instagram following
Source: https://docs.thehog.ai/api/scrapers/instagram-following
api-reference/openapi.json POST /api/v1/platform/scrapers/instagram/following
Fetch accounts followed by an Instagram username.
# POST /api/v1/platform/scrapers/instagram/following
> Get accounts an Instagram user is following.
Retrieve accounts that a public Instagram user is following.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/instagram/following \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"username": "instagram", "maxFollowing": 100}'
```
# List Instagram post comments
Source: https://docs.thehog.ai/api/scrapers/instagram-post-comments
api-reference/openapi.json POST /api/v1/platform/scrapers/instagram/post-comments
Fetch comments for an Instagram post or reel URL.
# POST /api/v1/platform/scrapers/instagram/post-comments
> Get comments on a specific Instagram post.
Retrieve comments on a specific Instagram post.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/instagram/post-comments \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"postUrl": "https://www.instagram.com/p/ABC123/", "maxComments": 50}'
```
# Get Instagram post
Source: https://docs.thehog.ai/api/scrapers/instagram-post-details
api-reference/openapi.json POST /api/v1/platform/scrapers/instagram/post-details
Fetch details for an Instagram post or reel URL.
# POST /api/v1/platform/scrapers/instagram/post-details
> Get full details for a specific Instagram post.
Get full details (captions, media, engagement) for a specific post by URL.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/instagram/post-details \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"postUrl": "https://www.instagram.com/p/ABC123/"}'
```
# List Instagram posts
Source: https://docs.thehog.ai/api/scrapers/instagram-posts
api-reference/openapi.json POST /api/v1/platform/scrapers/instagram/posts
Fetch recent posts for an Instagram username.
# POST /api/v1/platform/scrapers/instagram/posts
> Fetch recent posts from an Instagram account.
Retrieve recent posts from a public Instagram account.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/instagram/posts \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"username": "instagram", "maxPosts": 12}'
```
# Get Instagram profile
Source: https://docs.thehog.ai/api/scrapers/instagram-profile
api-reference/openapi.json POST /api/v1/platform/scrapers/instagram/profile
Fetch public profile details for an Instagram username.
# POST /api/v1/platform/scrapers/instagram/profile
> Fetch an Instagram user's profile information.
Retrieve an Instagram user's profile metadata.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/instagram/profile \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"username": "instagram"}'
```
# Get LinkedIn company
Source: https://docs.thehog.ai/api/scrapers/linkedin-company
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/company
Fetch public company details for a LinkedIn slug or URL.
# POST /api/v1/platform/scrapers/linkedin/company
> Get LinkedIn company details by slug or URL.
Retrieve public company metadata for a LinkedIn company slug or URL.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/company \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"identifier": "acme-inc"}'
```
# List LinkedIn company posts
Source: https://docs.thehog.ai/api/scrapers/linkedin-company-posts
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/company-posts
Fetch recent posts for a LinkedIn company page.
# POST /api/v1/platform/scrapers/linkedin/company-posts
> List recent LinkedIn posts from a company page.
Retrieve recent posts for a LinkedIn company slug.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/company-posts \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"companySlug": "acme-inc", "limit": 20}'
```
# Find LinkedIn companies
Source: https://docs.thehog.ai/api/scrapers/linkedin-finder
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/finder
Find LinkedIn company URLs from website domains or URLs.
# POST /api/v1/platform/scrapers/linkedin/finder
> Find LinkedIn company URLs from website domains or URLs.
Submit one or more website domains or URLs and get matching LinkedIn company URLs.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/finder \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"domains": ["https://example.com"]}'
```
# Search LinkedIn posts
Source: https://docs.thehog.ai/api/scrapers/linkedin-keyword-posts
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/keyword-posts
Search LinkedIn posts by keyword.
# POST /api/v1/platform/scrapers/linkedin/keyword-posts
> Search LinkedIn posts by keyword.
Retrieve LinkedIn posts matching a keyword, with optional match mode, sort, and date filters.
`config.matchMode` defaults to `exact`, which searches the keyword as a quoted phrase. Use `broad` to send the keyword without phrase quotes and let LinkedIn match related terms.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/keyword-posts \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"keyword": "b2b saas", "config": {"limit": 25, "matchMode": "broad", "sortBy": "recent", "dateFilter": "past-week"}}'
```
# List LinkedIn post comments
Source: https://docs.thehog.ai/api/scrapers/linkedin-post-comments
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/post-comments
Fetch comments for one or more LinkedIn post URLs.
# POST /api/v1/platform/scrapers/linkedin/post-comments
> List comments on LinkedIn posts.
Retrieve comments for one or more LinkedIn post URLs.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/post-comments \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"postUrls": ["https://www.linkedin.com/feed/update/urn:li:activity:123"], "maxItems": 50}'
```
# List LinkedIn post reactions
Source: https://docs.thehog.ai/api/scrapers/linkedin-post-reactions
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/post-reactions
Fetch reactions for one or more LinkedIn post URLs.
# POST /api/v1/platform/scrapers/linkedin/post-reactions
> List reactions on LinkedIn posts.
Retrieve reactions for one or more LinkedIn post URLs.
## Actor identity
Reaction actors keep the upstream `actor.id` and `actor.linkedinUrl` for backward compatibility. These values are source identifiers, not guaranteed canonical profile slugs. Use `actor.profileUrlKind`, `actor.sourceActorIdKind`, and `actor.resolutionStatus` to distinguish vanity `/in/{slug}` URLs from opaque LinkedIn member identifiers such as `ACoAA...`.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/post-reactions \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"postUrls": ["https://www.linkedin.com/feed/update/urn:li:activity:123"], "maxItems": 50}'
```
# Get LinkedIn profile
Source: https://docs.thehog.ai/api/scrapers/linkedin-profile
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/profile
Fetch public profile details for a LinkedIn username.
# POST /api/v1/platform/scrapers/linkedin/profile
> Get LinkedIn profile details by username.
Retrieve public profile metadata for a LinkedIn profile username.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/profile \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"username": "some-public-id"}'
```
# List LinkedIn profile comments
Source: https://docs.thehog.ai/api/scrapers/linkedin-profile-comments
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/profile-comments
Fetch recent LinkedIn posts a public profile has commented on.
# POST /api/v1/platform/scrapers/linkedin/profile-comments
> List posts a LinkedIn profile commented on.
Retrieve recent public LinkedIn posts a profile has commented on. Provide profile URLs or public profile usernames.
See [Find Outreach Hooks from LinkedIn Activity](/guides/linkedin-outreach-hooks) for an end-to-end script that combines profile comments and reactions into outreach context.
## Options
* `profiles`: LinkedIn `/in/` profile URLs or public profile usernames.
* `maxItems`: maximum comments to scrape per profile.
* `postedLimit`: optional post age filter. Accepted values: `any`, `24h`, `week`, `month`, `3months`, `6months`, `year`.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/profile-comments \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"profiles": ["https://www.linkedin.com/in/satyanadella"], "maxItems": 10, "postedLimit": "month"}'
```
# List LinkedIn profile posts
Source: https://docs.thehog.ai/api/scrapers/linkedin-profile-posts
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/profile-posts
Queue a LinkedIn profile posts scrape and poll the returned operation URL for results.
# POST /api/v1/platform/scrapers/linkedin/profile-posts
> Queue a LinkedIn profile posts scrape.
Returns `202 Accepted` with an `operationId`. Poll `GET /api/operations/{id}` until status is `succeeded` to fetch the posts.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/profile-posts \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"username": "some-public-id", "maxPosts": 20}'
```
# List LinkedIn profile reactions
Source: https://docs.thehog.ai/api/scrapers/linkedin-profile-reactions
api-reference/openapi.json POST /api/v1/platform/scrapers/linkedin/profile-reactions
Fetch recent LinkedIn posts a public profile has reacted to.
# POST /api/v1/platform/scrapers/linkedin/profile-reactions
> List posts a LinkedIn profile reacted to.
Retrieve recent public LinkedIn posts a profile has reacted to. Provide profile URLs or public profile usernames.
See [Find Outreach Hooks from LinkedIn Activity](/guides/linkedin-outreach-hooks) for an end-to-end script that combines profile reactions and comments into outreach context.
## Options
* `profiles`: LinkedIn `/in/` profile URLs or public profile usernames.
* `maxItems`: maximum reactions to scrape per profile.
* `postedLimit`: optional post age filter. Accepted values: `any`, `24h`, `week`, `month`, `3months`, `6months`, `year`.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/linkedin/profile-reactions \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"profiles": ["https://www.linkedin.com/in/satyanadella"], "maxItems": 10, "postedLimit": "month"}'
```
# Get shared SEO keywords
Source: https://docs.thehog.ai/api/scrapers/seo-competing-keywords
api-reference/openapi.json POST /api/v1/platform/scrapers/seo/competing-keywords
Returns organic keywords shared across the supplied domains.
# POST /api/v1/platform/scrapers/seo/competing-keywords
> Find organic keywords shared across domains.
Compare one or more competitor domains to discover overlapping organic keywords. Optionally exclude domains from the comparison.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/seo/competing-keywords \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"includedDomains": ["acme.com", "competitor.com"], "pageSize": 25}'
```
# Get SEO domain overview
Source: https://docs.thehog.ai/api/scrapers/seo-domain
api-reference/openapi.json POST /api/v1/platform/scrapers/seo/domain
Returns organic and paid search signals, keyword themes, and inferred tech stack for a domain.
# POST /api/v1/platform/scrapers/seo/domain
> Get organic and paid search signals for a domain.
Returns keyword counts, a short summary, keyword themes, and inferred tech stack for the domain you provide.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/seo/domain \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"domain": "acme.com"}'
```
# Get SEO keywords
Source: https://docs.thehog.ai/api/scrapers/seo-keywords
api-reference/openapi.json POST /api/v1/platform/scrapers/seo/keywords
Returns organic search keywords for a domain with optional filters and search-type segmentation.
# POST /api/v1/platform/scrapers/seo/keywords
> List organic search keywords for a domain.
Returns ranked keywords with volume, position, difficulty, and click estimates. Use `searchType` to focus on gains, losses, newly ranked terms, or the most valuable keywords.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/seo/keywords \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"domain": "acme.com", "searchType": "MostValuable", "pageSize": 25}'
```
# Get TikTok profile
Source: https://docs.thehog.ai/api/scrapers/tiktok-profile
api-reference/openapi.json POST /api/v1/platform/scrapers/tiktok/profile
Fetch public profile details and recent videos for a TikTok username.
# POST /api/v1/platform/scrapers/tiktok/profile
> Fetch a TikTok user's profile and recent videos.
Retrieve a TikTok user's profile information and recent videos.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/tiktok/profile \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"username": "tiktok", "maxVideos": 20}'
```
# Crawl website
Source: https://docs.thehog.ai/api/scrapers/web-crawl
api-reference/openapi.json POST /api/v1/platform/scrapers/web/crawl
Queue an asynchronous website crawl. Poll the returned operation URL for status and results.
# POST /api/v1/platform/scrapers/web/crawl
> Crawl a website and return discovered page content.
Crawl a website from a starting URL with an optional page limit.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/web/crawl \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "limit": 5}'
```
# Scrape web page
Source: https://docs.thehog.ai/api/scrapers/web-scrape
api-reference/openapi.json POST /api/v1/platform/scrapers/web/scrape
Fetch a web page and return readable text plus requested markdown, HTML, links, metadata, or schema-guided JSON.
# POST /api/v1/platform/scrapers/web/scrape
> Scrape a single web page and return its content.
Scrape a single web page and return readable content. By default the endpoint
returns the backward-compatible `url`, `text`, and `statusCode` fields. Use
`formats` when you need markdown, HTML, discovered links, page metadata, or
schema-guided JSON extraction.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/web/scrape \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/pricing", "renderJs": true, "formats": ["markdown", "metadata"]}'
```
## Formats
`formats` is optional and defaults to `["text"]`.
| Format | Returns |
| ---------- | --------------------------------------------------------------------------------------------------------------- |
| `text` | Readable text. This is always included for backward compatibility. |
| `markdown` | Markdown-friendly page content for agents and LLM workflows. |
| `html` | Fetched or rendered HTML when available. |
| `links` | Normalized links discovered on the page. |
| `metadata` | Page title, description, canonical URL, final URL, status code, content type, and size metadata when available. |
| `json` | Data extracted into your provided JSON Schema. |
Requested optional formats appear as additional fields under `data`. If a
requested format is unavailable, the field may be `null` or an empty array.
## Schema-guided JSON
Request `json` only when you provide `jsonSchema`. The schema defines the
returned keys and shape; page content is mapped into that schema and validated
before the response is returned. The root schema must be an object; use array
properties for repeated data such as comments, products, or plans.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/web/scrape \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/pricing",
"formats": ["markdown", "json"],
"jsonSchema": {
"type": "object",
"additionalProperties": false,
"required": ["plans"],
"properties": {
"plans": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["name", "price"],
"properties": {
"name": { "type": "string" },
"price": { "type": "string" }
}
}
}
}
},
"instructions": "Extract public pricing plans visible on the page."
}'
```
`jsonSchema` and `instructions` are only valid when `formats` includes `json`.
Schema-guided extraction performs additional model work and may use more credits
than a plain text or markdown scrape.
# Batch scrape web pages
Source: https://docs.thehog.ai/api/scrapers/web-scrape-batch
api-reference/openapi.json POST /api/v1/platform/scrapers/web/scrape/batch
Queue a batch scrape job and poll the returned operation URL for per-URL results.
# POST /api/v1/platform/scrapers/web/scrape/batch
> Queue multiple web page scrapes and poll for per-URL results.
Use batch scrape when you have many URLs and do not need the results in the
initial HTTP response. The endpoint returns an operation ID immediately; poll
`GET /api/operations/:id` until the operation reaches a terminal status.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/web/scrape/batch \
-H "Authorization: Bearer " \
-H "Content-Type: application/json" \
-H "Idempotency-Key: batch-2026-05-22-001" \
-d '{"urls": ["https://example.com/pricing", "https://example.com/about"], "maxConcurrency": 2}'
```
# Queue a deep web scrape job
Source: https://docs.thehog.ai/api/scrapers/web-scrape-jobs
api-reference/openapi.json POST /api/v1/platform/scrapers/web/scrape/jobs
Queue an async browser scrape for dynamic or long pages and poll the returned operation URL for results.
# POST /api/v1/platform/scrapers/web/scrape/jobs
> Queue a deep web scrape for long or dynamic pages and poll for the result.
Use deep scrape when a page needs more rendering time than the synchronous
scrape endpoint should spend, such as long comment threads, lazy-loaded content,
or pages with repeated "load more" controls. The endpoint returns an operation
ID immediately; poll `GET /api/operations/:id` until the operation reaches a
terminal status.
The result uses the same requested formats as single-page scrape. Metadata may
include capture details such as how many scrolls were completed and why capture
stopped. A deep scrape is still bounded by the limits you send, so use the
capture metadata to decide whether to run again with higher limits.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/web/scrape/jobs \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: deep-scrape-2026-06-24-001" \
-d '{
"url": "https://example.com/thread",
"formats": ["markdown", "metadata"],
"maxDurationMs": 120000,
"maxScrolls": 40,
"contentStableRounds": 3,
"expandClickableContent": true
}'
```
Use `formats: ["json"]` with `jsonSchema` when you want schema-guided
extraction from the captured page content. The schema defines the returned keys
and shape.
# Search web
Source: https://docs.thehog.ai/api/scrapers/web-search
api-reference/openapi.json POST /api/v1/platform/scrapers/web/search
Search the web and return normalized results in a stable response shape.
# POST /api/v1/platform/scrapers/web/search
> Search the web and return ranked results.
Run a web search and return result URLs, titles, and snippets.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/web/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"query": "AI CRM tools", "maxResults": 10}'
```
# Get X conversation thread
Source: https://docs.thehog.ai/api/scrapers/x-conversation
api-reference/openapi.json POST /api/v1/platform/scrapers/x/conversation
Fetch a public X (Twitter) conversation thread by post ID.
# POST /api/v1/platform/scrapers/x/conversation
> Get an X (Twitter) conversation thread by post ID.
Retrieve the posts in a conversation thread starting from a post ID.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/x/conversation \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"postId": "1234567890123456789", "maxTweets": 50}'
```
# Get X post by URL
Source: https://docs.thehog.ai/api/scrapers/x-post
api-reference/openapi.json POST /api/v1/platform/scrapers/x/post
Fetch a single public X (Twitter) post by its URL.
# POST /api/v1/platform/scrapers/x/post
> Get a single X (Twitter) post by URL.
Retrieve public details for a specific X post.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/x/post \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"postUrl": "https://x.com/elonmusk/status/123456789"}'
```
# Get X profile
Source: https://docs.thehog.ai/api/scrapers/x-profile
api-reference/openapi.json POST /api/v1/platform/scrapers/x/profile
Fetch public profile details and recent posts for an X (Twitter) username.
# POST /api/v1/platform/scrapers/x/profile
> Get an X (Twitter) profile and recent posts by username.
Retrieve public profile details and recent posts for an X username.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/x/profile \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"username": "elonmusk", "maxTweets": 20}'
```
# Search X posts
Source: https://docs.thehog.ai/api/scrapers/x-search-posts
api-reference/openapi.json POST /api/v1/platform/scrapers/x/search-posts
Search public X (Twitter) posts by keyword or query, with optional date, language, and location filters.
# POST /api/v1/platform/scrapers/x/search-posts
> Search X (Twitter) posts by keyword or query.
Search public X posts matching a query, with optional date, language, and location filters.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/x/search-posts \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"query": "typescript nestjs", "maxTweets": 20}'
```
# Get YouTube channel
Source: https://docs.thehog.ai/api/scrapers/youtube-channel
api-reference/openapi.json POST /api/v1/platform/scrapers/youtube/channel
Fetch public page content for a YouTube channel URL.
# POST /api/v1/platform/scrapers/youtube/channel
> Get public YouTube channel content.
Retrieve public page content for a YouTube channel URL.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/youtube/channel \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/@OpenAI"}'
```
# Get YouTube video
Source: https://docs.thehog.ai/api/scrapers/youtube-video
api-reference/openapi.json POST /api/v1/platform/scrapers/youtube/video
Fetch public page content for a YouTube video URL.
# POST /api/v1/platform/scrapers/youtube/video
> Get public YouTube video content and metadata.
Retrieve public page content and available video details for a YouTube video URL.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/platform/scrapers/youtube/video \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ"}'
```
# Get search result
Source: https://docs.thehog.ai/api/search/get-result
api-reference/openapi.json GET /api/v1/search/{id}
Check the status of a search and retrieve the result once it completes.
# GET /api/v1/search/:id
> Poll for search results.
Poll for results of a search submitted via `POST /api/v1/search`.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/v1/search/srch_01HZXYZ \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# List searches
Source: https://docs.thehog.ai/api/search/list
api-reference/openapi.json GET /api/v1/search
List previous searches for your organization.
# GET /api/v1/search
> List all search operations.
List all searches for your organization.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/v1/search?limit=5 \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
# Submit search
Source: https://docs.thehog.ai/api/search/submit
api-reference/openapi.json POST /api/v1/search
Run a search across supported web and social sources. The default response returns an operation to poll; add sync=true only when you want to wait briefly for an immediate result.
# POST /api/v1/search
> Submit a search across web, LinkedIn, X, Reddit, or TikTok. Returns 202.
Submit a search query across one or more platforms. Returns `202 Accepted` with a poll URL.
For Reddit post search, set `type` to `reddit_search`. Use `sort_by: "relevance"` for Reddit's relevance ranking or `sort_by: "recent"` for Reddit's newest-post ranking.
## Example
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"type": "web_search", "query": "AI CRM tools", "max_results": 10}'
```
# Authenticate with The Hog API
Source: https://docs.thehog.ai/authentication
Authenticate to The Hog API with the API key and API secret from your dashboard.
Every request to The Hog API — except the public health endpoint — requires authentication. Use the API key and API secret from the Credentials page in your dashboard. Send the public API key as `X-Access-Key` and the API secret as `X-Secret-Key`.
Keep your API keys and secret keys secure. Never expose them in client-side code, public repositories, or logs. If a key is compromised, rotate it immediately from your account settings.
## Headers
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
X-Access-Key: ak_xxxxxxxxxxxxxxxx
X-Secret-Key: sk_xxxxxxxxxxxxxxxx
```
Do not use the `Authorization` header for dashboard-created API credentials.
## Example request
```bash curl theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/companies/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"query": "Salesforce", "limit": 5}'
```
```python Python theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import httpx
response = httpx.post(
"https://developer.thehog.ai/api/v1/companies/search",
headers={
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
json={"query": "Salesforce", "limit": 5},
)
print(response.json())
```
```javascript Node.js theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const response = await fetch("https://developer.thehog.ai/api/v1/companies/search", {
method: "POST",
headers: {
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ query: "Salesforce", limit: 5 }),
});
const data = await response.json();
```
## Authentication errors
| Status code | Meaning | What to check |
| ------------------ | ---------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `401 Unauthorized` | Missing or invalid credentials | Verify your API key and API secret are correct and have not been revoked. |
| `403 Forbidden` | Valid credentials but insufficient permissions | Your key does not have access to this endpoint or resource. Check your plan and permissions. |
All error responses follow a consistent shape:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid or missing authentication credentials",
"path": "/api/v1/companies/search",
"requestId": "01HZXAMPLE000000000000000",
"timestamp": "2025-06-01T12:00:00.000Z"
}
```
Every API response includes an `X-Request-Id` header. Include this value when contacting support — it lets the team trace your specific request.
## Next steps
Once you can authenticate successfully, follow the [quickstart](/quickstart) to make your first company search, find people, and enrich a contact.
# Company-First Search in The Hog
Source: https://docs.thehog.ai/concepts/company-first-search
The Hog's company-first approach lets you find target accounts by firmographics and signals first, then drill into contacts — improving ICP match quality.
The Hog is built around a simple principle: find the right companies before you find the right people. Rather than searching a sea of contacts and reverse-engineering which accounts they belong to, you start by narrowing down a list of target accounts that fit your ICP, then pivot to the contacts who work there. This keeps your outreach focused and dramatically reduces noise at every stage of your pipeline.
## What you can search on
Company search accepts filters across three dimensions: firmographics, technographics, and signals. You can combine any of these in a single request to `POST /api/v1/companies/search`.
### Firmographics
Firmographic filters describe who a company is as a business entity.
| Field | Description | Example |
| ------------------------------- | ----------------------------- | ------------------- |
| `query` | Text search on name or domain | `"Acme"` |
| `filters.industries` | Industry verticals | `["Software"]` |
| `filters.employeeCount.min/max` | Headcount range | `10` / `500` |
| `filters.locations` | Country or city filters | `["United States"]` |
| `filters.company.domains` | Exact domain filters | `["acme.com"]` |
### Technographics
Technographic filters let you target companies based on the tools they use.
| Field | Description | Example |
| ------- | ------------------------------------------------- | ------------------------------ |
| `query` | Mention tools or technologies in natural language | `"companies using Salesforce"` |
### Signals
Signal filters surface companies showing intent or momentum right now.
| Field | Description | Values |
| ----------------- | --------------------------- | ----------------------- |
| `filters.signals` | Signal labels to prioritize | `["hiring", "funding"]` |
## How results look
Each company in the response includes a `signal_summary` array that summarises the most relevant signals (e.g. `["recent funding", "hiring in sales"]`), a `match_score` between 0 and 1, and the full set of firmographic and technographic fields that matched your query.
## Pivoting to people
Once you have a list of target companies, you pass company constraints such as domains or names in `filters.company` to `POST /api/v1/people/search`. This two-step flow keeps your people search tightly scoped to accounts that already meet your ICP criteria.
## Typical workflow
Decide which firmographic, technographic, and signal filters describe your ideal account. For example: software companies with 50–500 employees, using Salesforce, and actively hiring.
Send a `POST /api/v1/companies/search` request with your query and filters. Poll the returned operation, then review the company list and signal fields to validate the match quality.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/companies/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "Software companies using Salesforce and hiring engineers",
"filters": {
"employeeCount": { "min": 50, "max": 500 },
"signals": ["hiring"]
},
"limit": 25
}'
```
Each result includes firmographic data and signal indicators. Note the domains or names for the companies you want to pursue.
Pass company filters to `POST /api/v1/people/search` to find contacts. You can further filter by title, location, industry, or signals.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "VP of Sales",
"filters": {
"company": { "domains": ["acme.com"] }
},
"limit": 10
}'
```
Use `POST /api/enrichments` to retrieve verified email addresses and phone numbers for the contacts you want to reach.
Combine tool mentions in `query` with `filters.signals` such as `"hiring"` to find companies actively expanding in areas where your product fits.
The `limit` parameter defaults to 25 and caps at 100 per request.
# Credits and Usage in The Hog
Source: https://docs.thehog.ai/concepts/credits
The Hog charges credits for API calls that fetch, enrich, scrape, or research data.
Credits are the unit of consumption in The Hog. They're charged when an API call performs paid work to fulfil your request. Not every call costs credits — lightweight operations like health checks and polling run for free — but anything that fetches, enriches, scrapes, or researches data from external sources will draw from your credit balance.
## What costs credits
| Operation | Credit behaviour |
| ---------------------------------- | ---------------------------------------------------- |
| `POST /api/v1/companies/search` | Charged based on the companies searched and enriched |
| `POST /api/enrichments` | Charged per enrichment lookup attempt |
| `POST /api/v1/platform/scrapers/*` | Charged per scrape request |
| `POST /api/deep-research` | Charged for LLM-powered deep research |
## What is free
| Operation | Why it's free |
| ------------------------- | ------------------------------------------- |
| `GET /api/health` | Infrastructure probe — no external calls |
| `GET /api/operations/:id` | Polling — reads stored operation state only |
## Metered charges
Launch endpoints charge based on the work completed for your request. Responses expose customer-safe credit fields such as `creditsCharged`, estimates, and request metadata.
## Credit metering in company search responses
Company search responses include a `metering` object so you know exactly what was charged:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"data": [...],
"metering": {
"creditsCharged": 3,
"estimatedMaxCredits": 5
},
"meta": {
"requestId": "req_aabbccdd",
"cost": { "estimated": 5, "actual": 3 }
}
}
```
`creditsCharged` reflects what was actually deducted. `estimatedMaxCredits` is the ceiling that was reserved at the start of the call — you're only charged the actual amount.
## Insufficient credits — 402 error
If your account doesn't have enough credits to cover an operation, the API returns a `402 Payment Required` response before any external calls are made:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 402,
"error": "Payment Required",
"message": "Insufficient credits: 8 required, 3 available",
"path": "/api/enrichments",
"requestId": "req_nofunds",
"timestamp": "2026-05-06T10:00:00.000Z"
}
```
No credits are deducted when a `402` is returned. Reduce the request scope or add credits before retrying.
# Sync and Async Operations in The Hog
Source: https://docs.thehog.ai/concepts/sync-vs-async
Fast API calls return 200 immediately. Long-running tasks return 202 with a poll URL. Learn when each pattern applies and how to poll for results.
The Hog uses two response patterns depending on how long an operation takes. Fast operations return data immediately in the response body with a `200` status. Operations that require more processing time — like enriching large contact lists or running deep research — return a `202 Accepted` response with an operation ID you can poll until the work is done. Knowing which pattern to expect helps you design your integration correctly from the start.
## Sync operations (200)
These calls complete quickly and return data directly in the response. You don't need to do anything after the initial request.
## Async operations (202)
These calls kick off background work and return immediately with a poll URL. You retrieve the result by polling `GET /api/operations/:id` until the status reaches `succeeded` or `failed`.
| Endpoint | Async trigger |
| ------------------------------------------------- | ----------------------------------------------- |
| `POST /api/v1/companies/search` | Always async — company discovery |
| `POST /api/v1/people/search` | Always async — people discovery |
| `POST /api/enrichments` | Batch enrichments and signal enrichments |
| `POST /api/v1/search` | Search jobs submitted for background processing |
| `POST /api/deep-research` | Always async — LLM-powered deep research |
| `POST /api/v1/platform/scrapers/web/crawl` | Website crawl jobs |
| `POST /api/v1/platform/scrapers/web/scrape/batch` | Multiple page scrapes |
| `POST /api/v1/platform/scrapers/web/scrape/jobs` | Deep scrape for long or dynamic pages |
Data is available immediately in the `data` field.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"data": [
{
"id": "comp_xyz789",
"name": "Acme Corp",
"industry": "Software",
"employee_count": 220,
"is_hiring": true
}
],
"meta": {
"requestId": "req_aabbccdd"
}
}
```
The response contains an operation ID and a URL to poll. No result data yet.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_99887766",
"operationId": "op_99887766",
"status": "queued",
"pollUrl": "/api/operations/op_99887766",
"meta": {
"requestId": "req_11223344"
}
}
```
Call `GET /api/operations/:id` to check progress. When `status` is `succeeded`, `result` contains the full output.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_99887766",
"status": "succeeded",
"progress": 100,
"result": {
"email": "jane.doe@acme.com",
"phone": "+1-555-0100",
"emailVerified": true
},
"error": null
}
```
## How to poll
Once you have an `operationId`, call `GET /api/operations/:id` on a schedule until the status is terminal.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/operations/op_99887766 \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
### Operation status values
| Status | Meaning |
| ----------------- | ----------------------------------------------------------- |
| `queued` | Work is waiting to start |
| `processing` | Work is in progress — check `progress` for a 0–100 estimate |
| `succeeded` | Work is complete — read the `result` field |
| `failed` | Work failed — read the `error` field for details |
| `partial_success` | Some results were returned; check both `result` and `error` |
| `cancelled` | The operation was cancelled before completion |
Don't poll more aggressively than once per second. The operations endpoint has a dedicated rate limit. If you exceed it, you'll receive a `429` response.
### Recommended polling strategy
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Simple polling loop — wait 2 seconds between checks
while true; do
RESPONSE=$(curl -s https://developer.thehog.ai/api/operations/op_99887766 \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx")
STATUS=$(echo $RESPONSE | jq -r '.status')
echo "Status: $STATUS"
if [ "$STATUS" = "succeeded" ] || [ "$STATUS" = "failed" ]; then
echo $RESPONSE | jq '.result // .error'
break
fi
sleep 2
done
```
Estimate responses include:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"data": {
"estimatedCredits": 5,
"likelySyncOrAsync": "async",
"expectedLatencyRange": "10–30s",
"expectedLookupDepth": 2,
"withinPlanLimits": true
},
"meta": {
"requestId": "req_estimate001"
}
}
```
## Idempotency
For async `POST` requests, you can supply an `Idempotency-Key` header. If you retry the same request with the same key within the idempotency window, the API returns the original response rather than creating a duplicate operation.
This example uses a batch enrichment request, which is always asynchronous.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/enrichments \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Idempotency-Key: enrich-jane-doe-20260506" \
-H "Content-Type: application/json" \
-d '{
"identifiers": [
{ "linkedin_url": "https://www.linkedin.com/in/jane-doe-example" },
{ "email": "jane@example.com" }
],
"fields": ["contact.email", "contact.phone"]
}'
```
Use a deterministic idempotency key — such as a hash of the request payload or a stable record ID — so that retries after a network failure are safe and don't double-charge credits.
# Run Deep Research with LLM-Powered Analysis
Source: https://docs.thehog.ai/guides/deep-research
Submit a research prompt and JSON Schema to The Hog's deep research endpoint. Get back structured data matching your schema, extracted from web sources.
Deep research lets you ask open-ended research questions and receive structured, schema-conformant answers. You describe what you want to know in a natural language `prompt`, define the exact shape of the data you need as a JSON Schema, and The Hog browses the web, synthesizes findings with an LLM, and returns a result that matches your schema precisely. This is useful for building account intelligence, competitive analysis, market mapping, and any task that requires gathering information from multiple web sources and transforming it into structured data.
Deep research is always asynchronous. The endpoint returns HTTP 202 immediately with an `operationId`. Depending on the complexity of your prompt and schema, results typically arrive within 1–5 minutes. Poll `GET /api/operations/:id` until `status` is `"succeeded"`.
## Endpoint
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST https://developer.thehog.ai/api/deep-research
```
## Request fields
| Field | Type | Required | Description |
| -------- | --------- | -------- | ------------------------------------------------------------------ |
| `prompt` | string | Yes | Natural language research question or instruction |
| `schema` | object | Yes | JSON Schema that defines the structure of the result you want back |
| `model` | string | No | Override the default model (e.g. `"openai:gpt-4.1"`) |
| `urls` | string\[] | No | Optional seed URLs to include as starting points for research |
### Idempotency
Include an `Idempotency-Key` header to prevent duplicate jobs. If you submit the same key twice within the deduplication window, the second request returns the existing queued operation instead of starting a new one.
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
Idempotency-Key: your-unique-key-here
```
***
## Examples
```bash Start a deep research job theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/deep-research \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: research-acme-2026-05" \
-d '{
"prompt": "Research Acme Corp (acme.com). Find their main products, target customers, recent funding announcements, key executives, and any recent press coverage from the last 6 months.",
"schema": {
"type": "object",
"properties": {
"companyName": { "type": "string" },
"mainProducts": {
"type": "array",
"items": { "type": "string" }
},
"targetCustomers": { "type": "string" },
"recentFunding": {
"type": "object",
"properties": {
"amount": { "type": "string" },
"round": { "type": "string" },
"date": { "type": "string" }
}
},
"keyExecutives": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"title": { "type": "string" }
}
}
},
"recentPress": {
"type": "array",
"items": {
"type": "object",
"properties": {
"headline": { "type": "string" },
"source": { "type": "string" },
"date": { "type": "string" }
}
}
}
},
"required": ["companyName", "mainProducts", "targetCustomers"]
},
"urls": ["https://acme.com", "https://techcrunch.com"]
}'
```
```bash With seed URLs and model override theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/deep-research \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"prompt": "What are the top 5 CRM tools used by mid-market B2B SaaS companies in 2026? For each, note market share, pricing model, and key differentiator.",
"schema": {
"type": "object",
"properties": {
"tools": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"marketShare": { "type": "string" },
"pricingModel": { "type": "string" },
"keyDifferentiator": { "type": "string" }
},
"required": ["name"]
}
}
},
"required": ["tools"]
},
"model": "openai:gpt-4.1"
}'
```
### Accepted response (HTTP 202)
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01hxyz",
"operationId": "op_01hxyz",
"status": "queued",
"pollUrl": "/api/operations/op_01hxyz"
}
```
***
## Polling for results
Poll `GET /api/operations/:id` until `status` is `"succeeded"` or `"failed"`.
```bash Poll the operation theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/operations/op_01hxyz \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
```json In-progress response theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01hxyz",
"status": "processing",
"progress": 45,
"result": null,
"error": null
}
```
```json Completed response theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01hxyz",
"status": "succeeded",
"progress": 100,
"result": {
"companyName": "Acme Corp",
"mainProducts": ["Acme Cloud", "Acme Analytics"],
"targetCustomers": "Mid-market B2B SaaS companies with 50–500 employees",
"recentFunding": {
"amount": "$42M",
"round": "Series B",
"date": "2026-02"
},
"keyExecutives": [
{ "name": "Casey Nguyen", "title": "CEO" },
{ "name": "Jordan Rivera", "title": "CTO" }
],
"recentPress": [
{
"headline": "Acme Corp Raises $42M to Expand AI-Powered Analytics",
"source": "TechCrunch",
"date": "2026-02-14"
}
]
},
"error": null
}
```
***
## Steps to run deep research
Be specific about what you want to learn and from what time window. Narrow prompts produce more accurate structured results than broad open-ended ones.
Design the schema to match exactly the fields you need downstream. Use `required` to mark fields that must always be present. The result will conform to this schema.
Use a deterministic key (e.g. `research-{company}-{month}`) so that retries or duplicate submissions return the same operation instead of spawning redundant jobs.
Save the `operationId` from the 202 response. Poll every 10–30 seconds until `status` is `"succeeded"`. For production use, implement exponential backoff.
The `result` field in the completed operation matches your JSON Schema exactly, so you can map it directly into your data pipeline or CRM.
Deep research jobs consume credits proportional to the complexity of the prompt and the number of web sources queried. Use specific prompts and targeted `urls` to keep costs predictable. The `Idempotency-Key` header ensures you are not charged twice for duplicate submissions.
# Enrich Contacts with Emails and Phone Numbers
Source: https://docs.thehog.ai/guides/enrich-contacts
Get verified email addresses and phone numbers for your prospects. Control enrichment depth and choose sync or async delivery for bulk batches.
Contact enrichment turns a LinkedIn URL, email address, X handle, or GitHub username into verified email addresses and phone numbers. You can enrich contacts one at a time for immediate results, or submit large batches asynchronously and poll for completion.
## Endpoint overview
| Endpoint | Method | What it does |
| ---------------------- | ------ | ------------------------------------------------ |
| `/api/enrichments` | POST | Enrich one or more contacts with email and phone |
| `/api/enrichments/:id` | GET | Poll the status of an async enrichment job |
***
## Enrichment request
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST https://developer.thehog.ai/api/enrichments
```
### Input modes
You can enrich a single person immediately or submit a batch. Use exactly one of `identifier` or `identifiers`.
Pass one `identifier` object with one of the supported identity fields.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"identifier": {
"linkedin_url": "https://www.linkedin.com/in/jordan-rivera"
},
"fields": ["contact.email", "contact.phone"]
}
```
Pass an `identifiers` array with up to 100 identity objects. Batch requests are queued and return an operation to poll.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"identifiers": [
{ "linkedin_url": "https://www.linkedin.com/in/jordan-rivera" },
{ "email": "alex@example.com" },
{ "x_handle": "alex_sales" }
],
"fields": ["contact.email", "signals"]
}
```
### Request fields
| Field | Type | Default | Description |
| ---------------- | ------------------- | ------- | ------------------------------------------------------------------------------------ |
| `identifier` | PersonIdentifier | — | Single contact to enrich. Use this or `identifiers`, not both. |
| `identifiers` | PersonIdentifier\[] | — | Batch of up to 100 contacts. Use this or `identifier`, not both. |
| `fields` | string\[] | — | Required enrichment fields, such as `contact.email`, `contact.phone`, and `signals`. |
| `signals_config` | object | — | Optional signal collection settings when `fields` includes `signals`. |
### PersonIdentifier fields
Each identifier object should include one of these fields:
| Field | Type | Example |
| ----------------- | ------ | ------------------------------------------- |
| `linkedin_url` | string | `https://www.linkedin.com/in/jordan-rivera` |
| `email` | string | `jordan@example.com` |
| `x_handle` | string | `jordan_sales` |
| `github_username` | string | `jordanrivera` |
## Examples
```bash Sync contact enrichment theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/enrichments \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"identifier": {
"linkedin_url": "https://www.linkedin.com/in/jordan-rivera"
},
"fields": ["contact.email", "contact.phone"]
}'
```
```bash Async batch enrichment theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/enrichments \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"identifiers": [
{ "linkedin_url": "https://www.linkedin.com/in/jordan-rivera" },
{ "email": "alex@example.com" },
{ "github_username": "sam-dev" }
],
"fields": ["contact.email", "contact.phone", "signals"],
"signals_config": {
"platforms": ["linkedin", "x"],
"since_days": 30
}
}'
```
```bash Poll async result theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/enrichments/op_01hxyz \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
***
## Responses
### Sync enrichment (HTTP 200)
Single LinkedIn contact requests that only ask for `contact.email` and/or `contact.phone` can complete synchronously.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"data": {
"contact": {
"email": ["jordan@acme.com"],
"phone": ["+14155550100"]
}
},
"meta": {
"requestId": "req_01hxyz"
}
}
```
### Async completed result
When a batch enrichment succeeds, the poll response contains item-level statuses.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01hxyz",
"status": "succeeded",
"progress": 100,
"result": {
"items": [
{
"identifier": {
"linkedin_url": "https://www.linkedin.com/in/jordan-rivera"
},
"status": "success",
"data": {
"contact": {
"email": ["jordan@acme.com"],
"phone": ["+14155550100"]
}
}
}
],
"partial": false
},
"error": null
}
```
### Async accepted (HTTP 202)
Batch requests and signal requests return a job reference immediately.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01hxyz",
"operationId": "op_01hxyz",
"status": "queued",
"pollUrl": "/api/enrichments/op_01hxyz",
"meta": {
"requestId": "req_01habc"
}
}
```
Poll `GET /api/enrichments/:id` until `status` is `"succeeded"`. The enriched records are in `result`.
## Enrichment result fields
| Field | Type | Description |
| -------------------- | ------ | ----------------------------------------------------------- |
| `data.contact.email` | array | Verified email addresses when `contact.email` was requested |
| `data.contact.phone` | array | Verified phone numbers when `contact.phone` was requested |
| `data.signals` | object | Signal output when `signals` was requested |
| `items[].identifier` | object | Original identifier for a batch item |
| `items[].status` | string | `"success"` or `"failed"` for a batch item |
| `items[].data` | object | Enrichment data for a successful batch item |
| `items[].error` | object | Safe error message for a failed batch item |
# Find People with The Hog
Source: https://docs.thehog.ai/guides/find-people
Discover ICP-matched contacts with natural language queries, then enrich the contacts you want to reach.
Use the people search endpoint to find contacts using a natural language query, optionally scoped to a specific company or filtered by title and location. Then submit selected contacts to the enrichment endpoint to retrieve verified contact data.
## Endpoint overview
| Endpoint | Method | What it does |
| -------------------------------- | ------ | -------------------------------------------------- |
| `/api/v1/people/search/estimate` | POST | Estimate people search and contact-enrichment risk |
| `/api/v1/people/search` | POST | Find ICP-matched people via NL query |
| `/api/enrichments` | POST | Enrich selected contacts |
***
## People search
Use this endpoint to queue a contact discovery job from a natural language description. The API returns `202 Accepted` immediately; poll the returned URL to retrieve semantically ranked results.
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST https://developer.thehog.ai/api/v1/people/search
```
Run `POST /api/v1/people/search/estimate` with the same body first when you want
to size `maxCredits`. The estimate response returns the standard estimate fields
plus a breakdown of the base people search credits and contact enrichment risk.
The base people-search estimate scales with requested provider-result pages, so
larger `limit` values can raise the preflight ceiling even without contact
enrichment.
### Request fields
| Field | Type | Required | Description |
| ------------------- | --------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `query` | string | Yes | Natural language description, e.g. `"VP of Sales at a Series B SaaS company"` |
| `limit` | number | No | Maximum contacts to return; between 1 and 100 |
| `includeSignals` | boolean | No | Include signal context in results |
| `includeContacts` | boolean | No | Include contact fields when available. When `contactFields` is omitted, this requests email + phone. |
| `contactFields` | string\[] | No | Contact fields to enrich when `includeContacts` is true. Allowed values: `"email"` and `"phone"`. |
| `maxCredits` | number | No | Maximum credits the operation may charge after metered usage is priced. |
| `filters.titles` | string\[] | No | Exact or partial title filters (e.g. `["VP Sales", "Head of Revenue"]`) |
| `filters.locations` | string\[] | No | Location filters (e.g. `["New York", "London"]`) |
| `filters.company` | object | No | Company filters such as `names`, `domains`, `industries`, or `employeeCount` |
### Contact enrichment spend controls
Set `includeContacts: true` only when you want people search to run contact enrichment as part of the search job. Use `contactFields` to request email-only, phone-only, or both. For backward compatibility, `includeContacts: true` without `contactFields` requests both email and phone.
Use `maxCredits` to cap the final customer charge for the operation. The API
also checks the conservative preflight estimate before paid people or contact
enrichment work starts. If `maxCredits` is lower than that preflight ceiling,
the request fails with `402 Payment Required` and no paid people/contact work
starts. Actual billing is based on measured usage and can be lower than the cap.
### Target account matching
Use `filters.company.domains` or `filters.company.names` for target-account search. These fields represent the company you asked for. A `filters.company.linkedinUrls` value can help when you already know the exact company page, but it is treated as a platform handle rather than the canonical account identity.
When a search is scoped to target accounts, poll `GET /api/operations/:id` and inspect `result.meta`:
| Field | Meaning |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `targetAccountSearchMode` | `linkedin_company_page` means results were constrained by a LinkedIn company page. `profile_current_company` means results were matched against current profile company text. `unavailable` means The Hog could not confidently search the requested account with the available search path. |
| `targetAccountOutcome` | Explains the LinkedIn company-handle path: supplied, verified, unavailable/conflicting, or unresolved. Use `targetAccountSearchMode` to see how people were actually matched. |
| `message` | Human-readable guidance for empty or unavailable results. |
Each returned person may include `companyMatchEvidence` with `company_page` or `profile_current_job`, so you can tell why the person matched the account.
### Examples
```bash Search for VP of Sales contacts theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "VP of Sales at a B2B SaaS company",
"limit": 25
}'
```
```bash Scoped to a company with title and location filters theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "revenue leader",
"filters": {
"titles": ["VP Sales", "Chief Revenue Officer", "Head of Sales"],
"locations": ["United States", "Canada"],
"company": { "domains": ["salesforce.com"] }
},
"limit": 10
}'
```
```bash Title filters with signals theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "growth-focused marketing leader",
"filters": {
"titles": ["VP Marketing", "Head of Growth"]
},
"includeSignals": true,
"limit": 50
}'
```
```bash Email-only contact enrichment with a credit cap theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "VP Engineering at B2B SaaS companies",
"limit": 25,
"includeContacts": true,
"contactFields": ["email"],
"maxCredits": 63750
}'
```
```bash Estimate before queueing contact enrichment theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search/estimate \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "VP Engineering at B2B SaaS companies",
"limit": 25,
"includeContacts": true,
"contactFields": ["email"]
}'
```
### Response
The search returns HTTP `202` with an operation ID and poll URL.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01hxyz",
"operationId": "op_01hxyz",
"status": "queued",
"pollUrl": "/api/operations/op_01hxyz",
"meta": {
"requestId": "req_01hxyz"
}
}
```
## Typical workflow
Use `POST /api/v1/companies/search` with firmographic and signal filters to build your target account list. Note the `id` of each company you want to prospect.
Pass company constraints in `filters.company` along with a role-based `query`
(e.g. `"Head of Engineering"`) to surface relevant contacts.
Pass the person `id` from search results to `POST /api/enrichments` to retrieve verified email addresses and phone numbers.
Use `filters.company.domains` or `filters.company.names` to scope people
search to specific accounts — this significantly improves relevance compared
to a global search with the same query.
# Find Outreach Hooks from LinkedIn Activity
Source: https://docs.thehog.ai/guides/linkedin-outreach-hooks
Use LinkedIn profile reactions and comments to find recent posts your prospects engaged with, then turn that context into relevant outreach hooks.
When you already know a prospect's LinkedIn profile, you can use The Hog to inspect recent public posts they reacted to or commented on. This is useful when you want outreach to reference something timely instead of starting from a generic persona template.
This guide uses one profile as an example:
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
https://www.linkedin.com/in/paulonasc
```
## What you will build
The script below:
1. Fetches recent posts the profile reacted to.
2. Fetches recent posts the profile commented on.
3. Merges both signals by LinkedIn post.
4. Prints concise outreach hook ideas you can review before using.
Use this to personalize legitimate business outreach from public activity. Always review the generated hooks, avoid sensitive inferences, and respect unsubscribe and outreach rules in your market.
## Endpoints used
| Endpoint | What it returns |
| ----------------------------------------------------------- | -------------------------------------------- |
| `POST /api/v1/platform/scrapers/linkedin/profile-reactions` | Public posts a LinkedIn profile reacted to |
| `POST /api/v1/platform/scrapers/linkedin/profile-comments` | Public posts a LinkedIn profile commented on |
Both endpoints accept:
* `profiles`: LinkedIn `/in/` profile URLs or public usernames
* `maxItems`: maximum rows to return per profile
* `postedLimit`: one of `any`, `24h`, `week`, `month`, `3months`, `6months`, `year`
## JavaScript example
Create `linkedin-hooks.mjs`:
```js theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const API_BASE_URL = "https://developer.thehog.ai";
const ACCESS_KEY = process.env.HOG_API_ACCESS_KEY;
const SECRET_KEY = process.env.HOG_API_SECRET_KEY;
const profile = process.argv[2] ?? "https://www.linkedin.com/in/paulonasc";
if (!ACCESS_KEY || !SECRET_KEY) {
throw new Error("Set HOG_API_ACCESS_KEY and HOG_API_SECRET_KEY");
}
async function post(path, body) {
const response = await fetch(`${API_BASE_URL}${path}`, {
method: "POST",
headers: {
"X-Access-Key": ACCESS_KEY,
"X-Secret-Key": SECRET_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!response.ok) {
const text = await response.text();
throw new Error(`${path} failed with ${response.status}: ${text}`);
}
return response.json();
}
function postKey(item) {
return item.post?.postUrl ?? item.post?.postId ?? item.sourceUrl;
}
function summarizePost(post) {
const text = post?.text?.replace(/\s+/g, " ").trim();
if (!text) return "a recent LinkedIn post";
return text.length > 180 ? `${text.slice(0, 177)}...` : text;
}
function makeHooks(reactions, comments) {
const byPost = new Map();
for (const reaction of reactions) {
const key = postKey(reaction);
if (!key) continue;
const row = byPost.get(key) ?? {
post: reaction.post,
reactions: [],
comments: [],
};
row.reactions.push(reaction);
byPost.set(key, row);
}
for (const comment of comments) {
const key = postKey(comment);
if (!key) continue;
const row = byPost.get(key) ?? {
post: comment.post,
reactions: [],
comments: [],
};
row.comments.push(comment);
byPost.set(key, row);
}
return [...byPost.values()]
.sort((a, b) => b.comments.length - a.comments.length)
.slice(0, 10)
.map((row) => {
const author = row.post?.authorName ?? "someone in their network";
const postSummary = summarizePost(row.post);
const comment = row.comments[0]?.commentText;
return {
postUrl: row.post?.postUrl,
signal:
row.comments.length > 0
? `commented on ${author}'s post`
: `reacted to ${author}'s post`,
hook: comment
? `They commented: "${comment}". Reference the discussion around "${postSummary}".`
: `They reacted to a post about "${postSummary}". Use that topic as a light opener.`,
};
});
}
const request = {
profiles: [profile],
maxItems: 20,
postedLimit: "month",
};
const [reactionResponse, commentResponse] = await Promise.all([
post("/api/v1/platform/scrapers/linkedin/profile-reactions", request),
post("/api/v1/platform/scrapers/linkedin/profile-comments", request),
]);
const hooks = makeHooks(reactionResponse.data ?? [], commentResponse.data ?? []);
console.log(JSON.stringify({ profile, hooks }, null, 2));
```
Run it:
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
export HOG_API_ACCESS_KEY="ak_xxxxxxxxxxxxxxxx"
export HOG_API_SECRET_KEY="sk_xxxxxxxxxxxxxxxx"
node linkedin-hooks.mjs https://www.linkedin.com/in/paulonasc
```
## Python example
Create `linkedin_hooks.py`:
```python theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import json
import os
import sys
import requests
API_BASE_URL = "https://developer.thehog.ai"
ACCESS_KEY = os.environ["HOG_API_ACCESS_KEY"]
SECRET_KEY = os.environ["HOG_API_SECRET_KEY"]
profile = sys.argv[1] if len(sys.argv) > 1 else "https://www.linkedin.com/in/paulonasc"
def post(path, body):
response = requests.post(
f"{API_BASE_URL}{path}",
headers={
"X-Access-Key": ACCESS_KEY,
"X-Secret-Key": SECRET_KEY,
"Content-Type": "application/json",
},
json=body,
timeout=120,
)
response.raise_for_status()
return response.json()
def post_key(item):
post = item.get("post") or {}
return post.get("postUrl") or post.get("postId") or item.get("sourceUrl")
def summarize_post(post):
text = " ".join((post.get("text") or "").split())
if not text:
return "a recent LinkedIn post"
return text[:177] + "..." if len(text) > 180 else text
request_body = {
"profiles": [profile],
"maxItems": 20,
"postedLimit": "month",
}
reactions = post(
"/api/v1/platform/scrapers/linkedin/profile-reactions",
request_body,
).get("data", [])
comments = post(
"/api/v1/platform/scrapers/linkedin/profile-comments",
request_body,
).get("data", [])
by_post = {}
for reaction in reactions:
key = post_key(reaction)
if not key:
continue
by_post.setdefault(key, {"post": reaction.get("post") or {}, "reactions": [], "comments": []})
by_post[key]["reactions"].append(reaction)
for comment in comments:
key = post_key(comment)
if not key:
continue
by_post.setdefault(key, {"post": comment.get("post") or {}, "reactions": [], "comments": []})
by_post[key]["comments"].append(comment)
hooks = []
for row in sorted(by_post.values(), key=lambda value: len(value["comments"]), reverse=True)[:10]:
post_body = row["post"]
author = post_body.get("authorName") or "someone in their network"
summary = summarize_post(post_body)
comment_text = row["comments"][0].get("commentText") if row["comments"] else None
hooks.append(
{
"postUrl": post_body.get("postUrl"),
"signal": (
f"commented on {author}'s post"
if row["comments"]
else f"reacted to {author}'s post"
),
"hook": (
f'They commented: "{comment_text}". Reference the discussion around "{summary}".'
if comment_text
else f'They reacted to a post about "{summary}". Use that topic as a light opener.'
),
}
)
print(json.dumps({"profile": profile, "hooks": hooks}, indent=2))
```
Run it:
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
export HOG_API_ACCESS_KEY="ak_xxxxxxxxxxxxxxxx"
export HOG_API_SECRET_KEY="sk_xxxxxxxxxxxxxxxx"
python linkedin_hooks.py https://www.linkedin.com/in/paulonasc
```
## Example output
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"profile": "https://www.linkedin.com/in/paulonasc",
"hooks": [
{
"postUrl": "https://www.linkedin.com/feed/update/urn:li:activity:123",
"signal": "commented on someone in their network's post",
"hook": "They commented: \"Great breakdown.\" Reference the discussion around \"a recent LinkedIn post\"."
},
{
"postUrl": "https://www.linkedin.com/feed/update/urn:li:activity:456",
"signal": "reacted to someone in their network's post",
"hook": "They reacted to a post about \"AI agents for sales workflows\". Use that topic as a light opener."
}
]
}
```
## Production tips
* Keep `maxItems` small for interactive workflows; increase it only for batch jobs.
* Prefer `postedLimit: "month"` or shorter for timely hooks.
* Store the returned `postUrl` with your CRM activity so reps can review the source context.
* Use comments first when available: they usually reveal stronger intent than a reaction alone.
* De-duplicate hooks across prospects before generating outreach sequences.
# Local stdio MCP
Source: https://docs.thehog.ai/guides/local-mcp
Install The Hog's local stdio MCP server with npx for Claude Desktop, Claude Code, Cursor, Codex, VS Code, Windsurf, and other local MCP clients.
Use local stdio MCP when your client runs MCP servers on your machine with a command like `npx`.
## Requirements
* Node.js 20 or newer
* A The Hog API key and API secret from the Credentials page
* An MCP client that supports local stdio servers
Most MCP clients run the package for you with `npx`:
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
npx -y @thehog/mcp@latest
```
Pass both credential values through environment variables in your MCP client config:
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
THEHOG_ACCESS_KEY=YOUR_THEHOG_ACCESS_KEY THEHOG_SECRET_KEY=YOUR_THEHOG_SECRET_KEY npx -y @thehog/mcp@latest
```
In the dashboard UI, the public API key is the MCP `THEHOG_ACCESS_KEY`. The API secret is the MCP `THEHOG_SECRET_KEY`. Both are required for dashboard-created credentials.
Package and source:
* npm: [@thehog/mcp](https://www.npmjs.com/package/@thehog/mcp)
* GitHub: [The-Hog/the-hog-mcp](https://github.com/The-Hog/the-hog-mcp)
## Claude Desktop
For local stdio MCP, use the Claude Desktop app. The claude.ai web app cannot launch a local stdio command like `npx`; use [hosted remote MCP](/guides/use-mcp) for Claude in the web app or other hosted clients.
Claude Desktop config locations:
* macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
* Windows: `%APPDATA%\Claude\claude_desktop_config.json`
Add The Hog:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"mcpServers": {
"thehog": {
"command": "npx",
"args": ["-y", "@thehog/mcp@latest"],
"env": {
"THEHOG_ACCESS_KEY": "YOUR_API_KEY",
"THEHOG_SECRET_KEY": "YOUR_API_SECRET"
}
}
}
}
```
Restart Claude Desktop after saving the file. If Claude cannot find `npx`, use the absolute path from `which npx`.
## Claude Code
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
claude mcp add thehog \
-e THEHOG_ACCESS_KEY=YOUR_API_KEY \
-e THEHOG_SECRET_KEY=YOUR_API_SECRET \
-- npx -y @thehog/mcp@latest
```
Check that the server is connected:
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
claude mcp list
```
## Cursor
Create or update `.cursor/mcp.json` in a project, or `~/.cursor/mcp.json` globally:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"mcpServers": {
"thehog": {
"command": "npx",
"args": ["-y", "@thehog/mcp@latest"],
"env": {
"THEHOG_ACCESS_KEY": "${env:THEHOG_ACCESS_KEY}",
"THEHOG_SECRET_KEY": "${env:THEHOG_SECRET_KEY}"
}
}
}
}
```
Restart Cursor after changing the config. If Cursor cannot read shell env values, replace the `${env:...}` entries with literal strings like the Claude Desktop example.
## Codex
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
codex mcp add thehog \
--env THEHOG_ACCESS_KEY=YOUR_API_KEY \
--env THEHOG_SECRET_KEY=YOUR_API_SECRET \
-- npx -y @thehog/mcp@latest
```
Check that the server is registered:
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
codex mcp list
```
You can also edit `~/.codex/config.toml` directly:
```toml theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
[mcp_servers.thehog]
command = "npx"
args = ["-y", "@thehog/mcp@latest"]
enabled = true
[mcp_servers.thehog.env]
THEHOG_ACCESS_KEY = "YOUR_API_KEY"
THEHOG_SECRET_KEY = "YOUR_API_SECRET"
```
## VS Code / GitHub Copilot
VS Code uses `servers` instead of `mcpServers`. Add this to workspace `.vscode/mcp.json` or to your user MCP configuration:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"servers": {
"thehog": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@thehog/mcp@latest"],
"env": {
"THEHOG_ACCESS_KEY": "${input:thehog-api-key}",
"THEHOG_SECRET_KEY": "${input:thehog-api-secret}"
}
}
},
"inputs": [
{
"type": "promptString",
"id": "thehog-api-key",
"description": "The Hog API key",
"password": true
},
{
"type": "promptString",
"id": "thehog-api-secret",
"description": "The Hog API secret",
"password": true
}
]
}
```
Use the Command Palette commands `MCP: Open User Configuration`, `MCP: Open Workspace Folder MCP Configuration`, and `MCP: List Servers` to edit and verify the server.
## Windsurf
Add this to `~/.codeium/windsurf/mcp_config.json`:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"mcpServers": {
"thehog": {
"command": "npx",
"args": ["-y", "@thehog/mcp@latest"],
"env": {
"THEHOG_ACCESS_KEY": "${env:THEHOG_ACCESS_KEY}",
"THEHOG_SECRET_KEY": "${env:THEHOG_SECRET_KEY}"
}
}
}
}
```
Refresh MCP servers from Cascade after saving. If Windsurf cannot read shell env values, replace the `${env:...}` entries with literal strings like the Claude Desktop example.
## Other clients
Most local MCP clients accept the same `mcpServers` shape:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"mcpServers": {
"thehog": {
"command": "npx",
"args": ["-y", "@thehog/mcp@latest"],
"env": {
"THEHOG_ACCESS_KEY": "YOUR_API_KEY",
"THEHOG_SECRET_KEY": "YOUR_API_SECRET"
}
}
}
}
```
Use your client's MCP settings page or config file location for that JSON.
## Authentication and safety
The server runs locally over stdio. It does not host a public endpoint, does not require OAuth, and does not require a dashboard login. Your MCP client starts the local process, passes credentials through environment variables, and the server calls:
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
https://developer.thehog.ai/api
```
Follow these practices:
* Store API keys and secrets in your MCP client's local config, shell profile, or secret manager.
* Do not commit MCP configs that contain real API keys.
* Review tool calls before approving actions that spend credits, create monitors, or fetch large datasets.
* Use scoped credentials when your organization supports key scoping.
## Versioning
The MCP package is in the `0.x` release line while the tool surface stabilizes. Patch versions contain compatible fixes. Minor versions may add tools or adjust tool schemas before `1.0.0`.
# Personalized LinkedIn Outreach (Full Example)
Source: https://docs.thehog.ai/guides/personalized-linkedin-outreach
End-to-end open-source example: find who engaged with a LinkedIn profile, scrape their context, and draft personalized cold outreach DMs.
Developers have asked us a recurring question: can I detect what posts my prospects are liking and commenting on, and use that as a hook for cold outreach? This guide walks through a complete working example that does exactly that, end to end, from picking a target profile to writing a personalized DM for each prospect.
For a single-call snippet, see [LinkedIn outreach hooks](/guides/linkedin-outreach-hooks). This guide is the full pipeline.
## What you will build
A five-stage pipeline that starts with a sender and a target LinkedIn profile and ends with a folder of personalized draft DMs ready for human review.
1. **Stage 0** — Fetch the sender's own LinkedIn profile and summarize their voice and current company so the LLM has writing style and signature context.
2. **Stage 1** — Pull recent posts from the target profile (typically a high-signal author your prospects follow).
3. **Stage 2** — Find everyone who reacted to or commented on those posts, filter out teammates and noise, then enrich the top prospects with full profiles.
4. **Stage 3** — Scrape each prospect's own recent LinkedIn activity so the DM can reference what they actually care about.
5. **Stage 4** — Draft a personalized DM per prospect with an LLM and render a `demo.html` preview for review.
## The example repo
Clone the example to follow along:
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
git clone https://github.com/the-hog/hog-linkedin-outreach
cd hog-linkedin-outreach
```
The repo is MIT licensed, a single Python file, and uses only the Python standard library. OpenAI is called via raw HTTP through `urllib`, not the `openai` package, so there is no `pip install` step.
## Endpoints used
The pipeline uses six The Hog LinkedIn endpoints plus OpenAI for summarization and DM drafting.
| Endpoint | What it returns |
| ---------------------------- | ------------------------------------------------------------- |
| `linkedin/profile` | Full profile including experience, education, current company |
| `linkedin/profile-posts` | Recent posts from a profile |
| `linkedin/post-reactions` | Who reacted to a specific post |
| `linkedin/post-comments` | Who commented on a specific post |
| `linkedin/profile-reactions` | What a profile reacted to elsewhere |
| `linkedin/profile-comments` | What a profile commented on elsewhere |
| OpenAI `chat.completions` | Sender voice summary, prospect summaries, and final DM drafts |
## The data flow
Each stage caches its output to disk so re-running the script is cheap. The cache filenames double as a tour of the pipeline:
| File | Stage | Contents |
| ------------------------------- | ----- | -------------------------------------------------------- |
| `00a_sender_profile.json` | 0 | Raw sender profile from `linkedin/profile` |
| `00b_sender_summary.txt` | 0 | LLM-generated voice and company summary for the sender |
| `01_target_posts.json` | 1 | Recent posts from the target profile |
| `02_potential_prospects.json` | 2 | Everyone who reacted to or commented on the target posts |
| `02b_top_prospects.json` | 2 | Filtered and ranked list after exclusions |
| `02c_enriched_prospects.json` | 2 | Top prospects with full profiles attached |
| `03_prospect_activity.json` | 3 | Each prospect's own recent reactions and comments |
| `04_personalized_messages.json` | 4 | Final draft DMs |
| `demo.html` | 4 | Browser-ready preview of every draft side by side |
## The personalization payoff
Templated outreach fails because the recipient can tell it could have been sent to anyone. This pipeline gives the LLM enough specific context to write something that could only have been sent to one person.
For each DM, the model receives:
* **Sender voice** from the sender summary, so the draft sounds like the person sending it.
* **Recipient context** from the prospect's enriched profile, so the DM grounds in their role and company.
* **The specific post they engaged with**, including its text and author, so the opener is a real reference.
* **Their own words** when they left a comment, so the DM can quote or paraphrase what they actually said.
* **Their broader activity** from `profile-reactions` and `profile-comments`, so the DM can connect their public interests to your pitch.
The output is a DM that references real things the recipient said and did this week.
## Filtering for safety
Two config knobs at the top of the script keep your own teammates and obvious noise out of the prospect list:
* `EXCLUDE_COMPANIES` — drop anyone whose current company in their experience history matches one of these. This catches teammates whose LinkedIn headline does not mention the company name (a common gap that a headline-only filter misses).
* `EXCLUDE_HEADLINE_KEYWORDS` — drop anyone whose headline contains these substrings, useful for filtering investors, recruiters, or competitors when you do not want to message them.
The experience-based filter requires the prospect enrichment step. The cheaper headline filter runs first, so the script only spends profile credits on prospects that survive the initial cut.
## Costs and runtime
| Run | Hog calls | OpenAI calls | Wall time |
| --------------- | ---------- | ------------ | --------------- |
| First run | \~20 to 25 | \~40 | 5 to 10 minutes |
| Subsequent runs | Near zero | Near zero | Seconds |
Every stage reads from its cache file if present, so iterating on prompts, exclusion lists, or DM templates does not re-burn credits.
## Customizing
Open the script and look for the CONFIG block near the top (around lines 50 to 80). The variables you will change most often:
| Variable | What it controls |
| ---------------------------- | ------------------------------------------------------------------------------------ |
| `SENDER_USERNAME` | Your LinkedIn username, used to fetch your profile and seed the sender voice summary |
| `TARGET_USERNAME` | The author whose post engagement you want to mine for prospects |
| `EXCLUDE_COMPANIES` | Company names to drop from the prospect list (catches teammates) |
| `MAX_PROSPECTS_FOR_OUTREACH` | Cap on how many prospects make it through to the DM draft stage |
Past those, the prompt strings for the sender summary, prospect summary, and DM draft live inline and are easy to tune.
Review every drafted DM before sending. The script produces drafts, not approved messages. Respect LinkedIn's terms of service and outreach rules in your market.
# Search Companies by Firmographics and Tech Stack
Source: https://docs.thehog.ai/guides/search-companies
Use The Hog's company search to find target accounts by industry, employee count, revenue, technology, and buying signals like hiring and funding.
The company search endpoint is the starting point for building targeted account lists. You send a POST request with a natural-language query and optional structured filters, then poll the returned operation for ranked company results. The `query` field is required.
## Endpoint
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST https://developer.thehog.ai/api/v1/companies/search
```
## Request fields
`query` — free-text search on company name or domain (up to 256 characters)
`filters.company.domains` — exact domain filters (e.g. `["acme.com"]`)
`filters.industries`, `filters.locations`, `filters.employeeCount.min/max`
Include tools in `query`, or use `filters.signals` for known buying-signal categories.
`filters.signals` — short signal labels such as `["hiring", "funding"]`
### Pagination
| Field | Default | Maximum | Notes |
| ------- | ------- | ------- | ---------------- |
| `limit` | `25` | `100` | Results per page |
## Examples
```bash Simple text search theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/companies/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "Acme",
"limit": 10
}'
```
```bash Firmographic + technographic + signal filters theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/companies/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "Software companies using Salesforce and HubSpot",
"filters": {
"industries": ["Software"],
"locations": ["United States"],
"employeeCount": { "min": 50, "max": 500 },
"signals": ["hiring"]
},
"limit": 25
}'
```
```bash Signal-focused search theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/companies/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "FinTech companies hiring revenue teams",
"filters": {
"industries": ["FinTech"],
"signals": ["hiring"]
},
"limit": 20
}'
```
## Response
A successful submission returns HTTP `202` with an operation ID and poll URL. Poll `GET /api/operations/:id` until the operation succeeds.
```json Accepted response theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01hxyz",
"operationId": "op_01hxyz",
"status": "queued",
"pollUrl": "/api/operations/op_01hxyz"
}
```
### Response fields
| Field | Type | Description |
| -------------------- | ------ | ---------------------------------------- |
| `id` / `operationId` | string | Operation ID for polling |
| `status` | string | `queued` immediately after submission |
| `pollUrl` | string | URL to poll for status and final results |
### CompanyCard fields
| Field | Type | Description |
| ----------------------------- | --------- | --------------------------------------------------- |
| `id` | string | Unique company identifier |
| `name` | string | Company display name |
| `domain` | string | Primary domain |
| `website` | string | Full website URL |
| `industry` | string | Industry classification |
| `employee_count` | number | Headcount |
| `location` | string | Headquarters location |
| `founding_year` | number | Year the company was founded |
| `revenue_min` / `revenue_max` | number | Annual revenue range in USD |
| `tech_stack` | string\[] | Technologies and tools detected |
| `is_hiring` | boolean | Whether the company is actively hiring |
| `has_recent_funding` | boolean | Whether the company has had recent funding activity |
| `growth_band` | string | `"low"`, `"medium"`, or `"high"` |
| `match_score` | number | Relevance score from 0 to 1 |
| `signal_summary` | string\[] | Short human-readable signal descriptions |
## Steps to build a target account list
Run a search with a broad `query` and a small `limit` to gauge the universe of matching companies.
Add technologies your product integrates with or competes against directly into the natural-language `query`.
Add `filters.signals` values such as `"hiring"` or `"funding"` to surface companies in an active growth phase.
Use `limit` to control the number of results returned by each search operation.
Use the returned company domain or name in `filters.company` on `POST /api/v1/people/search` to find contacts at that account.
# Build Social Listening Workflows for X
Source: https://docs.thehog.ai/guides/social-listening-x
Use X keyword and profile monitors to track hot topics, competitors, executive posts, and new conversation opportunities.
Use monitors when you want a topic-based job that runs on a schedule. Use search when you want a one-off snapshot before creating a recurring monitor.
This guide shows examples for social media teams that want to find relevant conversations early, watch competitors, and track what executives or target accounts post on X.
## What you can build
| Workflow | API pattern | Example |
| -------------------------------- | ----------------------------- | -------------------------------------------------------------------------------- |
| Track hot topics | `x_keyword` monitor | New posts mentioning your category, feature, launch, or pain point |
| Monitor competitors | `x_keyword` monitor | Mentions of competitor names, pricing, launches, outages, or customer complaints |
| Watch company leaders | `x_profile` monitor | New posts from a CEO, founder, product leader, or analyst |
| Find conversation opportunities | `x_keyword` search or monitor | Posts where people are asking for tools, recommendations, or alternatives |
| Build a lightweight social inbox | monitor events polling | Store new matching posts, dedupe by URL, and route them to Slack or your CRM |
X keyword and profile monitors return matching posts, author usernames, post URLs, timestamps, and engagement counts when available. If you need a complete list of users who liked, reposted, or replied to a specific X post, treat that as a separate engagement expansion workflow rather than assuming every engagement identity is included in keyword monitor results.
## Create X monitors
Create separate monitors for each workflow so you can route and score results differently.
```bash Hot topic monitor theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/monitors \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "X: customer data platform conversations",
"type": "x_keyword",
"config": {
"query": "\"customer data platform\" OR \"CDP\""
},
"cadence_minutes": 60,
"max_results": 25
}'
```
```bash Competitor monitor theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/monitors \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "X: competitor pricing and complaints",
"type": "x_keyword",
"config": {
"query": "(\"Competitor A\" OR \"Competitor B\") (pricing OR expensive OR outage OR alternative)"
},
"cadence_minutes": 60,
"max_results": 25
}'
```
```bash Executive profile monitor theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/monitors \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "X: CEO posts",
"type": "x_profile",
"config": {
"username": "example_ceo"
},
"cadence_minutes": 60,
"max_results": 10
}'
```
## Poll new events
After a monitor runs, poll its events endpoint. Store your last successful poll timestamp and pass it as `since` so you only process new items.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl "https://developer.thehog.ai/api/v1/monitors/mon_01hxyz/events?since=2024-01-01T00:00:00.000Z&limit=50" \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
A typical social inbox stores:
| Field | Why it matters |
| ---------------------------- | ------------------------------------------- |
| `event_json.url` | Link for the social team |
| `event_json.id` | Source-native post ID to help dedupe |
| `event_json.author_username` | X account to review |
| `event_json.text` | Post text to score, summarize, or route |
| `event_json.created_at` | When the post was published, when available |
| `detected_at` | When the monitor found the post |
The exact `event_json` fields can vary by source, so write your ingestion to prefer stable fields and fall back gracefully.
## One-off X search before monitoring
Run a search first when you are testing query wording or building a prospect-facing demo.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "x_keyword",
"query": "\"product analytics\" \"need a tool\"",
"max_results": 20
}'
```
The response returns `202 Accepted` with a `poll_url`. Poll that URL until the search status is `succeeded`.
## JavaScript example: route new X posts
Create `x-social-listening.mjs`:
```js theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const API_BASE_URL = process.env.HOG_API_BASE_URL ?? "https://developer.thehog.ai";
const ACCESS_KEY = process.env.HOG_API_ACCESS_KEY;
const SECRET_KEY = process.env.HOG_API_SECRET_KEY;
const monitorId = process.argv[2];
const since = process.argv[3] ?? new Date(Date.now() - 60 * 60 * 1000).toISOString();
if (!ACCESS_KEY || !SECRET_KEY) {
throw new Error("Set HOG_API_ACCESS_KEY and HOG_API_SECRET_KEY");
}
if (!monitorId) {
throw new Error("Usage: node x-social-listening.mjs [since-iso]");
}
async function get(path) {
const response = await fetch(`${API_BASE_URL}${path}`, {
headers: {
"X-Access-Key": ACCESS_KEY,
"X-Secret-Key": SECRET_KEY,
},
});
if (!response.ok) {
const text = await response.text();
throw new Error(`${path} failed with ${response.status}: ${text}`);
}
return response.json();
}
function pickPost(event) {
const payload = event.event_json ?? {};
return {
detectedAt: event.detected_at,
url: payload.post_url ?? payload.url,
author: payload.author_username ?? payload.author ?? payload.author_name,
text: payload.content ?? payload.text ?? payload.title,
};
}
function score(post) {
const text = (post.text ?? "").toLowerCase();
const positiveIntent = ["alternative", "recommend", "need", "looking for"];
const competitorRisk = ["expensive", "outage", "broken", "switching"];
const tags = new Set();
if (positiveIntent.some((term) => text.includes(term))) {
tags.add("buying-intent");
}
if (competitorRisk.some((term) => text.includes(term))) {
tags.add("competitor-signal");
}
return {
...post,
tags: [...tags],
};
}
const params = new URLSearchParams({ since, limit: "50" });
const response = await get(`/api/v1/monitors/${monitorId}/events?${params}`);
const posts = (response.data ?? []).map(pickPost).filter((post) => post.url || post.text);
console.log(JSON.stringify(posts.map(score), null, 2));
```
Run it:
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
export HOG_API_ACCESS_KEY="ak_xxxxxxxxxxxxxxxx"
export HOG_API_SECRET_KEY="sk_xxxxxxxxxxxxxxxx"
node x-social-listening.mjs mon_01hxyz 2024-01-01T00:00:00.000Z
```
## Production pattern
Use one monitor per topic, competitor, campaign, or executive account. Narrow monitors are easier to route and score.
Poll `GET /api/v1/monitors/:id` to check `last_run_at`, then fetch `GET /api/v1/monitors/:id/events?since=...`.
Store the post URL or source-native ID before routing to Slack, a queue, or a CRM task.
Tag posts that mention buying intent, competitor pain, executive announcements, or urgent support issues.
Use the API to surface opportunities early, then let your social or sales team decide whether and how to join the conversation.
# Use The Hog with MCP
Source: https://docs.thehog.ai/guides/use-mcp
Connect The Hog to Claude, Cursor, Codex, VS Code, Windsurf, or any MCP client with hosted OAuth or the local stdio package.
The Hog MCP server lets AI tools call The Hog API tools directly from natural language. Use it when you want an agent to search companies, find people, enrich prospects, research accounts, monitor topics, or scrape and extract web data without hand-writing each HTTP request.
This is different from Mintlify's docs MCP endpoint. Mintlify exposes documentation context. The Hog MCP exposes The Hog API as executable tools.
## Choose a setup
Use the hosted MCP endpoint when your client supports remote MCP with OAuth. Use the local npm package when your client only supports local stdio servers or when you want credentials to stay entirely in your local client config.
| Setup | Best for | Authentication |
| ----------------- | -------------------------------------------------------------------------------------- | ------------------------------------------------ |
| Hosted remote MCP | Claude and other hosted MCP clients | Sign in with The Hog and select an organization |
| Local stdio MCP | Claude Desktop, Claude Code, Cursor, Codex, VS Code, Windsurf, and local coding agents | API key and API secret from the Credentials page |
## Hosted remote MCP
Hosted MCP does not require a manually created API key. Your MCP client connects to The Hog, opens a sign-in flow, and asks you to choose the organization that should be billed for tool calls.
Use this endpoint:
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
https://mcp.thehog.ai/mcp
```
When your MCP client asks for a remote server URL, paste the endpoint above. The client should open a browser-based OAuth flow. After you sign in and choose an organization, The Hog creates a connector-specific MCP URL for that client and organization.
If you belong to multiple organizations, connect each organization separately. Each connection is scoped to the organization you selected during authorization.
## Claude
Claude supports remote MCP through custom connectors. In Claude, open Settings, go to Connectors, choose Add custom connector, and enter:
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
Name: The Hog
URL: https://mcp.thehog.ai/mcp
```
After saving, click Connect. Claude opens the OAuth flow in your browser so you can sign in to The Hog and choose the organization for that connector.
For Team or Enterprise workspaces, an owner may need to add the custom connector at the organization level before members can connect it.
## Revoke access
You can view and revoke hosted MCP connections from the Remote MCP page in the dashboard:
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
https://platform.thehog.ai/settings/integrations/mcp
```
Revoking a connection blocks that MCP client from making further requests. It does not revoke your API keys.
### Hosted MCP security
* Hosted MCP uses OAuth instead of API keys.
* Tool calls are billed to the organization selected during authorization.
* The MCP client cannot switch organizations by sending headers or IDs.
* Revoked connections fail on the next MCP request.
* You should still review tool calls before approving actions that spend credits, create monitors, or fetch large datasets.
## Local stdio MCP
Use [local stdio MCP](/guides/local-mcp) when your client runs MCP servers on your machine with a command like `npx`.
Package and source:
* npm: [@thehog/mcp](https://www.npmjs.com/package/@thehog/mcp)
* GitHub: [The-Hog/the-hog-mcp](https://github.com/The-Hog/the-hog-mcp)
## Available tools
See [MCP tools](/reference/mcp-tools) for the workflow tools, direct API tools, example prompts, and async behavior.
# The Hog API
Source: https://docs.thehog.ai/index
Search companies, discover people, enrich contacts, and run research from one REST API.
The Hog is a GTM intelligence platform built for revenue teams that need fast, accurate data about target accounts and contacts. With a single REST API, you can search companies by firmographics and technographics, discover and enrich people, run deep research, and monitor important activity.
Make your first API call in minutes. Search companies, find people, and enrich contacts.
Get your API key and API secret, then learn how to authenticate every request.
Understand company-first search, credits, and async operations.
Full reference for every endpoint, including parameters, responses, and examples.
## What you can do
Find target accounts by industry, employee count, revenue, tech stack, hiring signals, and more.
Discover ICP-matched contacts with natural language queries and persona filters.
Get verified emails and phone numbers for your prospects with configurable coverage depth.
Run LLM-powered research jobs that return structured data conforming to your JSON Schema.
## Get started in 4 steps
Obtain your API key and API secret from your account settings. You'll send them as `X-Access-Key` and `X-Secret-Key` on every request.
Call `POST /api/v1/companies/search` with a query or firmographic filter, then poll the returned operation for matching accounts.
Search people at a target account, then call `POST /api/enrichments` with a LinkedIn URL or email to retrieve verified email and phone.
Use the returned operation ID to poll for async search, enrichment, and research results.
# The Hog: GTM Intelligence API for Revenue Teams
Source: https://docs.thehog.ai/introduction
The Hog is a REST API for go-to-market teams. Search companies, discover people, enrich contacts, run deep research, and monitor social mentions — all in one platform.
The Hog is a GTM intelligence API built for revenue teams. With a single REST API you can find target accounts, discover and enrich contacts, run deep research, and monitor social mentions — all in one platform.
## What you can do
Find target accounts by industry, headcount, revenue, tech stack, and more using firmographic and technographic filters.
Query contacts in plain language — "VP of Sales at Series B SaaS companies in the US" — and get ICP-ranked results.
Get verified emails and phone numbers for your prospects. Fast lookups return 200; deeper coverage returns 202 with a poll URL.
Trigger LLM-powered research jobs that return structured data conforming to any JSON Schema you define.
Set up recurring monitors to track keywords, profiles, and posts across LinkedIn, X, Reddit, TikTok, and the web.
Search across the web and social platforms in a single async API call.
Connect The Hog to Claude or your coding agent with hosted remote MCP or the local stdio MCP package.
## Company-first search philosophy
The Hog is designed around a company-first workflow. You start by finding the right accounts — filtered by firmographics, technographics, or signals — and then drill into the people at those companies. This keeps your outreach anchored to the accounts that actually matter rather than building lists of contacts in isolation.
A typical workflow looks like this:
1. **Search companies** to build a list of target accounts that match your ICP.
2. **Find people** at those accounts using a natural-language query scoped to a company ID.
3. **Enrich contacts** to get verified email addresses and phone numbers.
## Base URL
All API requests go to:
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
https://developer.thehog.ai
```
Every endpoint is prefixed with `/api`. For example, the company search endpoint is `POST https://developer.thehog.ai/api/v1/companies/search`.
## Next steps
Get your API key and learn how to authenticate every request.
Make your first API call in minutes with step-by-step examples.
Connect The Hog through hosted remote MCP or install the local stdio MCP package.
# Get Started with The Hog API
Source: https://docs.thehog.ai/quickstart
Make your first The Hog API call in minutes. Search companies, find people, and enrich contacts with step-by-step examples.
This guide walks you through the core The Hog workflow: find a company, discover people at that company, enrich a contact to get their email and phone number, and poll for results when the operation runs asynchronously. Each step builds on the previous one, so you can follow along end-to-end or jump to the section you need.
Building from Claude, Claude Code, Cursor, Codex, or another MCP client? See [Use The Hog with MCP](/guides/use-mcp) to connect through hosted remote MCP or install the local stdio MCP package.
Retrieve your API key and API secret from the Credentials page in your dashboard.
See [Authentication](/authentication) for the full header details.
All examples below send the API key as `X-Access-Key` and the API secret as `X-Secret-Key`.
Call `POST /api/v1/companies/search` with a natural-language query to find matching accounts. The endpoint returns `202 Accepted` with an operation ID; poll the operation to retrieve ranked companies.
```bash curl theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/companies/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "Salesforce",
"limit": 5
}'
```
```python Python theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import httpx
response = httpx.post(
"https://developer.thehog.ai/api/v1/companies/search",
headers={
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
},
json={"query": "Salesforce", "limit": 5},
)
data = response.json()
operation_id = data["operationId"]
```
```javascript Node.js theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const response = await fetch("https://developer.thehog.ai/api/v1/companies/search", {
method: "POST",
headers: {
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ query: "Salesforce", limit: 5 }),
});
const data = await response.json();
const operationId = data.operationId;
```
**Sample 202 response:**
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01HZXCOMPANY000000000001",
"operationId": "op_01HZXCOMPANY000000000001",
"status": "queued",
"pollUrl": "/api/operations/op_01HZXCOMPANY000000000001"
}
```
Poll `GET /api/operations/:id` until the operation succeeds. Use the returned company domain or name in the next step.
Call `POST /api/v1/people/search` with a natural-language query and optional company filters from the previous step. This endpoint also returns `202 Accepted`; poll the operation for ICP-ranked contacts.
```bash curl theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/v1/people/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"query": "VP of Sales",
"filters": {
"company": { "domains": ["salesforce.com"] }
},
"limit": 10
}'
```
```python Python theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
response = httpx.post(
"https://developer.thehog.ai/api/v1/people/search",
headers={
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
},
json={
"query": "VP of Sales",
"filters": {"company": {"domains": ["salesforce.com"]}},
"limit": 10,
},
)
operation_id = response.json()["operationId"]
```
```javascript Node.js theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const response = await fetch("https://developer.thehog.ai/api/v1/people/search", {
method: "POST",
headers: {
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
query: "VP of Sales",
filters: {
company: { domains: ["salesforce.com"] },
},
limit: 10,
}),
});
const { operationId } = await response.json();
```
**Sample 202 response:**
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01HZXPEOPLE000000000001",
"operationId": "op_01HZXPEOPLE000000000001",
"status": "queued",
"pollUrl": "/api/operations/op_01HZXPEOPLE000000000001",
"meta": { "requestId": "01HZXAMPLE000000000000002" }
}
```
Call `POST /api/enrichments` with one or more identity references — a LinkedIn URL, email address, or person ID — to retrieve verified contact information.
```bash curl theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/enrichments \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"identifier": {
"linkedin_url": "https://www.linkedin.com/in/alex-rivera-example"
},
"fields": ["contact.email", "contact.phone"]
}'
```
```python Python theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
response = httpx.post(
"https://developer.thehog.ai/api/enrichments",
headers={
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
},
json={
"identifier": {
"linkedin_url": "https://www.linkedin.com/in/alex-rivera-example",
},
"fields": ["contact.email", "contact.phone"],
},
)
result = response.json()
# 200 → enrichment complete; 202 → async, poll operationId
```
```javascript Node.js theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const response = await fetch("https://developer.thehog.ai/api/enrichments", {
method: "POST",
headers: {
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({
identifier: {
linkedin_url: "https://www.linkedin.com/in/alex-rivera-example",
},
fields: ["contact.email", "contact.phone"],
}),
});
// Check response.status: 200 = done, 202 = async
```
The enrichment endpoint returns either a **200** or a **202** response depending on how quickly the data can be resolved:
| Status | Meaning | Next step |
| -------------- | ------------------------------------ | --------------------------------------------------------- |
| `200 OK` | Enrichment completed synchronously | The `data` field contains verified contact details. |
| `202 Accepted` | Enrichment is running asynchronously | Use the `operationId` and `pollUrl` to check for results. |
**Sample 200 response:**
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"data": [
{
"id": "prs_01HZXPERSON0000000000001",
"canonicalPersonId": "prs_01HZXPERSON0000000000001",
"fullName": "Alex Rivera",
"title": "VP of Sales, North America",
"companyName": "Salesforce",
"location": "San Francisco, CA",
"emailStatus": "available",
"phoneStatus": "available",
"emails": [
{ "email": "alex.rivera@salesforce.com", "emailType": "work", "isVerified": true }
],
"phoneNumbers": [
{ "phoneNumber": "+14155550100", "phoneType": "direct", "isVerified": false }
],
"fromCache": false
}
],
"meta": {
"requestId": "01HZXAMPLE000000000000003",
"cost": { "estimated": 5, "actual": 4 }
}
}
```
**Sample 202 response:**
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"operationId": "op_01HZXOPERATION00000000001",
"status": "queued",
"pollUrl": "https://developer.thehog.ai/api/operations/op_01HZXOPERATION00000000001",
"meta": {
"requestId": "01HZXAMPLE000000000000004"
}
}
```
If you receive a 202, proceed to the next step to poll for the result.
When an operation returns a 202, call `GET /api/operations/:id` periodically until the `status` field is `completed` or `failed`.
```bash curl theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://developer.thehog.ai/api/operations/op_01HZXOPERATION00000000001 \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx"
```
```python Python theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import time
operation_id = "op_01HZXOPERATION00000000001"
while True:
resp = httpx.get(
f"https://developer.thehog.ai/api/operations/{operation_id}",
headers={
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
},
)
op = resp.json()
if op["status"] in ("succeeded", "failed"):
break
time.sleep(2)
result = op.get("result")
```
```javascript Node.js theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const operationId = "op_01HZXOPERATION00000000001";
async function poll(id) {
while (true) {
const res = await fetch(`https://developer.thehog.ai/api/operations/${id}`, {
headers: {
"X-Access-Key": "ak_xxxxxxxxxxxxxxxx",
"X-Secret-Key": "sk_xxxxxxxxxxxxxxxx",
},
});
const op = await res.json();
if (op.status === "succeeded" || op.status === "failed") return op;
await new Promise((r) => setTimeout(r, 2000));
}
}
const op = await poll(operationId);
```
**Sample completed response:**
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"id": "op_01HZXOPERATION00000000001",
"status": "succeeded",
"progress": 100,
"result": {
"items": [
{
"identifier": {
"linkedin_url": "https://www.linkedin.com/in/alex-rivera-example"
},
"status": "success",
"data": {
"contact": {
"email": ["alex.rivera@salesforce.com"],
"phone": ["+14155550100"]
}
}
}
],
"partial": false
},
"error": null
}
```
Poll at a reasonable interval — every 2–5 seconds is sufficient for most enrichment jobs. Deep research operations may take longer; check the `progress` field to track how far along the job is.
## What's next
You have completed the core workflow. From here you can:
Search across the web, LinkedIn, X, Reddit, and TikTok with a single API call.
Create recurring monitors to track mentions, keywords, and profiles across social platforms.
Kick off LLM-powered research jobs that return structured data conforming to a JSON Schema you define.
Understand sync responses, async operation polling, request IDs, and common result formats.
Connect The Hog to an MCP client with hosted remote MCP or local stdio.
# Error handling
Source: https://docs.thehog.ai/reference/error-handling
# Error Handling and HTTP Status Codes
> The Hog returns RFC 7807-style JSON error bodies for all failures. Learn the error shape, status codes, validation errors, and how to handle them.
When a request fails, The Hog API always returns a structured JSON body — never a bare string or an empty response. Every error body follows the same shape so you can handle failures consistently in your code, and every error includes a `requestId` you can share with support to pinpoint the exact failed call.
## Standard error body
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 400,
"error": "Bad Request",
"message": "Validation failed",
"path": "/api/v1/people/search",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-03-12T12:00:00.000Z",
"errors": [
{ "property": "query", "message": "query must be a string" }
]
}
```
| Field | Type | Description |
| ------------ | ------- | ------------------------------------------------------------ |
| `statusCode` | integer | HTTP status code |
| `error` | string | Short HTTP reason phrase (e.g. `"Bad Request"`) |
| `message` | string | Human-readable summary of the failure |
| `path` | string | The request path that triggered the error |
| `requestId` | string | UUID for this request — include this when contacting support |
| `timestamp` | string | ISO 8601 timestamp of when the error occurred |
| `errors` | array | Present only on 400 validation failures — see below |
## Validation errors (400)
When your request body fails validation, the top-level `message` is `"Validation failed"` and the `errors` array lists every field that failed, along with a plain-English description of the constraint that was violated.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
// HTTP 400 — validation failure
{
"statusCode": 400,
"error": "Bad Request",
"message": "Validation failed",
"path": "/api/v1/people/search",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z",
"errors": [
{ "property": "query", "message": "query must be a string" },
{ "property": "limit", "message": "limit must not be greater than 100" }
]
}
```
Each object in the `errors` array has two fields:
| Field | Type | Description |
| ---------- | ------ | ---------------------------------- |
| `property` | string | The request body field that failed |
| `message` | string | What constraint was violated |
Fix every entry in `errors` before retrying — the request will continue to fail until all validation rules pass.
## HTTP status codes
Your request body contains missing or invalid fields. The `errors` array lists every violation. Fix each field and retry.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 400,
"error": "Bad Request",
"message": "Validation failed",
"path": "/api/v1/companies/search",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z",
"errors": [
{ "property": "filters.headcount", "message": "headcount must be a positive number" }
]
}
```
The `X-Access-Key` or `X-Secret-Key` header was not provided, or the credential pair is invalid or revoked. Verify both values from the Credentials page.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 401,
"error": "Unauthorized",
"message": "Invalid or missing authentication credentials",
"path": "/api/v1/companies/search",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z"
}
```
Your organization does not have enough credits to complete the request. Top up your balance or reduce the scope of the request.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 402,
"error": "Payment Required",
"message": "Insufficient credits to complete this request",
"path": "/api/deep-research",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z"
}
```
The credentials are valid but The Hog cannot determine which organization the request belongs to. Check that you are using a dashboard-created API key and API secret for the intended organization.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 403,
"error": "Forbidden",
"message": "No organization context found",
"path": "/api/enrichments",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z"
}
```
The operation ID or resource you requested does not exist or does not belong to your organization.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 404,
"error": "Not Found",
"message": "Operation not found",
"path": "/api/operations/op_nonexistent",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z"
}
```
Your organization has exceeded the allowed request rate. Wait before retrying and use exponential backoff. See [Rate Limits](/reference/rate-limits) for details.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 429,
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please slow down and retry.",
"path": "/api/operations/op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z"
}
```
An unexpected error occurred on The Hog's servers. The `message` is intentionally generic in production. These errors are logged automatically. If they persist, contact support with your `requestId`.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 500,
"error": "Internal Server Error",
"message": "An unexpected error occurred",
"path": "/api/enrichments",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z"
}
```
## Quick reference
| Status | Meaning | Retry? |
| --------- | ------------------------------------ | -------------------------------- |
| 400 | Validation failed — fix the `errors` | No — fix the request first |
| 401 | Invalid or missing credentials | No — refresh your credentials |
| 402 | Insufficient credits | No — top up your balance |
| 403 | No organization context | No — check your credential setup |
| 404 | Resource not found | No |
| 429 | Rate limit exceeded | Yes — after exponential backoff |
| 500 / 503 | Server error | Yes — after a short wait |
## Using `requestId` for support
Every error body includes a `requestId` field. When you open a support ticket or file a bug report, always include this value. It maps directly to a specific request in The Hog's logs, so the support team can retrieve the full request context without needing you to reproduce the issue.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
# The requestId is in the error body AND the X-Request-Id response header
curl -i -X POST https://developer.thehog.ai/api/v1/companies/search \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"query": "acme"}'
# Look for: X-Request-Id: 3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a
```
# Idempotency
Source: https://docs.thehog.ai/reference/idempotency
# Idempotent Requests with The Hog API
> Pass the Idempotency-Key header on async POST requests to safely retry without creating duplicate jobs. The key is scoped to your organization.
Network errors and timeouts are a normal part of distributed systems. When you fire off an async request to The Hog and the connection drops before you receive a response, you can't be sure whether the job was created or not. Retrying blindly risks submitting the same job twice — consuming double the credits and producing duplicate results. Idempotency keys solve this by letting The Hog recognize a repeated request and return the existing job instead of creating a new one.
## Supported endpoints
Idempotency keys are accepted on these async POST endpoints:
| Endpoint | Description |
| ------------------------------- | ------------------------- |
| `POST /api/enrichments` | Contact enrichment |
| `POST /api/deep-research` | LLM-powered deep research |
| `POST /api/v1/search` | Multi-platform search |
| `POST /api/v1/companies/search` | Company discovery |
| `POST /api/v1/people/search` | People discovery |
## How to use it
Include the `Idempotency-Key` header with a unique string value in your POST request. A UUID v4 is the recommended format.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://developer.thehog.ai/api/deep-research \
-H "X-Access-Key: ak_xxxxxxxxxxxxxxxx" \
-H "X-Secret-Key: sk_xxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: example-idempotency-key" \
-d '{
"prompt": "What are the top strategic priorities for Acme Corp this quarter?",
"schema": { "type": "object", "properties": { "priorities": { "type": "array", "items": { "type": "string" } } } }
}'
```
If the request was already received with the same key, The Hog returns the **existing operation** — same `operationId`, same `pollUrl` — without creating a new job or charging additional credits.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Returned whether this is the first call or a retry — identical either way
{
"operationId": "op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"status": "queued",
"pollUrl": "https://developer.thehog.ai/api/operations/op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"meta": {
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a"
}
}
```
## Key scope
Idempotency keys are scoped **per organization**. Two different organizations that happen to use the same key value are treated as completely independent requests — there is no cross-organization interference.
## When to use idempotency keys
If a request times out before you receive a response, retry with the same key. You'll get back the existing job if it was received, or a new one if it wasn't.
After a 500 or 503 error, retry with the same key. The Hog will not create a duplicate job if the first request was successfully enqueued before the error occurred.
Any time you're unsure whether a request arrived — load balancer resets, client crashes — include a key and retry freely.
If your worker system guarantees at-least-once delivery, use a stable key derived from your own job ID to make The Hog calls naturally idempotent.
## Choosing a key
Generate a UUID v4 fresh for each **logical** request. Do not reuse a key across different requests that should produce different results.
```javascript theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { randomUUID } from 'crypto';
// Generate once per logical job, before the first attempt
const idempotencyKey = randomUUID();
// Use the same key for all retries of this specific job
const response = await fetch('https://developer.thehog.ai/api/deep-research', {
method: 'POST',
headers: {
'X-Access-Key': process.env.THEHOG_ACCESS_KEY,
'X-Secret-Key': process.env.THEHOG_SECRET_KEY,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify({ prompt: '...', schema: { /* ... */ } }),
});
```
A key is only meaningful within your organization's scope. Generate a new key for each distinct logical job — if you reuse the same key for genuinely different requests, the second request will return the result of the first one.
# MCP tools
Source: https://docs.thehog.ai/reference/mcp-tools
Reference the workflow and direct API tools exposed by The Hog MCP.
The MCP server exposes workflow tools for GTM jobs and API tools for direct control over a specific endpoint.
## Workflow tools
Use these first when your request maps to a GTM job rather than one API call:
| Tool | Use it for |
| -------------------------------- | -------------------------------------------------------------------------------------------- |
| `build_prospect_list` | Search target companies, find relevant people, and optionally enrich contacts. |
| `find_people_at_target_accounts` | Find contacts at a known list of company domains or names. |
| `enrich_prospect_list` | Enrich a batch of known prospects with requested contact fields or signals. |
| `research_company` | Crawl a company site, search recent web results, and run structured deep research. |
| `research_person` | Build a structured research dossier for a person or prospect. |
| `monitor_topic` | Create monitors for a topic, company, profile, or post, and optionally run them immediately. |
| `analyze_social_profile` | Fetch and summarize bounded public Instagram or TikTok profile data. |
| `scrape_and_extract` | Scrape one URL and optionally extract structured data with deep research. |
### Target account people search
`find_people_at_target_accounts` accepts company domains, company names, or company LinkedIn URLs. Prefer domains or names when you know the account. A LinkedIn URL is useful when you already know the exact company page, but the tool should not silently replace the requested account with a different company page.
When the workflow waits for the people-search operation to finish, the underlying result can include:
| Field | Meaning |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `targetAccountSearchMode` | `linkedin_company_page`, `profile_current_company`, or `unavailable`. |
| `targetAccountOutcome` | The LinkedIn company-handle resolution outcome: supplied, verified, unavailable/conflicting, or unresolved. Use `targetAccountSearchMode` to see how people were matched. |
| `companyMatchEvidence` | Per-person evidence summary: `company_page` or `profile_current_job`. |
If the workflow returns an operation ID instead of final people, call `get_operation` with that ID and read the same fields from the operation result.
## API tools
Use these when you want direct control over a specific public API endpoint:
| Area | Tools |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Companies and people | `search_companies`, `search_people` |
| Enrichment | `enrich_contact`, `enrich_contacts`, `get_enrichment` |
| Research and operations | `start_deep_research`, `get_operation` |
| Search | `submit_search`, `get_search_result`, `list_searches` |
| Web scraping | `search_web`, `crawl_website`, `scrape_web_page` |
| Social scraping | `get_instagram_profile`, `list_instagram_posts`, `get_instagram_post`, `list_instagram_post_comments`, `list_instagram_followers`, `list_instagram_following`, `get_tiktok_profile` |
| Monitors | `create_monitor`, `list_monitors`, `get_monitor`, `update_monitor`, `delete_monitor`, `run_monitor_now`, `list_monitor_events` |
## Example prompts
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
Build a prospect list of 20 Series B fintech companies in the US and find Heads of Partnerships at each company.
```
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
Research Acme Corp and return products, customers, competitors, recent signals, and sources.
```
```text theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
Create a weekly monitor for mentions of our brand on web search and run it once now.
```
## Async results
Many The Hog API calls run asynchronously. MCP tools may return an operation ID, poll URL, child operation IDs, warnings, and partial step results. If a tool returns an operation ID instead of final data, ask your client to call `get_operation` with that ID.
Deep-research-bearing tools (`research_company`, `research_person`, `scrape_and_extract`, `start_deep_research`) are **async-first**: because deep research runs for minutes, they return an operation ID immediately (status `queued`) rather than blocking. Poll `get_operation` until the status is `completed` to fetch the result. You may set `waitForResult: true` to wait inline, but the wait is capped at \~50s (below the \~60s MCP client/gateway ceiling); if it does not finish in time you still receive the operation ID to poll. Re-attaching with `get_operation` does not consume additional credits — do not re-issue the call to retry.
Slow LinkedIn profile post scrapes use the same pattern: `list_linkedin_profile_posts` queues work and returns an operation ID immediately. Poll `get_operation` until status is `succeeded` to fetch the posts.
# Rate limits
Source: https://docs.thehog.ai/reference/rate-limits
# Rate Limits for The Hog API
> The Hog enforces rate limits per organization and user to ensure fair usage. Polling operations has a separate dedicated throttle. Learn limits and retry behavior.
The Hog enforces rate limits on all API endpoints to ensure reliable service for every organization. Limits are tracked per organization and user, not per API key alone. When you exceed a limit, the API returns HTTP 429 and you must wait before retrying.
## Global rate limit
Every authenticated endpoint is covered by a global, per-organization-and-user rate limit of **600 requests per minute**. The limit applies across all endpoints combined, so a burst of company searches counts against the same bucket as a burst of enrichment requests for the same caller.
## Polling rate limit
`GET /api/operations/:id` has its own **dedicated rate limit** — separate from the global bucket — of **300 requests per minute per organization-and-user**. This limit exists because polling is the highest-frequency access pattern and must not crowd out other API traffic.
Do not poll `GET /api/operations/:id` in a tight loop or on every tick of a UI
refresh cycle. Aggressive polling will trigger HTTP 429 responses and block
other requests your organization is making simultaneously.
Poll at **2–5 second intervals** for short jobs such as enrichment and search.
Use **10–30 second intervals** for deep research jobs, which routinely take 30
seconds to several minutes to complete. If you receive a 429 on the poll
endpoint, honor the `Retry-After` header before resuming.
## HTTP 429 response
When you hit a rate limit, the API returns:
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
"statusCode": 429,
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please slow down and retry.",
"path": "/api/operations/op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a",
"timestamp": "2025-06-10T09:14:33.000Z"
}
```
429 responses include `Retry-After` and `X-RateLimit-*` headers. Treat
`Retry-After` as the minimum wait before the next request to that bucket.
## Retrying after 429
Use **exponential backoff** when you receive a 429. Do not retry immediately — the limit window must pass before your request will succeed.
Detect `statusCode === 429` in the error body or `response.status === 429`.
If the response includes `Retry-After`, wait at least that long. Otherwise start with a short delay and double it on each consecutive 429, up to a maximum. Add random jitter to avoid thundering-herd retries from parallel processes.
```javascript theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function retryWithBackoff(fn, maxRetries = 5) {
let attempt = 0;
while (attempt < maxRetries) {
try {
return await fn();
} catch (err) {
if (err.status !== 429 || attempt === maxRetries - 1) throw err;
const retryAfterSeconds = Number(err.headers?.['Retry-After']);
const baseDelay = Number.isFinite(retryAfterSeconds)
? retryAfterSeconds * 1000
: 1000 * Math.pow(2, attempt); // 1s, 2s, 4s, 8s, 16s
const jitter = Math.random() * 500;
await sleep(baseDelay + jitter);
attempt++;
}
}
}
```
After a 429 on the poll endpoint, resume at a slower interval after the `Retry-After` window.
## Recommended polling intervals
| Job type | Recommended interval |
| ----------------------------------------- | -------------------- |
| Enrichment (`POST /api/enrichments`) | 2-5 seconds |
| Search jobs (`POST /api/v1/search`) | 5-10 seconds |
| Deep research (`POST /api/deep-research`) | 10-30 seconds |
These intervals keep you well within the 300 requests/minute polling limit even when running multiple concurrent jobs.
# API Response Shapes and Data Formats
Source: https://docs.thehog.ai/reference/response-shapes
The Hog API uses predictable response shapes for sync, async, and operation polling flows.
The Hog API keeps response shapes stable for each endpoint so you can parse results and correlate requests reliably. This page describes the common sync, async, and polling patterns.
## The `X-Request-Id` header
Every authenticated response includes an `X-Request-Id` HTTP header containing a UUID that uniquely identifies the request. This value is also mirrored inside the response body as `meta.requestId`. Save it when you contact support — it lets the team locate the exact request in logs instantly.
```bash theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Example response header
X-Request-Id: 3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a
```
## Sync response (HTTP 200)
Fast operations complete within the request lifecycle and return HTTP 200. When an endpoint uses an envelope, the `data` field holds the endpoint-specific payload.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
// HTTP 200 — synchronous result
{
"data": {
// endpoint-specific payload, e.g. an array of companies or a context object
},
"meta": {
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a"
}
}
```
## Async accepted response (HTTP 202)
Long-running operations — batch enrichment, search, and deep research — are accepted immediately and processed in the background. The response contains everything you need to poll for the result.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
// HTTP 202 — async job accepted
{
"id": "op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"operationId": "op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"status": "queued",
"pollUrl": "https://developer.thehog.ai/api/operations/op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"meta": {
"requestId": "3f7a1c2e-88b4-4d0e-a1f5-0c9e2b3d7f4a"
}
}
```
| Field | Type | Description |
| ---------------- | ------ | ------------------------------------------------- |
| `id` | string | Unique ID for the background job |
| `operationId` | string | Unique ID for the background job |
| `status` | string | Always `"queued"` on acceptance |
| `pollUrl` | string | Fully-qualified URL to poll for status and result |
| `meta.requestId` | string | Correlates to the `X-Request-Id` header |
Use `pollUrl` directly in subsequent `GET` requests. See [Operation status response](#operation-status-response-get-apioperationsid) below for the shape returned while polling.
## Operation status response (`GET /api/operations/:id`)
Poll this endpoint after receiving a 202 to check progress and retrieve the result when the job finishes.
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
// In-progress operation
{
"id": "op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"status": "processing",
"progress": 45, // 0–100, or null when not yet tracked
"result": null, // null until status is "succeeded"
"error": null // null unless status is "failed"
}
```
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Completed operation
{
"id": "op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"status": "succeeded",
"progress": 100,
"result": {
// endpoint-specific result payload
},
"error": null
}
```
```json theme={null} theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Failed operation
{
"id": "op_01HZ9K2QW3RV4M5N6P7Q8R9S0T",
"status": "failed",
"progress": null,
"result": null,
"error": {
"message": "No results were found for the given input."
}
}
```
### Operation statuses
The job has been accepted and is waiting for a worker to pick it up.
A worker is actively running the job. Check `progress` (0–100) for completion
percentage.
The job finished successfully. Read the result from the `result` field.
The job encountered an unrecoverable error. Details are in the `error` field.
The job completed but some sub-tasks did not succeed. `result` contains
whatever was produced.
The job was cancelled before it completed.
| Field | Type | Description |
| ---------- | --------------- | -------------------------------------------------------------------- |
| `id` | string | Operation ID matching the `operationId` from the 202 response |
| `status` | string | Current status (see table above) |
| `progress` | integer \| null | Completion percentage (0–100), or `null` if not yet tracked |
| `result` | object \| null | Result payload when `status` is `"succeeded"` or `"partial_success"` |
| `error` | object \| null | Error detail when `status` is `"failed"` |
### Search result metadata
Search operations return a `result` object with `data` and `meta` fields when they finish. For people search scoped to target accounts, the metadata can include safe target-account status fields:
| Field | Values | Meaning |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `targetAccountSearchMode` | `linkedin_company_page`, `profile_current_company`, `unavailable` | How the search constrained people to the requested account. |
| `targetAccountOutcome` | `provided_linkedin_handle`, `verified_linkedin_handle`, `unverified_or_conflicting_linkedin_candidates`, `unresolved` | The LinkedIn company-handle resolution outcome. Use `targetAccountSearchMode` to see whether people were matched through a company page, current profile company text, or no available path. |
| `providerOutcome` | `hit`, `empty_clean`, `empty_partial_failure` | Whether the selected provider returned usable rows, returned no rows, or completed with partial provider failure. |
| `message` | string | A short user-facing explanation for empty or unavailable paths. |
People returned from a target-account search can include `companyMatchEvidence`:
| Value | Meaning |
| --------------------- | ------------------------------------------------------------------------------ |
| `company_page` | The person matched via a LinkedIn company page constraint. |
| `profile_current_job` | The person matched via current profile company text for the requested account. |
The operation response does not expose raw company candidates, candidate scores, provider run IDs, actor inputs, model IDs, pricing rows, COGS, or detailed resolver diagnostics.