Hanna Kir
04/30/2026, 1:26 PMMax Foster
05/03/2026, 7:41 PMemailTemplateId .
API returns a 400 demanding subject and message - even though according to the new API docs both should be ignored when emailTemplateId is provided.
We have a customer trying to create email sequence steps with PDF attachments via API V3.
The expected workflow based on the docs is:
• upload attachment
• create email template with that attachment
• create a sequence step referencing the template via variants.emailTemplateId.
The issue: emailTemplateId does not work. When provided, the API returns a 400 demanding subject and message
Based on my tests. when those are provided - the step is created with the content of the subject and `message`completely ignoring the template and skipping the attachment.
POST /v3/sequences/1678728/steps
{
"type": "Email",
"delayInMinutes": 0,
"executionMode": "Automatic",
"variants": [{ "emailTemplateId": 242978 }]
}
{
"status": 400,
"title": "Validation failed",
"detail": "The request body contains validation errors.",
"extensions": {
"errors": [
"Email template message is required.",
"Email template subject is required."
]
}
}
The workaround with using the emailTemplateId with the V2 calls (Create Campaign (Template Step Text) and Add Step to Campaign) seems to be working as expected and Steps are created with the template content and attachments.Hessan Haiderzada
05/06/2026, 1:54 PMIryna
05/12/2026, 1:10 PMMax Makarenko
05/15/2026, 4:32 PMMax Foster
05/20/2026, 5:37 AMemail_replied and linkedin_message_replied only fire on the first reply from a contact in a sequence. After that first event, any follow-up messages in the same thread are silent.
Requested: A new webhook event (or an option on the existing ones) that fires on every inbound reply from a prospect in the same sequence/thread - second, third, and beyond.
Why: Our customer is building automations that need to react to each response in a conversation, not just the initial one. Right now there's no way to get notified programmatically when a prospect sends a follow-up message.Iryna
05/22/2026, 1:58 PM"reply_inbox_meeting_intent": true/falseFin
05/25/2026, 2:36 PMHollis
05/27/2026, 4:16 PMHessan Haiderzada
06/09/2026, 10:59 AMHessan Haiderzada
06/14/2026, 2:36 PMHessan Haiderzada
06/14/2026, 2:36 PMlist email/call activity, list meetings), the Inbox API (list inbox threads, list messages in an inbox thread, categories, meeting-intent), get activities for a contact, contact update with `meetingStatus`/`callStatus`/`isOptedOut`, full Tasks CRUD, and Webhooks (subscriptions + event catalog + delivery logs). The gaps below are therefore mostly expose / stabilise / scale, not "build from scratch."
1. The #1 blocker: surface v3 in the MCP connector
Our agent talks to Reply only through the Reply MCP connector, not raw REST (the agent cannot make arbitrary authenticated HTTP calls). Today the connector exposes ~15 tools — essentially sequences, basic stats, mark_contacts_as_replied, add_contact_to_sequence, and connect_* helpers. None of the rich v3 surface above is reachable.
Ask: Expose the following v3 endpoints as MCP tools (read + write):
• Inbox: list/filter inbox threads, list messages in an inbox thread, thread categories, toggle meeting-intent.
• Reports: get email/call reporting overview, list email activity, list call activity, list meetings.
• Contacts: get/search contacts, get activities for a contact, update a contact (incl. meetingStatus, callStatus, isOptedOut).
• Webhooks: create/list/update subscriptions.
Without this, every read still requires manual copy-paste (today we paste reply text and screenshot the stats dashboard by hand).
2. De-Beta: a stable, versioned contract
Every endpoint we need is flagged "Beta — behavior, parameters and response shapes may change without notice." A production back-office for 100 clients cannot build on that.
Ask: Promote the Reports, Inbox, Contacts, Tasks and Webhooks endpoints to GA with a stable, versioned schema and a published deprecation policy.
3. Reads — the report inputs
3a. Inbound reply content + normalised category (biggest manual step today)
list messages in an inbox thread should return, per message: full body text, subject, sender, direction, timestamp, the canonical contact id + email, and the sequence/client. Add: a normalised reply-category / intent field per thread (e.g. interested, not_interested, out_of_office, referral/redirect, wrong_contact, meeting_request, opt_out) so we don't re-derive it. Make threads filterable by sequence/client, date range, and "unprocessed since X."
3b. Stats as data (so we stop screenshotting the dashboard)
get email reporting overview should return the full funnel as numbers — Total/Contacted, Delivered, Open, Reply, Interested, Meetings booked, Opt-outs, Bounce, Not reached — PLUS the per-sequence breakdown and a daily/weekly time series, all filterable by sequence group / client and date range. Today we paste a screenshot of this exact view; structured data lets us render it ourselves.
3c. Call activity with normalised dispositions
list call activity should return per call: contact id+email, datetime, normalised disposition (connected, no_answer, voicemail, wrong_number, not_interested, callback_requested, meeting_booked, opt_out), free-text note, attempt number, agent. Today these come from external Ringover/Excel exports; if calls flow through Reply, this endpoint removes that dependency. (Disposition normalisation matters — our manual data has 6+ spellings of "wrong number"/"not reached.")
3d. Meetings with full lifecycle
list meetings should include: contact, company, datetime, status lifecycle (booked → held → no_show → rescheduled → cancelled), attendees, sequence/client, source. Our "Meeting Tracker" is cumulative and needs the lifecycle, not a boolean.
3e. Unified "what changed since" feed (the dedup engine)
The single hardest part of weekly reporting is dedup — not re-reporting a prospect already covered, especially in re-engagement campaigns that re-hit prior contacts. Ask: a per-client/sequence activity stream filterable by date range that unifies replies, calls, meetings, opt-outs, and status changes, each stamped with a timestamp and the canonical contact id. ("Give me everything new for Client X between A and B.") This single capability eliminates ~90% of our manual dedup work.
4. Writes — status back to Reply
• Bulk + by-email status setters. Today update a contact is single-contact, by numeric id. We identify contacts by email and act in batches. Provide bulk setters that take a list of ids or emails (mirroring `mark_contacts_as_replied`'s prospectIds[]) for meetingStatus, callStatus, isOptedOut.
• Richer meetingStatus. Currently binary (none / meetingBooked). Extend to the lifecycle in 3d (held, no_show, rescheduled, cancelled) so the write-back matches the Meeting Tracker.
5. Scale & multi-tenancy (100 clients)
• First-class "client / workspace" grouping. Today we infer a client by sequence-name prefix (e.g. Atlas_MW_*, S4U_*). At 100 clients this is brittle. Provide a native client/workspace (or tag/folder) entity that groups sequences + contacts + inbox + stats + calls, and make every reporting endpoint filterable by it.
• List all clients/workspaces + per-client scoping in one call.
• Multi-tenant auth. One managed credential that can act across all client workspaces (or clean centralised per-client key management) — not 100 separate keys pasted around.
• Pagination, bulk, and rate limits sized for a nightly/weekly run across 100 clients (cursor pagination is there; confirm bulk read endpoints and rate-limit headroom for full-portfolio sweeps).
6. Reliability & identity
• Webhook coverage + reliability. Confirm the event catalog covers: reply received (with category), opt-out, meeting booked/updated, call logged (with disposition), bounce, and contact status change — with full payloads, delivery logs, and retry. Webhooks + the §3e activity feed are the real-time backbone of an autonomous loop.
• Canonical contact id everywhere. Surface the same stable contact id (and email) on every inbox message, call, meeting, and activity, so dedup is keyed on id — never on name spelling (we routinely hit "Müller" vs "Mueller", "Höschele" vs "Hoeschele").
Definition of done — the autonomous loop we want to run
For each client, on a schedule, with no human in the loop:
1. Pull the period's new activity (replies + calls + meetings + opt-outs) via the §3e feed/webhooks, scoped to that client.
2. Read reply bodies + categories, call dispositions, and meeting lifecycle (§3a/3c/3d).
3. Dedup against what was already reported, keyed on canonical contact id (§3e/§6).
4. Pull funnel + per-sequence stats as data (§3b) and render the visual.
5. Build the client report.
6. Write back statuses in bulk — meeting booked/held, opt-outs, replied (§4).
7. Human reviews the finished reports and the flagged judgment calls.
Everything above already half-exists in v3. Exposing it in the MCP connector, stabilising it out of Beta, adding a client/workspace dimension, and normalising the reply/call/meeting fields would let us run the whole thing autonomously.Hessan Haiderzada
06/30/2026, 12:24 PMIN_OTHER_SEQ and is left where it is (never force-moved into Cequence), and opted-out contacts are skipped too. Let me confirm the running enroll is behaving that way and see the status spread so far:
Checked enroll status tally + whether IN_OTHER_SEQ are skipped
Wait — your instruction surfaces a real risk I need to handle immediately. The custom fields (Personalisation, Job Posting, etc.) are account-level and shared across sequences. The running enroll imports with overwriteExisting=True, so any of these 377 who are active in another sequence (e.g. VDL) would have their shared fields overwritten with Cequence content — corrupting their other sequence's emails. I'm stopping the enroll now before it does more of that:
Stopped. Now I need to assess the blast radius before doing anything else. The enroll_csv runs the bulk import (overwrite=True) first, then the enroll loop — so the import may have already overwritten fields. The real exposure is only contacts active in another sequence that reuses these shared fields. Let me check: did the import overwrite all 377, and are the touched contacts in other active sequences?
Assessed overwrite extent + sequence membership of touched contacts
All 7 checked show sequences=[] and — notably — Personalisation does not match the Cequence content, suggesting the overwrite may not have taken. But gotcha #17 warns the sequences field reads [] for paused sequences, so I can't trust it blindly. Let me verify its reliability against a known active-VDL contact, and check the real overwrite state of the sample:
Tested sequences-field reliability + sample overwrite state
Two key facts: (1) the .sequences field is unreliable — a known active VDL contact also shows [], so I can't use it; (2) the import did overwrite the sample (the None ids fooled my earlier check, but the values are clearly Cequence content). So I need the authoritative cross-reference. Let me first quantify the damage (did the stopped enroll's bulk-import overwrite all 377?) and scope the active sequences:
Damaged check + active-sequence scope
This is a real problem I need to own. The bulk import overwrote all 377 contacts' shared account-level fields, and there are 83 active sequences (Affix, Flotiq, Aexus, Simreka, S4U…) all using the same canonical container fields. Any of my 377 who are active in those would have had their other campaign's personalization clobbered. I have to quantify the overlap authoritatively (the .sequences field is broken). Let me cross-reference my 377 against every active sequence's enrolled contacts:Hessan Haiderzada
06/30/2026, 12:24 PMGeorge Vitko
07/15/2026, 1:51 AMGeorge Vitko
07/15/2026, 1:51 AMGeorge Vitko
07/28/2026, 3:42 PMHessan Haiderzada
07/28/2026, 3:45 PMGeorge Vitko
07/28/2026, 3:55 PMGeorge Vitko
07/28/2026, 5:45 PMGeorge Vitko
07/28/2026, 5:57 PMHollis
08/04/2026, 9:46 PMHollis
08/18/2026, 7:16 PMHessan Haiderzada
08/19/2026, 3:58 PM