Skip to content
Pathbound DOCS

Apollo Sequences and Emails

These endpoints run outreach through your workspace’s Apollo account. You can create a sequence, enroll contacts in it, turn it on and off, and send one email to a contact now or at a set time. Apollo does the sending, from a mailbox of your Apollo team, and tracks opens and replies. Pathbound records each enrollment and each send on the contact’s timeline.

Use them when a script or an AI agent should start outreach from what Pathbound knows about a contact. Every enrollment and every send starts from a Pathbound contact ID.

Before the first call, connect Apollo under Integrations with a connection that includes the sequence permissions, have a workspace admin turn on Sequences or Single email under MCP Tools → Apollo, and use an API key that has the actions:write scope. The MCP server’s apollo_* tools call these endpoints (tools reference), except apollo_add_segment_to_sequence, which calls the segment endpoint.

EndpointScopeWhat it does
GET /v1/integrations/apollo/sendersactions:writeList the mailboxes you may send from.
GET /v1/integrations/apollo/sequencesactions:writeList the team’s sequences.
GET /v1/integrations/apollo/sequence-optionsactions:writeList the sending schedules and the rulesets in use.
POST /v1/integrations/apollo/sequencesactions:writeCreate an inactive sequence.
POST /v1/integrations/apollo/sequences/:sequence_id/activateactions:writeTurn a sequence on.
POST /v1/integrations/apollo/sequences/:sequence_id/pauseactions:writeTurn a sequence off.
POST /v1/integrations/apollo/sequences/:sequence_id/scheduleactions:writePoint a sequence at a sending schedule.
POST /v1/integrations/apollo/sequences/:sequence_id/contactsactions:writeEnroll up to 25 contacts in a sequence.
POST /v1/integrations/apollo/sequences/:sequence_id/contacts/stopactions:writeStop or remove up to 25 contacts.
GET /v1/integrations/apollo/contacts/:contact_id/sequence-activityactions:writeRead what happened to one contact in sequences.
POST /v1/integrations/apollo/contacts/:contact_id/send_emailactions:writeSend one email to a contact, now or at a set time.
GET /v1/integrations/apollo/scheduled-emailsactions:writeList single emails and their state.
DELETE /v1/integrations/apollo/scheduled-emails/:idactions:writeCancel a single email before it is sent.

The reads need actions:write too, because they show your team’s mailboxes, sequences and outreach to each contact. actions:write is opt-in: a key has it only when it was selected at creation.

The connection must include Apollo’s sequence and email permissions. A connection made before September 2026 does not, and is answered 412 needs_reconsent with the missing permissions in details.missing_scopes. A workspace admin reconnects Apollo under Integrations → Apollo.

Apollo answers some of these calls only on a paid Apollo plan. When it refuses for that reason the answer is 412 plan_required.

Two switches under MCP Tools → Apollo decide what may be done. Both are off until a workspace admin turns them on.

SwitchEndpoints it allows
SequencesEvery endpoint under /v1/integrations/apollo/sequences, GET /v1/integrations/apollo/sequence-options, and GET /v1/integrations/apollo/contacts/:contact_id/sequence-activity.
Single emailPOST /v1/integrations/apollo/contacts/:contact_id/send_email. A scheduled email reads the switch again when it is due.
Either oneGET /v1/integrations/apollo/senders.
NeitherGET /v1/integrations/apollo/scheduled-emails and DELETE /v1/integrations/apollo/scheduled-emails/:id.

Where a switch applies, the API reads it on every call and for every caller. A REST API key is held to it exactly as an MCP connection is, and a call with the switch off is answered 412 tool_disabled. The MCP server also reads the switches to decide which tools it lists.

Listing and canceling single emails are behind no switch in the API, so you can still review and cancel what is queued after Single email is turned off. Over MCP those two tools are listed only while the switch is on.

Every enrollment and every single email names the mailbox it goes out from, in sender_account_id. There is no default.

The mailbox must be one that GET /v1/integrations/apollo/senders returns: active in your Apollo team and, when a workspace admin has set Allowed sender mailboxes under Integrations → Apollo, on that list. With no list set, every active mailbox of the Apollo team may be used.

The mailbox is checked against Apollo again on every write, and once more when a scheduled email is due. A mailbox that is not allowed is refused with 403 sender_not_allowed, and one that is inactive in Apollo with 400 sender_inactive. Another mailbox is never used in its place.

Every POST on this page requires an Idempotency-Key header. Without it the call is refused with 400 IDEMPOTENCY_KEY_REQUIRED, before the body is checked.

HeaderRequiredDescription
Idempotency-Keyyes, on every POSTAny string that is unique to the thing you intend to do. Use a new one for each new intention, and the same one when you retry.

Within 24 hours, the same key on the same endpoint does the action once:

  • While the first call is still running, a second is answered 409 ACTION_IN_PROGRESS.
  • After the first call succeeded, a second is answered 200 with replayed: true, the action_id and a summary of the first result. On an enrollment or a stop the summary holds counts (enrolled_count, skipped_count, updated_count), not the per-contact lists. Nothing is done again.
  • After the first call failed, a second runs.

The key alone identifies the action: a different body under a used key is not run. Activate and pause are separate endpoints, so a key used to activate does not block a pause. To activate the same sequence a second time, after a pause, use a new key.

Send an Email keeps its own record: the same key within 24 hours returns the email that the first call created, in whatever state it is now, with replayed: true.

If your client times out, call again with the same key. See also Idempotency.

These endpoints call Apollo while you wait, and Pathbound paces its calls to Apollo. A call that Apollo rate-limits is retried for up to 45 seconds before it is answered 429 rate_limited.

GET /v1/integrations/apollo/senders

Required scope: actions:write

Returns the mailboxes an enrollment or a single email may name. Call it before you enroll or send, and take sender_account_id from it.

Terminal window
curl https://api.pathbound.ai/v1/integrations/apollo/senders \
-H "Authorization: Bearer $PATHBOUND_API_KEY"
{
"status": "success",
"senders": [
{
"sender_account_id": "66c8d9e0f1a2b3c4d5e6f701",
"email": "[email protected]",
"user_id": "66b7c8d9e0f1a2b3c4d5e6f7",
"is_default": true,
"active": true,
"provider": "Gmail",
"daily_limit": 50
}
],
"note": "Ask the user which mailbox to send from and confirm it by email address before enrolling or sending. There is no default."
}
FieldDescription
senders[].sender_account_idApollo’s ID for the mailbox. This is the value to send as sender_account_id.
senders[].emailThe mailbox’s address.
senders[].user_idThe Apollo user the mailbox belongs to.
senders[].is_defaultApollo’s own default flag. Pathbound does not use it to choose a mailbox.
senders[].activeAlways true here: inactive mailboxes are not listed.
senders[].providerThe mailbox provider, as Apollo names it.
senders[].daily_limitThe mailbox’s daily sending limit in Apollo, when it has one.
senders[].deliverabilityApollo’s figures for the mailbox, when it reports them: open_rate, reply_rate, bounce_rate, spam_block_rate, domain_health_score.
noteA sentence for a person or an AI agent. With no mailbox available it says how to add one.

An empty senders means no mailbox may be used: link an active mailbox in Apollo, or have an admin widen Allowed sender mailboxes. The list is read from Apollo and kept for up to a minute.

GET /v1/integrations/apollo/sequences

Required scope: actions:write

Returns the sequences in your Apollo team, including inactive ones created through Create a Sequence.

ParameterTypeDefaultDescription
qstring—Part of a sequence name, up to 200 characters.
include_archivedbooleanfalseInclude archived sequences.
pagenumber1Page number, 1 to 500.
per_pagenumber50Sequences per page, 1 to 100.
{
"status": "success",
"sequences": [
{
"sequence_id": "66f1a2b3c4d5e6f701234567",
"name": "Q4 renewals",
"active": false,
"archived": false,
"num_steps": 3,
"schedule_id": "66e0f1a2b3c4d5e6f7012345",
"is_owner": true,
"last_used_at": "2026-10-06T14:02:11.000Z",
"stats": {
"scheduled": 0,
"delivered": 42,
"opened": 30,
"clicked": 4,
"replied": 6,
"bounced": 1
}
}
],
"page": 1,
"per_page": 50,
"total": 12,
"total_pages": 1
}
FieldDescription
sequences[].sequence_idApollo’s ID for the sequence. Use it in the paths below.
sequences[].activeWhether the sequence is on.
sequences[].num_stepsThe number of steps.
sequences[].schedule_idThe sending schedule in force. Absent when the sequence uses Apollo’s team default. Resolve it with List Sequence Options.
sequences[].ruleset_idThe ruleset applied when the sequence was created. Absent when there is none.
sequences[].is_ownerWhether the Apollo user behind the connection owns the sequence.
sequences[].statsApollo’s counts for the sequence: scheduled, delivered, opened, clicked, replied, bounced. Also reply_rate, open_rate and bounce_rate, as Apollo reports them.
total, total_pagesApollo’s totals for the search. They count archived sequences too.

Archived sequences are taken out of each page after Apollo returns it, so a page can hold fewer than per_page sequences.

GET /v1/integrations/apollo/sequence-options

Required scope: actions:write

Returns the two things a sequence can be pointed at: the team’s sending schedules, and the rulesets already applied to the team’s sequences. It takes no parameters.

A sending schedule decides the days and hours Apollo may send a sequence’s emails. You can read the schedules and attach one to a sequence. The windows themselves are edited only in Apollo, under Settings → Sequences → Schedules.

A ruleset is a set of shared settings applied to a sequence. Apollo has no way to list or name rulesets, so this endpoint reports the ruleset IDs found on the team’s sequences, with the sequences that use each one.

{
"status": "success",
"schedules": [
{
"schedule_id": "66e0f1a2b3c4d5e6f7012345",
"name": "Normal Business Hours",
"is_default": true,
"time_zone": "America/Chicago",
"use_contacts_time_zone": false,
"skip_holidays": true,
"windows": {
"monday": [[8, 17]],
"tuesday": [[8, 17]],
"wednesday": [[8, 17]],
"thursday": [[8, 17]],
"friday": [[8, 17]]
},
"sending_hours": "Mon–Fri 8:00–17:00"
}
],
"rulesets_in_use": [
{
"ruleset_id": "66d9e0f1a2b3c4d5e6f70123",
"sequence_count": 4,
"used_by": ["Q4 renewals", "Trial follow-up"]
}
],
"note": "Sending windows are set in Apollo (Settings → Sequences → Schedules); …"
}
FieldDescription
schedules[].windowsDay of the week to a list of [start_hour, end_hour] pairs in 24-hour time. A day without a window is left out.
schedules[].sending_hoursThe same windows as one line of text. Empty when the schedule sends on no day.
schedules[].time_zoneThe time zone the windows are in.
schedules[].use_contacts_time_zoneWhen true, Apollo sends in each contact’s own time zone instead.
rulesets_in_use[].used_byUp to five sequences that use the ruleset, so a person can recognize it.

rulesets_in_use is read from the team’s first 100 sequences.

POST /v1/integrations/apollo/sequences

Required scope: actions:write

Required header: Idempotency-Key

Creates a sequence of 1 to 10 email steps in your Apollo team. The sequence is created inactive and nobody is enrolled, so this call sends nothing. Its steps are ready to send: once contacts are enrolled, activating the sequence is all that starts the emails.

FieldTypeRequiredDescription
namestringyesThe sequence’s name, 1 to 200 characters.
stepsobject[]yes1 to 10 email steps, in order.
steps[].bodystringyesThe email body, up to 100,000 characters. Apollo’s personalization variables, such as {{first_name}}, are passed on as written.
steps[].body_formatstringnohtml (default) or text. Text is converted to HTML.
steps[].subjectstringfor a new threadThe subject, up to 998 characters. Required on a step that starts a new thread. Leave it out on a reply.
steps[].wait_timenumberyesHow long to wait after the previous step, 0 to 365.
steps[].wait_modestringyesThe unit of wait_time: minute, hour or day.
steps[].thread_modestringnonew_thread or reply_to_thread. The first step is new_thread and cannot be anything else. Later steps default to reply_to_thread.
steps[].include_signaturebooleannoAppend the sender’s Apollo signature. Default true.
labelsstring[]noUp to 10 Apollo labels, each 1 to 100 characters.
max_emails_per_daynumbernoThe sequence’s daily cap in Apollo, 1 to 1000.
schedule_idstringnoA sending schedule from List Sequence Options. Without it the sequence uses Apollo’s team default. You can change it later.
ruleset_idstringnoA ruleset from List Sequence Options. Without it the sequence has none. It cannot be set or changed after the sequence is created.
{
"name": "Q4 renewals",
"steps": [
{
"subject": "Your renewal in December",
"body": "<p>Hi {{first_name}},</p><p>Your plan renews on December 1.</p>",
"wait_time": 0,
"wait_mode": "day"
},
{
"body": "<p>Hi {{first_name}}, a quick follow-up on my note below.</p>",
"wait_time": 3,
"wait_mode": "day"
}
]
}

Some settings are fixed. Every step is an automatic email with one version of its text. The sequence finishes for a contact who replies or is marked interested, pauses for one who answers with an out-of-office message, and keeps to Apollo’s bounce list.

{
"status": "success",
"action_id": "670f3a1b2c3d4e5f60718293",
"sequence_id": "66f1a2b3c4d5e6f701234567",
"sequence_name": "Q4 renewals",
"active": false,
"num_steps": 2,
"note": "Created as an inactive draft. …"
}

schedule_id and ruleset_id are returned when the sequence has them. action_id is the ID of Pathbound’s record of the action.

POST /v1/integrations/apollo/sequences/:sequence_id/activate
POST /v1/integrations/apollo/sequences/:sequence_id/pause

Required scope: actions:write

Required header: Idempotency-Key

activate turns the sequence on: Apollo starts sending its steps to every enrolled contact, from the mailbox each was enrolled with, on the sequence’s schedule. pause turns it off: every enrolled contact is paused and nothing more is sent until the sequence is activated again. To stop particular contacts, use Stop Contacts.

Neither takes a body.

ParameterTypeDescription
sequence_idstringApollo’s sequence ID, from List Sequences or Create a Sequence.
{
"status": "success",
"action_id": "670f3a1c2c3d4e5f60718294",
"sequence_id": "66f1a2b3c4d5e6f701234567",
"sequence_name": "Q4 renewals",
"active": true,
"num_steps": 2,
"scheduled": 18,
"note": "Sequence is active: Apollo now sends its steps to enrolled contacts on the sequence schedule. …"
}

active is the state Apollo reports after the call, not the one you asked for. scheduled is the sequence’s scheduled count, as Apollo reports it.

POST /v1/integrations/apollo/sequences/:sequence_id/schedule

Required scope: actions:write

Required header: Idempotency-Key

Points a sequence at one of the team’s sending schedules. This changes the days and hours its emails may go out, for contacts already enrolled too. Only the schedule is changed: the steps, the owner and the on or off state are not touched.

FieldTypeRequiredDescription
schedule_idstringyesA schedule_id from List Sequence Options.

A schedule that is not in your Apollo team is refused with 404 not_found. A schedule with no sending windows is refused with 400 validation, because Apollo does not accept an empty one.

{
"status": "success",
"action_id": "670f3a1d2c3d4e5f60718295",
"sequence_id": "66f1a2b3c4d5e6f701234567",
"sequence_name": "Q4 renewals",
"schedule_id": "66e0f1a2b3c4d5e6f7012345",
"schedule_name": "Normal Business Hours",
"sending_hours": "Mon–Fri 8:00–17:00",
"time_zone": "America/Chicago",
"use_contacts_time_zone": false,
"active": false,
"num_steps": 2,
"note": "Emails for this sequence now go out Mon–Fri 8:00–17:00 (America/Chicago). …"
}
POST /v1/integrations/apollo/sequences/:sequence_id/contacts

Required scope: actions:write

Required header: Idempotency-Key

Enrolls up to 25 contacts in an existing sequence, from the mailbox you name. If the sequence is active, Apollo starts emailing them on the sequence’s schedule. If it is inactive, nothing is sent until it is activated.

ParameterTypeDescription
sequence_idstringApollo’s sequence ID.
FieldTypeRequiredDescription
contact_idsstring[]yes1 to 25 Pathbound contact IDs. Duplicates count once.
sender_account_idstringyesThe mailbox to send from: a sender_account_id from List Senders.
start_atstringnoAn ISO 8601 time in the future. The contacts are enrolled paused, and Apollo starts them at that time. Without it they start in the sequence’s next sending window.
tagsstring[]noUp to 20 tags, each up to 64 characters, written on every contact that was enrolled.
Terminal window
curl -X POST https://api.pathbound.ai/v1/integrations/apollo/sequences/66f1a2b3c4d5e6f701234567/contacts \
-H "Authorization: Bearer $PATHBOUND_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: q4-renewals-batch-1" \
-d '{
"contact_ids": [
"665f1c2ab3d4e5f601234567",
"665f1c2ab3d4e5f601234568",
"665f1c2ab3d4e5f601234569"
],
"sender_account_id": "66c8d9e0f1a2b3c4d5e6f701",
"tags": ["campaign:q4-renewals"]
}'

Each contact is matched to a contact in your Apollo team by email address, or created there. That costs no Apollo credits.

Apollo decides whom it accepts. It refuses a contact who is already in another sequence, whose email is unverified, who is at a do-not-contact stage, and so on. Apollo has options that override these refusals, and Pathbound never sends them. A refused contact comes back in skipped with Apollo’s reason.

{
"status": "success",
"action_id": "670f3a1e2c3d4e5f60718296",
"sequence": { "sequence_id": "66f1a2b3c4d5e6f701234567", "name": "Q4 renewals" },
"sender_email": "[email protected]",
"requested": 3,
"enrolled": 2,
"enrolled_contact_ids": ["665f1c2ab3d4e5f601234567", "665f1c2ab3d4e5f601234568"],
"skipped": [
{ "contact_id": "665f1c2ab3d4e5f601234569", "reason": "no_email" }
],
"tags_applied": ["campaign:q4-renewals"]
}

start_at is echoed when you sent one. A call in which every contact is skipped is still a 200, with enrolled: 0.

skipped[].reasonMeaning
not_found_in_pathboundNo contact with this ID in your workspace.
no_emailThe contact has no email address.
already_enrolledThe contact is already active or paused in this sequence.
bridge_failedThe contact could not be matched or created in Apollo.
anything elseApollo’s own reason for refusing the contact, as Apollo wrote it.

A workspace may enroll a set number of contacts a day through these endpoints and the MCP tools together, counted in UTC. Skipped contacts do not count. A call that would pass the cap is refused with 429 budget_exceeded.

To enroll every member of a saved segment as a background job, use POST /v1/segments/:ref/actions.

POST /v1/integrations/apollo/sequences/:sequence_id/contacts/stop

Required scope: actions:write

Required header: Idempotency-Key

Stops up to 25 contacts in a sequence so that no further step is sent to them, or removes them from it.

FieldTypeRequiredDescription
contact_idsstring[]yes1 to 25 Pathbound contact IDs.
modestringnostop (default) ends future steps and keeps the contact’s history in the sequence. remove takes the contact out of the sequence.
reasonstringnoA short reason, up to 300 characters. It is kept on Pathbound’s record and on the contact’s timeline.
{
"status": "success",
"action_id": "670f3a1f2c3d4e5f60718297",
"sequence_id": "66f1a2b3c4d5e6f701234567",
"mode": "stop",
"requested": 2,
"updated": 1,
"updated_contact_ids": ["665f1c2ab3d4e5f601234567"],
"skipped": [
{ "contact_id": "665f1c2ab3d4e5f601234569", "reason": "not_enrolled" }
]
}

updated counts the contacts Apollo was asked to stop or remove. A contact is skipped with not_found_in_pathbound, or with not_enrolled when Pathbound has never enrolled or emailed it through Apollo. Pathbound does not check with Apollo that each of the others was in this sequence.

GET /v1/integrations/apollo/contacts/:contact_id/sequence-activity

Required scope: actions:write

Returns what happened to one contact in Apollo sequences: Pathbound’s own enrollment records, and Apollo’s activity feed for the contact.

This read counts toward your usage the way reading the contact’s timeline does. See Usage and metering.

ParameterTypeDescription
contact_idstringThe Pathbound contact ID.
ParameterTypeDefaultDescription
sequence_idstring—Only this sequence.
{
"status": "success",
"contact_id": "665f1c2ab3d4e5f601234567",
"apollo_contact_id": "66a6b7c8d9e0f1a2b3c4d5e6",
"enrollments": [
{
"sequence_id": "66f1a2b3c4d5e6f701234567",
"sequence_name": "Q4 renewals",
"status": "replied",
"sender_email": "[email protected]",
"enrolled_at": "2026-10-06T14:02:11.000Z",
"last_event_at": "2026-10-08T09:41:27.000Z"
}
],
"events": [
{
"type": "replied",
"occurred_at": "2026-10-08T09:41:27.000Z",
"sequence_id": "66f1a2b3c4d5e6f701234567",
"sequence_name": "Q4 renewals",
"step_position": 1
},
{
"type": "enrolled",
"occurred_at": "2026-10-06T14:02:11.000Z",
"sequence_id": "66f1a2b3c4d5e6f701234567",
"sequence_name": "Q4 renewals"
}
]
}
FieldDescription
enrollments[]Pathbound’s records of the enrollments made through Pathbound, latest first. start_at is present for a delayed start, and reason when a stop gave one.
enrollments[].statusenrolled, paused, replied, bounced, finished, stopped, removed or failed.
events[]Up to 50 entries of Apollo’s activity feed for the contact.
events[].typeenrolled, paused, resumed, replied, completed, removed or failed.
notePresent when the contact was never enrolled or emailed through Apollo by Pathbound. events is then empty.

Opens, clicks and replies to each message are on the contact’s timeline, as events.

POST /v1/integrations/apollo/contacts/:contact_id/send_email

Required scope: actions:write

Required header: Idempotency-Key

Sends one email to a contact through Apollo, from the mailbox you name, now or at send_at. The email goes to the contact’s email address, read from the contact record. The request cannot set it.

ParameterTypeDescription
contact_idstringThe Pathbound contact to email.
FieldTypeRequiredDescription
sender_account_idstringyesThe mailbox to send from: a sender_account_id from List Senders.
subjectstringyesThe subject, up to 998 characters.
bodystringyesThe email body.
body_formatstringnohtml (default) or text. Text is converted to HTML.
ccstring[]noUp to 5 addresses.
bccstring[]noUp to 5 addresses.
trackbooleannoApollo’s open and click tracking. Default true.
send_atstringnoAn ISO 8601 time within the next 30 days. Without it, or with a time less than a minute away, the email is sent now.
Terminal window
curl -X POST https://api.pathbound.ai/v1/integrations/apollo/contacts/665f1c2ab3d4e5f601234567/send_email \
-H "Authorization: Bearer $PATHBOUND_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: followup-665f1c2a-2026-10-13" \
-d '{
"sender_account_id": "66c8d9e0f1a2b3c4d5e6f701",
"subject": "Following up on Thursday",
"body": "Hi Ada,\n\nHere are the notes from our call.",
"body_format": "text"
}'

The answer is 202 when the email was scheduled and 200 otherwise.

{
"status": "success",
"email": {
"scheduled_email_id": "670f3b2c3d4e5f6071829304",
"contact_id": "665f1c2ab3d4e5f601234567",
"sender_account_id": "66c8d9e0f1a2b3c4d5e6f701",
"subject": "Following up on Thursday",
"send_at": "2026-10-13T15:04:05.000Z",
"status": "sent",
"attempts": 1,
"apollo_message_id": "670f3b2d9a8b7c6d5e4f3a2b",
"sent_from": "[email protected]",
"sent_at": "2026-10-13T15:04:08.000Z",
"action_id": "670f3b2c3d4e5f6071829303",
"created_at": "2026-10-13T15:04:05.000Z"
}
}

A 200 does not mean the email was sent. Read email.status. Once the request has passed its checks, whatever happens to the email is reported on the email, not as an HTTP error.

email.statusMeaning
scheduledWaiting for send_at.
sentApollo reports the email sent. sent_at is when, and sent_from is the address Apollo used.
sendingApollo has the email and has not confirmed it yet, because it paces each mailbox. Pathbound keeps checking. Look again with List Scheduled Emails.
delayedNot sent yet. It is tried again at next_attempt_at, and failure says why.
failedNot sent, and it will not be tried again. failure.code and failure.message say why.
canceledCanceled before it was sent.

The body of the email is not returned.

Pathbound holds a scheduled email itself and hands it to Apollo at send_at. At that moment, and for an email sent now, it checks again that:

  • the API key that asked is still active and still has actions:write, and its owner is still a verified member of the workspace (principal_revoked otherwise);
  • Single email is still on and the Apollo connection still works;
  • the contact still exists, and its email address is the one it had when you asked (recipient_changed otherwise);
  • the mailbox may still be used.

An email that fails one of these ends failed. It is never sent from another mailbox or to another address.

An email is delayed and tried again when the mailbox has reached its Apollo sending limit (an hour later), when Apollo rate-limits the call, when Apollo fails (15 minutes later), or when the workspace has sent its daily allowance of single emails (at the start of the next day, UTC). After four attempts it ends failed.

An email is handed to Apollo at most once. If Apollo’s answer is lost, the email stays sending while Pathbound asks Apollo for its status, and it ends failed with failure.code unconfirmed if Apollo never confirms it. Such an email may have gone out: look at the message in Apollo before you send it again.

failure.code is one of the error codes below, principal_revoked, recipient_changed, unconfirmed, or Apollo’s own reason when Apollo reports that the send failed.

GET /v1/integrations/apollo/scheduled-emails

Required scope: actions:write

Returns the single emails created through Send an Email, whatever their state, latest send_at first. Emails that were sent at once are listed too.

ParameterTypeDefaultDescription
contact_idstring—Only emails to this contact.
statusstring—One of scheduled, sending, delayed, sent, failed, canceled.
limitnumber50The most emails to return, 1 to 200.
{
"status": "success",
"emails": [
{
"scheduled_email_id": "670f3b2c3d4e5f6071829305",
"contact_id": "665f1c2ab3d4e5f601234567",
"sender_account_id": "66c8d9e0f1a2b3c4d5e6f701",
"subject": "Your renewal in December",
"send_at": "2026-10-20T14:00:00.000Z",
"status": "scheduled",
"attempts": 0,
"sent_from": "[email protected]",
"action_id": "670f3b2c3d4e5f6071829306",
"created_at": "2026-10-13T15:10:00.000Z"
}
]
}

Each entry has the fields of email in Send an Email. Before an email is sent, sent_from is the address of the mailbox you chose.

DELETE /v1/integrations/apollo/scheduled-emails/:id

Required scope: actions:write

Cancels an email that is scheduled or delayed. An email in any other state cannot be canceled, and the call is refused with 409 validation and the state in details.status. The Idempotency-Key header is optional here.

ParameterTypeDescription
idstringThe scheduled_email_id of the email.
{
"status": "success",
"email": {
"scheduled_email_id": "670f3b2c3d4e5f6071829305",
"contact_id": "665f1c2ab3d4e5f601234567",
"sender_account_id": "66c8d9e0f1a2b3c4d5e6f701",
"subject": "Your renewal in December",
"send_at": "2026-10-20T14:00:00.000Z",
"status": "canceled",
"attempts": 0,
"sent_from": "[email protected]",
"action_id": "670f3b2c3d4e5f6071829306",
"created_at": "2026-10-13T15:10:00.000Z"
}
}

An email that was still scheduled created nothing in Apollo, so there is nothing to remove there. A delayed email has been through a send attempt: the contact was matched or created in Apollo and a draft message was written there before the send was refused, and canceling does not remove them. Delete the draft in Apollo if you do not want it kept.

Each enrollment, each stop and each email that was sent is written to the contact’s timeline as a pathbound_action event. Its data.action_type is apollo_add_to_sequence, apollo_stop_in_sequence or apollo_send_email, and data carries the sequence, the subject and the sending address, as they apply.

What recipients then do is read back from Apollo about every 30 minutes and written to the same timeline: apollo_email_sent, apollo_email_opened, apollo_email_clicked, apollo_email_replied, apollo_email_bounced, apollo_email_unsubscribed, apollo_email_spam_blocked, apollo_sequence_finished, apollo_sequence_stopped and apollo_sequence_failed.

An error has the shape { "status": "error", "code": "…", "error": "…" }, with a hint and details where the tables name them. See Errors for the answers every endpoint shares.

StatuscodeMeaning
400noneA path, query or body value failed validation. details lists each field.
403noneThe API key does not have actions:write. required_scopes lists it.
412integration_missingApollo is not connected. Connect it under Integrations.
412invalid_credentialsApollo no longer accepts the connection. Reconnect Apollo.
412needs_reconsentThe connection predates the permissions this endpoint needs (details.missing_scopes). A workspace admin reconnects Apollo.
412tool_disabledThe switch for this endpoint is off (details.tool). A workspace admin turns it on under MCP Tools → Apollo.
412plan_requiredApollo refused the call for the Apollo plan or for the permissions of the connection. If the plan is a paid one, reconnect Apollo.
403forbiddenApollo refused the call for another reason. The message carries Apollo’s own.
404not_foundApollo answered that the record does not exist.
409dnc_blockedApollo’s Do Not Contact settings block the call.
422validationApollo rejected the request. The message carries Apollo’s own.
429mailbox_limitApollo answered that the sending mailbox reached its limit. Try later, or choose another mailbox.
429rate_limitedApollo’s rate limit held after retries. details.retry_after is in seconds.
502upstream_errorApollo failed or did not answer.
500upstream_error or noneThe call failed unexpectedly.

The first four 412 answers are checked in the order of the table: connected, accepted, permissions, switch.

GET /v1/integrations/apollo/scheduled-emails and DELETE /v1/integrations/apollo/scheduled-emails/:id do not call Apollo. Of the rows above, only the 400 and the scope 403 apply to them.

StatuscodeMeaning
400IDEMPOTENCY_KEY_REQUIREDThe Idempotency-Key header is missing.
409ACTION_IN_PROGRESSA call with this key is still running. Wait and call again with the same key.
StatuscodeMeaning
400validationCreate: the first step is not a new thread, or a step that starts a new thread has no subject. Schedule: the schedule has no sending windows.
404not_foundSchedule: the schedule_id is not one of your team’s schedules.
StatuscodeMeaning
400validationEnroll: start_at is not in the future.
400sender_inactiveEnroll: the mailbox is inactive or disconnected in Apollo. Choose another from List Senders.
403sender_not_allowedEnroll: the mailbox is not one you may send from. An admin can widen Allowed sender mailboxes.
404noneActivity: the contact does not exist in your workspace.
429budget_exceededEnroll: the workspace’s enrollments for the day are used (details.cap, details.used). Try again the next day, UTC.
StatuscodeMeaning
400validationsend_at is more than 30 days ahead.
400sender_inactiveSend: the mailbox is inactive or disconnected in Apollo.
403sender_not_allowedSend: the mailbox is not one you may send from.
404not_foundThe contact, or the scheduled email, does not exist in your workspace.
409validationCancel: the email is no longer scheduled or delayed (details.status).
422validationThe contact has no email address (details.code is CONTACT_EMAIL_MISSING).

Everything Apollo refuses after these checks, such as a contact under Do Not Contact or a mailbox at its limit, is reported in email.status and email.failure, not as an HTTP error.