# Quick Leaves API > B2B data enrichment API built from the public web: company details, customers, partners, vendors, > competitors and people for a given company domain, each relationship with the public page that shows it. Authentication: send `X-API-Key: gtm_live_…` (or `Authorization: Bearer gtm_live_…`). Every metered response carries `X-Credits-Cost` (credits charged for this call) and `X-Credits-Remaining`. Errors are RFC 9457 problem+json. You are never charged for errors, 202s, 404s or 503s, with one exception: `404 company_not_found` from `/company/details` costs 1 credit. Responses use snake_case JSON. `domain` accepts a bare domain, a URL, or an email address. A company's old domain (one it moved away from) answers with the company under its current domain, at the same price. Freshness: company endpoints always answer from stored data at once (typically < 50 ms) and refresh data older than 30 days in the background; `fresh=true` queues that refresh now. `cache=only` reads stored data, also when stale, and never queues anything: a company not in the graph is a free `404` with code `not_in_graph`, and `cache=only` together with `fresh=true` is `400 conflicting_parameters`. A company never seen before is crawled while you wait (typically 5–20 s) and returns partial data; if that takes longer you get `202` with `Retry-After` and nothing is charged. `X-Enrichment-Status` says what you got: `complete`, `partial` (some fields are still being filled: industry, business model and similar companies may be missing), `refreshing`, `refresh_deferred` (stored data; your organization already has 50 refreshes waiting, so none was queued and `fresh=true` adds no credit) or `queued`. Poll the free `/company/status` endpoint until it says `complete` instead of polling a paid endpoint. Or add `callback_url=https://…` to details, customers or competitors: once the company is `complete` (or `not_found`) we POST a Standard Webhooks message (`webhook-id`, `webhook-timestamp`, `webhook-signature`; body `{"type":"company.enrichment.completed","timestamp":…,"data":{"domain":…,"status":…}}`) signed with the secret from `/callbacks/secret`. Free; retried up to 6 times over about 9 hours; dropped after 24 h without `complete`; no redirects followed; at most 100 pending per organization (more is a free `429 callback_limit`). An organization may have at most 10 never-seen companies waiting for their first data (200 from `/company/batch`, which wait behind all other work); another one is answered `429` with `Retry-After` (free). Companies already in the graph, or already queued, never count. A domain whose crawl found no website answers `404` for a day (1 credit on `/company/details`, free elsewhere), then is crawled again. Queued work is shared out between organizations in turn. Trial organizations (made by a console sign-up, no payment yet) have lower limits until their first payment: 60 requests a minute per key, 3 never-seen companies waiting at once (3 from batches), 25 new never-seen companies a UTC day and 2 active keys. Over a limit the answer is the usual free `429` (`rate_limited` or `queue_full`) and its `detail` names the trial limit. A sign-up with a verified work e-mail gets 200 trial credits for 30 days, once per e-mail domain. ## Prices Errors, `202`, `404`, `429` and `503` answers cost no credits, except `404 company_not_found` from `/company/details`, which costs 1. A call is refused with `402` before any work when the balance is below its maximum price. | Endpoint | Credits | Free when | | --- | --- | --- | | `GET /api/v1/company/details` | 2 (+1 with `fresh=true`); 1 for `404 company_not_found` | `202` queued, `404 not_in_graph` with `cache=only` | | `GET /api/v1/company/customers` | 1 + 2 per row returned over all lists (`include=customers,partners`), at most 401 a page per list | `202` queued | | `GET /api/v1/company/vendors` | 1 + 2 per vendor returned, at most 401 a page | `404 not_in_graph`, an empty list held back because the company's domain is not verified | | `GET /api/v1/company/people` | 1 + 1 per person returned, at most 101 a page; executives in details are free | `202` queued, an empty list while `partial` | | `GET /api/v1/company/competitors` | 3 | `202` queued, an empty list while `partial` | | `POST /api/v1/company/batch` | 2 per distinct found domain (up to 50 entries) | `queued`, `queue_full`, `not_found`, `invalid` and duplicate entries | | `GET /api/v1/company/search` | 1 per started 50 rows returned | an empty answer | | `GET /api/v1/company/status` | 0 | | | `GET /api/v1/profile` | 2 (+1 with `fresh=true`) | no person found | | `POST /api/v1/work-email/lookup` | `valid` 2, `likely_valid_pattern` or `catch_all_domain` 1, `unknown` or `invalid` 0 | | | `GET /api/v1/credits`, `GET /api/v1/usage`, `GET /api/v1/pricing`, `GET /api/v1/billing/plans`, `POST /api/v1/billing/checkout` | 0 | | | `POST /mcp` (each tool) | the price of the endpoint the tool calls | the same cases | ## MCP - [MCP server](https://api.quickleaves.com/mcp): stateless Streamable HTTP, same key (`X-API-Key` or `Authorization: Bearer`), same prices, rate limit and error codes as REST. Tools: `company_details`, `company_customers`, `company_competitors`, `company_status`, `company_batch`, `company_search`, `company_vendors`, `company_people`, `profile_lookup`, `work_email_lookup`, `credits_balance`, `usage`. Each result is JSON with `data`, `credits_charged`, `credits_remaining` and `trace_id`; an error result has `code`. `GET /mcp/health` is free and needs no key. ### MCP tools - `company_details`: Company profile: firmographics, technographics, hiring. Never-seen companies are crawled (partial data, or queued). Costs 2 credits (+1 with fresh=true); 1 when no company is found; 0 when queued or, with cache=only, not stored. - `company_customers`: Customers publicly evidenced for the company, verified domains only unless includeUnverified, with evidence quotes; include=partners adds partner platforms from its integration and partner pages. Pages of up to 200 per list; pass next_cursor or partners_next_cursor back as cursor. Costs 1 credit + 2 per row returned over all lists; 0 when queued. - `company_vendors`: Vendors of the company: companies whose own pages publicly name it as a customer, with the vendor's evidence page and quote. Rows only when the company's domain is verified unless includeUnverified (an empty list held back for that reason is free). Answers from stored data only; an unknown company is not_in_graph at no cost. Pages of up to 200. Costs 1 credit + 2 per vendor returned. - `company_people`: People named on the company's own team, about and leadership pages, with the published title, executive roles (ceo, cto, founder, …), seniority and the page where each was seen; executives first. Filter by seniority, role or title. No e-mail: use work_email_lookup. Pages of up to 100. Costs 1 credit + 1 per person returned; 0 when queued or for an empty partial list. - `company_competitors`: Competitors: evidenced (compare pages) first, then similar companies (basis similar, same market, not confirmed competitors). Costs 3 credits; 0 when queued or for an empty partial list. - `company_status`: Enrichment status of a company (complete, partial, refreshing, queued, not_found) without starting a crawl. Free. - `company_batch`: Company details for up to 50 domains in one call, one result per input (found, queued, queue_full, not_found, invalid). Never crawls while you wait. Costs 2 credits per distinct found domain. - `company_search`: Finds enriched companies by what they do, from a plain-words query; rows have the company card and similarity and match_score, and an answer may be empty. Never crawls. Costs 1 credit per started 50 rows; 0 when empty. - `profile_lookup`: The person described by an openly published page (bio, speaker page). Login-walled and people-search sites are rejected. Costs 2 credits (+1 with fresh=true); 0 when no person is found. - `work_email_lookup`: Finds and checks a work e-mail; no e-mail is sent. Billed by verdict: valid 2 credits, likely_valid_pattern or catch_all_domain 1, unknown or invalid 0. - `credits_balance`: The credit balance, split into plan and pay-as-you-go credits with their expiry dates. Free. - `usage`: Requests by status class and credits charged, per UTC day and operation, over at most 92 days. Free. ## Removal requests No public process to remove a person or a company from the graph is published yet. ## Endpoint reference Generated from the OpenAPI document (`/openapi/v1.json`). ### GET /api/v1/company/details Company firmographics Company profile (firmographics, technographics, hiring). Always answers from stored data at once; data older than 30 days, or fresh=true, is refreshed in the background. A company never seen before is crawled while you wait (up to about 25 s) and returns partial data; if that takes longer the answer is 202 with Retry-After and costs nothing. The X-Enrichment-Status header is complete, partial (some fields are still being filled), refreshing, refresh_deferred (stored data; the organization already has 50 refreshes waiting, so none was queued) or queued. Costs 2 credits (+1 with fresh=true, except when refresh_deferred); 1 credit when no company is found (404 company_not_found); 0 when queued or, with cache=only, not in the graph. An organization may have at most 10 never-seen companies waiting for their first data; another one is answered 429 with Retry-After at no charge. Parameters: - `domain` (query, required): Company website, URL or email domain, e.g. stripe.com - `fresh` (query): Queue a background re-crawl now, even within the 30-day window (+1 credit). - `cache` (query): Set to only to answer from stored data, also stale, and never start a crawl or a refresh. A company not in the graph is 404 not_in_graph at no cost. Cannot be combined with fresh=true. - `callback_url` (query): https URL to POST a signed Standard Webhooks message to once the company is complete (or not found), within 24 h. Get the signing secret from GET /api/v1/callbacks/secret. Free. Responses: - `200`: OK - `202`: Accepted - `429`: Too Many Requests Example response: ```json { "domain": "airtable.com", "name": "Airtable", "description": "500,000\u002B brands use Airtable to enable real-time collaboration, automate repetitive tasks \u0026 manual work, and streamline business processes in minutes. Join them.", "industry": "Data Infrastructure", "headquarters": { "country": "US", "city": "San Francisco" }, "founded_year": 2012, "employee_count": { "min": 700, "max": 700 }, "business_model": "b2b", "pricing_motion": "hybrid", "logo_url": "https://www.airtable.com/favicon.ico", "identifiers": { "lei": null, "sec_cik": null, "isin": null }, "technographics": { "tech_stack": [ "apple", "atlassian", "atlassian_statuspage" ], "email_provider": "google_workspace", "email_security_gateway": null, "email_pattern": "first.last" }, "hiring": { "open_roles_by_department": [ { "department": "Sales", "open_roles": 3 }, { "department": "Marketing", "open_roles": 1 } ], "open_roles_total": 4, "observed_at": "2026-10-22T05:10:22.727522\u002B00:00" }, "last_enriched_at": "2026-10-22T05:10:22.727522\u002B00:00", "websites": [ "airtable.com", "dopt.com" ], "tagline": "Build Enterprise-ready AI Workflows, Apps \u0026 Agents", "cover_image_url": "https://cdn.sanity.io/images/hlcyrtq5/production/00c20d5108d1335f5a243ddcd70ea4a2d6d9a844-1200x630.webp", "social_profiles": { "linkedin": "https://www.linkedin.com/company/airtable", "x": "https://x.com/airtable", "facebook": "https://www.facebook.com/airtableapp", "instagram": "https://www.instagram.com/airtable", "youtube": "https://www.youtube.com/c/AirtableApp", "github": null, "tiktok": null }, "company_type": "private", "public_listing": null, "sic_code": null, "executives": [] } ``` ### GET /api/v1/company/customers Verified customers and partner platforms of a company B2B companies publicly evidenced as customers of the target, with confidence scores and verbatim evidence quotes. Only customers with a verified domain are returned unless include_unverified=true; each item carries domain_status. include=partners (or include=customers,partners) adds partners: integration, partner and marketplace listings on the company's own pages. fresh=true queues a background re-crawl. A company never seen before behaves as in /company/details (partial data or 202). Costs 1 credit + 2 credits per row returned over all lists; 0 when queued. Parameters: - `domain` (query, required): Company website, URL or email domain - `max_results` (query): Maximum customers per page (1–200, default 20). Bounds the maximum cost. - `fresh` (query): Queue a background re-crawl now, even within the 30-day window. - `cache` (query): Set to only to answer from stored data, also stale, and never start a crawl or a refresh. A company not in the graph is 404 not_in_graph at no cost. Cannot be combined with fresh=true. - `include_unverified` (query): Also return customers whose domain is guessed from the name or was rejected (see domain_status). - `cursor` (query): next_cursor (include=customers) or partners_next_cursor (include=partners) of the previous page; omit for the first page. Send the same domain, max_results and include_unverified, and one list in include. - `include` (query): Comma list of the lists to return: customers (default), partners. max_results applies to each list, and the price counts the rows of all lists together. investors is not offered yet. - `callback_url` (query): https URL to POST a signed Standard Webhooks message to once the company is complete (or not found), within 24 h. Get the signing secret from GET /api/v1/callbacks/secret. Free. Responses: - `200`: OK - `202`: Accepted - `429`: Too Many Requests Example response: ```json { "company": { "domain": "stripe.com", "name": "Stripe" }, "customers": [ { "domain": "carousell.sg", "name": "Carousell", "confidence": 1, "evidence": { "quote": "/customers/carousell", "url": "https://stripe.com/newsroom/stories/carousell-and-stripe" }, "source_count": 19, "first_seen_at": "2026-10-19T14:09:30.094156\u002B00:00", "last_verified_at": "2026-10-22T10:33:53.751575\u002B00:00", "basis": "evidenced", "domain_status": "verified", "card": { "description": null, "industry": null, "logo_url": null, "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": false, "tagline": null, "linkedin": null, "x": null }, "reason": null, "match_score": null, "similarity": null }, { "domain": "edfenergy.com", "name": "Edf", "confidence": 0.96, "evidence": { "quote": "/customers/edf", "url": "https://stripe.com/customers/edf" }, "source_count": 1, "first_seen_at": "2026-10-19T14:09:30.094156\u002B00:00", "last_verified_at": "2026-10-22T10:33:53.751575\u002B00:00", "basis": "evidenced", "domain_status": "verified", "card": { "description": null, "industry": null, "logo_url": null, "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": false, "tagline": null, "linkedin": null, "x": null }, "reason": null, "match_score": null, "similarity": null } ], "count": 2, "max_results": 2, "min_confidence": 0.7, "include_unverified": false, "next_cursor": "MC45Nnw2MzkyODI2MjAzMzc1MTU3NTB8MDFhMTU0N2VmOWVlNzBiNWE1NmQ1MGIwODNlNWVlMTg", "partners": [ { "domain": "linear.app", "name": "Linear", "confidence": 0.8436, "evidence": { "quote": "Linear partners with Stripe to handle billing and payments.", "url": "https://stripe.com/" }, "source_count": 1, "first_seen_at": "2026-10-19T14:09:41.897158\u002B00:00", "last_verified_at": "2026-10-20T19:36:24.41401\u002B00:00", "basis": "evidenced", "domain_status": "verified", "card": { "description": "Purpose-built for planning and building products with AI agents.", "industry": "Software", "logo_url": "https://linear.app/static/apple-touch-icon.png?v=2", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true, "tagline": "The system for product development", "linkedin": null, "x": "https://x.com/linear" }, "reason": null, "match_score": null, "similarity": null } ], "partners_count": 1, "partners_next_cursor": null } ``` ### GET /api/v1/company/competitors Competitors of a company Direct competitors: publicly evidenced competitors first (basis=evidenced: compare/vs pages, alternatives), then similar companies (basis=similar): companies in the same market, often with another product, not confirmed competitors. Each row has a reason (compare_page, compare_page_text, similar_profile); a similar row's confidence is how often such rows are real competitors, with its similarity and match_score beside it. Similar companies appear once X-Enrichment-Status is complete. fresh=true queues a background re-crawl at no extra cost. Costs 3 credits; 0 when queued, and 0 for an empty list while the status is partial. A company never seen before behaves as in /company/details. Parameters: - `domain` (query, required): Company website, URL or email domain - `limit` (query): Maximum competitors to return (1–25, default 10). - `fresh` (query): Queue a background re-crawl now, even within the 30-day window. No extra cost. - `cache` (query): Set to only to answer from stored data, also stale, and never start a crawl or a refresh. A company not in the graph is 404 not_in_graph at no cost. Cannot be combined with fresh=true. - `callback_url` (query): https URL to POST a signed Standard Webhooks message to once the company is complete (or not found), within 24 h. Get the signing secret from GET /api/v1/callbacks/secret. Free. Responses: - `200`: OK - `202`: Accepted - `429`: Too Many Requests Example response: ```json { "company": { "domain": "stripe.com", "name": "Stripe" }, "competitors": [ { "domain": "paddle.com", "name": "Paddle", "confidence": 0.8, "evidence": { "quote": "/compare/stripe", "url": "https://www.paddle.com/compare/stripe" }, "source_count": 1, "first_seen_at": "2026-10-19T15:19:46.401102\u002B00:00", "last_verified_at": "2026-10-20T19:35:00.466324\u002B00:00", "basis": "evidenced", "domain_status": "verified", "card": { "description": "Increase revenue, reduce risk and reduce cost with Paddle, the payment solution powering global revenue for n8n, Letterboxd \u0026 AdGuard. One platform that handles billing, tax and compliance.", "industry": "E-Commerce", "logo_url": "https://www.paddle.com/images/paddle-spark.png", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true }, "reason": "compare_page", "match_score": null, "similarity": null }, { "domain": "explo.co", "name": "Explo", "confidence": 0.7, "evidence": { "quote": "/stripe-vs-explo", "url": "https://www.explo.co/stripe-vs-explo" }, "source_count": 1, "first_seen_at": "2026-10-19T14:53:51.624724\u002B00:00", "last_verified_at": "2026-10-19T14:53:57.060849\u002B00:00", "basis": "evidenced", "domain_status": "verified", "card": { "description": "An embedded analytics solution for product and engineering teams. Interactive dashboards, self-serve reporting, Explo AI, and enterprise-grade security all for your end users.", "industry": "Cybersecurity", "logo_url": "https://cdn.prod.website-files.com/62f681c18d50329187681754/62f681c18d503265d86818da_favicon.ico", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true }, "reason": "compare_page", "match_score": null, "similarity": null }, { "domain": "numeral.com", "name": "Numeral", "confidence": 0.7, "evidence": { "quote": "/stripe-tax-alternative", "url": "https://www.numeral.com/stripe-tax-alternative" }, "source_count": 1, "first_seen_at": "2026-10-19T14:28:36.858537\u002B00:00", "last_verified_at": "2026-10-19T14:28:48.47187\u002B00:00", "basis": "evidenced", "domain_status": "verified", "card": { "description": "Numeral automates sales tax, VAT and GST compliance for ecommerce and SaaS businesses, from nexus monitoring and registrations to filing and remittance.", "industry": "Government", "logo_url": "https://cdn.prod.website-files.com/6a219d3ca4f9ef92939b285c/6a68bd170d8ac003735e8f06_Numeral-Logomark-Indigo-White.png", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true }, "reason": "compare_page", "match_score": null, "similarity": null } ], "count": 3, "limit": 3 } ``` ### GET /api/v1/company/status Enrichment status of a company Where a company stands, without starting a crawl: complete, partial (some fields are still being filled), refreshing, queued, or not_found (no data and nothing queued; call a company endpoint to start). Poll this after a 202 or a partial answer instead of a paid endpoint. Free. Parameters: - `domain` (query, required): Company website, URL or email domain Responses: - `200`: OK Example response: ```json { "domain": "stripe.com", "status": "complete", "last_enriched_at": "2026-10-20T19:36:24.41401\u002B00:00", "fields_completed_at": "2026-10-20T19:36:24.41401\u002B00:00" } ``` ### POST /api/v1/company/batch Company firmographics for up to 50 domains Details for up to 50 domains in one call, one result per input in input order: status found (data set), queued (never-seen company, crawled in the background; poll /company/status), queue_full (the organization's batch slots for never-seen companies are taken: 200, or 3 at once and 25 a UTC day for a trial organization; batch companies run after all other work), not_found (cache=only and not in the graph, or the last crawl found no website) or invalid (error set). Never crawls while you wait; stale data is refreshed in the background as in /company/details. cache=only reads stored data and queues nothing. Costs 2 credits per distinct found domain; queued, not found, invalid and duplicate entries cost 0. The balance must cover 2 credits per distinct valid domain first. It has its own per-key rate limit (default 30 batches per minute). JSON body: - `domains`: - `cache`: Responses: - `200`: OK - `400`: Bad Request - `429`: Too Many Requests Example response: ```json { "results": [ { "input": "stripe.com", "domain": "stripe.com", "status": "found", "enrichment_status": "complete", "last_enriched_at": "2026-10-20T19:36:24.41401\u002B00:00", "data": { "domain": "stripe.com", "name": "Stripe", "description": "Stripe powers online and in-person payment processing and financial solutions for businesses of all sizes.", "industry": "Financial Services" }, "error": null }, { "input": "linear.app", "domain": "linear.app", "status": "found", "enrichment_status": "complete", "last_enriched_at": "2026-10-21T19:10:16.97606\u002B00:00", "data": { "domain": "linear.app", "name": "Linear", "description": "Purpose-built for planning and building products with AI agents.", "industry": "Software", "headquarters": { "country": null, "city": null }, "founded_year": null, "employee_count": { "min": null, "max": null }, "business_model": "b2b", "pricing_motion": "hybrid", "logo_url": "https://linear.app/static/apple-touch-icon.png?v=2", "identifiers": { "lei": null, "sec_cik": null, "isin": null }, "technographics": { "tech_stack": [ "anthropic", "apple", "aws", "cloudflare", "docusign", "hubspot", "microsoft_365", "nextjs", "notion", "openai", "postmark", "slack", "stripe", "zoom" ], "email_provider": "google_workspace", "email_security_gateway": null, "email_pattern": "first" }, "hiring": { "open_roles_by_department": [ { "department": "GTM", "open_roles": 14 }, { "department": "Product", "open_roles": 13 }, { "department": "Operations", "open_roles": 2 } ], "open_roles_total": 29, "observed_at": "2026-10-21T19:10:16.97606\u002B00:00" }, "last_enriched_at": "2026-10-21T19:10:16.97606\u002B00:00", "websites": [ "linear.app" ], "company_type": "unknown", "public_listing": null, "sic_code": null }, "error": null }, { "input": "not-a-domain", "domain": null, "status": "invalid", "enrichment_status": null, "last_enriched_at": null, "data": null, "error": { "code": "invalid_domain", "message": "\u0027not-a-domain\u0027 is not a fully-qualified domain." } } ], "found": 2, "queued": 0, "not_found": 0, "failed": 1, "credits_charged": 4 } ``` ### GET /api/v1/company/search Find companies by what they do Ranks enriched companies by the meaning of a free-text query, for example q=tools to chase unpaid invoices. Each row has the company card and its similarity and match_score. Only strong matches are shown, so an answer can have fewer rows than max_results, or none. Never crawls. Costs 1 credit per started 50 rows returned; an empty answer costs 0. It has its own per-key rate limit (default 60 searches per minute). When search is busy the answer is 503 busy with Retry-After, at no cost. Parameters: - `q` (query): What the companies do, in plain words (3–200 characters). - `max_results` (query): Maximum rows to return (1–50, default 10). Responses: - `200`: OK - `400`: Bad Request - `429`: Too Many Requests - `503`: Service Unavailable Example response: ```json { "query": "tools to chase unpaid invoices", "results": [ { "domain": "getharvest.com", "name": "Harvest", "similarity": 0.7536, "match_score": 4.104, "card": { "description": "Time tracking and management software with powerful easy reporting and streamlined online invoicing. Loved by 73,000 businesses. Get started for free.", "industry": "Software", "logo_url": "https://www.getharvest.com/hubfs/apple-touch-icon.png", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true, "tagline": null, "linkedin": null, "x": null } }, { "domain": "midday.ai", "name": "Midday", "similarity": 0.7398, "match_score": 3.573, "card": { "description": "Invoicing, automatic reconciliation, time tracking, documents, and financial exports in one place. The business stack that replaces the tools you\u0027ve outgrown.", "industry": "Software", "logo_url": "https://cdn.midday.ai/logo.png", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true, "tagline": null, "linkedin": null, "x": null } }, { "domain": "tmetric.com", "name": "TMetric", "similarity": 0.7377, "match_score": 3.494, "card": { "description": "TMetric is a leading time tracking solution to boost your team\u0027s productivity. Keep track of working hours, bill clients, and automate payroll.", "industry": "Software", "logo_url": "https://tmetric.com/media/43il1ypw/tmetric-logo-with-text.svg", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true, "tagline": null, "linkedin": null, "x": null } } ], "count": 3, "max_results": 3 } ``` ### GET /api/v1/company/vendors Vendors that name a company as their customer The reverse of /company/customers: companies whose own customer pages or case studies publicly name the target as a customer, with confidence scores and the vendor's evidence page and quote. Rows come back only when the target's own domain is verified (company_domain_status); otherwise the list is empty and free. include_unverified=true also returns rows for an unverified target and vendors with unverified domains. Answers from stored data only: never crawls or queues, and a company not in the graph is 404 not_in_graph at no cost. Costs 1 credit + 2 credits per vendor returned, also 1 for an empty list of a verified company. Parameters: - `domain` (query, required): Company website, URL or email domain, e.g. openai.com - `max_results` (query): Maximum vendors per page (1–200, default 20). Bounds the maximum cost. - `include_unverified` (query): Also return rows when the company's domain or the vendor's domain is guessed or rejected (see company_domain_status and domain_status). - `cursor` (query): next_cursor of the previous page; omit for the first page. Send the same domain, max_results and include_unverified. Responses: - `200`: OK - `400`: Bad Request - `404`: Not Found Example response: ```json { "company": { "domain": "openai.com", "name": "OpenAI" }, "company_domain_status": "verified", "vendors": [ { "domain": "clay.com", "name": "Clay", "confidence": 0.988, "evidence": { "quote": "/customers/open-ai", "url": "https://www.clay.com/customers" }, "source_count": 1, "first_seen_at": "2026-10-19T13:48:47.171756\u002B00:00", "last_verified_at": "2026-10-19T13:48:53.44877\u002B00:00", "basis": "evidenced", "domain_status": "verified", "card": { "description": "Infrastructure to get any data, run agentic workflows, and launch GTM plays.", "industry": "E-Commerce", "logo_url": "https://cdn.prod.website-files.com/61477f2c24a826836f969afe/6a3a92ab3c92c9caa6245619_dot-com_favicon_2026_512.png", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true, "tagline": null, "linkedin": null, "x": null }, "reason": null, "match_score": null, "similarity": null }, { "domain": "notion.com", "name": "Notion", "confidence": 0.986, "evidence": { "quote": "/customers/openai", "url": "https://www.notion.com/customers" }, "source_count": 1, "first_seen_at": "2026-10-19T14:01:13.65149\u002B00:00", "last_verified_at": "2026-10-19T14:01:19.450338\u002B00:00", "basis": "evidenced", "domain_status": "verified", "card": { "description": "Build Custom Agents, search across all your apps, and automate busywork. The AI workspace where teams get more done, faster.", "industry": "Software", "logo_url": "https://www.notion.com/front-static/logo-ios.png", "headquarters_country": null, "employee_count": { "min": null, "max": null }, "enriched": true, "tagline": null, "linkedin": null, "x": null }, "reason": null, "match_score": null, "similarity": null } ], "count": 2, "max_results": 2, "min_confidence": 0.7, "include_unverified": false, "next_cursor": "MC45ODZ8NjM5MjgwMTUyNzk0NTAzMzgwfDAxYTE1MzQxODg3ZjdjOTZiMzY1NWRiNTU4Mjc0MmY1" } ``` ### GET /api/v1/company/people People of a company People named on the company's own public pages (team, about, leadership), with the published title, executive roles and seniority read from it, and the page where each was seen. Executives first, then by name. Investors, advisors and board members are left out, and only the people from the latest check of those pages are shown. No e-mail: use /work-email/lookup. A company never seen before behaves as in /company/details (partial data or 202). Costs 1 credit + 1 per person returned; an empty list costs 1, or 0 while the status is partial; 0 when queued. To have a person removed, e-mail support@quickleaves.com with the page URL, or the full name and the company domain; the person is deleted and kept out of later crawls. Parameters: - `domain` (query, required): Company website, URL or email domain, e.g. linear.app - `seniority` (query): Only this band: c_suite, vp, director, manager or ic. - `role` (query): Only people with this executive role: ceo, cto, cfo, coo, cmo, cro, cpo, ciso, founder, co_founder, president, chair or other. - `title` (query): Only titles that contain this text (no case). - `limit` (query): People per page (1–100, default 25). Bounds the cost. - `cursor` (query): next_cursor of the previous page; omit for the first page. Send the same filters. - `fresh` (query): Queue a background re-crawl now, even within the 30-day window. - `cache` (query): Set to only to answer from stored data, also stale, and never start a crawl or a refresh. A company not in the graph is 404 not_in_graph at no cost. Cannot be combined with fresh=true. Responses: - `200`: OK - `202`: Accepted - `429`: Too Many Requests Example response: ```json { "company": { "domain": "example.com", "name": "Example" }, "people": [ { "full_name": "Jane Doe", "first_name": "Jane", "last_name": "Doe", "title": "Co-founder \u0026 CEO", "roles": [ "co_founder", "ceo" ], "seniority": "c_suite", "profile_url": "https://www.example.com/about/team", "evidence": { "quote": null, "url": "https://www.example.com/about/team" }, "last_verified_at": "2026-10-22T15:18:22.056499\u002B00:00" }, { "full_name": "John Roe", "first_name": "John", "last_name": "Roe", "title": "CTO", "roles": [ "cto" ], "seniority": "c_suite", "profile_url": "https://www.example.com/about/team", "evidence": { "quote": null, "url": "https://www.example.com/about/team" }, "last_verified_at": "2026-10-22T15:18:22.056499\u002B00:00" }, { "full_name": "Alex Poe", "first_name": "Alex", "last_name": "Poe", "title": "VP of Engineering", "roles": [], "seniority": "vp", "profile_url": "https://www.example.com/about/team", "evidence": { "quote": null, "url": "https://www.example.com/about/team" }, "last_verified_at": "2026-10-22T15:18:22.056499\u002B00:00" } ], "count": 3, "limit": 3, "next_cursor": "MXwwMTk5YTFiMmMzZDRlNWY2MDcxODI5M2E0YjVjNmQ3ZXxBbGV4IFBvZQ" } ``` ### GET /api/v1/profile Professional profile from a public page The person described by an openly published page (company bio, speaker page, personal site): name, title, seniority, company, location and an address only when the page prints it. Login-walled and people-search sites are rejected. Costs 2 credits (+1 with fresh=true); 0 when no person is found. Parameters: - `url` (query, required): Absolute http(s) URL of a public page about the person. - `fresh` (query): Re-fetch the page even if it was read within 30 days (+1 credit). Responses: - `200`: OK Example response: ```json { "full_name": "Jane Doe", "first_name": "Jane", "last_name": "Doe", "title": "Co-founder \u0026 CEO", "seniority": "c_suite", "company": { "domain": "example.com", "name": "Example" }, "location": null, "email": null, "profile_url": "https://www.example.com/about/team", "last_verified_at": "2026-10-21T21:30:21.3121618\u002B00:00" } ``` ### POST /api/v1/work-email/lookup Find and verify a work e-mail Finds and checks the work e-mail of a person at a company. No e-mail is sent. Billed by verdict: valid 2 credits; likely_valid_pattern or catch_all_domain 1; unknown/invalid 0. JSON body: - `first_name`: Given name as published, e.g. Jane. - `last_name`: Family name as published, e.g. Doe. - `domain`: Company domain, URL or any address at the company. Responses: - `200`: OK Example response: ```json { "domain": "stripe.com", "email": null, "deliverability": "unknown", "confidence": 0, "evidence": "no conclusive evidence", "domain_has_mx": true, "provider": "quickleaves" } ``` ### GET /api/v1/credits Current credit balance The balance, split into plan credits (spent first) and pay-as-you-go credits, with their expiry dates. Free. Responses: - `200`: OK Example response: ```json { "credits_remaining": 34579, "plan_credits": 0, "payg_credits": 34579, "plan_credits_expire_at": null, "payg_next_expiry_at": null } ``` ### GET /api/v1/usage Requests and credits per day and endpoint Per UTC day and operation: requests by status class (counted as they finish, flushed every 5 s) and the net credits the ledger charged. At most 92 days; the last 30 by default. Free; its own rate limit (default 60 per minute per key). Parameters: - `from` (query): First UTC day, yyyy-MM-dd (default: 29 days before to). - `to` (query): Last UTC day, yyyy-MM-dd (default: today). Responses: - `200`: OK - `400`: Bad Request Example response: ```json { "from": "2026-10-21", "to": "2026-10-21", "days": [ { "day": "2026-10-21", "operation": "GET /api/v1/company/competitors", "requests": 3, "succeeded": 3, "client_errors": 0, "server_errors": 0, "credits": 1485 }, { "day": "2026-10-21", "operation": "GET /api/v1/company/customers", "requests": 3, "succeeded": 3, "client_errors": 0, "server_errors": 0, "credits": 24095 }, { "day": "2026-10-21", "operation": "GET /api/v1/company/details", "requests": 9112, "succeeded": 9112, "client_errors": 0, "server_errors": 0, "credits": 36365 } ], "requests": 9118, "credits": 61945 } ``` ### GET /api/v1/pricing Plans, endpoint prices and the free trial The plans and credit packs with their list price (minor units, e.g. cents), the credits of every endpoint, and the free trial with its limits. No API key needed; cached for 5 minutes. Free. Responses: - `200`: OK Example response: ```json { "plans": [ { "code": "pack_2k", "name": "2,000 credits (PAYG)", "kind": "credit_pack", "credits": 2000, "price": 2900, "currency": "USD", "interval": null, "rank": 0 }, { "code": "pack_10k", "name": "10,000 credits (PAYG)", "kind": "credit_pack", "credits": 10000, "price": 11900, "currency": "USD", "interval": null, "rank": 0 }, { "code": "pack_50k", "name": "50,000 credits (PAYG)", "kind": "credit_pack", "credits": 50000, "price": 49900, "currency": "USD", "interval": null, "rank": 0 }, { "code": "starter_monthly", "name": "Starter \u2014 5,000 credits / month", "kind": "subscription", "credits": 5000, "price": 4900, "currency": "USD", "interval": "month", "rank": 1 }, { "code": "growth_monthly", "name": "Growth \u2014 25,000 credits / month", "kind": "subscription", "credits": 25000, "price": 19900, "currency": "USD", "interval": "month", "rank": 2 }, { "code": "scale_monthly", "name": "Scale \u2014 100,000 credits / month", "kind": "subscription", "credits": 100000, "price": 59900, "currency": "USD", "interval": "month", "rank": 3 } ], "endpoints": [ { "endpoint": "\u0060GET /api/v1/company/details\u0060", "credits": "2 (\u002B1 with \u0060fresh=true\u0060); 1 for \u0060404 company_not_found\u0060", "free_when": "\u0060202\u0060 queued, \u0060404 not_in_graph\u0060 with \u0060cache=only\u0060" }, { "endpoint": "\u0060GET /api/v1/company/customers\u0060", "credits": "1 \u002B 2 per row returned over all lists (\u0060include=customers,partners\u0060), at most 401 a page per list", "free_when": "\u0060202\u0060 queued" }, { "endpoint": "\u0060GET /api/v1/company/vendors\u0060", "credits": "1 \u002B 2 per vendor returned, at most 401 a page", "free_when": "\u0060404 not_in_graph\u0060, an empty list held back because the company\u0027s domain is not verified" }, { "endpoint": "\u0060GET /api/v1/company/people\u0060", "credits": "1 \u002B 1 per person returned, at most 101 a page; executives in details are free", "free_when": "\u0060202\u0060 queued, an empty list while \u0060partial\u0060" }, { "endpoint": "\u0060GET /api/v1/company/competitors\u0060", "credits": "3", "free_when": "\u0060202\u0060 queued, an empty list while \u0060partial\u0060" }, { "endpoint": "\u0060POST /api/v1/company/batch\u0060", "credits": "2 per distinct found domain (up to 50 entries)", "free_when": "\u0060queued\u0060, \u0060queue_full\u0060, \u0060not_found\u0060, \u0060invalid\u0060 and duplicate entries" }, { "endpoint": "\u0060GET /api/v1/company/search\u0060", "credits": "1 per started 50 rows returned", "free_when": "an empty answer" }, { "endpoint": "\u0060GET /api/v1/company/status\u0060", "credits": "0", "free_when": "" }, { "endpoint": "\u0060GET /api/v1/profile\u0060", "credits": "2 (\u002B1 with \u0060fresh=true\u0060)", "free_when": "no person found" }, { "endpoint": "\u0060POST /api/v1/work-email/lookup\u0060", "credits": "\u0060valid\u0060 2, \u0060likely_valid_pattern\u0060 or \u0060catch_all_domain\u0060 1, \u0060unknown\u0060 or \u0060invalid\u0060 0", "free_when": "" }, { "endpoint": "\u0060GET /api/v1/credits\u0060, \u0060GET /api/v1/usage\u0060, \u0060GET /api/v1/pricing\u0060, \u0060GET /api/v1/billing/plans\u0060, \u0060POST /api/v1/billing/checkout\u0060", "credits": "0", "free_when": "" }, { "endpoint": "\u0060POST /mcp\u0060 (each tool)", "credits": "the price of the endpoint the tool calls", "free_when": "the same cases" } ], "trial": { "credits": 200, "valid_days": 30, "eligibility": "A console sign-up with a work e-mail that Google or Microsoft verifies, once per e-mail domain.", "limits": { "requests_per_minute": 60, "never_seen_waiting": 3, "never_seen_bulk_waiting": 3, "never_seen_per_day": 25, "active_keys": 2 } } } ``` ### GET /api/v1/billing/plans Purchasable plans and credit packs Responses: - `200`: OK Example response: ```json [ { "code": "pack_2k", "name": "2,000 credits (PAYG)", "kind": "credit_pack", "credit_grant": 2000 }, { "code": "pack_10k", "name": "10,000 credits (PAYG)", "kind": "credit_pack", "credit_grant": 10000 }, { "code": "pack_50k", "name": "50,000 credits (PAYG)", "kind": "credit_pack", "credit_grant": 50000 }, { "code": "starter_monthly", "name": "Starter \u2014 5,000 credits / month", "kind": "subscription", "credit_grant": 5000 }, { "code": "growth_monthly", "name": "Growth \u2014 25,000 credits / month", "kind": "subscription", "credit_grant": 25000 }, { "code": "scale_monthly", "name": "Scale \u2014 100,000 credits / month", "kind": "subscription", "credit_grant": 100000 } ] ``` ### POST /api/v1/billing/checkout Create a Dodo Payments checkout session Returns a hosted checkout URL for a subscription or a PAYG credit pack. Credits are granted when the payment webhook arrives. A workspace holds one subscription: a second subscription checkout answers 409 subscription_exists; change the plan in the console instead. Free. JSON body: - `plan`: - `quantity`: - `customer_email`: - `customer_name`: - `return_url`: Responses: - `201`: Created Example response: ```json { "session_id": "cks_example", "checkout_url": "https://checkout.example.com/cks_example", "plan": "pack_10k", "credit_grant_amount": 10000 } ``` ### GET /api/v1/callbacks/secret Secret that signs your callbacks The whsec_ secret of your organization. Every callback carries webhook-id, webhook-timestamp and webhook-signature (v1, HMAC-SHA256 over id.timestamp.body), so any Standard Webhooks library verifies it. Free. Responses: - `200`: OK - `503`: Service Unavailable ### POST /api/v1/callbacks/secret/rotate Replace the callback secret Makes a new secret and returns it. The old secret stops at once: callbacks sent after this call, also retries, carry only the new signature. Free. Responses: - `200`: OK - `503`: Service Unavailable ## Docs - [Full reference: prices, MCP tools, every endpoint with an example answer](https://api.quickleaves.com/llms-full.txt) - [Agent skill (SKILL.md; its version changes with its content)](https://api.quickleaves.com/skills/quickleaves/SKILL.md) - [OpenAPI document](https://api.quickleaves.com/openapi/v1.json) - [Interactive reference](https://api.quickleaves.com/docs) ## Status codes - 400 invalid input · 401 missing/invalid key · 402 insufficient credits · 404 not found (free, except `company_not_found` from `/company/details`: 1 credit) · 202 queued for enrichment (free; retry after `Retry-After`) · 429 rate limited or too many new companies queued (free; honour `Retry-After`) · 503 at capacity (free; honour `Retry-After`) ## Error codes and headers Every error body has a stable `code` (schema `ErrorCode` in the OpenAPI document) and a `trace_id`. Branch on `code`, not on `title`. Codes: `invalid_request`, `invalid_domain`, `invalid_url`, `conflicting_parameters`, `batch_too_large`, `invalid_api_key`, `invalid_signature`, `insufficient_credits`, `organization_suspended`, `not_found`, `company_not_found`, `profile_not_found`, `not_in_graph`, `payload_too_large`, `rate_limited`, `queue_full`, `callback_limit`, `callbacks_disabled`, `subscription_exists`, `internal_error`, `upstream_error`, `busy`. A `402 insufficient_credits` body also has `required_credits`. `403 organization_suspended` means the organization's API access is suspended (for example during a payment dispute); contact support@quickleaves.com. Every authenticated response carries `X-RateLimit-Limit` (requests per minute for your key), `X-RateLimit-Remaining` (requests left in the key's bucket now) and `X-RateLimit-Reset` (seconds until the bucket is full again), plus the credit headers. Company answers (200) carry `X-Data-Age-Days` (whole days since the data was last collected) and `Last-Modified`.