Skip to content
Pathbound DOCS

Resend

These endpoints act in the Resend account your workspace has connected. You name a Pathbound contact, and Pathbound reads the address from the contact record and makes the call to Resend with your workspace’s Resend API key. Use them to keep Resend segments in step with what you know about your customers, to send a branded or templated email from your sending domain, and to start automations you built in Resend.

Pathbound also reads your Resend contacts, segments and domains on a schedule, so a contact’s segment membership and subscription status are on its profile. That sync only reads. For a one-to-one email from a person’s own mailbox, use Gmail.

Before the first call, connect Resend, create an API key with the actions:write scope, and have a workspace admin switch on the actions you need: see Before you call. The MCP tools whose names start with resend_ call the same endpoints: see MCP tools.

EndpointScopeWhat it does
GET /v1/integrations/resend/segmentsactions:writeLists the segments in your Resend account.
POST /v1/integrations/resend/segmentsactions:writeCreates a segment.
POST /v1/integrations/resend/segments/:segment_id/contactsactions:writeAdds up to 25 contacts to a segment.
DELETE /v1/integrations/resend/segments/:segment_id/contacts/:contact_idactions:writeRemoves one contact from a segment.
DELETE /v1/integrations/resend/segments/:segment_idactions:writeDeletes a segment.
GET /v1/integrations/resend/contacts/:contact_id/segmentscontacts:readLists the segments a contact is in.
GET /v1/integrations/resend/contacts/:contact_id/emailscontacts:readLists the emails Pathbound sent to a contact through Resend.
POST /v1/integrations/resend/contacts/:contact_id/emailsactions:writeSends an email to a contact.
GET /v1/integrations/resend/eventsactions:writeLists the events your Resend account defines.
POST /v1/integrations/resend/contacts/:contact_id/eventsactions:writeSends one event for a contact.
POST /v1/integrations/resend/broadcastsactions:writeCreates a broadcast to a segment. Does not send it.
POST /v1/integrations/resend/broadcasts/:broadcast_id/sendactions:writeSends or schedules a broadcast.

Resend is connected. Connect it under Integrations → Resend in the dashboard, with a Resend API key that has Full access. A key with sending access only cannot read the account’s domains, segments and templates, which these endpoints depend on.

The scope. actions:write is opt-in: a key holds it only when it was selected for that key. See Scopes.

The admin switches. A workspace admin switches each group of actions on under MCP Tools → Resend in the dashboard. Every switch is off until an admin turns it on. The page is named for AI agents, but the API checks a switch on every request to the endpoints it governs: an API key is held to it exactly as an agent is. With a switch off, its endpoints answer 412 with the code tool_disabled.

SwitchName in error messagesEndpoints it governs
Manage segmentsresend_manage_segmentsCreate a segment, add contacts, remove a contact, delete a segment.
Send emailresend_send_emailSend an email.
Send eventsresend_send_eventList events, send an event.
Create broadcastsresend_manage_broadcastsCreate a broadcast.
Send broadcastsresend_send_broadcastsSend a broadcast.

Three reads are governed by the key’s scope alone and work with every switch off: List Segments, List a Contact’s Segments and List Emails Sent to a Contact. For an AI agent, the matching tools are still hidden while their switch is off.

GET /v1/tenant/capabilities reports which switches are on, under tool_settings.

Contacts are named by their Pathbound id. The address is read from the contact record, so a request never carries the contact’s address.

Resend’s own ids. segment_id and broadcast_id are the ids Resend gives its objects. An id has to be one plain token of letters, digits, _ and -. Anything else is refused with 400.

The sender. from on an email or a broadcast has to be on a domain that is verified for sending in your Resend account, written as [email protected] or Acme <[email protected]>. Otherwise the request is refused with 422 FROM_NOT_VERIFIED, and available_domains lists the domains you can use. Pathbound learns about a newly verified domain at its next Resend sync.

Idempotency. The endpoints that create or send take an Idempotency-Key header, and each endpoint below says whether it requires one. A request with a key that succeeded in the last 24 hours returns the first answer with replayed: true and does nothing again. See Idempotency.

StatuscodeMeaningWhat to do
400noneA parameter is not valid. details names it.
400IDEMPOTENCY_KEY_REQUIREDThe endpoint requires the Idempotency-Key header.
403noneThe key lacks the scope. required_scopes names it.
409ACTION_IN_PROGRESSA request with this Idempotency-Key is still being processed.Ask again with the same key.
412integration_missingResend is not connected.Connect Resend.
412invalid_credentialsThe stored Resend API key no longer works.Connect Resend again with a working key.
412tool_disabledA workspace admin has not switched this action on.Switch it on under MCP Tools → Resend.
404RESEND_NOT_FOUNDResend does not know the segment, broadcast or contact.
422RESEND_REJECTEDResend refused the request. error is Resend’s own reason, for example a plan limit, and resend_status is the status Resend answered with.
429RATE_LIMITEDResend’s rate limit was reached.Retry after retry_after_seconds.
500noneThe request failed. Resend may or may not have carried it out.Where the endpoint takes an Idempotency-Key, retry with the same key, and read the endpoint’s notes on retrying.

When Resend refuses the stored key, Pathbound treats the key as dead, and every later request is answered with 412 invalid_credentials until Resend is connected again. The request that meets the refusal is answered by what Resend said:

  • a 401 or a 403 is answered with 412 invalid_credentials at once (the two event endpoints are the exception for a 403);
  • Resend answers a revoked key with a 400, and that request is answered with 422 RESEND_REJECTED and resend_status: 400. On Add Contacts to a Segment it is answered 200 with every contact failed.
GET /v1/integrations/resend/segments

Required scope: actions:write

Returns every segment in your Resend account, read from Resend at the time of the call. Use it to find a segment_id.

Terminal window
curl https://api.pathbound.ai/v1/integrations/resend/segments \
-H "Authorization: Bearer $PATHBOUND_API_KEY"
{
"status": "success",
"segments": [
{
"id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"name": "Trial users",
"created_at": "2026-10-02T09:14:51.000Z"
}
]
}

Each segment is returned as Resend holds it.

POST /v1/integrations/resend/segments

Required scope: actions:write · Switch: Manage segments

HeaderRequiredDescription
Idempotency-KeyyesA key of your choosing for this one segment.
FieldTypeRequiredDescription
namestringyesThe segment’s name. At most 255 characters.
{
"status": "success",
"action_id": "670bd4a9a1b2c3d4e5f60750",
"segment_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"name": "Trial users"
}

Resend limits the number of segments by plan. At the limit, the answer is 422 RESEND_REJECTED with Resend’s message.

After a 500, list the segments before you retry: Resend may have created the segment, and a retry would then create a second one with the same name.

POST /v1/integrations/resend/segments/:segment_id/contacts

Required scope: actions:write · Switch: Manage segments

Adds up to 25 Pathbound contacts to a Resend segment. For each one, Pathbound reads the email, first name and last name from the contact record, creates the contact in Resend if it is not there yet, and adds it to the segment.

This endpoint takes no Idempotency-Key: adding a contact that is already in the segment changes nothing.

To add everyone in a saved Pathbound segment, however many, run the resend_add_to_segment action on it as a background job: see Run an Action on a Segment. To send to the whole segment afterwards, create a broadcast for the Resend segment and send it.

ParameterTypeDescription
segment_idstringThe Resend segment’s id.
FieldTypeRequiredDescription
contact_idsstring[]yes1 to 25 Pathbound contact ids.
Terminal window
curl -X POST https://api.pathbound.ai/v1/integrations/resend/segments/78261eea-8f8b-4381-83c6-79fa7120f1cf/contacts \
-H "Authorization: Bearer $PATHBOUND_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "contact_ids": ["665f1c2ab3d4e5f601234567", "665f1c2ab3d4e5f601234568"] }'
{
"status": "success",
"action_id": "670bd5f0a1b2c3d4e5f60755",
"segment_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"results": [
{ "contact_id": "665f1c2ab3d4e5f601234568", "status": "skipped", "error": "contact_email_missing" },
{ "contact_id": "665f1c2ab3d4e5f601234567", "status": "added", "resend_contact_id": "e169aa45-1ecf-4183-9955-b1499d5701d3" }
],
"summary": { "added": 1, "skipped": 1, "failed": 0 }
}

The request succeeds as a whole even when some contacts do not: read results. They are not in the order you sent, so match them by contact_id.

statusMeaning
addedThe contact is in the segment. resend_contact_id is Resend’s id for the contact, when Resend returned one.
skippedNothing was sent to Resend. error is contact_not_found (no such contact in your workspace) or contact_email_missing.
failedResend refused this contact. error is Resend’s reason.

A 401 or 403 from Resend, or its rate limit, fails the whole request with 412 or 429. Contacts that were added before that point stay in the segment, so the request can be sent again as it is. A key that Resend has revoked is different: every contact comes back failed in a 200, as described under Errors on every endpoint.

DELETE /v1/integrations/resend/segments/:segment_id/contacts/:contact_id

Required scope: actions:write · Switch: Manage segments

Removes one contact from a Resend segment. The contact itself stays in Resend.

ParameterTypeDescription
segment_idstringThe Resend segment’s id.
contact_idstringThe Pathbound contact’s id.
{
"status": "success",
"segment_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf",
"contact_id": "665f1c2ab3d4e5f601234567"
}
DELETE /v1/integrations/resend/segments/:segment_id

Required scope: actions:write · Switch: Manage segments

Deletes the segment in Resend. This cannot be undone. The contacts that were in it are not deleted.

{
"status": "success",
"segment_id": "78261eea-8f8b-4381-83c6-79fa7120f1cf"
}

In addition to the errors on every endpoint:

StatuscodeMeaning
404noneRemove a contact: no such contact in your workspace.
422CONTACT_EMAIL_MISSINGRemove a contact: the contact has no email address.
GET /v1/integrations/resend/contacts/:contact_id/segments

Required scope: contacts:read

Returns the Resend segments a contact is in, as of the last Resend sync. A contact you added to a segment a moment ago appears here after the next sync.

{
"status": "success",
"segments": [
{ "id": "78261eea-8f8b-4381-83c6-79fa7120f1cf", "name": "Trial users" }
]
}

segments is empty when the contact is not in Resend. A contact that does not exist in your workspace is answered with 404.

GET /v1/integrations/resend/contacts/:contact_id/emails

Required scope: contacts:read

Returns the emails Pathbound sent to this contact through Resend, newest first, 50 at most. That covers emails sent with Send an Email and emails sent by an email automation. Email sent from Resend without Pathbound is not listed.

{
"status": "success",
"emails": [
{
"id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
"subject": "Your invoice for October",
"status": "succeeded",
"sent_at": "2026-10-13T14:31:07.204Z"
}
]
}
FieldDescription
idResend’s id for the email.
statusAlways succeeded: Resend accepted the email. It is not a delivery status.
sent_atWhen Resend accepted it. Absent on an email that was scheduled.
scheduled_atPresent on a scheduled email: the time as it was given in the request.
POST /v1/integrations/resend/contacts/:contact_id/emails

Required scope: actions:write · Switch: Send email

Sends one email to a contact through Resend, from your verified sending domain. The email is written in the request, or is a template of your Resend account.

ParameterTypeDescription
contact_idstringThe contact to email. The recipient is the address on the contact record.
HeaderRequiredDescription
Idempotency-KeyyesA key of your choosing for this one email.
FieldTypeRequiredDescription
fromstringyesThe sender, on a verified domain.
subjectstringyesThe subject line. At most 998 characters.
bodystringone of the twoThe email’s content.
template_idstringone of the twoThe id of a template in your Resend account. When both are sent, the template is used and body is ignored.
body_formatstringnohtml (the default) or text. Applies to body.
ccstring[]noAddresses to copy.
bccstring[]noAddresses to copy without showing them.
reply_tostring[]noReply-to addresses.
scheduled_atstringnoWhen Resend should send the email, for example 2026-10-20T09:00:00Z. The value is passed to Resend as written. Leave it out to send now.
Terminal window
curl -X POST https://api.pathbound.ai/v1/integrations/resend/contacts/665f1c2ab3d4e5f601234567/emails \
-H "Authorization: Bearer $PATHBOUND_API_KEY" \
-H "Idempotency-Key: 5d0b6f1a-7c3e-4b92-a1d4-0e8f3c6b9a27" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <[email protected]>",
"subject": "Your invoice for October",
"body": "<p>Hi Ada,</p><p>Your invoice is ready on your account page.</p>"
}'
{
"status": "success",
"action_id": "670bd6b3a1b2c3d4e5f60761",
"email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
"sent_at": "2026-10-13T14:31:07.204Z",
"sender": "Acme <[email protected]>"
}

With scheduled_at, the response carries scheduled_at in place of sent_at. A scheduled email is held by Resend, not by Pathbound, and this API has no endpoint that cancels it.

The send appears on the contact’s timeline as a pathbound_action event with data.action_type set to resend_send_email.

Retrying. If the request fails with a 500 or you get no answer, retry with the same Idempotency-Key. Pathbound passes a key derived from yours to Resend, and Resend does not send the same email twice under one key within 24 hours.

In addition to the errors on every endpoint:

StatuscodeMeaning
400BODY_OR_TEMPLATE_REQUIREDThe request carries neither body nor template_id.
404noneNo such contact in your workspace.
422CONTACT_EMAIL_MISSINGThe contact has no email address.
422FROM_NOT_VERIFIEDfrom cannot be used. reason is domain_not_verified, or no_verified_domain when the account has no domain verified for sending. available_domains lists the usable ones.
GET /v1/integrations/resend/events

Required scope: actions:write · Switch: Send events

Returns the events your Resend account defines, with the payload fields each one declares. An event is what starts an automation built in Resend: a welcome series when user.created arrives, a follow-up when demo.booked does. You build the automation in Resend, with its steps, its delays and its templates, and Pathbound only sends the event that starts it. Events and automations are created in Resend, not through Pathbound.

To send an event for everyone who submits a form on your site, instead of one contact at a time, use a Resend event automation.

Terminal window
curl https://api.pathbound.ai/v1/integrations/resend/events \
-H "Authorization: Bearer $PATHBOUND_API_KEY"
{
"status": "success",
"events": [
{ "name": "demo.booked", "schema": { "plan": "string", "seats": "number" } },
{ "name": "user.created", "schema": null }
]
}
FieldDescription
events[].nameThe event’s name. Pass it to Send an Event exactly as returned.
events[].schemaThe payload fields the event declares, each with its type (string, number, boolean or date). null when it declares none.
truncatedtrue when the account has more events than were read. Pathbound reads the first 500.

Resend’s own system events, whose names start with resend:, are left out. The response does not say which automations an event starts or what they send: that is not visible from Pathbound.

POST /v1/integrations/resend/contacts/:contact_id/events

Required scope: actions:write · Switch: Send events

Sends one of your Resend events for one contact. Resend then runs every active automation that triggers on that event, for that contact. One contact per request.

A 200 means that Resend accepted the event. It does not mean that an email was sent: Pathbound cannot see which automations the event started or what they do.

ParameterTypeDescription
contact_idstringThe contact the event is for. It goes to the address on the contact record, and Resend creates the contact if it does not know the address.
HeaderRequiredDescription
Idempotency-KeyyesA key of your choosing for this one event.
FieldTypeRequiredDescription
eventstringyesThe event’s name, exactly as List Events returns it. Capitals count.
payloadobjectnoData for the automation. See below.

The body takes these two fields only. Any other field is refused with 400 UNKNOWN_FIELD, so a request cannot name an address, a Resend contact or a segment.

The event has to exist. Its name is checked against your account’s events before anything is sent, and a name that matches none is refused with 422 RESEND_EVENT_NOT_FOUND. A name that starts with resend: is never accepted.

The payload is a flat object: each value is a string, a number or a boolean, and a date is written as an ISO 8601 string. It holds at most 50 fields. A field name is letters, digits and underscores, at most 64 characters, and does not start with a digit. A string is at most 2,000 characters, and the whole payload at most 10,000 bytes as JSON. A payload that breaks one of these rules is refused whole and nothing is sent. The automation can print these values in its emails, so keep to the fields the event’s schema declares.

An unsubscribed contact is refused. A contact that Resend lists as unsubscribed, as of the last sync, gets 422 CONTACT_UNSUBSCRIBED and no event is sent.

Terminal window
curl -X POST https://api.pathbound.ai/v1/integrations/resend/contacts/665f1c2ab3d4e5f601234567/events \
-H "Authorization: Bearer $PATHBOUND_API_KEY" \
-H "Idempotency-Key: 9a3e7b52-4c1d-4f68-b0a9-6d2e8f1c5b74" \
-H "Content-Type: application/json" \
-d '{
"event": "demo.booked",
"payload": { "plan": "growth", "seats": 12 }
}'
{
"status": "success",
"action_id": "670bd8e2a1b2c3d4e5f60774",
"contact_id": "665f1c2ab3d4e5f601234567",
"event": "demo.booked",
"accepted_at": "2026-10-13T14:40:19.660Z",
"note": "Resend accepted the event. Which automations it started, and what they send, is decided in Resend and is not visible here."
}

The contact’s timeline gets a pathbound_action event with data.action_type set to resend_send_event and the event’s name. Pathbound keeps the names of the payload’s fields and never their values.

Resend does not deduplicate events: a second request is a second event, and it starts every automation again. So Pathbound sends an event one time and never repeats a send whose outcome it does not know.

  • The same Idempotency-Key within 24 hours returns the first answer with replayed: true. Nothing is sent again.
  • When Resend does not answer (a timeout, a dropped connection, a server error), the answer is 502 with the code SEND_UNCONFIRMED. Resend may have accepted the event. Do not retry: the same key gets SEND_UNCONFIRMED again for 24 hours, and a new key would send a second event. Check the automation’s runs in Resend first, and send again under a new Idempotency-Key only if the event did not arrive.
  • When Resend refuses the event with a clear answer, nothing was accepted, and you can correct the request and send it again under the same key.
{
"status": "error",
"error": "Resend did not answer; the event may have been accepted",
"code": "SEND_UNCONFIRMED",
"action_id": "670bd8e2a1b2c3d4e5f60774",
"hint": "Check the automation's runs in Resend before sending again. Do not retry this request: Resend does not deduplicate events, so a second one starts the automation again. To send deliberately, use a new Idempotency-Key."
}

In addition to the errors on every endpoint. Except for SEND_UNCONFIRMED, every error here means that no event was sent.

StatuscodeMeaningWhat to do
400UNKNOWN_FIELDThe body carries a field other than event and payload. details names it.Remove the field.
400noneevent is not a usable name, or payload breaks a rule. details says which.
404CONTACT_NOT_FOUNDNo such contact in your workspace.
422CONTACT_EMAIL_MISSINGThe contact has no email address.
422CONTACT_EMAIL_INVALIDThe contact’s email is not one plain address.
422CONTACT_UNSUBSCRIBEDThe contact is unsubscribed in Resend.Nothing. Resubscribing is the contact’s own choice.
422RESEND_EVENT_NOT_FOUNDYour Resend account defines no event of this name.Use a name from List Events, or create the event in Resend.
422RESEND_REJECTEDResend refused the request, for example because a payload value has the wrong type for a field the event declares. error is Resend’s reason.Correct the request.
502RESEND_UNAVAILABLEResend could not be reached while Pathbound read your account’s events.Retry with the same key.
502RESEND_UNEXPECTED_RESPONSEResend answered in a form Pathbound does not recognize.Retry later with the same key.
502SEND_UNCONFIRMEDResend did not answer. The event may have been accepted.Do not retry. Check the automation’s runs in Resend.

On these two endpoints a 403 from Resend is answered with 422 RESEND_REJECTED and Resend’s reason, and does not mark your key as dead.

POST /v1/integrations/resend/broadcasts

Required scope: actions:write · Switch: Create broadcasts

Creates a broadcast in Resend: one email addressed to a whole segment. It is not sent until you call Send a Broadcast. A broadcast always goes to a segment.

HeaderRequiredDescription
Idempotency-KeyyesA key of your choosing for this one broadcast.
FieldTypeRequiredDescription
namestringyesA name for the broadcast.
segment_idstringyesThe Resend segment to send to.
fromstringyesThe sender, on a verified domain.
subjectstringyesThe subject line. At most 998 characters.
bodystringyesThe email’s content. A broadcast cannot use a template.
body_formatstringnohtml (the default) or text.
preview_textstringnoThe preview text shown in the inbox.
reply_tostring[]noReply-to addresses.

A broadcast can use Resend’s personalization placeholders in its subject and body: {{{FIRST_NAME|fallback}}}, {{{LAST_NAME|fallback}}}, {{{EMAIL}}} and {{{RESEND_UNSUBSCRIBE_URL}}}.

{
"status": "success",
"action_id": "670bda15a1b2c3d4e5f60782",
"broadcast_id": "559ac32e-9ef5-46fb-82a1-b76b840c0f7b"
}

Keep broadcast_id: this API has no endpoint that lists broadcasts.

After a 500, a retry can create a second broadcast. Neither one is sent until you send it.

POST /v1/integrations/resend/broadcasts/:broadcast_id/send

Required scope: actions:write · Switch: Send broadcasts

Sends a broadcast to every contact in its segment, now or at scheduled_at. Check the broadcast and the size of its segment before you call this.

This endpoint takes no Idempotency-Key. Resend refuses to send a broadcast that has already been sent.

ParameterTypeDescription
broadcast_idstringThe id returned by Create a Broadcast.
FieldTypeRequiredDescription
scheduled_atstringnoWhen Resend should send the broadcast, for example 2026-10-20T09:00:00Z. The value is passed to Resend as written. Leave it out to send now.
{
"status": "success",
"action_id": "670bdb47a1b2c3d4e5f60790",
"broadcast_id": "559ac32e-9ef5-46fb-82a1-b76b840c0f7b"
}

With scheduled_at, the response carries it back as given.

In addition to the errors on every endpoint:

StatuscodeMeaning
400BODY_REQUIREDCreate: the request carries no body.
422FROM_NOT_VERIFIEDCreate: from cannot be used. available_domains lists the usable domains.
404RESEND_NOT_FOUNDSend: Resend does not know the broadcast.