Explee Public API
Version: 1.0.0
> Tip: This documentation is designed for humans. To integrate with AI agents, provide them with the OpenAPI schema at https://api.explee.com/public/api/openapi.json instead.
Search millions of companies worldwide using natural language queries and structured filters!
Rate limit: 10000 requests per hour, 150 concurrent requests per organization. Timeout: 90s.
Authentication
ApiKeyAuth: apiKey - Get your API key at [API Keys](https://explee.com/app-auto-gtm/api-keys)
Endpoints
POST /public/api/v1/search/companies
Companies
Search for companies using structured definitions.
## How It Works
Provide a structured definition of your target companies in the `definition` field — our AI will find matching companies.
All other filters are optional.
See the request schema below for the full list of available filters.
**Definition examples:**
- `"YouTube video summarization tool"`
- `"electronic signature platform"`
- `"AI B2B SaaS"`
- `"real estate company"`
## AI Enrichment
Use the `criteria` parameter to score companies against custom criteria.
Each company will be evaluated and scored (0-5) with reasoning for each criterion.
## Pricing
- **First 10 results are free** (including AI enrichment)
- A **positive credit balance is required for every request**, free results included (an organization at 0 credits gets a 402)
- Free results are limited per organization by plan: **free 50/day + 10/min · starter 200/day + 15/min · growth 500/day + 20/min · pro 750/day + 25/min · agency 1500/day + 30/min · enterprise 3000/day + 30/min** requests that include free results. An entirely-free request beyond the limit gets 429; a request with `page_size` above the free zone is never rejected, but once the day's limit is spent its whole page is billed
- **0.5 credits** per company after the first 10
- **+0.1 credits** per company per criterion after the first 10
Example: 150 companies with 2 criteria = 50 billable × (0.5 + 0.1 × 2) = 35 credits (first 10 are free)
Empty results = 0 credits.
## Deduplication
Pass dedup list ids in `exclude_lists` to skip companies you already own — they are not returned
and not charged. Free results zone does not apply. See the Deduplication endpoints.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/search/companies-by-domains
Companies by Domains
Find companies by their domains.
**How it works:**
1. Provide a list of company domains (up to 1000)
2. The system looks up each domain and returns **at most one** company profile per domain (the best match by quality score)
**Pricing:**
- **0.5 credit(s)** per company found
- **0 credits** for domains not found
**Limits:**
- Maximum 1000 domains per request
- Maximum 10000 companies per response
**Deduplication:**
- Pass dedup list ids in `exclude_lists` — matched companies are not returned and not charged
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/search/people
People
Search for people (employees) at companies matching your criteria.
## How It Works
Provide `job_titles` in `people_filters` to find people by their role.
Use `company_filters.definition` to narrow down which companies to search.
Use `company_linkedin_ids` to restrict results to a specific list of company LinkedIn IDs.
**Job title examples:**
- `["Head of Sales", "VP Sales"]`
- `["CTO", "VP Engineering"]`
- `["Founder", "CEO"]`
## AI Enrichment
Use the `criteria` parameter in `people_filters` to score people against custom criteria.
Each person will be evaluated and scored (0-5) with reasoning for each criterion.
## Pricing
- **First 10 results are free** (including AI enrichment)
- A **positive credit balance is required for every request**, free results included (an organization at 0 credits gets a 402)
- Free results are limited per organization by plan: **free 50/day + 10/min · starter 200/day + 15/min · growth 500/day + 20/min · pro 750/day + 25/min · agency 1500/day + 30/min · enterprise 3000/day + 30/min** requests that include free results. An entirely-free request beyond the limit gets 429; a request with `page_size` above the free zone is never rejected, but once the day's limit is spent its whole page is billed
- **1.0 credit** per person after the first 10
- **+0.1 credits** per person per criterion after the first 10
Example: 150 people with 2 criteria = 50 billable × (1.0 + 0.1 × 2) = 60 credits (first 10 are free)
Empty results = 0 credits.
## Deduplication
Pass dedup list ids in `exclude_lists` to skip people you already own — they are not returned
and not charged. A companies list excludes everyone at its domains. Free results zone does not apply.
See the Deduplication endpoints.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/search/people-by-domains
People by Domains
Find people at companies by their domains.
**How it works:**
1. Provide a list of company domains (up to 1000) and job titles to search for
2. The system finds companies by domains
3. Returns up to `people_per_company` people per found company with matching job titles
**Job title matching:**
- Uses semantic search: "Head of Sales" will match "VP Sales", "Sales Director", etc.
- Multiple job titles are combined with OR logic
**Parameters:**
- `people_per_company`: Number of people to return per company (1-1000, default: 1)
**Limits:**
- Maximum 1000 domains per request
- Maximum 20 job titles per request
- Maximum 1000 people per company
- Maximum 10000 people per response (total)
**Billing:**
- 1 credit per person returned
**Deduplication:**
- Pass dedup list ids in `exclude_lists` — matched people are not returned and not charged
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/search/nl-to-filters
NL to Filters
Convert a free-form natural language query into structured filters for companies and people search.
## How It Works
Send any query in plain English (or another language), for example:
- `"SaaS companies using Stripe"`
- `"Founders of AI startups in Germany"`
- `"B2B fintech companies in US and Canada"`
The endpoint returns parsed filters in the same shape used by search endpoints:
- `companies_filters`
- `people_filters`
- `focus` (`companies` or `people`)
This endpoint does not perform a search and does not charge credits.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/enrich/email
Find email by name
Find email address for a single person.
## How It Works
Provide the person's first name, last name, and company domain.
## Presets
| Preset | Cost | Success Rate | Description |
|--------|------|--------------|-------------|
| **basic** | 1.5 credits | ~50% | Single provider, pattern-based lookup. Fast and cheap. |
| **premium** | 5.0 credits | ~78% | 6 providers with cross-validation. Higher accuracy. |
## Pricing
You are only charged when an email is found.
Email not found = 0 credits.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/enrich/phone
Find phone by LinkedIn URL
Find the work phone number for a single person.
## How It Works
Provide the person's LinkedIn profile URL (`linkedin_url`) and we'll find their work
phone. You can also pass a known `email` if you have one.
## Presets
| Preset | Cost | Success Rate | Description |
|--------|------|--------------|-------------|
| **basic_new** | 15.0 credits | ~45% | Faster, lower-cost lookup. |
| **premium** | 30.0 credits | ~60% | Broader, multi-source lookup. Higher hit rate. |
## Pricing
You are only charged when a phone is found.
Phone not found = 0 credits.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/enrich/email/batch
Find email by name (batch request)
Find email addresses for multiple contacts in one request (async).
**How it works:**
1. Submit up to 100 contacts with first_name, last_name, company_domain
2. Receive a `task_id` immediately
3. Poll GET endpoint with `task_id` to check status and retrieve results
**Limits:**
- Maximum 100 contacts per batch
**Pricing:**
- **basic**: 1.5 credits per found email
- **premium**: 5 credits per found email
- Only charged for emails found (not found = 0 credits)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/enrich/email/batch/{task_id}
Find email by name (batch results)
Check status and retrieve results for a batch request.
**Statuses (in meta.status):**
- `pending` — processing in progress, poll again in a few seconds
- `completed` — results ready, `contacts` array contains enriched data
- `failed` — error occurred, see `meta.error` for details
**Response structure:**
- `contacts` — null while pending, array when completed
- `meta.status` — current processing status
- `meta.error` — error description (null if no error)
- `meta.credits_charged` — credits used (only charged for found emails)
**Typical workflow:**
1. POST to submit batch, get `task_id`
2. GET with `task_id`, check `meta.status`
3. If `pending`, wait 2-5 seconds and poll again
4. When `completed`, read `contacts` array
Parameters
task_id (path, required): Task ID returned from POST request
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Batch not found
POST /public/api/v1/find-and-enrich
Find people and enrich their emails (async)
Search for people matching your filters and enrich their emails in a single async job.
**How it works:**
1. Submit search filters + `max_contacts` (how many contacts with emails you want, max 500 per call)
2. Receive a `task_id` immediately
3. Poll the GET endpoint with `task_id` for `progress` (with `eta_seconds`) and results
4. For more than `max_contacts`, call again with the previous response's `next_cursor`
**Pricing:**
- **Search is free** — you are never charged for people searched.
- **basic**: 1.5 credits per found email · **premium**: 5 credits per found email.
- You are charged ONLY for emails actually found. Worst-case credits are held up front (402 if insufficient).
**Deduplication:** pass `exclude_lists` to skip people you already own — they are not enriched and not charged.
A companies list skips everyone at its domains.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/find-and-enrich/{task_id}
Find-and-enrich job status and results
Check progress and retrieve results for a find-and-enrich job.
**Statuses (in meta.status):**
- `pending` — running; read `meta.progress` (incl. `eta_seconds`) and poll again
- `completed` — results ready; `contacts` holds the enriched contacts, `meta.next_cursor`/`meta.has_more` for paging
- `failed` — error occurred (or timed out — credits released), see `meta.error`
Only contacts with a found email are returned. `meta.credits_charged` reflects found emails only.
Parameters
task_id (path, required): Task ID returned from POST request
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Job not found
GET /public/api/v1/tasks
List async tasks
List all async tasks for your organization, including find-and-enrich jobs,
batch email enrichments, and campaign lead imports.
**Use cases:**
- Track async jobs across every API key owned by the same organization
- Find task IDs you may have lost
- Monitor pending vs completed tasks
**Response:**
- `tasks` — array of task objects with status and result URL
- `total` — total count for pagination
**Filtering:**
- Use `status` parameter to filter by task status (pending, completed, failed)
Parameters
status (query, optional): Filter by task statuslimit (query, optional): Maximum number of tasks to returnoffset (query, optional): Number of tasks to skip (for pagination)
Responses
200: Successful Response422: Validation Error
GET /public/api/v1/billing/balance
Get balance
Return your organization's net credit balance — the same number shown on the
Explee dashboard.
Poll this to decide when to top up — when `remain` drops below the threshold you
need for upcoming requests, add credits on your billing page
(https://explee.com/app-auto-gtm/billing).
## Response
```json
{ "remain": 4200 }
```
`remain` is the net balance in credits (1 credit = $0.01): prepaid funds minus
any active postpaid (outreach) usage that hasn't been collected yet. It can be
**negative** if the org is carrying postpaid debt.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/autogtm/projects
List outreach projects
List the outreach projects owned by your organization.
Authenticated by the same `X-API-Key` as the rest of this API — the key resolves
to your organization, and its active projects are returned newest first.
**Response:**
- `projects` — active projects with `id`, `domain` (the project's identity in
the app), and `daily_budget_usd` (the project-wide daily budget anchor,
`null` when not set).
- `total` — number of projects returned.
Use a project `id` to filter the campaigns list
(`GET /public/api/v1/autogtm/campaigns?project_id=…`).
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/autogtm/projects
Create outreach project
Create an outreach project — the app's **New project** dialog in one call. For
an agency: one project per client.
Send **either** the company `domain` **or**, for a company with no website,
`no_website` with the dialog's three answers (`business` — what it sells,
`customer` — the ideal customer, `geo` — the markets).
The call answers at once with the project's `id` and `status: creating`.
Explee then analyses the company (about 1-2 minutes) and adds the project's
suggested campaigns. Poll `GET /public/api/v1/autogtm/projects/{project_id}`:
- `creating` — still working; poll again in 15-30 seconds;
- `ready` — the campaigns are there (`GET /public/api/v1/autogtm/campaigns?project_id=…`),
each in `discovery`;
- `failed` — nothing to build from (`failure_reason`); the domain is free to
create the project again.
Nothing sends after this call. Start a campaign with
`POST /public/api/v1/autogtm/campaigns/{campaign_id}/start`, or add your own with
`POST /public/api/v1/autogtm/campaigns`. Sending stays within the project's
daily budget (`daily_budget_usd`, change it with
`PATCH /public/api/v1/autogtm/projects/{project_id}/budget`). All projects spend
your organization's one balance; `GET /public/api/v1/autogtm/billing/usage`
splits the spend by `project_id`.
Available to organizations that have paid at least once (a top-up or a plan).
**Errors** (`code` in the body):
- `payment_required` (402) — your organization has never paid; top up first.
- `project_exists` (409) — your organization already has a project on this
domain; `detail` names its id. A retry after a timeout lands here, so it is
safe to repeat a `domain` call. A `no_website` call is not deduplicated: after a
timeout, list your projects before repeating it.
- `domain_unavailable` (409) — the domain can't host a project: a free-mail,
example or public-company domain, a domain several other organizations
already use, or one Explee does not serve. Contact support if it is your
client's real domain.
- `creation_in_progress` (429) — 5 projects of your organization are still
`creating`; wait until one is `ready` or `failed`.
- `analysis_unavailable` (503) — the analysis could not start; retry in a minute.
Optional `sender_name` sets the name first emails go out under, with the
checks and errors of `PUT /public/api/v1/autogtm/projects/{project_id}/sender-name`
(`sender_name_invalid`, `sender_name_rejected`, `sender_name_not_in_plan`,
`sender_name_check_unavailable`). It is checked before anything is created:
a refused name creates no project.
Free. At most 20 calls per hour per organization, refusals included.
Request Body
Request body required
Responses
202: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: `payment_required`: the organization has never paid. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: Validation error. Check request body and parameters.429: `creation_in_progress`, or the hourly limit.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.409: `project_exists` or `domain_unavailable`.503: `analysis_unavailable`: the analysis could not start.
GET /public/api/v1/autogtm/projects/{project_id}
Get one outreach project
One active project of your organization — the same fields as an item of `GET /public/api/v1/autogtm/projects`.
Parameters
project_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Unknown `project_id` (or not your project).
GET /public/api/v1/autogtm/projects/{project_id}/sender-name
Get the project's sender name
The project's sender name: the From name its first emails go out under. An
empty `sender_name` is Automatic: each mailbox sends under its own name.
Parameters
project_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Unknown `project_id` (or not your project).
PUT /public/api/v1/autogtm/projects/{project_id}/sender-name
Set the project's sender name
Set the project's sender name — the app's **Emails → Sender name**. For an
agency: put the name of the person at your client who signs the emails.
Send `{"sender_name": "Maria Lopez"}`; `{"sender_name": ""}` goes back to
Automatic (each mailbox sends under its own name). Spaces are collapsed.
Saving the same name again changes nothing.
**Where the name applies.** Emails go out from Explee's shared mailboxes. A
mailbox takes your name only when its address fits the name (e.g. `m@…` for
Maria Lopez); the others send under their own name, and so do some emails in
Explee's sender-name tests. A conversation keeps the name of its first email:
a new name applies to new conversations only. Mailboxes bought for your own
domain send under the names chosen in the order.
**Errors** (`code` in the body):
- `sender_name_invalid` (422) — over 100 characters, an email address or a
control character in it;
- `sender_name_rejected` (422) — not a real person's first and last name: a
company, brand, team or role, a famous person, a placeholder. `detail` says
which; nothing is saved;
- `sender_name_not_in_plan` (403) — the Starter plan has no custom sender
name; clearing it still works;
- `sender_name_check_unavailable` (503) — the name could not be checked right
now; retry after `Retry-After` seconds.
Free. At most 20 saves per 10 minutes per organization.
Parameters
project_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: `sender_name_invalid` or `sender_name_rejected`.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Unknown `project_id` (or not your project).403: `sender_name_not_in_plan`: the Starter plan.503: `sender_name_check_unavailable`: retry later.
GET /public/api/v1/autogtm/projects/{project_id}/monthly-cap
Get the project's monthly cap
The project's monthly cap: the most it may spend on emails in a calendar month
(UTC), and what it has spent since the 1st. `monthly_cap_usd: null` = no cap.
Parameters
project_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Unknown `project_id` (or not your project).
PUT /public/api/v1/autogtm/projects/{project_id}/monthly-cap
Set the project's monthly cap
Set or remove the project's monthly cap — the app's **Budget → Monthly cap**.
Send `{"monthly_cap_usd": 2000}`; `{"monthly_cap_usd": null}` removes the cap.
The month is the calendar month in UTC. Once the next email would take the
month's spend past the cap, nothing sends until the 1st or until the cap is
raised (the campaigns show `monthly_cap_reached`). Raising or removing the cap
resumes sending within minutes. The daily budget still applies inside the cap.
Range 500–1,000,000 USD. Free.
Parameters
project_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Unknown `project_id` (or not your project).
GET /public/api/v1/autogtm/campaigns
List outreach campaigns
List the outreach campaigns owned by your organization.
Authenticated by the same `X-API-Key` as the rest of this API — the key resolves
to your organization, and campaigns are returned across all of its projects.
Pass `project_id` (see `GET /public/api/v1/autogtm/projects`) to get one
project's campaigns only.
**Response:**
- `campaigns` — campaigns with `id`, `project_id`, `name`, `target_url`,
`daily_limit_usd`, and lifecycle `status`. Archived campaigns are left out
unless you pass `include_archived=true`.
- `total` — number of campaigns returned.
Use a campaign `id` to scope follow-up management calls (inbox replies, budget,
start/stop, analytics).
Parameters
project_id (query, optional): Return only this project's campaigns (see `GET /public/api/v1/autogtm/projects`).include_archived (query, optional): Also return archived campaigns (`status: archived`), e.g. to find one to unarchive.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Unknown `project_id` (or not your project).
POST /public/api/v1/autogtm/campaigns
Create campaign
Create a campaign that Explee finds the leads for — the app's **New campaign**
button.
Only `project_id` and `name` are required. Explee drafts every targeting field
you leave out (offer, customer problem, criteria, example clients) from the name
and your project; a field you send replaces the draft (`[]` means "none").
Search `keywords` are always drafted from the name. Geography and company size
default to the project's.
Each call creates a new campaign — unless you retry it with the same
`Idempotency-Key` (below): then you get the campaign the first call created.
**Lifecycle after this call** (`status` in `GET /public/api/v1/autogtm/campaigns`):
1. `discovery` — created, nothing runs yet. Review or edit it with
`GET` / `PATCH /public/api/v1/autogtm/campaigns/{campaign_id}`.
2. `POST …/campaigns/{campaign_id}/start` — Explee searches for leads. Works
with Auto-manage campaigns on or off.
3. `review` — the lead list is ready. Approve it with
`POST …/campaigns/{campaign_id}/approve`. With Auto-manage campaigns ON it
is also approved automatically at the end of the project's review window
(12 hours by default); with it OFF only `approve` sends it.
4. `outreach` — sending, within the campaign and project budgets.
`POST …/stop` at any point parks the campaign (`listening`); a later `start`
resumes it — from a stopped review that means sending without a further
approve.
Creation is free. Returns the campaign's full definition (on a repeat with the
same `Idempotency-Key`: that campaign's definition as it is now).
**Safe retries:** send an `Idempotency-Key` header (any unique string, e.g. a
UUID) and repeat the exact same request with the same key if you don't get an
answer. Within 24 hours a repeat returns what the first request created (the
same task, list or campaign) and does nothing again. The same key with a different body is rejected (`422`,
`idempotency_key_reused`); a repeat that arrives while the first request is
still running gets `409` `idempotency_key_in_use` — wait `Retry-After` seconds
and repeat. A key replays its first answer even if that import later
`failed` — to retry a failed import, send a new key.
Parameters
Idempotency-Key (header, optional): Optional. Any unique string up to 255 characters (a UUID works well). Send the same key again when you retry this request — after a timeout, a dropped connection or a 5xx — and within 24 hours you get the first answer back instead of a second write. Reusing a key with a different body answers `422` `idempotency_key_reused`; a retry that arrives while the first request is still running answers `409` `idempotency_key_in_use` — retry after `Retry-After`.
Request Body
Request body required
Responses
201: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: `target_geography` holds text that is no place.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Unknown `project_id` (or not your project).409: The project is paused for review by Explee (`blocked_by_moderation`), or a request with this `Idempotency-Key` is still running (`idempotency_key_in_use`).503: Drafting the campaign or reading its geography failed — retry.
GET /public/api/v1/autogtm/campaigns/{campaign_id}
Get campaign definition
Read everything that decides who a campaign contacts and what it says — the
app's **Campaign** tab in one call.
**Who it targets:** `offer`, `customer_problem`, `target_role`,
`target_geography`, `target_company_size`, `positive_criteria`,
`negative_criteria`, `example_clients`, and the derived `keywords`.
**What it says:** `instructions` (first email), `followup_instructions` (shared
by every follow-up), `language`, and the project-level `reply_instructions`.
**When it says it:** `schedule` (the send days) and `followups` (how many
emails the sequence has and how far apart — a project-level setting, the
same for every campaign of the project).
`targeting_editable` is `false` for a campaign built from your own imported
lead list — its audience is that list, so the targeting fields are locked.
Free, and the natural first call when auditing an account: one request per
campaign tells you whether it is aimed at the right people, before a single
email goes out.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
PATCH /public/api/v1/autogtm/campaigns/{campaign_id}
Update campaign definition
Correct a campaign's definition — send only the fields you are changing.
An omitted field keeps its value; an empty string, empty list or `null` clears
it — except `name`, which a campaign always has, so clearing it is a `422`.
An unknown field name is rejected with `422` rather than silently ignored, so
a typo can never look like a successful write. Returns the full definition as
it now stands.
**Re-aiming costs leads.** Every field Explee searches with re-aims the
campaign, exactly as in the app: `name`, `offer`, `customer_problem`,
`target_role`, `target_geography`, `target_company_size`, `positive_criteria`,
`negative_criteria` and `example_clients`. A real change to any of them drops
the leads this campaign has not contacted yet and makes Explee search again.
Sending the value a field already has is not a change. Only `language` and
`schedule` change nothing about who is contacted. Emails already sent are never
affected, and contacts already in a sequence keep it.
**The new search is not instant.** On a running campaign it starts about 5
minutes after your *last* targeting change, so a series of edits costs one
search, not one per edit. Each further targeting change restarts that wait:
send all your changes, then leave the campaign alone. Until the search starts,
the campaign keeps its current `status` and lead pool; when it starts, `status`
turns `searching`. On a stopped campaign the new targeting applies when you
start it again; on a campaign not launched yet, at launch.
**A running campaign pauses for review.** When the new search finishes, a
campaign that was sending moves to `review` (`status_reason`
`re_search_from_outreach`) and sends nothing until its new lead list is
approved: `POST /public/api/v1/autogtm/campaigns/{campaign_id}/approve`. With
Auto-manage campaigns ON it is also approved automatically at the end of the
project's review window (12 hours by default); with it OFF only `approve`
resumes sending.
**Briefs are moderated before they are saved.** `instructions` and
`followup_instructions` go through the same two checks the app's email editor
runs before it lets you save a brief: the brief itself is judged together with
the campaign's offer (the `offer`, `customer_problem` and criteria sent in the
same request, if any), and then a sample email is written from the brief for
one of the campaign's leads and that email is checked too. The answer usually
takes 10–30 seconds (up to about 85). A brief or sample email that does not
pass is a `422` and the whole request writes nothing. If moderation cannot
check it in time, the answer is a `503` (with `Retry-After`) and nothing is
written either: send the same request again. At most 3 brief checks per
organization run at once; a fourth is a `429` (with `Retry-After`). A passing
brief applies to the emails written from now on; it does not re-aim the
campaign and does not drop leads.
The rule for this endpoint: **anything a person can edit on the campaign in the
app, you can edit here** — with the exceptions below, each of which exists
because the app validates it in a second step this endpoint cannot reproduce.
Read-only here: `target_url` and `reply_instructions` (their own two-step
save in the app), `keywords` (Explee derives it; read-only in the app too) and
`followups` (a project-level setting shared by every campaign of the project:
sending the current values back is accepted, different ones are a `422`).
Budget has `PATCH /public/api/v1/autogtm/campaigns/{campaign_id}/budget`,
status has `start` / `stop`.
Parameters
campaign_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: The campaign's briefs didn't pass content moderation, so nothing was saved. Both briefs are checked together, as in the app: rewrite the one at fault and send it again; the campaign keeps its current briefs.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.409: Targeting is locked: this campaign runs on your imported lead list.503: Content moderation couldn't check the brief right now, so nothing was saved. Send the same request again in a minute.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/my-copy
Get campaign My copy
Read the campaign's first email setup — the two switches of the app's
first-email editor: **Instructions | My copy** (`mode`) and **From project |
Custom** (`source`).
`mode` `instructions`: Explee writes each first email from the `instructions`.
`mode` `my_copy`: your `subject` and `body` go out, with the variables filled
in for each lead. Both texts are always kept, so switching loses nothing. In
`my_copy` mode 90% of a campaign's leads get your text and 10% get the AI email
from the saved `instructions`, so you can compare the two. Follow-ups are never
affected.
`source` `project`: the campaign sends the project's first email, and `mode`,
`subject` and `body` are the project's (`GET /public/api/v1/autogtm/projects/{project_id}/my-copy`).
Switch it with `PUT .../my-copy/source`.
`stopped` is set when Explee switched the first email back to `instructions`
on its own because 10% or more of your text bounced. Free.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
PATCH /public/api/v1/autogtm/campaigns/{campaign_id}/my-copy
Update campaign My copy
Turn My copy on or off for one campaign with its own first email (`source`
`campaign`), or change its text — the editor's **Apply**. Send only the fields
you change. `mode` `my_copy` needs a `body`: send it in the same request unless
the campaign already has one.
A campaign with `source` `project` sends the project's first email and is not
edited here (`409` `follows_project`): change the project's
(`PATCH /public/api/v1/autogtm/projects/{project_id}/my-copy`), or give the
campaign its own first (`PUT .../my-copy/source`) and edit that.
The save runs the app's checks before anything is written, so it takes a few
seconds, up to about a minute:
- **The text.** Variables are `{{first_name}}`, `{{company}}`, `{{job_title}}`,
`{{company_city}}`, `{{sender_first_name}}`, `{{sender_company}}`, each
optionally with a fallback: `{{company_city|your city}}`. `{a|b}` picks one
variant per lead. `{{ai: instruction}}` is a line Explee writes for each lead
(up to 5). No links, domains, emails, phone numbers or HTML; the subject
can't start with `Re:` or `Fwd:`. The sign-off is Explee's: the mailbox
persona's name is added under your text.
- **Moderation.** Your text is rendered for 3 leads and checked by the same
moderation as in the app.
A text that fails is a `422` with `code` `my_copy_invalid`, every finding in
`errors` (and `warnings`), and nothing saved: fix it and send it again. A text
that passes is saved and goes live for the next first emails; findings worth
fixing come back in `warnings`. Sending the text that is already live is not
checked again. `409` with `code` `my_copy_changed`: the text changed while it
was being checked — read it and send your change again. Two saves run at a
time per organization; a third gets `429`: retry it when one finishes.
Parameters
campaign_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: `my_copy_invalid`: the text failed a check; nothing saved.429: Two My copy saves are already running for your organization (or a rate limit): retry.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.409: `my_copy_changed`: the text changed during the checks. `follows_project`: the campaign sends the project's first email (`source` `project`).
PUT /public/api/v1/autogtm/campaigns/{campaign_id}/my-copy/source
Set campaign My copy source
Choose where the campaign takes its first email from — the app's **From
project | Custom** switch. `project` makes the campaign send the project's
first email, `campaign` gives it its own. The switch moves the whole first
email, `instructions` included, and loses nothing: switching back brings the
other text back.
A campaign that never had a first email of its own starts from a copy of the
project's (when the project has one), so what its leads get doesn't change
until you edit it. Free, no
checks: both texts already passed them.
Parameters
campaign_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/my-copy/preview
Preview campaign first email
See the campaign's first email the way leads get it — the app's **What leads
get** panel. The email that is live now (My copy or the AI email from the
instructions, the campaign's own or the project's) is rendered for the
campaign's 3 preview leads, the same leads the app shows: variables, `{a|b}`
and `{{ai: …}}` lines filled in, signed by the sender.
A rendered email is kept until the text changes, so asking again is instant.
A fresh render writes the `{{ai: …}}` lines and takes seconds per lead. Every
preview call runs in the same two-at-a-time slot per organization as a save
(`429` beyond).
A lead that gets no email comes back with `error` instead of failing the
call: `my_copy_skipped` (the lead would be skipped — an empty variable with
no fallback, say), `generation_failed` (retry), `render_later` (not rendered
in this call to keep it short — ask again, finished renders are kept),
`no_leads_yet` (the campaign has no leads to preview on yet). Free.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: Validation error. Check request body and parameters.429: Two My copy saves are already running for your organization (or a rate limit): retry.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
GET /public/api/v1/autogtm/projects/{project_id}/my-copy
Get project My copy
Read the project's default first email — **Project defaults** in the app's
first-email editor. Every campaign in `campaign_ids` sends it.
`mode` `instructions`: Explee writes each first email from the `instructions`.
`mode` `my_copy`: your `subject` and `body` go out, with the variables filled
in for each lead. Both texts are always kept, so switching loses nothing. In
`my_copy` mode 90% of a campaign's leads get your text and 10% get the AI email
from the saved `instructions`, so you can compare the two. Follow-ups are never
affected.
Free.
Parameters
project_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.
PATCH /public/api/v1/autogtm/projects/{project_id}/my-copy
Update project My copy
Turn My copy on or off for the project's default first email, or change its
text. Send only the fields you change. Every campaign in `campaign_ids`
(`source` `project`) sends the result; campaigns with their own first email are
not touched.
Turning My copy on needs `body` in the same request, as in the app.
The save runs the app's checks before anything is written, so it takes a few
seconds, up to about a minute:
- **The text.** Variables are `{{first_name}}`, `{{company}}`, `{{job_title}}`,
`{{company_city}}`, `{{sender_first_name}}`, `{{sender_company}}`, each
optionally with a fallback: `{{company_city|your city}}`. `{a|b}` picks one
variant per lead. `{{ai: instruction}}` is a line Explee writes for each lead
(up to 5). No links, domains, emails, phone numbers or HTML; the subject
can't start with `Re:` or `Fwd:`. The sign-off is Explee's: the mailbox
persona's name is added under your text.
- **Moderation.** Your text is rendered for 3 leads and checked by the same
moderation as in the app.
A text that fails is a `422` with `code` `my_copy_invalid`, every finding in
`errors` (and `warnings`), and nothing saved: fix it and send it again. A text
that passes is saved and goes live for the next first emails; findings worth
fixing come back in `warnings`. Sending the text that is already live is not
checked again. `409` with `code` `my_copy_changed`: the text changed while it
was being checked — read it and send your change again. Two saves run at a
time per organization; a third gets `429`: retry it when one finishes.
Parameters
project_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: `my_copy_invalid`: the text failed a check; nothing saved.429: Two My copy saves are already running for your organization (or a rate limit): retry.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.409: `my_copy_changed`: the text changed during the checks.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/approve
Approve campaign lead list
Approve a campaign's lead list so it starts sending now, instead of waiting for
the automatic approval at the end of the review window — the **Approve**
button in the app.
Only for a campaign in `review`. A campaign already sending (`outreach`) is a
no-op; any other status is a `409`.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.409: The campaign is not in `review`, or its project is paused.
POST /public/api/v1/autogtm/campaigns/import
Create a campaign from your own leads (import)
Create a new campaign from your own lead list (async).
Each call creates a **new** campaign in the given project — the campaign is
built for your leads only (no agent lead discovery) and starts sending
automatically once live, within your project budget.
**How it works:**
1. Submit `project_id`, a campaign `name`, and up to 30,000 `leads`
2. Receive a `task_id` immediately
3. Poll `GET /public/api/v1/autogtm/campaigns/import/{task_id}` until `completed`
4. `result.campaign_id` is your new campaign — it appears in the campaigns list
**Per lead** — mandatory: `email`, `first_name`, `last_name`, `company_domain`,
`job_title`; recommended: `linkedin_url` (enriches the lead from Explee's
contact base for a richer email). Leads missing mandatory fields are skipped
(reported in the result), never a request-level error. Duplicates of leads
already contacted in the project and do-not-contact entries are dropped.
**Your copy brief** — optional `instructions` (first email),
`followup_instructions` (all follow-ups) and `language`: the same brief you
would type in the app's email editor, set here at import time so no manual
step is needed. Omit them and the campaign is briefed from your project
description alone. A brief is checked by content moderation before the import
is queued, as `PATCH /autogtm/campaigns/{campaign_id}` checks it: the brief
itself, then a sample email written from it (usually a few seconds, up to about
85): a refused brief or sample email is a `422`, a check that could not finish
is a `503`, and in both cases nothing is imported.
**Map every row back:** give each lead an optional `client_ref` (your own id
for that row, e.g. a CRM contact id). Once the import is `completed`,
`GET /public/api/v1/autogtm/campaigns/import/{task_id}/rows` lists every
submitted lead with its `index`, your `client_ref` and its outcome:
`imported` with the lead's `person_id`, or `skipped` with a reason code.
**Pricing:** the import itself is free. Emails are verified at send time at
Explee's cost; sending is billed as usual.
**Safe retries:** send an `Idempotency-Key` header (any unique string, e.g. a
UUID) and repeat the exact same request with the same key if you don't get an
answer. Within 24 hours a repeat returns what the first request created (the
same task, list or campaign) and does nothing again. The same key with a different body is rejected (`422`,
`idempotency_key_reused`); a repeat that arrives while the first request is
still running gets `409` `idempotency_key_in_use` — wait `Retry-After` seconds
and repeat. A key replays its first answer even if that import later
`failed` — to retry a failed import, send a new key.
Parameters
Idempotency-Key (header, optional): Optional. Any unique string up to 255 characters (a UUID works well). Send the same key again when you retry this request — after a timeout, a dropped connection or a 5xx — and within 24 hours you get the first answer back instead of a second write. Reusing a key with a different body answers `422` `idempotency_key_reused`; a retry that arrives while the first request is still running answers `409` `idempotency_key_in_use` — retry after `Retry-After`.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: The brief didn't pass content moderation, so nothing was imported. Rewrite it and send the import again.429: Too many pending imports, or too many brief checks running.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Unknown `project_id` (or not your project).409: `idempotency_key_in_use`: a request with this `Idempotency-Key` is still running.503: Content moderation couldn't check the brief right now, so nothing was imported. Send the same request again in a minute.
GET /public/api/v1/autogtm/campaigns/import/{task_id}
Campaign import status/result
Check status and retrieve the result of a campaign import.
**Statuses:**
- `pending` — import in progress; `progress` shows the current stage. Poll
every few seconds.
- `completed` — done; `result.campaign_id` is the new campaign (or `null` if
no leads survived validation/dedup — then no campaign was created).
- `failed` — see `error`.
Parameters
task_id (path, required): Task ID returned from the import POST.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Import task not found.
GET /public/api/v1/autogtm/campaigns/import/{task_id}/rows
Campaign import: every lead's outcome
The outcome of **every** lead you submitted to a completed import, in the order
you sent them — one row per lead, so `total` always equals the number of leads.
Each row carries its `index` in your `leads` array, the `client_ref` you gave
it, and either `outcome: "imported"` with the lead's `person_id`, or
`outcome: "skipped"` with a `reason`: `missing_fields`, `invalid_email`,
`duplicate_in_file`, `already_contacted`, `already_in_project`,
`do_not_contact` (on your suppress list or opted out of contact) or `unknown`.
Page with `offset` / `limit` (up to 5,000 rows per call) until `has_more` is
false. Before the import is `completed` this answers `409`
`import_not_completed`.
Parameters
task_id (path, required): Task ID returned from the import POST.offset (query, optional): Rows to skip.limit (query, optional): Rows per page, up to 5000.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Import task not found.409: The import is not `completed` yet (`import_not_completed`), or it completed before per-lead results existed (`rows_unavailable`).
GET /public/api/v1/autogtm/hot-leads
List hot leads
Every **hot lead** across your organization — people who replied to your
outreach with real interest — newest first, as enriched contacts ready to
map into CRM fields.
**Polling:** pass `since` (ISO 8601) with your last poll time to get only
leads that went hot after it — the Zapier/Make pattern. `became_hot_at` of
the newest item is your next cursor. `became_hot_at` is when the lead turned
hot in Explee, usually a few minutes after they wrote (`replied_at`). A lead
can come back with a newer `became_hot_at` when they reply again, so upsert
on `person_id`. Pass `project_id` to get one project's leads only.
A lead leaves the feed when you dismiss it in the inbox («Not a hot lead»)
or when it later unsubscribes. To read the full conversation or answer:
`GET /autogtm/campaigns/{campaign_id}/inbox/{person_id}` and `…/reply`.
Parameters
campaign_id (query, optional): Only this campaign. Omit for the whole organization.project_id (query, optional): Only this project. Omit for the whole organization.since (query, optional): Only leads that became hot at/after this time (ISO 8601). Use for polling.limit (query, optional): Page size.offset (query, optional): Pagination offset.source (query, optional): Set by our ready-made Zapier and AI-agent recipes; counts delivered leads per source in Settings → Integrations. Omit it in your own code.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: `campaign_id` or `project_id` not found or not owned by your organization.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/leads
List contacted leads
Every lead this campaign has already emailed — the contact, how many emails
they got and when, and where the conversation stands (replied, bounced,
unsubscribed, the status your team set, the latest reply). Most recently
emailed first. The same list as **Export CSV** on the Sent tab.
The list is live: a lead emailed again moves to the top, so upsert on
`person_id` when you walk the pages by `offset`.
**To walk a live campaign without missing a lead,** pass
`order=first_emailed`: the leads come oldest first email first, and each
response carries `next_cursor`. Pass only `cursor` (the `next_cursor` of the
previous response) on every next call. While `has_more` is true, call again;
once it is false, keep `next_cursor` and come back with it later to read the
leads emailed since. A lead's first email never changes, so this walk doesn't
skip or repeat a lead while the campaign sends. A lead appears here once its
first email has settled: usually a minute after it, longer while an earlier
email of the campaign is still being confirmed.
Leads that haven't been emailed yet are not listed. Available on the plans that
include lead export; other plans get `403`.
To read the full conversation or answer:
`GET /autogtm/campaigns/{campaign_id}/inbox/{person_id}` and `…/reply`.
Parameters
campaign_id (path, required)limit (query, optional): Page size, up to 5000.offset (query, optional): Pagination offset.order (query, optional): `last_emailed` (default): most recently emailed first, paged by `offset`. `first_emailed`: by first email, oldest first, paged by `cursor`.cursor (query, optional): The `next_cursor` of your previous response; implies `order=first_emailed`.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), or 4 concurrent requests per organization reached — a limit shared by `campaigns/{id}/leads`, `campaigns/{id}/status`, `projects/{id}/inbox`, the `inbox/changes` feeds and `billing/usage`. Retry shortly.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.403: Lead export isn't available on your plan.404: Campaign not found or not owned by your organization.
GET /public/api/v1/autogtm/projects/{project_id}/inbox
List project inbox conversations
List the project's conversations (contacted people) across all its campaigns,
most recent first — the app's Inbox. Pass `campaign_id` for one campaign only.
**Tabs:** `need_reply` — replies awaiting a human answer (start here),
`replied` — everyone who replied, `sent` — everyone contacted. Omit for the
full universe.
Each conversation carries its `campaign_id`: read the thread and reply at
`…/campaigns/{campaign_id}/inbox/{person_id}`. To poll for what changed since
your last call, use `…/projects/{project_id}/inbox/changes`.
Parameters
project_id (path, required)campaign_id (query, optional): Only this campaign's conversations. Omit for the whole project.tab (query, optional): Filter: `need_reply`, `replied` or `sent`. Omit for all.limit (query, optional): Page size.offset (query, optional): Pagination offset.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), or 4 concurrent requests per organization reached — a limit shared by `campaigns/{id}/leads`, `campaigns/{id}/status`, `projects/{id}/inbox`, the `inbox/changes` feeds and `billing/usage`. Retry shortly.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization, or the campaign is not in it.
GET /public/api/v1/autogtm/projects/{project_id}/inbox/changes
List project inbox changes
The project's conversations, across all its campaigns, with a new message since
your last call. Pass `campaign_id` for one campaign only. Each conversation
carries its `campaign_id` for the thread and reply paths.
Only a reply from the lead (and its classification) or your reply to them
counts, oldest first. Campaign emails (first touch, follow-ups) don't count,
and neither does a lead status you change in the app. Use it to react to
replies without re-reading the inbox.
**First call:** pass `since` (ISO 8601), or nothing to read every conversation
that has a reply, from the start. **Every next call:** pass only `cursor` — the
`next_cursor` of the previous response. While `has_more` is true, call again
right away; once it is false, store `next_cursor` and come back with it on your
next poll.
A conversation comes back each time it gets a message, and now and then without
one (a status write on its latest reply), so upsert on `person_id`. A page can
hold fewer than `limit` conversations, or none, while `has_more` is
true. A change shows up here about a minute after it happens. A conversation
hidden from the inbox (e.g. it unsubscribed) stops coming back. `needs_reply`
and `lead_status` are as of the call; a status changed in the app since does
not bring the conversation back, so re-read the thread before you act on it.
Parameters
project_id (path, required)campaign_id (query, optional): Only this campaign's conversations. Omit for the whole project.since (query, optional): First call only: conversations with a message at/after this time (ISO 8601). Omit both `since` and `cursor` to read from the start.cursor (query, optional): Every next call: the `next_cursor` of your previous response.limit (query, optional): Page size.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), or 4 concurrent requests per organization reached — a limit shared by `campaigns/{id}/leads`, `campaigns/{id}/status`, `projects/{id}/inbox`, the `inbox/changes` feeds and `billing/usage`. Retry shortly.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization, or the campaign is not in it.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/inbox
List campaign inbox conversations
**Deprecated — use `GET /public/api/v1/autogtm/projects/{project_id}/inbox?campaign_id=…`**,
which reads the same conversations and the whole project in one call. This path
keeps working.
List the campaign's conversations (contacted people), most recent first.
**Tabs:** `need_reply` — replies awaiting a human answer (start here),
`replied` — everyone who replied, `sent` — everyone contacted. Omit for the
full universe.
To poll for what changed since your last call, use `…/inbox/changes`.
Parameters
campaign_id (path, required)tab (query, optional): Filter: `need_reply`, `replied` or `sent`. Omit for all.limit (query, optional): Page size.offset (query, optional): Pagination offset.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/inbox/changes
List campaign inbox changes
**Deprecated — use `GET /public/api/v1/autogtm/projects/{project_id}/inbox/changes?campaign_id=…`**.
This path keeps working.
The campaign's conversations with a new message since your last call.
Only a reply from the lead (and its classification) or your reply to them
counts, oldest first. Campaign emails (first touch, follow-ups) don't count,
and neither does a lead status you change in the app. Use it to react to
replies without re-reading the inbox.
**First call:** pass `since` (ISO 8601), or nothing to read every conversation
that has a reply, from the start. **Every next call:** pass only `cursor` — the
`next_cursor` of the previous response. While `has_more` is true, call again
right away; once it is false, store `next_cursor` and come back with it on your
next poll.
A conversation comes back each time it gets a message, and now and then without
one (a status write on its latest reply), so upsert on `person_id`. A page can
hold fewer than `limit` conversations, or none, while `has_more` is
true. A change shows up here about a minute after it happens. A conversation
hidden from the inbox (e.g. it unsubscribed) stops coming back. `needs_reply`
and `lead_status` are as of the call; a status changed in the app since does
not bring the conversation back, so re-read the thread before you act on it.
Parameters
campaign_id (path, required)since (query, optional): First call only: conversations with a message at/after this time (ISO 8601). Omit both `since` and `cursor` to read from the start.cursor (query, optional): Every next call: the `next_cursor` of your previous response.limit (query, optional): Page size.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), or 4 concurrent requests per organization reached — a limit shared by `campaigns/{id}/leads`, `campaigns/{id}/status`, `projects/{id}/inbox`, the `inbox/changes` feeds and `billing/usage`. Retry shortly.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/inbox/{person_id}
Read a conversation thread
The full conversation with one contact: our outbound emails and their replies,
in order, plus the reply gate (`can_reply`). Every message carries its `cc`
addresses and the metadata of its `attachments` (name, type, size).
To answer, POST to `/reply` with just your message text.
Parameters
campaign_id (path, required)person_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/inbox/{person_id}/attachments/{attachment_id}
Download an attachment
Get a download link for a file attached to a message in this conversation —
one the lead sent you or one you sent. Take `attachment_id` from
`messages[].attachments[].id` of the thread.
Returns `url`, a signed link to the file valid for 5 minutes (`expires_at`):
fetch it with a plain GET, no API key. A file listed with `stored: false` was
received but could not be stored — `410`.
Parameters
campaign_id (path, required)person_id (path, required)attachment_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such attachment in this conversation, or campaign not found.410: The file was received but could not be stored (`stored: false`).
POST /public/api/v1/autogtm/campaigns/{campaign_id}/attachments
Upload an attachment
Upload a file to attach to a reply in this campaign. Send it as
`multipart/form-data` with the field `file`, then pass the returned `id` in
`attachment_ids` of `…/inbox/{person_id}/reply`.
**Limits:** up to 25 MB per file; PDF, PNG, JPEG, GIF, WebP, DOCX, PPTX, XLSX,
TXT. Every file is checked by the same content moderation as uploads in the app
— a refused file is `400` with the reason; if the check is briefly unavailable,
`503` (retry). A reply carries up to 10 files, and their total must fit the
sending mailbox (`413` on `…/reply`). Up to 200 uploads per hour per API key
(`429` beyond that).
Parameters
campaign_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: Validation error. Check request body and parameters.429: More than 200 uploads in the last hour for this API key.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.400: File refused by content moderation, or its type is not allowed.413: File larger than 25 MB.503: Moderation or file storage briefly unavailable — retry.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/inbox/{person_id}/reply
Reply in a thread
Reply to this contact — send just the message text.
You reply to the **lead**, not to an email address: the server resolves the
recipient, the subject (`Re: …`) and the threading from the contact's real
conversation, so a reply can only ever go back to the person who wrote to you —
never to an address you supply. The message goes through the same compliance
gate and content moderation as replies sent from the app.
**Files:** upload each via `POST …/attachments` and pass the ids in
`attachment_ids` (up to 10). Allowed only in a thread the lead has replied to.
**Cc:** by default the reply keeps the people the lead had on Cc (`reply_all`,
only when their latest message is a real conversation — as in the app)
plus your campaign's `reply_cc_emails`. Add per-reply addresses in
`cc_emails`; set `reply_all: false` to drop the lead's Cc.
Allowed only for a contact who has **replied** and isn't `unsubscribe`
— otherwise `403`. You may send at most three replies per message the lead sent
you (`429` if exceeded). The send is recorded under your organization's owner
identity (an API key carries no user).
Parameters
campaign_id (path, required)person_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Too many replies to this contact in the last 24h.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.403: Reply blocked: `unsubscribe` thread, or the contact never replied.409: Another reply to this contact is being sent right now — retry after the `Retry-After` seconds.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/inbox/{person_id}/note
Read the lead note
The team-shared note on this lead — the same free-text field your team sees
and edits in the Explee inbox (Lead info panel). `note` is `null` when no
note has been set.
Parameters
campaign_id (path, required)person_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign or lead not found, or not owned by your organization.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/inbox/{person_id}/note
Set the lead note
Set (or clear) the lead's team-shared note. The note is one shared text per
lead, last-write-wins — a write here replaces what a teammate typed in the
app, and vice versa.
Pass `{"note": null}` (or an empty string) to clear it.
Parameters
campaign_id (path, required)person_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign or lead not found, or not owned by your organization.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/inbox/{person_id}/status
Set the lead status
Set (or clear) the lead's status — the same status picker your team uses in
the Explee inbox, and the `lead_status` the inbox list returns.
- `status` is one of the project's statuses: `Hot`, `Demo`, `Won`, `Lost`,
`Unqualified`, or a custom stage added in the app. An unknown name answers
400 with the allowed list. `null` clears the status.
- A status can be set only after the lead has replied (409 before that);
clearing always works.
- Any status but `Hot` cancels a pending autopilot reply to this lead.
- `Hot`, `Demo` and `Won` push the lead to your connected HubSpot, as in the app.
Parameters
campaign_id (path, required)person_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign or lead not found, or not owned by your organization.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/inbox/{person_id}/mark-replied
Mark the conversation as replied
Mark the conversation as replied — you answered the lead outside Explee.
The conversation leaves the `need_reply` tab and the inbox badge, and a
pending autopilot reply to this lead is cancelled. The lead's status does not
change. If the lead writes again, the conversation comes back to `need_reply`.
Parameters
campaign_id (path, required)person_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign or lead not found, or not owned by your organization.
GET /public/api/v1/autogtm/projects/{project_id}/budget
Get project daily budget
Read the project's total daily outreach budget (the anchor the dashboard
slider sets).
Per-campaign allocations are derived from this number automatically — see
`daily_limit_usd` on each campaign in `GET /autogtm/campaigns`.
Parameters
project_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.
PATCH /public/api/v1/autogtm/projects/{project_id}/budget
Set project daily budget
Set the project's total daily outreach budget.
The change is spread across the project's active campaigns proportionally —
exactly what the dashboard slider does. **`0` pauses all sending** while
keeping campaigns configured (the explicit off switch): the sending campaigns
park at once, as with the app's Stop. Range `0`–`300`, the slider's range.
Parameters
project_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.
PATCH /public/api/v1/autogtm/campaigns/{campaign_id}/budget
Set campaign daily budget
Set one campaign's daily budget.
The campaign's `daily_limit_usd` is set directly and the project's total daily
budget follows as the sum of its running campaigns — the other campaigns are not
touched (grow or shrink the total spend, not redistribute a fixed one).
**Editable only while Autopilot is OFF** (`GET/PATCH …/projects/{id}/autopilot`):
while it's ON the agent owns the split and this returns `409`. A paused / not-yet-
running campaign holds no allocation, so setting its budget also returns `409` —
resume it first. To set the whole-project budget instead, use
`PATCH …/projects/{id}/budget`.
Parameters
campaign_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.409: Auto-manage campaigns is ON (budget is agent-managed) or the campaign is not running.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/stop
Stop campaign
Stop a campaign **from any status**, idempotently: interrupts a running lead
search, cancels queued outreach emails, and freezes a pending review's
auto-approve countdown. Nothing sends until it is started again.
Always available, in either mode — stopping is the user's right; only
(re)starting is agent-owned while Auto-manage campaigns is ON.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/start
Start campaign
Re-enable a stopped campaign — the status-aware inverse of stop:
- stopped while sending → resumes sending (requires an affordable balance);
- stopped in review → un-freezes the review countdown;
- stopped during lead search → re-runs the search.
Already-running or archived campaigns are a no-op.
Returns **409** while Auto-manage campaigns is enabled for the project — Explee decides
when campaigns start. Exception: a campaign you parked yourself (stopped, or
restored from archive) can always be started again, in either mode. Turn
Autopilot off (`PATCH …/projects/{project_id}/autopilot`) to start any other
campaign yourself. A campaign paused by billing (daily budget $0, no card,
unpaid balance) gets a 409 that names that cause: fix it and the campaign
resumes on its own.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account. `no_card`: no card was ever accepted for your organization. Add one on the Billing page of the Explee app, then retry.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.409: Auto-manage campaigns is ON for the project — Explee decides when campaigns start. A campaign paused by billing is refused too; the message names the cause to fix. `code`: `autopilot_managed`, `billing_paused` or `blocked_by_moderation`.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/archive
Archive campaign
Archive a campaign **from any status**: signals a running lead search to stop,
cancels queued outreach emails and pending auto-replies, and drops the
campaign from `GET /public/api/v1/autogtm/campaigns` and from the budget split.
Always available, in either mode, like stop. Archiving an archived campaign is
a no-op. Undo with `POST …/campaigns/{campaign_id}/unarchive`.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
POST /public/api/v1/autogtm/campaigns/{campaign_id}/unarchive
Unarchive campaign
Restore an archived campaign. It comes back **paused** and sends nothing until
you call `POST …/campaigns/{campaign_id}/start`, which is allowed even while
Auto-manage campaigns is on. Auto-reply stays off.
A campaign that is not archived is left as is (no-op). Find archived campaign
ids with `GET /public/api/v1/autogtm/campaigns?include_archived=true`.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/analytics
Campaign analytics
Campaign performance for a period: emails sent, replies, reply rate, hot leads,
spend, cost per lead, budget allocation, the leads pool and the manual lead
funnel. The same numbers the Explee dashboard shows — use them to drive your
own budget/start/stop decisions.
Parameters
campaign_id (path, required)period (query, optional): Aggregation window.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
GET /public/api/v1/autogtm/projects/{project_id}/analytics
Project analytics
Project-level performance for a period: the aggregate totals (emails, replies,
reply rate, hot leads, spend) plus the per-campaign breakdown — exactly what the
Explee dashboard shows for a project. Both the totals and the per-campaign rows
cover the requested `period`.
Parameters
project_id (path, required)period (query, optional): Aggregation window.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.
GET /public/api/v1/autogtm/campaigns/{campaign_id}/status
Campaign send state
Is this campaign sending right now, and if not, why — the status line the
Explee app shows on the project page, for one campaign.
- `state` — one stable code (see the field). `sending_now` is `true` only for
`sending` and `scheduled`.
- `message` — the reason in one sentence; `next_action` — the call (or app step)
that unblocks it, `null` when there is nothing to do but wait.
- `today` — emails sent and queued today, the next queued send, today's spend
against the campaign's daily budget.
- `allowed_actions` — the control calls the campaign accepts now (`start`,
`stop`, `approve`, `archive`, `unarchive`); anything not listed answers 409
or can only be a no-op. `start` while a lead search already runs is accepted
and changes nothing. `start` is left out while the project's daily budget is
$0 or a payment problem stops sending (`zero_budget`, `no_payment_method`,
`balance_empty`, `payment_failed`): fix that first.
Project- and account-level blockers (a $0 project budget, no payment method, an
empty balance, a failed payment, moderation) stop this campaign too, so they are
reported here as its `state`. Free, read-only; poll it no more than once a
minute — the counters behind it refresh every two minutes.
Parameters
campaign_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), or 4 concurrent requests per organization reached — a limit shared by `campaigns/{id}/leads`, `campaigns/{id}/status`, `projects/{id}/inbox`, the `inbox/changes` feeds and `billing/usage`. Retry shortly.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Campaign not found or not owned by your organization.
POST /public/api/v1/autogtm/suppress-list/people
Suppress people
Store a list of people to suppress — the same lists the **Suppress list** page
in the app shows, so a list pushed from your CRM sits next to the CSVs your
team uploaded and behaves identically.
A list applies to **every** outreach campaign of the projects it covers, running
or not: all projects of your organization by default, or only the ones you name
in `project_ids` (an agency keeps each client's list to that client's projects).
Every email is checked against it right before it goes out, so an address added
here stops a sequence that is already mid-flight, not just future ones.
Matching is exact: a person by their email address (case-insensitive, but
`[email protected]` and `[email protected]` are two different entries), a company by
its domain (the lead's company domain or the domain of its email address —
`acme.com` does not cover `eu.acme.com`, list each domain you use).
One call = one list, exactly like uploading one CSV: a `list` name that is
already taken gets a `(2)` suffix rather than merging, and lists are
independent — the same person on two lists is suppressed until both are gone.
Delete a list you no longer want.
Each person needs at least one identifier: an email, a LinkedIn URL, or a full
name; a row left without a usable one (including a malformed address) comes back
in `skipped` instead of failing the whole batch. **Outreach stops on the email** — the name and LinkedIn fields are stored
but not actively used today; they are kept because a suppressed person is more
than their email address, and the day outreach runs somewhere other than email
(LinkedIn and the like) those are the fields that will match. To suppress
everyone at a company use the companies endpoint.
**Safe retries:** send an `Idempotency-Key` header (any unique string, e.g. a
UUID) and repeat the exact same request with the same key if you don't get an
answer. Within 24 hours a repeat returns what the first request created (the
same task, list or campaign) and does nothing again. The same key with a different body is rejected (`422`,
`idempotency_key_reused`); a repeat that arrives while the first request is
still running gets `409` `idempotency_key_in_use` — wait `Retry-After` seconds
and repeat. A key replays its first answer even if that import later
`failed` — to retry a failed import, send a new key.
Parameters
Idempotency-Key (header, optional): Optional. Any unique string up to 255 characters (a UUID works well). Send the same key again when you retry this request — after a timeout, a dropped connection or a 5xx — and within 24 hours you get the first answer back instead of a second write. Reusing a key with a different body answers `422` `idempotency_key_reused`; a retry that arrives while the first request is still running answers `409` `idempotency_key_in_use` — retry after `Retry-After`.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: `project_not_found`: a `project_ids` entry is not a project of yours (on a PATCH, ids the list already names are kept as-is, a deleted project's included).429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.409: `idempotency_key_in_use`: a request with this `Idempotency-Key` is still running.
GET /public/api/v1/autogtm/suppress-list/people
People suppress lists
Your people lists — the ones on the app's Suppress list page, newest first.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/autogtm/suppress-list/people/{list_name}
Read a people list
The people stored in one list. `total` is the exact size; page through it with `limit`/`offset`.
Parameters
list_name (path, required): List name.limit (query, optional): Entries per page.offset (query, optional): Entries to skip.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such list in your organization.
PATCH /public/api/v1/autogtm/suppress-list/people/{list_name}
Change a people list's projects
Change which projects a list applies to: `{"project_ids": [4021, 4022]}`, or
`{"project_ids": null}` for all projects of your organization. Takes effect on
the next email: narrowing a list re-opens sending to the projects it no longer
covers, widening it stops them. Emails already cancelled by the list stay
cancelled. An empty array is a `422` — to apply a list nowhere, delete it.
Ids the list already names are kept as-is: sending back the id of a project
you have since deleted does not fail.
Parameters
list_name (path, required): List name.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: `project_not_found`: a `project_ids` entry is not a project of yours (on a PATCH, ids the list already names are kept as-is, a deleted project's included).429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such list in your organization.
DELETE /public/api/v1/autogtm/suppress-list/people/{list_name}
Delete a people list
Remove a whole list, exactly like deleting it on the Suppress list page — its people stop being suppressed unless another list still holds them.
Parameters
list_name (path, required): List name.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such list in your organization.
POST /public/api/v1/autogtm/suppress-list/companies
Suppress companies
Store a list of company domains to suppress — nobody at these companies is
contacted.
A list applies to **every** outreach campaign of the projects it covers, running
or not: all projects of your organization by default, or only the ones you name
in `project_ids` (an agency keeps each client's list to that client's projects).
Every email is checked against it right before it goes out, so an address added
here stops a sequence that is already mid-flight, not just future ones.
Matching is exact: a person by their email address (case-insensitive, but
`[email protected]` and `[email protected]` are two different entries), a company by
its domain (the lead's company domain or the domain of its email address —
`acme.com` does not cover `eu.acme.com`, list each domain you use).
One call = one list, exactly like uploading one CSV: a `list` name that is
already taken gets a `(2)` suffix rather than merging, and lists are
independent. Delete a list you no longer want.
Domains are normalized (`https://www.acme.com/careers` → `acme.com`), so two
spellings of one company collapse into a single entry. Values that are not a
domain come back as `skipped`. Subdomains are separate entries — `acme.com`
does not cover `eu.acme.com`.
**Safe retries:** send an `Idempotency-Key` header (any unique string, e.g. a
UUID) and repeat the exact same request with the same key if you don't get an
answer. Within 24 hours a repeat returns what the first request created (the
same task, list or campaign) and does nothing again. The same key with a different body is rejected (`422`,
`idempotency_key_reused`); a repeat that arrives while the first request is
still running gets `409` `idempotency_key_in_use` — wait `Retry-After` seconds
and repeat. A key replays its first answer even if that import later
`failed` — to retry a failed import, send a new key.
Parameters
Idempotency-Key (header, optional): Optional. Any unique string up to 255 characters (a UUID works well). Send the same key again when you retry this request — after a timeout, a dropped connection or a 5xx — and within 24 hours you get the first answer back instead of a second write. Reusing a key with a different body answers `422` `idempotency_key_reused`; a retry that arrives while the first request is still running answers `409` `idempotency_key_in_use` — retry after `Retry-After`.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: `project_not_found`: a `project_ids` entry is not a project of yours (on a PATCH, ids the list already names are kept as-is, a deleted project's included).429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.409: `idempotency_key_in_use`: a request with this `Idempotency-Key` is still running.
GET /public/api/v1/autogtm/suppress-list/companies
Company suppress lists
Your blocked-company lists — the ones on the app's Suppress list page, newest first.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/autogtm/suppress-list/companies/{list_name}
Read a company list
The domains stored in one list. `total` is the exact size; page through it with `limit`/`offset`.
Parameters
list_name (path, required): List name.limit (query, optional): Entries per page.offset (query, optional): Entries to skip.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such list in your organization.
PATCH /public/api/v1/autogtm/suppress-list/companies/{list_name}
Change a company list's projects
Change which projects a list applies to: `{"project_ids": [4021, 4022]}`, or
`{"project_ids": null}` for all projects of your organization. Takes effect on
the next email: narrowing a list re-opens sending to the projects it no longer
covers, widening it stops them. Emails already cancelled by the list stay
cancelled. An empty array is a `422` — to apply a list nowhere, delete it.
Ids the list already names are kept as-is: sending back the id of a project
you have since deleted does not fail.
Parameters
list_name (path, required): List name.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: `project_not_found`: a `project_ids` entry is not a project of yours (on a PATCH, ids the list already names are kept as-is, a deleted project's included).429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such list in your organization.
DELETE /public/api/v1/autogtm/suppress-list/companies/{list_name}
Delete a company list
Remove a whole list, exactly like deleting it on the Suppress list page — its companies stop being suppressed unless another list still blocks them.
Parameters
list_name (path, required): List name.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such list in your organization.
POST /public/api/v1/autogtm/webhooks
Add a webhook
Add a webhook: we POST each new event of the project to `url`, signed with the
webhook's own secret (returned here). A project can have up to
20 webhooks; they also appear in the app under
**Settings → Integrations**. Zapier REST hooks: subscribe with this call,
unsubscribe with `DELETE /autogtm/webhooks/{id}`.
**Events.** Two different events: one is every reply, the other is the moment a
lead turns hot. Subscribe to the one your workflow needs; with both, a hot reply
arrives as each.
`hot_lead.received` — **lead turns hot**: once per lead, when its reply is Hot. A
later reply of the same lead does not send it again. Use it to create a deal. The
body is the lead exactly as `GET /autogtm/hot-leads` returns it, in an envelope:
```json
{"event": "hot_lead.received", "delivery_id": "…", "created_at": "…",
"project_id": 12, "test": false, "lead": {…}}
```
`reply.received` — **every reply**: each reply the inbox shows, hot, not interested,
auto-replies and out-of-office included. What the inbox hides is not sent
(unsubscribes, system noise, removal requests). The body carries the lead and
the reply:
```json
{"event": "reply.received", "delivery_id": "…", "created_at": "…",
"project_id": 12, "test": false,
"lead": {"person_id": "…", "campaign_id": 34, "name": "…", "email": "…", …},
"reply": {"id": "…", "intent": "not_interested", "is_hot": false,
"subject": "…", "text": "…", "received_at": "…"}}
```
Only leads that turn hot, and replies that arrive, after the webhook was added
are sent, each once per webhook; earlier ones are in the hot-leads feed and the
inbox. A delivery that fails on our
side or gets a 5xx / 408 / 429 is retried for at least 6 hours; any other 3xx
or 4xx is your endpoint's answer and is not retried (`last_error` says why).
Webhooks need a plan with CRM push (Standard and up): otherwise `403`.
Request Body
Request body required
Responses
201: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.
GET /public/api/v1/autogtm/webhooks
List webhooks
The webhooks of one project, oldest first, as **Settings → Integrations** shows them.
Parameters
project_id (query, required): The project.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.
GET /public/api/v1/autogtm/webhooks/{webhook_id}
Get a webhook
One webhook with its signing secret.
Parameters
webhook_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such webhook in your organization.
DELETE /public/api/v1/autogtm/webhooks/{webhook_id}
Delete a webhook
Stop sending events to this URL and drop its secret. Zapier calls this when a zap is turned off.
Parameters
webhook_id (path, required)
Responses
204: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: No such webhook in your organization.
GET /public/api/v1/autogtm/projects/{project_id}/domain-suggestions
Suggest domains to order
Free `.com` names for the project's brand, ready to order, and what to order:
- `domains` — each was free at the registry just now and is in nobody's order.
The brand is the project's website; pass `brand` to build names from another
one, and the names you already have in `exclude` to get the next ones.
- `package` — one domain + 5 mailboxes: price a month and
emails a day at full speed.
- `plan` — how many domains the project's daily budget needs, how many its
orders already hold, and `domains_to_buy`.
Registry lookups are limited per organization per hour (`429` `domain_lookup_limit`,
with `Retry-After`).
`order_url` opens the app's order form with the free names on it (up to
20; `null` with fewer than 2 free). Give it to a
person: they add the senders and the domains' legal owner, confirm the mailbox
addresses and pay the first month by card. Our team then buys the domains and
sets up the mailboxes; they warm up for 7 days, then send this
project's campaigns first.
Parameters
project_id (path, required)brand (query, optional): Website or name to build names from; the project's website by default.count (query, optional): How many free names to return.exclude (query, optional): Comma-separated names to skip.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found, or not owned by your organization.
GET /public/api/v1/autogtm/projects/{project_id}/domain-availability
Check domains
Check your own picks, comma-separated: each is `free`, `taken` (registered, or
in someone's order), `unknown` (the registry didn't answer, retry) or
`invalid` (not a second-level `.com` we can buy).
`order_url` opens the app's order form with the free names on it (up to
20; `null` with fewer than 2 free). Give it to a
person: they add the senders and the domains' legal owner, confirm the mailbox
addresses and pay the first month by card. Our team then buys the domains and
sets up the mailboxes; they warm up for 7 days, then send this
project's campaigns first.
Parameters
project_id (path, required)domains (query, required): Up to 20 comma-separated names.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found, or not owned by your organization.
GET /public/api/v1/autogtm/projects/{project_id}/autopilot
Get autopilot settings
Read the project's autopilot and auto-reply settings.
- `autopilot_enabled` — the Explee autopilot agent. While ON it manages
campaigns and the per-campaign budget split (per-campaign budget edits return
409); turn it OFF to control budgets yourself.
- `auto_reply_enabled` / `auto_reply_delay_minutes` — AI auto-reply behaviour.
- `reply_cc_emails` — project defaults added to CC on every manual or automatic reply.
Parameters
project_id (path, required)
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.
PATCH /public/api/v1/autogtm/projects/{project_id}/autopilot
Set autopilot settings
Update the project's autopilot / auto-reply settings. Send only the fields you
want to change — at least one is required.
Turning `autopilot_enabled` **off** hands per-campaign budgets back to you
(`PATCH …/campaigns/{id}/budget` stops returning 409); turning it **on** makes
them agent-managed again.
Parameters
project_id (path, required)
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: No fields to update.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Project not found or not owned by your organization.
GET /public/api/v1/autogtm/billing
Outreach balance
Your outreach balance and today's spend — what the Billing tab of the app shows.
Free, read-only.
Check `send_status` before you start or scale campaigns: anything but `ok` means
emails stop until a person tops up or adds a card on the billing page
(https://explee.com/app-auto-gtm/billing).
`daily_budget_usd` is a ceiling, not a promise to spend: spend stays lower on
days when fewer leads are ready.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/autogtm/billing/usage
Outreach spend by day
Outreach spend by UTC day for the last `days` days (today included) — the Usage
panel of the app's Billing tab. Free, read-only.
Spend is emails sent × your email price (paid LinkedIn touches count as emails).
Replies are free. The window total is also split by what paid for it: trial
credits, the plan's included emails, or money.
Parameters
days (query, optional): Window length in UTC days, today included: 1-90.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), or 4 concurrent requests per organization reached — a limit shared by `campaigns/{id}/leads`, `campaigns/{id}/status`, `projects/{id}/inbox`, the `inbox/changes` feeds and `billing/usage`. Retry shortly.500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/autogtm/billing/activity
Credits activity
Where your balance came from: top-ups, plan emails, trial and referral credits — the last 50 deposits, newest first, as the Credits activity list of the app shows them. Free, read-only.
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/me
Get API key owner
Who this API key is: the organization it belongs to, its plan, the credit
balance, what the key may reach (`key`), the rate limits and where the docs
are. A good first call to check a key works. Free.
## Response
```json
{
"organization": {"id": "4ca77b5d-…", "name": "Acme"},
"plan": "pro",
"balance": {"remain": 4200},
"key": {"project_ids": null, "read_only": false},
"rate_limits": {
"requests_per_hour": 10000, "max_concurrent_requests": 150, "heavy_read_max_concurrent_requests": 4,
"free_zone": {"per_day": 750, "per_minute": 25}, "timeout_seconds": 90
},
"docs": {"reference": "https://api.explee.com/public/api/docs", "openapi": "…/openapi.json", "llms_txt": "…/llms.txt"}
}
```
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/feedback
Send feedback
Send us freeform feedback about the API: request a feature, report a problem,
tell us data is missing or wrong — anything, in your own words.
The message lands directly with the Explee team. We read everything, though we
don't guarantee an individual reply. No credits are charged.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/dedup/people
People Lists
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/dedup/people
Create People List
Create an immutable list of people you already own. Pass the person objects returned by people search or
find-and-enrich in `people`; they are matched by LinkedIn URL, normalized email, or first name + last name +
company domain. Existing integrations can keep using the legacy `linkedin_urls` field.
Pass the returned id in `exclude_lists` on people search — matched people are not returned and not charged.
Lists can't be modified: to grow your ledger, create a new list per batch and pass all ids;
consolidate periodically. URLs are normalized on write; unparseable values are skipped and reported.
**Limits:** 100,000 values per list; per search request: 100 lists, 500,000 values combined.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/dedup/people/{list_id}
Get People List
Returns the list metadata and all stored values.
Parameters
list_id (path, required): Dedup list id (returned on creation).
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Dedup list not found.
DELETE /public/api/v1/dedup/people/{list_id}
Delete People List
Removes the whole list. Excluded people will appear (and be charged) in search results again.
Parameters
list_id (path, required): Dedup list id (returned on creation).
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Dedup list not found.
GET /public/api/v1/dedup/companies
Companies Lists
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
POST /public/api/v1/dedup/companies
Create Companies List
Create an immutable list of companies you already own (`domain` values from search results).
Pass the returned id in `exclude_lists` on companies search — matched companies are not returned and not charged.
The same id works on people search, people-by-domains and find-and-enrich: everyone at a listed company is skipped
(exact domain match, subdomains are separate companies). People and companies lists can be mixed in one request.
Lists can't be modified: to grow your ledger, create a new list per batch and pass all ids;
consolidate periodically. Domains are normalized on write; unparseable values are skipped and reported.
**Limits:** 100,000 values per list; per search request: 100 lists, 500,000 values combined.
Request Body
Request body required
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.
GET /public/api/v1/dedup/companies/{list_id}
Get Companies List
Returns the list metadata and all stored values.
Parameters
list_id (path, required): Dedup list id (returned on creation).
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Dedup list not found.
DELETE /public/api/v1/dedup/companies/{list_id}
Delete Companies List
Removes the whole list. Excluded companies will appear (and be charged) in search results again.
Parameters
list_id (path, required): Dedup list id (returned on creation).
Responses
200: Successful Response401: Invalid or missing API key. Include `X-API-Key` header.402: Insufficient credit balance. Every request needs a positive balance, including requests that fall entirely inside the free results zone. Top up your account.422: Validation error. Check request body and parameters.429: Rate limit exceeded (10000/hour), concurrent limit reached (150 per organization), or free preview quota exceeded (search requests entirely within the free results zone; the quota depends on your plan).500: Internal server error. Contact support if persists.504: Request timeout. Please try again later.404: Dedup list not found.