# StableEnrich API Reference ## Authentication All endpoints require micropayment. Include payment headers as per the HTTP 402 specification. Payments are processed on Base mainnet (eip155:8453), Solana, or Tempo. ## Base URL https://stableenrich.dev All endpoints are relative to this base URL. ## Agent Workflow (Progressive) 1. Discover candidate endpoints with `mcp__agentcash__discover_api_endpoints("https://stableenrich.dev")`. 2. If discovery reports `guidanceAvailable=true` but guidance is omitted, only re-run with `include_guidance=true` when domain-level methodology is needed. 3. For selected POST/PUT/PATCH endpoints, call `mcp__agentcash__check_endpoint_schema` before first fetch. 4. Execute with `mcp__agentcash__fetch`. If no endpoint matches the user task, stop this origin flow and switch to another origin. ## Schema Discovery All endpoints support schema discovery via the `check_endpoint_schema` tool. Use it on the selected endpoint to confirm request schema and pricing before execution. ## Web Scraping For web scraping tasks, always start with **Firecrawl `/api/firecrawl/scrape`** ($0.0126/request). It provides comprehensive page content with clean markdown formatting. If you need to scrape many URLs and cost is a concern, consider **Exa `/api/exa/contents`** ($0.002/request) as a cheaper alternative for bulk processing. --- # Research Methodology (Fan-out / Population Tasks) Use this playbook for ambiguous, broad, or "find many candidates" requests (e.g., "junior hedge fund carry-trade people who might start a company"): 1. **Detect fan-out**: If the request implies a population or list-building task, avoid single-search answers. Plan for *many* queries and a large candidate pool. 2. **Clarify constraints**: Restate the target, must-haves, nice-to-haves, geography, seniority, timeframe, and desired output size. If unclear, make explicit assumptions and proceed. 3. **Broad-to-narrow pipeline**: - **Seed**: Use multiple discovery sources to build an initial pool (Exa `/api/exa/search` with `category: "linkedin profile"` for people discovery, Firecrawl for web lists, Google Maps for local orgs, Apollo org-search for company IDs). - **Expand**: Generate query variants (synonyms, titles, strategies, regions) and paginate until you reach a healthy pool (aim 50–100 candidates). - **Enrich**: Use Apollo people-search + people-enrich (and Minerva enrich for LinkedIn/demographic data, or Clado contacts-enrich for email/phone) to fill details; dedupe by name + company + profile URL. - **Filter**: Apply the must-haves; keep 30–50 high-confidence matches. 4. **Tool choreography**: Use **mcp__agentcash__fetch** for all paid endpoints. Verify Apollo org IDs with /api/apollo/org-search before large people searches to avoid wasted calls. 5. **Evidence and transparency**: Track sources per candidate; note uncertainty; surface how the list was constructed and where gaps remain. --- # Google Maps API ## POST /api/google-maps/text-search/full Search for places using a text query with full field details (includes ratings, reviews, contact info, and atmosphere data). Price: $0.08 per request Example: ```json { "textQuery": "coffee shops in San Francisco", "maxResultCount": 5 } ``` --- ## POST /api/google-maps/text-search/partial Search for places using a text query with partial field details (basic info only, lower cost). Price: $0.02 per request. Same request body as /text-search/full. --- ## POST /api/google-maps/nearby-search/full Search for places near a geographic location with full details. Price: $0.08 per request Example: ```json { "locationRestriction": { "circle": { "center": { "latitude": 37.7749, "longitude": -122.4194 }, "radius": 1000 } }, "maxResultCount": 5 } ``` --- ## POST /api/google-maps/nearby-search/partial Search for places near a geographic location with partial details. Price: $0.02 per request. Same request body as /nearby-search/full. --- ## GET /api/google-maps/place-details/full Get full details for a specific place by ID. Price: $0.05 per request Example: GET /api/google-maps/place-details/full?placeId=ChIJN1t_tDeuEmsRUsoyG83frY4 --- ## GET /api/google-maps/place-details/partial Get partial details for a specific place by ID. Price: $0.02 per request. Same query parameters as /place-details/full. --- ## GET /api/google-maps/solar/building-insights Google Solar API — closest building insights for a lat/lng. Use this as a cheap probe to confirm Solar coverage for an address and to read the imagery capture date (`imageryDate`) before fetching the full data layers. Price: $0.02 per request Query parameters: - `latitude` (required) — building latitude - `longitude` (required) — building longitude - `requiredQuality` (optional, default `HIGH`) — `LOW` | `MEDIUM` | `HIGH` Example: GET /api/google-maps/solar/building-insights?latitude=37.4220&longitude=-122.0841&requiredQuality=LOW Returns roof segments, sunshine hours, panel capacity estimates, plus `imageryDate` and `imageryProcessedDate`. --- ## GET /api/google-maps/solar/data-layers Google Solar API — aerial GeoTIFF data layers for a building. Returns signed URLs for the actual aerial RGB photograph (`rgbUrl`), digital surface model (`dsmUrl`), shade/flux maps, and a building mask, along with `imageryDate` (the capture date of the photo). Price: $0.08 per request Query parameters: - `latitude` (required) - `longitude` (required) - `radiusMeters` (optional, default `50`, max `175`) — radius around the lat/lng to include - `view` (optional, default `FULL_LAYERS`) — `DSM_LAYER` | `IMAGERY_LAYERS` | `IMAGERY_AND_ANNUAL_FLUX_LAYERS` | `IMAGERY_AND_ALL_FLUX_LAYERS` | `FULL_LAYERS` - `requiredQuality` (optional, default `HIGH`) — `LOW` | `MEDIUM` | `HIGH` - `pixelSizeMeters` (optional, default `0.25`) — must be one of `0.1`, `0.25`, `0.5`, `1.0` - `exactQualityRequired` (optional, default `false`) Example: GET /api/google-maps/solar/data-layers?latitude=37.4220&longitude=-122.0841&radiusMeters=50&view=IMAGERY_LAYERS The returned URLs are signed and expire — fetch the GeoTIFFs promptly. To convert a GeoTIFF to PNG/JPEG use `gdal_translate` or any image library that reads TIFF. --- ## GET /api/google-maps/aerial-view/lookup-video Google Aerial View API — look up a previously rendered 3D flyover video for an address (or by `videoId`). Returns video URIs (landscape, portrait, thumbnail) and metadata. Returns `state: PROCESSING` if a video has been requested but not finished rendering. Price: $0.01 per request Query parameters (provide one): - `address` — street address to look up - `videoId` — existing video ID Example: GET /api/google-maps/aerial-view/lookup-video?address=1600+Amphitheatre+Parkway+Mountain+View+CA --- ## POST /api/google-maps/aerial-view/render-video Google Aerial View API — request rendering of a new flyover video for an address. The render is asynchronous; poll `/api/google-maps/aerial-view/lookup-video` until `state: ACTIVE` to retrieve the finished URIs. Price: $0.01 per request Example: ```json { "address": "1600 Amphitheatre Parkway, Mountain View, CA" } ``` --- # Apollo API IMPORTANT: Organization Lookup Workflow When performing people searches filtered by organization (using organization_ids or q_organization_domains), you MUST first verify the exact organization identifier using /api/apollo/org-search. Apollo performs exact matching on organization IDs and domains - if the identifier is incorrect or misspelled, the search will return zero results or the wrong company's employees. This verification step is critical to avoid wasted requests and incorrect data. Recommended workflow: 1. Call /api/apollo/org-search with the company name or domain 2. Confirm the returned organization_id and domain match your intended target 3. Use the verified identifier in your /api/apollo/people-search calls EXTREMELY IMPORTANT: When Apollo People Search returns names, it will return them in an obfuscated manner. It is absolutely critical that you then immediately use the /api/apollo/people-enrich endpoint to get their full information. You should pass the person's ID directly into enrich to ensure you get correct data for the person. If Apollo does not return the needed data, always fall back to Minerva or Clado. Use Minerva `/api/minerva/resolve` + `/api/minerva/enrich` for LinkedIn data, demographics, and personal contact info. Use Clado `/api/clado/contacts-enrich` for email/phone enrichment from a LinkedIn URL. ## POST /api/apollo/people-search Search for people/contacts matching criteria. Price: $0.02 per request Example: ```json { "q_keywords": "software engineer", "person_locations": ["San Francisco"], "per_page": 5 } ``` --- ## POST /api/apollo/org-search Search for organizations/companies matching criteria. Price: $0.02 per request Example: ```json { "q_keywords": "saas", "organization_locations": ["United States"], "per_page": 5 } ``` --- ## POST /api/apollo/people-enrich Enrich a person's profile with additional data. Price: $0.0495 per request Example: ```json { "email": "tim@apple.com" } ``` --- ## POST /api/apollo/org-enrich Enrich an organization's profile by domain. Price: $0.0495 per request Example: ```json { "domain": "apollo.io" } ``` --- # Exa API (Web Search & Research) ## POST /api/exa/search Semantic web search for finding relevant pages. Price: $0.01 per request Supports an optional `category` parameter to filter results by content type: `"company"`, `"research paper"`, `"news"`, `"pdf"`, `"github"`, `"tweet"`, `"personal site"`, `"linkedin profile"`, `"financial report"`. **People/Profile Search Tip**: Use `category: "linkedin profile"` for high-level people or profile searches. This scopes results to LinkedIn profiles and is a fast, cheap way to find people before enriching with Apollo or Clado. Example: ```json { "query": "best practices for building AI agents", "numResults": 5 } ``` LinkedIn profile search example: ```json { "query": "hedge fund portfolio manager New York", "category": "linkedin profile", "numResults": 10 } ``` --- ## POST /api/exa/find-similar Find pages similar to a given URL. Price: $0.01 per request Example: ```json { "url": "https://openai.com", "numResults": 5 } ``` --- ## POST /api/exa/contents Extract content from specific URLs. Price: $0.002 per request Example: ```json { "urls": ["https://example.com"] } ``` --- ## POST /api/exa/answer Get an AI-generated answer to a question based on web search. Price: $0.01 per request Example: ```json { "query": "What is the capital of France?" } ``` --- # Firecrawl API (Web Scraping) ## POST /api/firecrawl/scrape Scrape and extract content from a URL. Price: $0.0126 per request Example: ```json { "url": "https://example.com" } ``` --- ## POST /api/firecrawl/search Search the web and get scraped results. Price: $0.0252 per request Example: ```json { "query": "best coffee shops", "limit": 5 } ``` --- # Clado API (Contact Enrichment) Note: Clado is useful as a fallback when Apollo doesn't return personal emails or phone numbers. For LinkedIn profile data (experience, education, skills), use Minerva `/api/minerva/enrich` instead. ## POST /api/clado/contacts-enrich Enrich contact information from LinkedIn URL, email, or phone number. Must provide exactly one of: linkedin_url, email, or phone. Price: $0.20 per request Example: ```json { "linkedin_url": "https://www.linkedin.com/in/satyanadella" } ``` --- # Serper API (Google Search) ## POST /api/serper/news Google News search via Serper.dev. Price: $0.04 per request Example: ```json { "q": "OpenAI funding", "num": 10, "gl": "us", "hl": "en" } ``` --- ## POST /api/serper/shopping Google Shopping search via Serper.dev. Price: $0.04 per request Example: ```json { "q": "wireless earbuds", "num": 10, "gl": "us", "hl": "en" } ``` --- ## POST /api/serper/images Google Images search via Serper.dev. Generic public image discovery — products, places, screenshots, anything visual. For headshots/profile photos prefer `/api/serper/people-image-search`, which is tuned for that use case. Price: $0.04 per request Example: ```json { "q": "eiffel tower at night", "num": 10, "gl": "us", "hl": "en" } ``` --- ## POST /api/serper/people-image-search Google Images search tuned for finding a specific person — headshot/profile-photo candidates when LinkedIn/profile-photo APIs return null or a default avatar. Same backend as `/api/serper/images` but with calling guidance below. Price: $0.04 per request Headshot search guidance: - Resolve identity before ranking images when the person is ambiguous. Use Apollo, Exa LinkedIn profile search, or Minerva to confirm the profile slug, company, and title; do not rely on name alone. - LinkedIn profile photos may be limited to connections, a broader network, or LinkedIn members only. Only public photos are reliably indexable by Google. If a scraper returns `default_avatar: true` or a placeholder, use public non-LinkedIn sources tied to the confirmed identity. - If the first image search fails, research the confirmed profile for other disambiguating terms, such as school, city, past employers, projects, or personal sites, then retry Google Images with those terms. - Query syntax matters. Start with exact-name and company terms, for example: `"Ryan Sproule" "Merit Systems" LinkedIn headshot` or `"Mason Hall" "Merit Systems" profile photo`. - Use `num: 5-10`, `gl: "us"`, and `hl: "en"` for US business profiles unless the user gives another locale. - Prefer candidates whose result title/source page matches the person and company, from credible sources such as LinkedIn, the person's own website, company/team pages, RootData, Crunchbase, or news profiles. - Prefer square-ish, high-resolution human headshots. Reject obvious logos, default avatars, LinkedIn `videocover`, `feedshare`, cover/banner/background images, and images where the result title points to another person. - If no single result is clearly correct, return the top candidates with source URLs and explain the uncertainty. Example: ```json { "q": "\"Ryan Sproule\" \"Merit Systems\" LinkedIn headshot", "num": 10, "gl": "us", "hl": "en" } ``` --- ## POST /api/serper/lens Google Lens reverse image search via Serper.dev. Pass a public image URL and get visually similar pages, products, and sources. Price: $0.20 per request Example: ```json { "url": "https://example.com/photo.jpg", "gl": "us", "hl": "en" } ``` --- # Whitepages API (People & Property Search) ## POST /api/whitepages/person-search Search for people by name, phone number, or address. Price: $0.44 per request Example: ```json { "first_name": "John", "last_name": "Smith", "state_code": "CA" } ``` --- ## POST /api/whitepages/property-search Get property ownership, resident, and property details by address. Price: $0.44 per request IMPORTANT: The state parameter is named `state_code`, NOT `state`. You must use the field name `state_code` with a two-letter state abbreviation (e.g., "CA", "NY", "TX"). Using `state` instead of `state_code` will result in the field being ignored. Example: ```json { "street": "123 Main St", "city": "San Francisco", "state_code": "CA" } ``` WRONG (will not work): ```json { "street": "123 Main St", "city": "San Francisco", "state": "CA" } ``` --- # Reddit API IMPORTANT - Two-step pattern for Reddit research: 1. Use /api/reddit/search to find relevant posts. Responses are lightweight — selftext is truncated to 500 chars. Posts with `selftextTruncated: true` have more content available. 2. For any post where you need the full text or comments, call /api/reddit/post-comments with the post's permalink. This returns the complete untruncated selftext plus all comments. This pattern keeps search results small (< 2KB for 10 posts) while letting you drill into specific posts when needed. ## POST /api/reddit/search Search Reddit posts by query. Returns truncated previews for efficient browsing. Price: $0.02 per request Example: ```json { "query": "AI agents", "sort": "top", "timeframe": "week", "maxResults": 10 } ``` --- ## POST /api/reddit/post-comments Get a Reddit post's full details and comments. Use this to get untruncated selftext and discussion for posts found via search. Price: $0.02 per request Example: ```json { "url": "https://www.reddit.com/r/AskReddit/comments/abc123/example_post" } ``` --- # Hunter API (Email Verification) ## POST /api/hunter/email-verifier Verify email deliverability via Hunter.io. Price: $0.03 per request Example: ```json { "email": "test@stripe.com" } ``` --- # Influencer API (Social Media Influencer Enrichment) The Influencer API helps you enrich social media influencer profiles across multiple platforms (Instagram, TikTok, YouTube, Facebook). Use this for influencer marketing research and social media contact enrichment. ## POST /api/influencer/enrich-by-email Find social media profiles associated with an email address. Price: $0.40 per request Example: ```json { "email": "creator@example.com", "platform": "instagram", "enrichment_mode": "enhanced" } ``` --- ## POST /api/influencer/enrich-by-social Enrich a social media profile with additional data including contact info. Price: $0.40 per request Example: ```json { "platform": "instagram", "username": "example_creator", "enrichment_mode": "enhanced", "email_required": "must_have" } ``` # Cloudflare Browser Rendering API (Website Crawling) IMPORTANT - Two-step async pattern for Cloudflare crawl: The crawl endpoint is long-running (up to ~2 minutes). It uses an async pattern: 1. POST /api/cloudflare/crawl — pays and starts the crawl, returns a signed JWT token (202 response) 2. GET /api/cloudflare/jobs?token= — SIWX-authenticated (free), poll until job is complete Poll every 3–5 seconds. The job typically completes in 30–120 seconds depending on site size and render mode. ## POST /api/cloudflare/crawl Start a website crawl. Returns a JWT token to poll for results. Price: $0.10 per crawl job Parameters: - `url` (string, required) — starting URL to crawl - `limit` (number, default 10, max 25) — maximum pages to crawl - `depth` (number, default 1, max 3) — maximum link depth from starting URL - `formats` (array, default ["markdown"]) — response formats: "html", "markdown", "json" - `render` (boolean, default false) — execute JavaScript when crawling (slower, costs more) - `source` (string, optional) — URL discovery: "all", "sitemaps", or "links" - `options` (object, optional) — crawl scope: - `includeExternalLinks` (boolean) — follow links to external domains - `includeSubdomains` (boolean) — follow links to subdomains - `includePatterns` (string[]) — wildcard patterns for URLs to include - `excludePatterns` (string[]) — wildcard patterns for URLs to exclude (higher priority) Example: ```json { "url": "https://example.com", "limit": 5, "depth": 1, "formats": ["markdown"] } ``` Response (202): ```json { "token": "" } ``` --- ## GET /api/cloudflare/jobs?token= Poll crawl job status. Requires SIWX wallet authentication (same wallet that paid). Free — no x402/MPP payment. Use `mcp__agentcash__fetch_with_auth` (not `fetch`) for this endpoint. Response shape (Cloudflare's result returned directly): ```json { "id": "", "status": "", "records": [ { "url": "https://example.com/page", "status": "completed", "markdown": "...", "metadata": { "status": 200, "url": "...", "title": "..." } } ], "total": 10, "finished": 8, "skipped": 2, "browserSecondsUsed": 45.2, "cursor": "..." } ``` Page `status` values: `queued` | `completed` | `errored` | `disallowed` | `skipped` | `cancelled` To determine completion, check `result.finished + result.skipped >= result.total` or poll until no pages remain `queued`. Full polling workflow: ``` 1. token = fetch POST /api/cloudflare/crawl → response.token 2. loop: result = fetch_with_auth GET /api/cloudflare/jobs?token={token} if result.finished + result.skipped >= result.total → done, use result.records else → wait 3-5s, repeat ``` --- # Minerva API (Person Identity & Enrichment) Minerva is a consumer identity graph. Use it to resolve person identities to unique Minerva PIDs, enrich profiles with demographics/work/contact data, validate emails, and infer country from contact signals. **Recommended workflow:** 1. Use `/api/minerva/resolve` to match a person and get their Minerva PID + LinkedIn URL 2. Use `/api/minerva/enrich` with the returned PID for instant, comprehensive enrichment 3. Use `/api/minerva/validate-emails` to pre-screen emails before resolve/enrich **Minerva vs Apollo:** Minerva excels at consumer profiles (demographics, income/wealth estimates, address history, life events). Apollo excels at B2B/professional data. Use Minerva when you need personal contact info, financial signals, or household data. ## POST /api/minerva/resolve Resolve person identity to a Minerva PID and LinkedIn URL. Supports fuzzy matching (name + contact info) and reverse lookup (email or phone only, no name required). Price: $0.02 per request Standard fuzzy match example: ```json { "records": [ { "record_id": "user_001", "first_name": "John", "last_name": "Smith", "emails": ["[email protected]"] } ] } ``` Reverse lookup (email only, no name needed): ```json { "records": [{ "record_id": "user_002", "emails": ["[email protected]"] }] } ``` Use `match_condition_fields: ["linkedin_url"]` to only return matches that have a LinkedIn profile. --- ## POST /api/minerva/enrich Enrich person records with demographics, work history, education, contact info (emails + phones), address history, financial signals (income/wealth range), relatives, and social profiles. Price: $0.05 per request Three lookup modes — by Minerva PID (fastest), by LinkedIn URL, or by name/email/phone: ```json { "records": [ { "record_id": "user_001", "minerva_pid": "p-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6" }, { "record_id": "user_002", "linkedin_url": "https://www.linkedin.com/in/janedoe" }, { "record_id": "user_003", "first_name": "John", "last_name": "Smith", "emails": ["[email protected]"] } ], "return_fields": ["full_name", "personal_emails", "phones", "work_experience"] } ``` Use `return_fields` to limit response size. Use `match_condition_fields` (e.g., `["email", "phone"]`) to only return matches that have specific data. --- ## POST /api/minerva/validate-emails Check if email addresses exist in the Minerva database. Returns validation status and last-seen timestamp. Use before resolve/enrich to pre-screen lists. Price: $0.01 per request ```json { "records": ["[email protected]", "[email protected]"] } ``` --- # Common Features ## Field Filtering Most endpoints support an `excludeFields` parameter to reduce response size by omitting specific fields. Pass an array of dot-notation field paths to exclude. Google Maps endpoints default to excluding "photos" - pass an empty array to include them. ## Pagination - Apollo search endpoints support pagination via `page` and `per_page` parameters. - Google Maps search endpoints support pagination via `pageToken` (returned as `nextPageToken` in responses). - Exa search supports `numResults` up to 100. ## Error Handling All endpoints return standard HTTP status codes. Payment-required responses (402) include x402/MPP payment instructions in headers. On server errors (5xx), payments are not settled. --- # Pricing Summary | Endpoint | Price | |----------|-------| | Google Maps Text Search (Full) | $0.08 | | Google Maps Text Search (Partial) | $0.02 | | Google Maps Nearby Search (Full) | $0.08 | | Google Maps Nearby Search (Partial) | $0.02 | | Google Maps Place Details (Full) | $0.05 | | Google Maps Place Details (Partial) | $0.02 | | Google Solar Building Insights | $0.02 | | Google Solar Data Layers | $0.08 | | Google Aerial View Lookup Video | $0.01 | | Google Aerial View Render Video | $0.01 | | Apollo People Search | $0.02 | | Apollo Org Search | $0.02 | | Apollo People Enrich | $0.0495 | | Apollo Org Enrich | $0.0495 | | Exa Search | $0.01 | | Exa Find Similar | $0.01 | | Exa Contents | $0.002 | | Exa Answer | $0.01 | | Firecrawl Scrape | $0.0126 | | Firecrawl Search | $0.0252 | | Clado Contacts Enrich | $0.20 | | Serper News | $0.04 | | Serper Shopping | $0.04 | | Serper Images | $0.04 | | Reddit Search | $0.02 | | Reddit Post Comments | $0.02 | | Whitepages Person Search | $0.44 | | Whitepages Property Search | $0.44 | | Hunter Email Verifier | $0.03 | | Influencer Enrich by Email | $0.40 | | Influencer Enrich by Social | $0.40 | | Minerva Resolve | $0.02 | | Minerva Enrich | $0.05 | | Minerva Validate Emails | $0.01 | | Cloudflare Crawl (start) | $0.10 | | Cloudflare Jobs (poll) | Free (SIWX) |