REST API overview
The REST API gives your own code everything your workspace holds: contacts, companies, deals, events, conversations and meeting notes. It also lets your code act: tag records, save segments, write knowledge pages, set up automations, enrich records, and send email through the tools you have connected.
Every request goes to one base URL and carries an API key:
curl https://api.pathbound.ai/v1/contacts?limit=5 \ -H "Authorization: Bearer $PATHBOUND_API_KEY"Create a key under Settings → API keys in the dashboard. Authentication explains keys and scopes, and the Quickstart makes the first three calls with you.
What the API covers
Section titled “What the API covers”Each page lists its endpoints in a table at the top.
Read and write your records
Section titled “Read and write your records”| Area | What you can do | Scopes |
|---|---|---|
| Contacts | Create, list, filter, read, update and delete people. Read a contact’s timeline, conversations, meeting transcripts and notes. | contacts:read, contacts:write |
| Companies | The same for companies, with conversations rolled up across everyone at the company. | companies:read, companies:write |
| Deals | Create, list, read, update and delete deals and their notes. | deals:read, deals:write |
| Events | List and count tracked events: page views, clicks, form submissions and events written by integrations. | events:read |
| Tags | Add and remove tags on contacts, companies and deals, one record or thousands at a time. | the record’s write scope |
| Segments | Save a set of filters under a name, reuse it on other endpoints, and run an action on everyone in it. | the record’s read and write scopes |
Read at scale
Section titled “Read at scale”| Area | What you can do | Scopes |
|---|---|---|
| Batch and aggregate | Read up to 25 records in one request, read notes from many meetings, and group and count on the server. | the record’s read scope |
| Schema and usage | Find out which fields you can filter on, how much of your plan is used, and which integrations are connected. | differs by endpoint |
| Knowledge | Read and write your workspace’s own pages about its business. | knowledge:read, knowledge:write |
Get data in and out as it happens
Section titled “Get data in and out as it happens”| Area | What you can do | Scopes |
|---|---|---|
| Streaming | Push changes to your endpoint, or act on matching records automatically. | streams:read, streams:write |
| Forms | Post a form on your site to Pathbound, and email everyone who submits it. | events:read to list forms |
| Identify | Tell Pathbound which of your users a visitor is, from your server. | contacts:write |
Act in your connected tools
Section titled “Act in your connected tools”These endpoints send to real people or spend credits with a provider. Each one needs an opt-in scope, and most need the integration connected and a switch turned on by a workspace admin.
| Area | What you can do | Scope |
|---|---|---|
| Gmail | Send, schedule and draft email from your own mailbox. | actions:write |
| Resend | Manage segments, send an email, send an event, and send broadcasts in your Resend account. | actions:write |
| Apollo sequences | Create sequences, enroll contacts and send single emails through Apollo. | actions:write |
| Instantly | Add a lead to a campaign and update a lead’s interest. | actions:write |
| Enrichment and prospecting | Enrich your records and find new people and companies through Apollo or Hunter. | enrichment:write |
If you want an AI agent to do this work instead of your code, connect it to the MCP server. The MCP tools call these same endpoints.
Requests
Section titled “Requests”- Send JSON with
Content-Type: application/jsonon every request that has a body. - All times are ISO 8601 in UTC, for example
2026-10-12T09:30:00.000Z. A date filter accepts any ISO 8601 date or date-time. - Every successful response is a JSON object with
"status": "success".
Every record id is a 24-character hexadecimal string, for example 665f1c2ab3d4e5f601234567. An id in any other form is refused, on most endpoints with 400. An id that is well formed but belongs to no record in your workspace is answered with 404, whether or not it exists in another workspace.
Contacts, companies, deals and events name their id contact_id, company_id, deal_id and event_id. Responses also carry it as _id or id for older integrations. Use the named field in new code.
Pagination
Section titled “Pagination”List endpoints page with page (starting at 1) and limit, and return a pagination object:
{ "pagination": { "page": 1, "limit": 10, "total_pages": 42, "total_items": 418 }}limit goes up to 100 on contacts, companies, deals and events. The default differs by endpoint and is given in each endpoint’s parameter table, so pass limit rather than relying on it.
A few endpoints page differently, and say so on their page: a contact’s events use limit and offset, and long texts (a meeting transcript, a knowledge page) are read in parts.
Counting
Section titled “Counting”For a “how many” question, add count_only=true. The response is { "status": "success", "count": 1234 }, with no records. Counting is free and never counts against your plan.
For “how many by X”, use POST /v1/aggregate instead of paging through a list.
How much of each record comes back
Section titled “How much of each record comes back”The fields parameter on contact, company and deal lists chooses the shape of each row:
fields | Each row holds | Counts against your plan |
|---|---|---|
ids | The record’s id and nothing else. | No |
summary | The id and a handful of key properties. | Yes |
full (the default) | The whole record. | Yes |
| a comma-separated list (contact lists only) | The id and the fields you name. | Yes, unless every field you name is an id |
The cheapest way to work through a large set is to filter with fields=ids, then read the records you need with POST /v1/batch/details.
Filtering
Section titled “Filtering”List endpoints take three kinds of filter, and you can combine them. Every filter narrows the result: a record must pass all of them.
Named parameters such as lifecycle_stage, country or created_after. Each endpoint’s page lists its own.
Typed filters. The filters parameter is a JSON array of up to 10 conditions, each {"field", "op", "value"}:
curl -G https://api.pathbound.ai/v1/contacts \ -H "Authorization: Bearer $PATHBOUND_API_KEY" \ --data-urlencode 'filters=[{"field":"lifecyclestage","op":"in","value":["customer","opportunity"]},{"field":"emailable.score","op":"gte","value":80}]' \ --data-urlencode 'fields=ids'field is a property of the record (lifecyclestage, jobtitle, industry) or a field of a connected source written source.field (emailable.score, hubspot.hs_lead_status, and apollo.employee_count on a company). GET /v1/schema lists the fields your workspace has, with the type of each and the operators it takes.
op | Value | Meaning |
|---|---|---|
eq, neq | a string, number or boolean | Equal, not equal. |
in, nin | an array of 1 to 100 values | Is one of, is none of. |
gt, gte, lt, lte | a number or a date | Greater than, at least, less than, at most. |
contains | a non-empty string | Contains the text, ignoring case. |
exists | true or false (default true) | The field has a value, or has none. |
A number or date field takes the comparison operators and not contains. A text field takes contains and not the comparison operators. A filter that names an unknown source field, or an operator its field does not take, is answered with 400 and the code invalid_filter. It is never dropped.
eq, neq, in and nin compare the whole stored value, capitals included: "United States" does not match united states. contains ignores case. The named parameters are more forgiving: country=united states matches whatever the capitals.
Tags and segments. tags_any and tags_all filter on tags. segment and segments_any scope a list to a saved segment.
Errors
Section titled “Errors”An error response has a 4xx or 5xx status and "status": "error". A request that fails validation looks like this:
{ "status": "error", "error": "Validation failed", "details": [ { "type": "field", "path": "limit", "location": "query", "value": "500", "msg": "Limit must be between 1 and 100" } ]}Many other errors carry a code:
{ "status": "error", "code": "not_found", "error": "Contact not found"}error is a sentence for a person. code is a stable word for your code to branch on, and is present when the error has one. details says more when there is more to say: the parameter that failed, the limit that was reached. Many responses also carry a timestamp.
| Status | Meaning |
|---|---|
400 | The request is not valid. details names the parameter. |
401 | The API key is missing, wrong or switched off, or the user who created it has not verified their email. See Authentication. |
402 | Your plan’s allowance is used up, or the workspace has no active plan. See Usage and metering. |
403 | The key lacks a scope the endpoint needs. The error text names the missing scope. |
404 | No such record in your workspace. |
409 | The request conflicts with something that exists: a contact with that email, or a request with the same Idempotency-Key still in flight. |
412 | Something has to be set up first: an integration is not connected, or an admin has not switched the action on. code says which. |
422 | The request is well formed but cannot be carried out as asked. code says why. |
429 | A rate limit or a quota was reached. Wait for the number of seconds in the Retry-After header when it is present. |
5xx | Something failed on our side. A read can be repeated. For a request that sends or spends, read Idempotency first. |
Idempotency
Section titled “Idempotency”A request that sends something or spends something must not happen twice because a network connection dropped. Those endpoints take an Idempotency-Key header, and most of them require it:
curl -X POST https://api.pathbound.ai/v1/contacts/665f1c2ab3d4e5f601234567/send_email \ -H "Authorization: Bearer $PATHBOUND_API_KEY" \ -H "Idempotency-Key: 7c1f0d5e-3b0a-4a3e-9a51-2f6f6e0f8f11" \ -H "Content-Type: application/json" \ -d '{ "subject": "Next steps", "body": "Hi Ada, ..." }'- Choose one key per thing you intend to do, for example a UUID you store with the job. Use the same key when you retry that one thing, and a new key for the next.
- A request with a key that already succeeded in the last 24 hours returns the first answer and does nothing again. One endpoint remembers a key for longer: a job on a segment, for 30 days.
- A request with a key that is still being processed is answered with
409and the codeACTION_IN_PROGRESS. Wait and ask again with the same key. - An endpoint that requires the header answers
400with the codeIDEMPOTENCY_KEY_REQUIREDwithout it.
Several sends are at most once, and their pages say so. When the provider does not answer, Pathbound cannot know whether the message went out, and it does not try again. You get the code SEND_UNCONFIRMED. Do not repeat such a request under a new key before you have checked, in the provider or in the mailbox’s Sent folder, whether it was sent.
Rate limits
Section titled “Rate limits”Requests are limited per workspace, counted across all of its keys and connected AI agents, and per IP address. The limits are set as a guard against runaway loops and abuse, well above what an integration needs in normal use, so there is nothing to plan around: read with a few requests in parallel and you will not meet them.
A request over a limit is answered with 429. The workspace limit answers with the code QUOTA_EXCEEDED and a Retry-After header: wait that many seconds and send the request again. Responses carry RateLimit-* headers that show how much of the current window is left.
Some endpoints have limits of their own, given on their pages: the public form endpoint, sends through a provider, and enrichment, which is bounded by a daily credit budget.
If you plan a large backfill or expect sustained high volume, write to [email protected] first.
Usage and metering
Section titled “Usage and metering”Plans are measured in active profiles: the customers your workspace read in the current billing cycle. A customer is a company with everyone in it, or a contact that belongs to no company. Reading the same customer again in the same cycle, through any endpoint and any number of times, counts once. Nothing is billed per request.
Free, on every plan:
- Every write: creating, updating, importing in bulk, tagging, notes.
- Counts and aggregates:
count_only=true,total_items,POST /v1/aggregate. - Filtering, sorting, searching and segment scoping when the response holds ids only (
fields=ids). GET /v1/schema,GET /v1/usage,GET /v1/tags, and listing segments.- Listing events across the workspace with
fields=summary. - A
dry_run, on the endpoints that take one.
Counts as reading a customer: any response that returns something about them. That includes a single contact, company or deal, a list with fields=summary or fields=full, a timeline, conversations, and POST /v1/batch/details. A deal counts as the company or contact it belongs to.
Check before you read. Contact and company lists, a single contact and POST /v1/batch/details take dry_run=true, which tells you what the read would cost. Nothing is returned and nothing is counted:
{ "status": "success", "dry_run": true, "match_count": 25, "estimated_activations": 7 }estimated_activations is how many customers the read would add to this cycle’s count. GET /v1/usage returns how many you have used and how many remain.
At the limit. A plan’s allowance is a hard limit and never a charge. A read that would take you over it is answered with 402 and one of these codes, and everything you have already read this cycle stays readable:
code | Meaning |
|---|---|
BILLING_PLAN_LIMIT | The plan’s active profiles for this cycle are used up. |
BILLING_TRIAL_EXPIRED | The trial ended and no plan was chosen. |
BILLING_SUBSCRIPTION_PAUSED | The subscription is paused. |
BILLING_SUBSCRIPTION_INACTIVE | The subscription was canceled, or there never was one. |
Plans and what each includes are on the pricing page.
REST keys and AI agents
Section titled “REST keys and AI agents”An AI agent connected through the MCP server calls these same endpoints, with a few deliberate differences:
- Deleting a contact or a company is available to an API key and refused for an agent.
- Hiding contact PII. A workspace can hide contacts’ personal details from AI agents. That setting applies to agents only: an API key always receives the full record.
- Switches for agents. A workspace admin switches groups of tools on and off for agents under MCP Tools in the dashboard. Some of those switches also apply to an API key. Each page says which ones apply to its endpoints.