How tools behave
Tools reject arguments they do not declare instead of ignoring them. An argument a tool never supported would otherwise come back as a result that silently does not match the request - an inventedfilters on a search, for
example, returning the unfiltered list. The error names the unsupported
arguments, lists the supported ones, and points at the supported way to express
the same request where one exists.
Errors and recovery
Tool failures retainisError: true and readable error text, and also return
structuredContent with { success: false, error: { code, message, howToFix, docsUrl } }. HTTP errors include statusCode; a valid API Retry-After header
adds retryAfterSeconds. These fields are omitted when unavailable. The OpenAI
profile uses safe recovery descriptions and known codes or status-derived
fallbacks, omitting raw backend diagnostics.
Use the error code and recovery guidance to choose your next step. The client
does not retry automatically. After an uncertain send_email outcome, reuse the
original idempotencyKey with unchanged input and inspect emailSendId when
available. A retry hint alone does not mean repeating a write is safe.
Successful results keep their existing shapes. Recoverable partial subscriber
event imports retain their counts and row failures without isError; inspect
those rows before retrying failed records.
Duplicate resources
If a tool call would create a duplicate segment name or sending domain, the error includes a stablecode, an agent-friendly description, a concrete resolution, and a docsUrl. For segments, call list_segments and reuse the existing segment ID or choose a different name. For websites, call list_websites; if the domain is not listed for the selected company, it belongs to another company or account and must be removed, reassigned, or replaced with a different sending domain.
Working across multiple workspaces
Callget_account to list the companies your connection can access and your
role in each one. Then call select_company, or pass companyId on a tool that
supports it, before working with company data.
The selection sticks until you change it: the local server keeps it for as long
as the MCP process runs, and a hosted connection remembers it for up to 30 days
per API key. A companyId passed on an individual call applies to that call
only. If the selected company is later deleted, or your access to it is removed,
get_account clears the selection and falls back to a company you can still
reach, so you are never locked out by a stale choice.
Changing the selected company does not create a separate subscription. Companies
owned by the same user share that owner’s core email plan, monthly email usage,
and email credits. A company you joined uses its own owner’s billing pool.
Sender-health pauses and the daily sending cap remain company-specific, while a
serious owner-account ban affects every company that owner controls.
See Workspaces, Billing, and Shared Limits
for invoice, add-on, quota, and reputation details.
Subscribers
add_subscriber- Add a new subscriber by email, or by phone alone for a phone-only (SMS) contact; its status is creation-only, so useupdate_subscriberfor an existing contact. Thesubscribers:writescope covers a nonemptylistIdsarray in this call; omit it to let a new contact follow the workspace default lists while an existing contact keeps its memberships, or pass[]to join no list. The data-ingest presets support explicit lists in this call. Imports into explicit lists and dedicated list membership tools still requirelists:write. PasscreatedAtwhen importing from another platform to keep the contact’s original signup date, so date-relative segments are right immediately; an existing contact’s date only ever moves earlier, and supplying it skips sequence enrollment by default. PassenrollInSequences: trueto override that default with an API key that hasautomations:triggercreate_subscriber_import- Queue up to 5,000 full CRM subscriber records in one call, including names, external IDs, phone numbers, tags, lists, statuses, custom attributes, and a per-recordcreatedAtsignup date. A nonemptylistIdsarray requireslists:write. Workspace-default opt-in can requireautomations:triggerfor active contacts, and double opt-in always requires it. PassidempotencyKeyfrom retry loops so a resent request returns the already-queued import instead of creating a second batchget_subscriber_import- Check import progress and row-level outcome counts. Every excluded row is explained:skippedReasonssums toskippedCountandfailedReasonssums tofailedCount, so a migration can be proven complete without inspecting individual contactsupdate_subscriber- Update profile fields, attributes, tags, or global status; the legacyattributesspelling merges keys into the existing custom-attribute map, while the REST-compatiblecustomAttributesspelling replaces the public map and removes unspecified keys.status: "unsubscribed"suppresses future marketing while preserving history.firstName,lastName,timezone, andphoneare native profile fields, so set them here rather than as custom attributes -timezonetakes an IANA identifier (e.g.America/New_York) and enables recipient-local campaign delivery - a national-format number needsphoneCountry(for exampleIT), and changing a number resets SMS consent unless you sendsmsConsentin the same callremove_subscriber- Unsubscribe while preserving history, or permanently delete only withhardDelete: trueget_subscriber- Get subscriber detailslist_subscriber_attributes- List the custom attribute names in use across the account, each withvalueType(string,number, orboolean),isArray,mixedTypes, an examplesampleValue, andsampledContacts. WhenmixedTypesis true, contacts hold different types for the key andvalueTypeisstring. Call it beforeadd_subscriberorupdate_subscriberto reuse existing names and send matching types, for example a zip code as the string"02134". PassincludeNested: truefor paths such asprofile.tiersearch_subscribers- Search by free-text query, tags, lists, segments, or a custom attribute. Omitlimitand the tool walks every page for you and returns all matches in one call. To read a large audience in chunks instead, passlimitand followpagination.nextCursoruntilpagination.hasMoreis false;offsetandpagealso work below 1,000,000 skipped matches and are whatpagination.nextOffsetis for whennextCursoris null. Use cursors for deeper audiences. Filter on a custom attribute withattributeplusattributeValueand an optionalattributeOperator(is,contains,gt,gte,lt,lte, oris_not_empty);is_not_emptyneeds no value and matches every contact that has the attribute set. Attribute filters cannot be combined withsegmentId- create a segment for compound oris_not/is_emptyattribute rules. Each subscriber carriesunsubscribedAt, the date the contact opted out; use it rather thanupdatedAt, which any later tag or attribute write moves. Narrow to a window of opt-outs withunsubscribedAfterandunsubscribedBefore, which skip contacts that carry no opt-out date - active contacts and imports with no known date. Bare dates use UTC midnight; datetimes must includeZor an explicit offsettrigger_subscriber_event- Emit a custom event for one subscriber exactly as an integration would. This is the supported way to exercise event triggers, matching-field idempotency, branch conditions, and stop conditions end to end without waiting for real traffic. PassoccurredAtto backfill an event that already happened: more than an hour in the past it is recorded as history, counted by segments and the timeline but running no sequences, sync rules, waiting steps or webhooks. Never use it to test a live automation, since the side effects you are testing will not run. Pass your owneventIdto make a retry safe: a repeated live event returns the existingeventwithduplicate: true, while a repeated historical event stays in theeventsarray and incrementsduplicatestrigger_subscriber_events- Emit several events for one subscriber in order, up to 500 per call. When every event carries anoccurredAtmore than an hour old the batch imports as history in one idempotent write; add your owneventIdso a re-run writes nothing new
account: "org_123" or account: { externalId: "org_123", role: "owner" } to trigger_subscriber_event. Object references also accept name, domain, and attributes. The contact is attached before recording the event, which carries event.account.* context. Until the workspace has Accounts on, account is ignored and the result includes accountIgnored; call upsert_account first. The batch tool retains its existing contract; use the single-event tool when attaching an account.
import_subscriber_events- Record up to 25 events for many subscribers, each carryingemailor an existing contact’sexternalIdplus a source-ownedeventId. Contacts whose rows are all more than an hour old import silently as history; any recent row makes that contact’s whole group live. Retrying reuses one receipt and repairs downstream work idempotentlybulk_add_subscriber_tags/bulk_remove_subscriber_tags- Add or remove tags across up to 500 existing subscribers identified byemails,externalIds, orsubscriberIds. Built for reconciling derived-tag backlogs: unknown identifiers come back innotFoundinstead of creating contacts, and tag automations stay off unless you passtriggerAutomations: true
Accounts
Accounts are the companies, workspaces or teams your contacts belong to. They are unrelated toget_account, which returns your own Sequenzy account. Account attributes fan out to every member as account.<name> for segments and {{account.<name>}} merge tags; members have a role (owner, admin, member). See Accounts.
list_accounts- List accounts with search across name, external ID and domain, plus paging and sorting byupdatedAt,createdAt,name,memberCountorlastEventAtget_account_by_external_id- Get one account by the customer-owned organization id, with up to 100 members and their roles (owners first)upsert_account- Create or update an account by external ID. Attributes merge into the stored map (nulldeletes a key;replaceAttributes: truereplaces everything). Optionalmembersare added in the same calldelete_account- Delete an account and its memberships; contacts are kept and theiraccount.*values clearedlist_account_members- List members with rolesadd_account_member/remove_account_member- Attach or detach a contact byemailorsubscriberExternalId. Adding a new email creates the contact; re-adding with aroleupdates it, without one keeps the current roletrigger_account_event- Record an event on the account (for exampletrial_ending) and deliver it toowners(default, falling back to admins),admins,allornone. Each recipient gets a normal contact event carryingevent.account.*, so sequences, sync rules and matching-field enrollment onaccount.externalId(once per account) all work. PasseventIdfor idempotent retries andoccurredAt(ISO 8601) to preserve the original event timelist_account_events- Recent account timeline events, newest firstlist_account_suggestions- Read-only: work email domains several contacts share (minContacts, default 3;limit, default 25), with up to 10sampleEmails, skipping personal and disposable providers, your sending domains, domains where a contact already belongs to an account and domains an account already usesaccept_account_suggestions- Create accounts for up to 25domainsthe user confirmed. Each domain becomes an account (external ID and domain set to the domain) with its unassigned contacts as members, or its contacts join the one account already using that domain. Results arecreated,updatedorskipped(no_contacts,multiple_accounts,already_in_account); retries are safe, and no sync rules or segment-entered sequences rundetect_account_organization_ids- Read-only: event properties and contact attributes that hold your organization ID, such asworkspaceId, with how many organizations each has and the matchingnameKeypreview_accounts_from_organization_id- Read-only: the biggest accounts apropertyKeywould create, each with thenameit would get (fromnameKey, otherwise its contacts’ shared work email domain),domain,contactCountandsampleEmails. Show it to the user before creating anythingcreate_accounts_from_organization_id- Start a background run that creates one account per organization ID and adds its contacts as members, after the user confirms the preview. ReturnsjobIdandalreadyRunning; nothing is sent, existing names and roles are kept, and reruns are safeget_account_organization_id_job- Check that run:queued,running,completedwith counts, orfailedwith the error
Lists
list_lists- List subscriber lists. Each list includessubscriberCount(current members of any status) andactiveSubscriberCount(current members with status=active). Members who unsubscribed from the list are not countedcreate_list- Create a subscriber listupdate_list- Update a list’s name, description, or privacydelete_list- Permanently delete a list and all of its memberships; subscribers themselves are keptadd_subscribers_to_list- Bulk add up to 500 subscribers to a list from an email arrayremove_subscribers_from_list- Remove up to 500 subscribers from a list by email; subscribers stay in your audience and unmatched emails are returned innotFound
Campaigns
Usecreate_campaign_for_audience to create a blank draft from selected contacts, contact filters, or an email activity drilldown. Preserve the complete group and time window across pages. Review selectedCount and eligibleCount, then use the existing campaign tools to edit, inspect, clear or schedule the draft. See selection inputs and limits.
list_campaigns- List campaigns with status, label,limit, andoffsetfilters, including reviewer feedback inrejectionCommentfor rejected campaigns. Each item carries delivery pacing (sendTimeOptimization,sendTimeWindowHours,spreadOverHours,sendInRecipientTimezone,scheduledTimezone) so a company-wide Send Time Optimization audit does not need oneget_campaigncall each. STO is campaign-only; sequences usesendingWindow. Results are paginated: the default page size is 50 andlimitis capped at 100. Read the returnedpaginationobject (limit,offset,count,total,hasMore) and keep paging withoffsetwhilehasMoreistrue- one call does not necessarily return every campaignget_campaign- Get campaign details and stats, including the saved audience intargetLists(null when targeting is still unset), the linked email body inemailId(the same record the template tools read; reusable astemplateIdincreate_campaign, null for SMS campaigns), and reviewer feedback inrejectionCommentfor rejected campaigns.rejectionCommentstaysnullwhile a campaign is still inwaiting_approval. Finished campaigns also report recorded pacing throughspreadOverHours,sendTimeOptimization, andsendTimeWindowHours, plus the recipient cap inmaxRecipients(nullfor the whole audience), alongsidesentAt- which is stamped when the last recipient is handed off for native sends, so on a paced send it marks the end of the delivery window. Imported campaigns may not include source-provider pacing metadata, so absent pacing fields do not prove delivery happened all at once. Note thatcomputedListsis email personalization (product lists rendered inside the email), not audience targetingget_campaign_audience- Resolve exactly who a campaign will reach: targeting kind, resolved list and segment names (with amissingflag for deleted references), filters, include/exclude rules, a plain-language summary, and a live recipient count.isUnset: truemeans scheduling would send to every active subscriberlist_campaign_goals/create_campaign_goal/update_campaign_goal/delete_campaign_goal- Manage persisted event, subscriber-attribute, or tag-applied conversion goals attached to one campaign. These appear on the campaign report as named conversion steps after sent/opened/clickedcreate_campaign- Create a campaign from a prompt, raw HTML, or Sequenzy blocks; native blocks include Poll and NPS surveys. Prompt generation saves the generated subject, preview text, company logo/footer, and uses the company font. PassemailPreset: "branded" | "minimal"to set Style > Format for native blocks; this is separate from prompt-generationstyle, cannot be combined withhtml, and is unsupported when the whole email is one raw HTML block. Applying minimal removes standalone logos; restoring branded generates a new logo unless the authored logo block is sent again. Defaults to draft, withstatus: "sent"available for archived/imported sent campaigns. PasstargetLists(or thesegmentId/listIdsshorthands) to save the audience on the draft, or omit them and choose it inupdate_campaignorschedule_campaign. Set the sending identity either withsenderProfileId/replyProfileIdfromlist_sender_profiles- each already carries its own display name, so send them withoutfromEmail/fromNameandreplyTo/replyToName- or withfromEmail/replyToplus optionalfromName/replyToNameto name a profile Sequenzy creates for that addressupdate_campaign- Edit a draft, including reply-to settings, raw HTML, or Sequenzy blocks such as Poll and NPS surveys. PassemailPresetto change Style > Format without rewriting copy, subject to the same native-block and logo-loss rules ascreate_campaign. AcceptstargetLists(or thesegmentId/listIdsshorthands) to retarget the draft, ortargetLists: nullto clear saved targeting. Sending identity follows the same rule ascreate_campaign: a profile ID replaces both the address and the display name. SetsendTimeOptimizationandsendTimeWindowHours(1-24, default 12) on the draft; they are used when the campaign is later scheduled unlessschedule_campaignoverrides them. STO is campaign-only - there is no company or sequence toggle.maxRecipients(1-10,000,000, ornullto clear) caps the send to the first N matching subscribers by subscriber idschedule_campaign- Schedule a draft or already scheduled campaign; passtargetListsor thelistIdsshorthand to pick the audience at schedule time (omitting both reuses saved targeting, or defaults to every active subscriber), andrecurringInterval: "weekly"or"monthly"to repeat it automatically, re-evaluating audience membership at every run. PasssendTimeOptimization: trueto deliver each recipient at their predicted best hour withinsendTimeWindowHoursofscheduledAt(default 12h, max 24); this is campaign-only and is not available on sequences.spreadOverHourstakes precedence and turns STO off.maxRecipientssends to at most that many audience members (omit to keep the draft’s saved cap,nullto clear it; recipients already reached count against it on resume). PasssendInRecipientTimezone: truewithscheduledTimezone(the IANA zone thescheduledAtwall time refers to) to deliver at that wall-clock time in each recipient’s own stored timezone; contacts without a timezone receive the campaign atscheduledAtitself. The returnedcampaign.statusis eitherscheduledorwaiting_approval.waiting_approvalmeans the campaign was held for safety review and nothing sends until a reviewer approves it - most common on new accounts and recently registered sending domains. It is a successful outcome, not an error, and scheduling again does not clear it; check the campaign withget_campaigninsteadunschedule_campaign- Remove a scheduled send and recurrence, returning the campaign to an editable draft that can be scheduled againsend_test_email- Send test to single addressrender_email- Render a campaign, sequence email step, or template to the exact email-safe HTML that would be sent, for embedding a visual preview in an external dashboard or builder, or for checking merge tags before anyone is enrolled. Pass exactly one ofcampaignId,sequenceIdplusnodeId, ortemplateId.unresolvedMergeTagslists every tag that did not resolve, with reasonunknown(nothing provides that name, so it stays empty for every recipient) orno_value(recognized or unverifiable, but blank for this contact) - the HTML alone cannot tell them apart. An unknown name is reported even when adefaultfilter supplied text in its place, because that fallback then reaches every recipient while the HTML looks correctly personalized. A name is only calledunknownwhen the render had a source to check it against. Without the contact’s attributes nothing is checkable - a bare{{plan}}reads the same attribute map as{{subscriber.plan}}- so pass a storedsubscriberIdor an inlinesubscriberwithcustomAttributes. Beyond that,{{event.*}}needs sample event properties invariables, since a real send fills those from the enrolling event, and{{recommendedProducts.*}}needs a storedsubscriberIdthe catalog has something to recommend for. Rendering a transactional email needsvariables, since its tags come from thevariablesof each send call and carry no prefix marking them. Otherwise they reportno_valuerather than being called typos. An optional attribute this contact never had set is kept out ofunknownby checking the names other contacts in the account carry, which needs thesubscribers:readscope. A sequence step downstream of a create-discount step renders{{discount.*}}from that step’s real configuration with a placeholderTEST-CODEfor the code; on a step some paths reach without running that discount step, and on a standalone template,{{discount.*}}reportsno_valueinstead of being called a typo.unevaluatedConditionsdoes the same job for conditional blocks: a condition on stored subscriber state (tag,segment,list,status,event, purchases, engagement) can only be evaluated for a storedsubscriberId, or for atagcondition an inlinesubscribercarryingtags, and anything else renders as false - indistinguishable in the HTML from a contact who genuinely does not match. Read-only: it never sends or modifies anythingcancel_campaign- Cancel a scheduled, paused, or sending campaign; remaining emails are not sent and the campaign cannot be restartedpause_campaign- Pause a campaign that is currently sendingresume_campaign- Resume a paused campaign, optionally spreading the remaining delivery over 1-72 hours withspreadOverHoursduplicate_campaign- Duplicate a campaign as a new draft.mode: "campaign"(default) copies the campaign and its email,"ab_test"also copies the A/B test with all variants, and"variant"copies a single variant’s content (requiresvariantId)resend_campaign_to_non_openers- Create a draft that resends a sent campaign to everyone in the same audience who didn’t open it. Available 6 hours after the campaign finishes sending, and never for imported already-sent campaigns (Sequenzy has no opens for a send it did not deliver); returns the draft and an estimate of how many subscribers haven’t opened the original. The draft must be scheduled or sent separately Every audience format keeps opener exclusions that manual additions cannot override. Resending a resend also preserves exclusions from earlier campaigns. Your audience is evaluated live, so new members can qualify even if they never received the original. If an older resend draft lacksexcludedCampaignOpenerIds, recreate it from the original campaign and review the new draft before scheduling.share_campaign- Create (or fetch) the campaign’s public “view in browser” link. The hosted page renders an anonymized copy - sample contact, inert unsubscribe link, no open/click tracking - so the URL is safe to forward to anyone. Idempotent: an already-active link is returned withcreated: falseinstead of being rotated.get_campaignreports the current link asshareUrlunshare_campaign- Revoke the public link; the shared URL returns 404 immediately, and sharing again later mints a different URLdelete_campaign- Permanently delete a campaign; sending, scheduled, or paused campaigns must be cancelled withcancel_campaignfirst
Saved Forms
list_forms- List saved forms, audience settings, and public action URLscreate_form- Create and publish a form scoped to one or more list IDs, optionally with brandthemeoverridesupdate_form- Rename a form, retarget its audience, edit its copy, restyle its theme, or replace its content blocks (read the current blocks vialist_formsfirst)get_form_embed- Get the action URL, hosted JavaScript, native form, and fetch example
blocks with update_form. The
Update Saved Form reference
documents every form-field property, including the mapsTo targets, choice
options, and hidden field behavior. A group block can arrange recursive
children as a stack, row, grid, or image overlay; groups may nest up
to three levels and responsive rows/grids collapse to one column on small
screens. Overlay requires exactly one direct image. Use overlayColor,
overlayShade (0-100), and overlayPosition (top, center, or bottom) to
control the image treatment. gap spaces the foreground children without
moving the background image; nested images only enable Overlay for their own
subgroup.
For a static Astro, Hugo, Jekyll, Cloudflare Pages, Netlify, or GitHub Pages
site, start with list_forms, call create_form if needed, then use
get_form_embed. The returned browser code never includes a Sequenzy API key;
the opaque form ID selects the server-managed lists, tags, duplicate behavior,
and success action.
Popups
Popups are the on-site overlay capture surface: one script tag on the site, with the trigger, page targeting, schedule, and display frequency owned by Sequenzy. Use saved forms instead when the signup box should sit inline in the page.list_popups- List popups with their status, counts, and engagement rates. Content blocks are omitted unless you passincludeContent, so listing a workspace stays cheapget_popup- Get one popup’s complete content blocks, trigger, targeting, schedule, frequency, and themecreate_popup- Create a popup from a starting template and get its embed script; published by defaultupdate_popup- Rename, publish or unpublish viastatus, retarget, retime, edit copy, restyle, or replace content blocksduplicate_popup- Copy a popup into a new draft with its own counts, leaving the original liveget_popup_embed- Get the script URL plus HTML, React/Next.js, WordPress, and Shopify snippetsdelete_popup- Permanently delete a popup and its view and conversion counts
create_popup accepts a template for the starting design (newsletter-modal,
discount-offer, countdown-launch, minimal-slide-in, exit-lead-magnet,
live-demo, launch-modal, paper-digest, stark-takeover, top-bar,
announcement-bar, or fullscreen-welcome), then update_popup refines it.
Unlike saved forms, listIds is optional: omit it and the popup captures into
every list, matching the dashboard default.
Popup block arrays support the same recursive group layout as saved forms.
The trigger, targeting, schedule, frequency, and visual objects are
merged key by key, so setting trigger.delaySeconds keeps the rest of the
trigger. To stop a popup showing without losing its stats or invalidating its
embed script, set status: "draft" rather than deleting it.
Every popup carries a stats object with the full funnel: views (shown),
starts (began filling in), and conversions (submitted), plus startRate,
conversionRate, and completionRate. A rate is null rather than 0 when
its denominator is zero, so a popup nobody has seen yet does not read as a
popup nobody converted on. To trial a change against a performer, use
duplicate_popup and publish the copy rather than editing the original.
Landing Pages
list_landing_pages- List landing pages with status, metrics, content, and URLsget_landing_page- Get landing page details, editor content, lifetime metrics, public URLs, and a signedpreviewUrlthat works for drafts. Useget_landing_page_statsfor unique visits, referrers, and crawler hitsget_landing_page_stats- Mailchimp-style report: visits, unique visits, clicks, subscribes, conversion rate, daily histogram, referrers, UTM sources, and crawler hits. Preview URLs and the editor are never countedrender_landing_page- Return a visitor-facing preview URL for a landing page without publishing it. Drafts keeppublicUrlnull; openpreviewUrlto check layout, copy, and#formanchors. The preview is not indexed and draft forms do not collect contactscreate_landing_page- Create a draft landing page from default template content or supplied JSONupdate_landing_page- Edit landing page name, slug, or full editor-compatible contentpublish_landing_page- Publish a landing page, optionally saving name, slug, or content firstunpublish_landing_page- Return a landing page to draft, optionally saving edits firstduplicate_landing_page- Copy a landing page into a new draft with its own slug and statsdelete_landing_page- Delete a landing pageconnect_landing_page_domain- Connect a workspace domain, or providelandingPageIdfor a hostname dedicated to one pageupdate_landing_page_domain_settings- Update or verify workspace/page domain settings; provide the samelandingPageIdfor a dedicated page domainremove_landing_page_domain- Remove a dedicated page domain while preserving its workspace and Sequenzy fallback URLs
version, template, seo, theme, and blocks. Blocks render in slot order - top (full-width band above the hero), hero, form, body, footer - so put banner images or announcement bars in the top slot. A video block takes a pasted YouTube URL in url; other providers and direct video files are not supported. The seo object also accepts faviconUrl (falls back to the company logo) and hideFromSearchEngines (adds a noindex, nofollow tag for private pages). The API validates CTA, pricing, footer, and form redirect URLs before saving or publishing. Button and pricing CTA URLs also accept in-page anchors: #form scrolls to the page’s single form block, #section-<sectionId> and #block-<blockId> scroll to any section or block, and #top returns to the top - use these for repeated CTAs on a one-form page instead of adding a second form. The theme object accepts sectionAnimation (none, fade, slide-up, zoom-in) and sectionAnimationSpeed (slow, normal, fast) for a scroll reveal on the published page. Custom landing page subdomains require a CNAME record pointing to pages.sequenzydns.com; root domains require an A record pointing to 76.76.21.21 (the www host also redirects to the root when its CNAME points to pages.sequenzydns.com). Call update_landing_page_domain_settings with verify: true after DNS changes propagate. A dedicated page domain opens at its hostname root and never exposes sibling pages; existing workspace and Sequenzy URLs remain as fallbacks.
Company
create_api_key- Create a company API key and return its one-time secret on the standard MCP surface. It is omitted from the OpenAI-reviewed surface; userequest_api_key_handoffthererequest_api_key_handoff- Prepare an owner-confirmed link that opens the dashboard create-key form prefilled with a suggested name and permissions. Use it when key management is blocked because the active key lacksapi_keys:manage. It creates nothing and never returns a key: hand the URL to the workspace owner and stop. PassreplaceApiKeyId(or"current") to rotate, and the dashboard offers to revoke the predecessor once the replacement exists. Needs onlyaccount:readlist_api_keys- List company API keys as non-secret metadata, including IDs, prefixes, permission receipts, usage timestamps, and the active-key markerupdate_api_key- Rename a company API key or replace its permissions in place, without issuing a new key. Reach for this when a call fails with a missing-scope error: the key value is unchanged, so no client has to be re-wired, and added permissions apply on the next retry. Removed permissions may remain usable for up to five minutes while API caches expire.presetandscopesreplace the whole selection rather than merging into it, so calllist_api_keysfirstrevoke_api_key- Permanently revoke an exact company API key by ID after checking it withlist_api_keys(delete_api_keyis a compatibility alias)get_company- Get company details, product info, brand colors, AI writing context, effective localization settings, the read-onlyemailBrandingentitlement, anddefaultSubscriberListIds- the workspace default lists new contacts join when nothing targets them explicitly.emailBranding.visiblereports whether “Sent with Sequenzy” is added to future sends; the reason, tier, subscription status, required action, andsubscriptionUrllet an agent explain the entitlement and hand a billing-authorized user to the real Account -> Subscription page. Branding is injected at render/send time, so a paid entitlement removes it from future sends by existing live sequences without editing their blocks. It is not a writableupdate_companysetting. A JSONnullfordefaultSubscriberListIdsis every current and future list, not an empty selection;[]is no list at all. An ordinary profile or attribute upsert for an active contact keeps that contact’s memberships unless it names lists explicitly; capture submissions and explicit lifecycle reactivations can reapply target or default lists. Change the setting withupdate_company. Read it before connecting an integration that has no per-integration list targeting of its own (Dodo Payments, PostHog, Polar, Paddle, and similar), because live contacts and payment-provider backfills land there. PostHog history imports are different: contacts created by that import have no list memberships. Send Time Optimization is not a company setting; audit campaigns withlist_campaignsorget_campaignget_app_urls- Generate dashboard links for resources and company administration. When a company is resolved, the result includes the canonicalsubscriptionURL. ThesettingsTabvaluesbillingandsubscriptionare compatibility aliases for Account -> Subscription; they do not invent a nonexistent Settings tabupdate_company- Edit product info, brand context, the brandemailDesignPrompt(art direction for AI-designed emails - layout, density, imagery, CTA prominence, separate fromtoneVoice; when empty, the next email generation prefills it with the direction derived from the brand, and an empty string clears it so the next generation writes a fresh one), and the default email theme (emailThemeaccepts partial updates;nullresets it - to restyle a single sequence email instead, patch that step’semailThemewithupdate_sequence_node), or set account-widefromEmailandreplyTodefaults (From domains must be verified); sendfromNameorreplyToNamealone to rename the existing default profile’s display name, or pair them withsenderProfileId/replyProfileIdfromlist_sender_profilesto pick and rename a specific profile. SetdefaultSubscriberListIdsto choose which lists new contacts join when nothing targets them explicitly - forms, API writes, events, tag actions, imports, and every integration without its own targeting. The three states differ:nullis every current and future list,[]is no list at all, and an array is exactly those lists. Unknown or foreign list IDs are rejected rather than skipped, and the change applies only to later writes - nobody is moved or removed retroactively, so a list already filled by a backfill still needsremove_subscribers_from_list. Profile, branding, and AI-context fields needcompany_profile:manage(included in Safer agent access); the sending-identity, reply-tracking, anddefaultSubscriberListIdsfields needcompanies:manageadd_sending_domain- Add a sending domain and return the SPF, DKIM, MAIL FROM, inbound and optional company tracking CNAME records for setup. OptionalmailFromPrefixchooses the bounce subdomain (add_websiteremains as a compatibility alias)get_tracking_domain- Read the company tracking domain, its status, whether links use it now, and its CNAME recordset_tracking_domain- Set or change the company tracking domain every sending domain uses for tracked links and opens. Any subdomain works; it never blocks sending, and changing it keeps links in emails already sent working while the old CNAME staysverify_tracking_domain- Check the company tracking domain’s CNAME and HTTPS certificate nowremove_tracking_domain- Remove the company tracking domain; links in emails already sent through it stop workingconfigure_sending_domain- Deprecated: set<trackingPrefix>.<domain>as the company tracking domain when none is set; preferset_tracking_domainlist_websites/check_website- Read stored aggregate, SPF, DKIM, MAIL FROM status, the envelope sender domain, and the Apple Email Source domains derived from sender profilesverify_sending_domain- Run a fresh DNS verification and returnverifiedseparately fromreadyToSendand selected home-transport readinessget_email_design_system- Get the visual identity every AI-generated email renders inside: the design code (kicker style, title alignment, button shape, divider style, density, sanctioned opener treatments) and the composition spine (hero-led|editorial|product-spec). The identity is stored as the company’s design direction text; the tool returns the parsed tokens, the raw text, andisDefaultwhile the identity is still purely derived from brand contextupdate_email_design_system- Adjust that identity (partial update) orresetit to the brand-derived defaults; the change is written into the design direction text (custom prose is preserved) and applies to every future AI email generation and sequence enrichment. Requirescompany_profile:manageget_sync_rules- Get the automatic tag changes applied when events fire, plus whether the optional platform preset is activeupdate_sync_rules- Replace the full sync rule set ([]disables rules;nullopts into the inherited SaaS/ecommerce preset); rules support subscriber-tag conditions and a product match (tags, collections, product types, vendors) for commerce eventsget_shopify_automation_settings- Get the connected Shopify store’s browse-abandonment, cart-abandonment, and price-drop settings with defaults appliedupdate_shopify_automation_settings- Update browse-abandonment, cart-abandonment, and/or price-drop settings (partial update;nullresets a section to the defaults)list_integrations- List connected integrations (Stripe, Shopify, Supabase, Clerk, ad platforms, and so on) with connection state, sync health, last sync time, and last sync error.lastSyncSkippedreports records the last store sync could not import normally, split into profiles that were kept but cannot receive email and records that were not imported at all. Credentials, access tokens, and webhook secrets are never returned; the OpenAI-reviewed surface also removes raw sync-error detailget_integration- Inspect one connected integration in depth: what it syncs, every event it emits and when, the tags each event applies through the account’s sync rules, which sequences trigger on each event, 24h webhook activity, and prioritized recommendations.unusedEventslists the events nothing acts on yet,availableActionssays what can be called on it right now,ingestionreports the bulk sync state and which lists new contacts land on (with names), Shopifypixelcarries the live storefront tracking state, and WebflowwebflowCapturereports the exact selected native forms, retained fields, required double opt-in, list IDs, sequence toggle, webhook state, and schema fetch time. An emptywebflowCapture.formsmeans capture is off. For Attio,details.mappedListCount0 plus anattio_lists_unmappedrecommendation means list joins are not synced until you map lists withupdate_attio_settingslist_integration_capabilities- Describe what each provider does whether or not it is connected: category, connect method, what it syncs, every event with the moment that triggers it, attributes written, supported actions, availability, and caveats. Coverage differs sharply - only Shopify has storefront browse tracking, only Stripe and Chargebee cover the full trial lifecycle - so check here instead of assuming an event existsget_event_schema- Read what a built-in event payload actually contains: a real example payload per provider, plus every property path with its type, the merge tag that resolves it, and a note wherever the sample alone is ambiguous. OmiteventNameto list every documented event.documented: falsemeans no sample is published, never that the event name is invalid - custom events carry exactly the properties you sendconnect_integration- Connect an API-key or webhook-secret provider on the standard MCP surface (Polar, Paddle, Dodo, Lemon Squeezy, Whop, Creem, Chargebee, Clerk, PostHog, Segment, Affonso, or Attio). Credentials are validated where possible, stored encrypted, and never returned; payment providers queue their initial revenue backfill, and PostHog and Segment can import event history. The response includes the webhook URL to configure at the provider with the same secret. It is omitted from the OpenAI-reviewed surface; complete setup in the dashboard or local CLI insteadlist_integration_activity- Recent integration webhook and sync activity with action, status, event type, matched contact, and error. The log to read when an integration says connected but nothing is arriving. Retained 24 hours; payloads are sanitized so no credentials appeardisconnect_integration- Disconnect Lemon Squeezy and remove its managed webhook. InspectcleanupWarningand repeat the call to retry cleanup; local ingestion is already stopped. Other providers disconnect from the dashboardset_integration_sync_enabled- Turn bulk imports and backfills on or off. Disabling keeps the connection, credentials, and live webhook delivery active. Does not disconnect the integration, and does not stop it creating contactsset_integration_list_targeting- Choose which lists the contacts an integration creates join. This is the tool for “stop this integration adding people to my marketing lists”:set_integration_sync_enabledonly pauses bulk backfills and leaves the live webhook writing. Affects list membership only on future provider writes -nullfalls back to the workspace default lists,[]joins none, and nobody is ever removed from a list. Webflow deliberately rejectsnull; use[]or explicit list IDs, and configure its native forms, field allowlists, required double opt-in, and sequence enrollment in the dashboard. With no selected Webflow forms, capture is off and no contacts are created. Wix/Webflow submissions, Shopify customer updates, and Supabase resubscriptions can add existing contacts to new targets; Stripe targeting applies only when its webhook creates a subscriber. It does not stop contacts being created, attributes syncing, sync-rule tags, or defaultany_contactenrollments, which fire precisely because the contact joined no list. Explicitany_listand specific-list sequences require a matching membership and do not enroll a list-less contact; pair this tool withpause_sequence_enrollmentswhenany_contactenrollment must stop too. Honored by Supabase, Stripe, Shopify, Wix, and Webflow. For a provider that is not on that list (Dodo Payments, PostHog, Polar, Paddle, WooCommerce, and similar), this tool returns an error and live contacts instead follow the workspace defaults - read and change those withdefaultSubscriberListIdsonget_company/update_company. A JSONnullon that field means every list, not none;[]means none, remembering that the default is workspace-wide and repoints every other untargeted contact source too. PostHog history imports are an exception and create contacts without list memberships. Needsintegrations:manage, which Safer agent access deliberately withholdssync_integration- Queue a manual re-sync: customers and revenue for a payment provider (Stripe, Polar, Paddle, Dodo, Lemon Squeezy, Creem, Chargebee, Whop), the user backfill for Supabase, or the event-history import for PostHog and Segment. The Supabase run reads the table already configured for that integration and cannot be pointed elsewhere; run it before a campaign that needs names or plan attributes on users who existed before the trigger was installed. The PostHog and Segment runs are the supported way to retry an event-history import that failed or was interrupted: they restart from the beginning with the stored credentials, and already-imported events dedupe. Returns immediately; pollget_integrationforsyncStatus. Other providers re-sync from the dashboardget_integration_pixel- Check whether a Shopify store’s storefront tracking pixel is installed and reporting to this account. Read live from Shopify on every call, because a merchant can remove the pixel without Sequenzy hearing about it.pixel.healthyis the field to branch on,pixel.errordistinguishes a confirmed outage from an unknown Shopify read, anddependentEventsnames the events that rely on the pixel. Shopify onlyactivate_integration_pixel- Install the storefront pixel, or repoint an existing one at this account. Idempotent (changed: falsewhen already live). Events start arriving on the next storefront visit and nothing is backfilled, so run it before building the sequence. Fails with a message naming the reconnect step when the store granted an older permission setget_attio_mapping- Inspect a connected Attio integration’s list mapping: Sequenzy lists, live Attio people-lists (id, api slug, name), the savedlistMap, andmappedListCount. Call this when Attio is connected but mappings are empty, beforeupdate_attio_settings, so you have Attio list ids instead of asking the user to paste UUIDs. Reads Attio live. Attio onlyupdate_attio_settings- Set which Sequenzy lists sync into which Attio people-lists using the stored access token. Does not require the secret again — do not reconnect just to change mappings.listMapis a full replacement ({}clears every mapping). Unmapped lists are not synced; unmapping does not remove anyone from Attio. Needsintegrations:manage, which Safer agent access deliberately withholdslist_web_tracking_keys- List the publishable keys that let a non-Shopify website send on-site events into this workspace. Each returns its origin allowlist,unrestricted,lastUsedAt, and a paste-readyinstallSnippet. A key withlastUsedAt: nullhas not successfully authenticated an event yet; check deployment, instrumentation or traffic, and the origin allowlistget_web_tracking_key- One key with its install snippet and ingest endpoint. Use it to hand over the exact script tag rather than rebuilding one, since the snippet embeds both the key and the workspace idcreate_web_tracking_key- Create a publishable key and return the install snippet. This is what turns on product views, cart activity, and browse abandonment for a site that is not Shopify or WooCommerce. Always passallowedOrigins; an empty allowlist accepts events from any site. Nothing is backfilled for the period before the snippet is deployedupdate_web_tracking_key- Rename a key, replace its origins (the list is replaced, not appended), or revoke it withisActive: false. Revoking preserves the key value so the matching snippet can still be found on the sitedelete_web_tracking_key- Permanently delete a key. Any page still running the snippet starts being rejected, so the snippet must come off the site toolist_sender_profiles- List sender (From) and reply-to profiles, which are the account defaults, and whether each sender address sits on a verified sending domainupdate_sender_profile- Rename one sender or reply-to profile in place without changing which profile is the account default. Use it to standardize a display name across the several identities a mailbox can carry (for exampleViraj from SnapCountdown toSnapCount); passtype: "reply"for a reply-to profile. Only the name changes - the address, its sending domain, and the default From/Reply-To selection are untouched. To change which profile is the default, useupdate_companyinstead. Requirescompanies:managedelete_sender_profile- Permanently delete one sender (From) profile. It refuses to delete the last sender or a profile used by a live campaign, active sequence (including a step override), or transactional email. Eligible draft and rejected campaigns plus the account default move to the best remaining sender when needed; reviewfallbackSenderProfileIdbefore sending. Reply-to profiles are not supported. Requirescompanies:manageget_notification_preferences- Get which account notifications Sequenzy emails the API key’s own user for this company (new subscriber, form submitted, campaign finished, weekly report), with the modes each event supports and the platform defaultsupdate_notification_preferences- Change those settings. Modes areoff,instant,daily, andweekly;dailyis only valid fornew_subscriberandweeklyonly forweekly_report. Instant form-submission notifications stop after 50 per workspace per UTC day. The Monday weekly report is on by default for the workspace owner (off for invited members until they opt in) and only sent for weeks with more than 10 emails sent; setweekly_reporttooffto stop it. Useful before a large migration, though imports never trigger new-subscriber notifications and busy days fall back to a daily summary automatically. Never reads or writes a teammate’s settingsget_tracking_settings- Get open/click/unsubscribe tracking flags, the opt-instrictBotFilteringEnabledbot-detection flag, the default attribution window, automatic UTM tagging, the company tracking domain and its status, inbound reply-tracking settings, and theconsentblock withdoubleOptInEnabled, the confirmation email ID, and the post-confirmation redirect URLupdate_tracking_settings- Turn open, click, and unsubscribe tracking on or off account-wide, opt in or out ofstrictBotFilteringEnabled, set the default attribution window, require double opt-in for new contacts withdoubleOptInEnabled, set where the hosted confirmation page sends subscribers after they confirm withdoubleOptInRedirectUrl(nullkeeps them on the branded confirmation page), and configure automatic UTM tagging (autoUtmSettingsmerges over the stored templates; anullfield stops that parameter, andnullfor the whole object resets them to the defaults). Applies to emails sent afterwards; reply tracking stays onupdate_company. EnablingdoubleOptInEnabledrequires a sender profile and provisions the confirmation email automatically; it does not change contacts that are already active
unsubscribeTrackingEnabled: false with update_tracking_settings to send
unsubscribe links directly to https://sequenzy.com, even with a custom tracking
domain. This applies to subsequent sends. Actual unsubscribes
and their email attribution are still recorded.
get_sending_status- Check whether company-level sending isactive,paused, orsuspended, why, and what it takes to restore it. Returns the pause reason and reason kind, the automated sender-health review state, whether one-click resume is available (and if not, which gate is blocking it), the enforcement counts and thresholds for permanent bounces, temporary bounces, and complaints, and ordered remediation steps. Requires onlyaccount:readresume_sending- Restore sending paused by a high permanent-bounce rate, after fixing the cause. RequireslistSanitizationConfirmed: true, thecompanies:managescope, and owner or admin access. It is a client of the same control the dashboard uses, not a bypass: only a permanent-bounce pause qualifies, the automated review must have cleared it, and it never removes suppressions
get_sending_status first whenever a send, sequence step, or test send fails for a reason that is not a validation error. A company-level pause blocks every send, so a test send that “works” in configuration terms still never leaves - send_test_email and send_sequence_test_email return a SENDING_PAUSED error carrying the same reason and steps.
Do not tell the user to wait for a bounce rate to expire. Sender-health enforcement uses all-time totals counted from a reset watermark rather than a rolling window, so metricsWindow.expiresAt is always null and the rate does not decay. It only moves as more real (non-test) sends accumulate, or when a resume moves the watermark. Test sends are excluded from the denominator, so they cannot dilute it either.
Only pass listSanitizationConfirmed: true after the user has confirmed the remediation. It is recorded on the account’s audit trail as their statement that the source of the invalid addresses is fixed and permanent bounces remain suppressed. When selfResume.canSelfResume is false, relay selfResume.unavailableReason and the remediation.steps instead of retrying - waiting_for_review clears on its own, while blocked_by_ai, review_failed, blocked_by_admin, and unsupported_reason need a support review.
For a new sending domain, call add_sending_domain, publish the records in website.dnsRecords, wait for DNS propagation, and then call verify_sending_domain. Treat website.readyToSend as the sending gate: DNS may be verified while the selected SES home region is still activating. Checking or verifying an unconfigured domain returns a recovery message that points back to add_sending_domain.
For a site that is NOT Shopify - a custom storefront, headless shop, marketplace, or SaaS marketing site - the equivalent check is list_web_tracking_keys. The same events (product views, collection views, search, cart activity, and the browse and cart abandonment built on them) require a publishable key and an installed script tag, and a workspace with no key, a revoked key, or a key that has never been used produces none of them. Create one with create_web_tracking_key and relay installSnippet verbatim. Identified events also require a short-lived token minted by the customer’s authenticated backend through POST /api/v1/web-tracking-identities; tell them to call sequenzy.identify(email, identityToken) at sign-in and checkout. A publishable key alone only records anonymous activity and cannot trigger subscriber automation.
For Shopify specifically, check get_integration_pixel (or the pixel field on get_integration) before building anything that depends on on-site behavior. Browse abandonment, cart recovery, product views, collection views, and storefront search all come from the storefront pixel, and a store with a confirmed missing or stale pixel produces none of them - the sequence is built correctly, enrolls nobody, and no error appears anywhere. If pixel.error is set, retry rather than treating the unknown state as an outage. activate_integration_pixel repairs a confirmed unhealthy configuration without a dashboard visit.
Call get_event_schema before writing any {{event.*}} merge tag or event property filter. list_integration_capabilities names the events a provider emits; this shows what is inside one. Guessing is not safe here: an unrecognized merge tag renders as an empty string rather than an error, so a wrong property name ships silently broken. It is also the only place that states what a sample cannot - *Cents fields are minor units while predictedLtv is whole currency units, price is a preformatted display string, churnRisk is a 0-95 percent, and orderId is a string on Shopify but a number on WooCommerce. Custom event names are absent by design and are still fully supported.
Before building automations on an integration, call get_integration. It answers whether the work is “connect something” or “turn on a sequence”: unusedEvents names events with no listening sequence, and recommendations flags listeners that are not accepting enrollments. observedByAccount, accountLastSeenAt, and accountNeverReceivedEvents are explicitly account-wide because another integration or the public events API can update the same event definition. Use the retained activity log for connection-specific delivery diagnosis. On the standard MCP surface, connect_integration accepts credentials the user explicitly provides; prefer the dashboard or local CLI when secrets should stay outside the AI conversation. The OpenAI-reviewed surface omits this tool. Use disconnect_integration for Lemon Squeezy; other provider disconnects remain in the dashboard.
Sequences
list_sequences- List sequences with dashboard-compatible status, search, label, limit, and offset filters. Branch oneffectiveStatus(draft,live,enrollment_paused,paused,archived) rather thanstatus, which readsactiveeven when new enrollments are paused;acceptsNewEnrollments,processesExistingEnrollments, and the plain-languageeffectiveStatusSummaryare returned alongside it. The legacytriggerConfig.activeflag is not read by the runtime and now mirrorsacceptsNewEnrollmentsget_sequence- Get sequence details plus normalizedsequence.nodeswith each node’sid,nodeType, currentconfig,updatedAt, andupdateHintsdescribing editable/managed fields and the concurrency token to return; reusablesequence.edges,graphRevision, and editablesequence.emailsare also returned, including each linked email’s effectiveemailPreset(brandedorminimal).sequence.emailscovers every email-sending step, includingaction_ab_teststeps - those reportnodeType: "action_ab_test"with anabTestsummary whosevariants[]entries include fullblockswhenab_tests:readis granted, and their step-level copy is control variant A only (see editing the content of a sequence A/B step). Send Time Optimization is campaign-only; sequences usesendingWindow(allowed local hours/days), which is a shared gate, not per-subscriber predicted send timessimulate_sequence- Dry-run a sequence without sending mail or enrolling anyone. Nobody is auto-enrolled on activate. Without a subscriber it reports who currently matches and activation readiness errors. PasssubscriberIdoremailto walk that stored contact’s branch path, andlimit(1-25, default 10) to control the current-match sample. Call this beforeenable_sequencesend_sequence_test_email- Send one savedaction_emailstep to 1-10 internal reviewers without enabling the sequence or enrolling subscribers. Pass thesequenceIdandnodeIdfrom aget_sequenceemail entry only when itsnodeTypeisaction_email;action_ab_testvariants are not supported by this tool and should be inspected onget_sequence.sequence.emails[].abTest.variants. Each result includes a durableemailSendIdforget_email_sendcreate_sequence- Create a sequence with:- Only
namefor a blank, disabled trigger-to-completion draft matching the dashboard;triggerdefaults tocontact_added - Dashboard metadata (
description,labels,userCancellable, and sequence BCC recipients) plus full From/Reply-To identity trigger: "inbound_webhook"with integration metadata, in addition to list, tag, segment, event, inactivity, and frequency triggerstrigger: "segment_entered"plussegmentIdfor saved-segment entry automationstrigger: "segment_exited"plussegmentIdto enroll active contacts who stop matching a saved segmentlistIdsfor acontact_addedtrigger covering several lists, andtagNamesfor atag_addedtrigger covering several tags - joining or receiving ANY of them enrolls the contact (up to 25 values each). Use these when the user says “when added to list A or list B”listScopeforcontact_addedtriggers with no list at all:any_contact(the default) enrolls every contact that is added, including the list-less contacts an integration creates when its list targeting is empty, whileany_listwaits until the contact joins a list. It cannot be combined withlistId/listIdsgoal- AI generates email contentdurationDays- total duration used to space AI-generated emails when usinggoalemailStyle-visual(designed) orplain(text-first) for AI-generated emails; defaults to the company’s saved preferencestepswithblocks- Sequenzy JSON block formatstepswithhtml- Any HTML (React Email, MJML, provider exports, etc.) preserved as one raw HTML blockstepswithattachments- URL-backed file attachments ([{ filename, path }]) fetched at send time. For event-triggered sequences,pathcan use an event value such as{{event.file_url}}, andfilenamecan also contain merge tags (max 10 per email, 15MB total)enrollmentMode: "matching_field"for event-triggered product-, variant-, order-, or subscription-specific sequences that should block duplicate active runs only for the same resolved field- A scalar
enrollmentFieldPath, such asorder.idorproduct.providerVariantId, when you wantmatching_fieldto use a custom event property. Array traversal with[]is supported bypropertyFilters, not enrollment keys propertyFiltersforevent_receivedtriggers - only start the sequence when the event properties match, e.g. scope a purchase sequence to one product with{ "path": "lineItems[].providerProductId", "operator": "equals", "value": "prod_123" }(orproductIdsfor Stripesaas.purchaseevents)- For
event_receivedsequences, step content can use{{event.amount}},{{event.order.id}}, or other{{event.*}}merge tags from the event payload that enrolled the subscriber - Custom-event responses include
eventTrackingCodepluseventTracking, which gives the endpoint, normalized trigger filters, a generated payload example,examplePayloadMatchesFilters, the direct docs URL, and arguments forget_integration_guide. When the example does not satisfy every filter automatically, followexamplePayloadNoteand adapt it before sending
- Only
update_sequence- Modify a sequence, target a specific step with theemailIdornodeIdreturned byget_sequence(email steps only -action_ab_teststeps keep their copy on the test’s variants), atomically replace its typed trigger, or updateenrollmentMode/enrollmentFieldPath. SetbccEmailsto blind-copy team inboxes on every email the sequence sends (useclearBccEmailsto remove them). Email steps also acceptattachments([{ filename, path }]) - URL-backed files fetched and attached at send time;pathmay be an{{event.*}}URL template resolved separately for each enrollment, and[]removes them. Tag, list, wait, condition, and webhook steps added throughinsertStepsor abranchpath carry their node fields inconfig:action_add_tag/action_remove_tagtaketagName(ortagIdwhen you have the real tag ID),action_add_to_list/action_remove_from_listtakelistId,logic_wait_for_eventtakeseventNamewithtimeoutDays/timeoutAction,logic_conditiontakesconditionTypeplus its resource field,action_webhooktakes an HTTPSurlwith optionalmethod(GET/POST/PUT/PATCH/DELETE),headers, a JSONbodytemplate,resultKey(saves the response for later{{webhooks.KEY.data.field}}merge tags), andonError(continue/exit/fail), andaction_aitakes a merge-tagprompt, a requiredresultKey,outputFieldswith per-field fallbacks whose combined limits fit a 2000-token response budget, and optionalincludeTags/includeEventProperties/includeRecentEvents(withrecentEventLimit, 1-50, default 10)/includeAttributescontext selectors so later steps can read{{ai.KEY.field}}; SMS, discount, and delay steps keep using their step-level fieldsupdate_sequence_node- Patch one existing node in place using itsnodeId. It cannot edit the copy of anaction_ab_teststep, which lives on the test’s variants - read those blocks fromget_sequence.sequence.emails[].abTest.variantsand change each one withupdate_ab_test_variant. It supports every stored node type: delays, email/SMS content, actions, conditions, branch configuration without topology changes, webhooks, and triggers. Pass the node’s latestupdatedAtasexpectedUpdatedAtto prevent stale writes.action_emailnodes acceptemailThemeto restyle that one step’s linked email -{ "emailTheme": { "colors": { "background": "#ffffff" } } }repaints only that email’s background and leaves the account-wide theme and every other email alone. It is a partial patch merged into the email’s current theme (or the company theme when the step has no override yet);nulldrops the override so the step follows the company theme again, andget_sequenceechoes the stored override back asemailThemeupdate_sequence_nodes- Apply multiple type-aware node patches atomically. Use this for bulk edits such as changing every 5-minute delay to 7 days, or restyling several email nodes at once with{ "emailPreset": "minimal" }or{ "emailTheme": { "colors": { "background": "#ffffff" } } }; either every patch commits or none doedit_sequence_graph- Atomically move, reconnect, delete, or deep-copy existing sequence nodes using the latestgraphRevision; deleting a step immediately moves parked recipients to its unique surviving successor, or completes them when no successor remains, and returnsmigratedRecipientCount/completedRecipientCount; active sequences require explicit structural-change confirmationinsert_sequence_step- Insert a typed email, SMS, delay, discount, subscriber-update, tag/list, outbound webhook, AI, condition,logic_wait_for_event, orlogic_branchstep. AI steps (type: "ai") accept a merge-tagprompt, a requiredresultKey,outputFieldswith per-field fallbacks, and optional context selectors; later steps read the output with{{ai.KEY.field}}merge tags. Webhooks accept an HTTPS URL, a GET/POST/PUT/PATCH/DELETE method, string-valued headers, a JSONbodytemplate, aresultKeythat saves the response for later{{webhooks.KEY.data.field}}merge tags, andonErrorfailure behavior; URL, headers, and body support merge tags resolved at execution time. Wait nodes accepteventName,timeoutDays, andtimeoutAction. Branch paths accept typed conditions plustargetNodeId/elseTargetNodeId, new path steps, or both, so one atomic call can route a reply path to completion and Else to an existing follow-up. PasssplitMode: "random"withrandomPercentagesto make the branch a weighted A/B split instead, which routes by percentage rather than by condition and has no else pathenable_sequence/disable_sequence- Control statusduplicate_sequence- Create an independent draft copy, including graph, emails, and sequence A/B testscreate_sequence_from_example- Clone a public email gallery sequence into a draft with the example’s trigger and timing (up to 12 emails); AI writes each email in your brand in the background, so pollget_sequenceuntilenrichmentStatusiscompletearchive_sequence/unarchive_sequence- Move a sequence into the dashboard archive or restore it as a draftlist_sequence_goals/create_sequence_goal/update_sequence_goal/delete_sequence_goal- Manage the persisted event, subscriber-attribute, or tag-applied conversion goals shown by the dashboardget_sequence_inbound_webhook/configure_sequence_inbound_webhook/rotate_sequence_inbound_webhook_secret- Read and configure the secret endpoint, field mapping, sample payload, and setup state attached to an inbound-webhook sequence trigger on standard MCP. The OpenAI-reviewed surface removes credential-bearing URLs from read/configure results and omits secret rotation; use the returned sequence dashboard URL thereenroll_sequence_audience- Estimate (default) or, withdryRun: false, start a background run that enrolls a whole audience ({ type: "all" }, lists, a segment, a filter, or rules) with no per-call cap. Contacts already in the sequence are skipped and unsubscribed or bounced contacts are never enrolled. This is how a manual-trigger countdown sequence gets its audience; late enrollees skip steps whose key date already passed. Poll withget_sequence_audience_enrollment, list runs withlist_sequence_audience_enrollments, stop one withcancel_sequence_audience_enrollment.enroll_subscribers_in_sequence- Manually enroll up to 500 subscribers by email, subscriber ID, or both. Only active subscribers are enrolled: unknown emails are returned innotFound, and inactive, unavailable, or already enrolled subscribers are counted inskipped. PasstargetNodeId(a non-triggernodeIdfromget_sequence) to start at a specific step instead of the first step after the trigger. The sequence must be accepting entrants.list_sequence_enrollments- List the individual contacts enrolled in a sequence, with the node each one is sitting on. This is the contact-level view behindget_sequence_statsenrollmentCounts: filter bycurrentNodeId(IDs come fromenrollmentCounts.byCurrentNodeorget_sequence),status(defaults to active and waiting),subscriberId, oremail. Each row carriesemail,firstName,lastName,currentNodeLabel,currentNodeType,enrollmentStartedAt,waitUntil(when a waiting contact resumes),failedReason(why afailedenrollment stopped;nullotherwise), andmovedFromNodeId/movedAt/moveReason(set whenmove_sequence_enrollmentsreleased the contact onto its current step),enteredVia(the list, tag, segment, event, inactivity check, or frequency check that enrolled the contact - the way to tell entrants apart when a trigger covers several lists or tags),entryContext(event id and property keys, never values), andbranchDecisions(redacted if/else verdicts with the compared field name and a missing/empty/nonempty/equals_expected summary). Passstatus: "failed"to triage a step that is not delivering - failures are terminal, and the samefailedReasonon onecurrentNodeIdacross several contacts points at that step rather than at the contacts. Sort withwait_until_ascto see who moves next, and page withlimit(up to 500) andoffsetuntilpagination.hasMoreisfalseto export the full list. The response always echoes the sequence’s single configuredstopCondition, including anymatchConfigevent-property filters, field comparison, orentry_audienceresolver; entry-audience defaults usevalue: nulland resolve the enrolling tag or list per contact. A stop condition is re-checked when an enrollment next runs a step, not when its event arrives, so a contact whose stop event already landed can keep reportingwaitinguntil its delay expires. PassstopConditionMatch: trueto inspect the current state and readstopConditionMatchesper row, wherenullmeans “not determined” rather than “does not match”. This is a non-atomic snapshot: a step already past its stop check may still finish. See when a stop condition actually cancels.get_sequence_enrollment- Read one enrollment token, including bounded ClickHousenodeHistory. Use this when a completed token lists asenteredViaunknown or Sequence completed with no email: reconstructed branch decisions are redacted (field name + missing/empty/nonempty/equals_expected), never the raw compared value. ChecknodeHistoryTruncatedandbranchDecisionsTruncatedbefore treating either audit trail as complete. TakeenrollmentIdfromlist_sequence_enrollments.cancel_sequence_enrollments- Stop active or waiting enrollments in a required sequence. TargetcancelAll: trueto drain every enrollment (the right move when segment-triggered contacts share no entry field value, and the only way to stop contacts already mid-flight - pausing enrollment just blocks new entrants),subscriberIdsfor a batch of up to 500,subscriberIdfor one contact, or entry-eventfieldValues. Field-value cancellation can usefieldPathor the sequence’s configuredenrollmentFieldPath. Every bulk target defaults todryRun: true; passdryRun: falseto apply, then repeat the call while the response reportsremainingCountabove zero.move_sequence_enrollments- Release a bounded batch of contacts off one sequence step and onto another, keeping their enrollment. Use this instead of cancel-then-re-enroll when you want the next N contacts waiting on a delay to continue early: cancelling discards the enrollment’s entry event properties, stop-condition snapshots, and start date, and re-enrolling is refused while new enrollment is paused. RequiresfromNodeId;targetNodeIddefaults to that step’s only next step.limitdefaults to 100 and caps at 500,sortdefaults towait_until_asc(longest-waiting first),dailyLimitrefuses to release more than that many onto the target step in a rolling 24 hours, andtagsmarks the released wave with existing tag names (needssubscribers:tag). Defaults todryRun: true; passdryRun: falseto apply, then repeat whileremainingCountis above zero. Moved contacts become active immediately, so the sequence emails them as soon as a worker picks them up.realign_sequence_enrollments- Pull waiting enrollments in a required sequence forward to the start of its sending window on the day they are already scheduled for. Run it after changingsendingWindow(or a wait-until-weekday step) on a live sequence: existing waits keep the time their delay produced, so a widened window never reaches contacts already parked on an email-bound delay step and a narrowed one defers them to the next allowed day. Sequence windows never advance SMS, webhooks, branches, or other non-email actions. A wait only ever moves earlier, never onto a different local day, and never before now; nobody is cancelled or re-enrolled. Narrow it withnodeIdsorsubscriberIds. Defaults todryRun: true; passdryRun: falseto queue an applied job.get_sequence_enrollment_realignment- Poll thejobIdreturned by an appliedrealign_sequence_enrollmentscall. Whenstatusiscompleted, inspectresult; ifresult.hasMoreis true, queue the next bounded apply withresult.nextCursorascursor.
blocks on create_sequence, update_sequence, and
insert_sequence_step are validated against the same block schema campaigns and
transactional emails use. A structurally invalid block is rejected with the step,
block index, and field named rather than stored, because a stored block the
renderer cannot render fails every enrollment at that step. Fields that parse but
will not render as their name suggests come back in an advisory warnings array
on success, so treat a quiet response - not just a successful one - as
confirmation that everything you sent took effect. A standalone button block may
be written with buttonText and buttonUrl, which are accepted as aliases for
text and url.
For node updates, call get_sequence immediately before writing. Start with the
returned node config and send only changed fields. Delay nodes use a readable
patch such as { "delay": { "days": 7 } }, delayMs, waitUntil, or
waitUntilWeekday (for example { "waitUntilWeekday": { "day": "sunday", "startTime": "09:00", "endTime": "12:00", "timezone": "America/Los_Angeles" } }
to hold the next step until the next Sunday-morning window; contacts already
inside the window continue immediately). A waitUntilWeekday delay placed
immediately before an email is a hard timing gate for that send - any
intervening step can move delivery outside the weekday window. A
sequence-level sendingWindow holds emails at send time but does not
reschedule the graph. Node
updates for action_email can set { "emailPreset": "minimal" } to change
only that linked email’s Style > Format without changing the company theme.
This applies the same transformation as the dashboard to native Sequenzy
blocks, including emails that contain supported custom HTML blocks. An email
stored entirely as one standalone raw HTML block does not support emailPreset,
and emailPreset cannot be combined with html or htmlContent.
Existing node patches and arbitrary graph topology are intentionally separate:
use insert_sequence_step for a new typed branch or wait node, and use
edit_sequence_graph to add/remove branch paths, reconnect edges, reorder
nodes, or convert the flow structure. Updating an active sequence requires
confirmLiveChange: true after
the user confirms the impact. Recipients already waiting keep their existing
scheduled timestamp; the new delay applies to recipients that reach that node
after the update.
For the common “suppress the second email after a reply” flow, call
get_sequence, take the first email, follow-up, and completion node IDs, then
insert the branch in one request:
splitMode: "random". Each path becomes a weighted variant, no
subscriber attribute is evaluated, and the percentages must sum to 100. A
random split has no else path, so omit conditionType, all condition-specific
fields, elseSteps, and elseTargetNodeId:
create_ab_test with automationNodeId instead.
Branches inside a branch path
A path’ssteps array builds one linear chain of nodes, so it cannot contain
another branch. Nested branches are still supported - insert them as their own
insert_sequence_step call:
- Insert the outer branch. End each path with the step the nested branch
should follow, such as the wait before the flow re-evaluates the contact.
Every path’s last step automatically connects to whatever already followed
afterNodeId, so the shared steps after the branch exist only once. - Read
addedBranchPathNodeIdsfrom the response. It maps each branch ID to that path’s new node IDs, in order, so no extraget_sequencecall is needed. - For each path that needs to re-evaluate, insert a second
logic_branchwithafterNodeIdset to that path’s last node ID. Its own paths reconnect to the same shared step downstream.
addedBranchPathNodeIds: { "catalogue_empty": ["node_a", "node_b"], "else": [] }.
Insert the Day 21 re-check after node_b, and each of its paths ends at
node_final_email without copying that email:
logic_branch object inside a path’s steps array is rejected with a
message pointing at this pattern. For a check that only needs to gate the flow -
continue when it passes, exit the sequence when it does not - use a
nodeType: "logic_condition" step inside the path instead; it stays linear and
needs no second call.
Transactional
list_transactional_emails- Search and filter transactional templates by name, slug, subject/title, or active state; sort by delivery metrics; and return each template’s dashboard URLget_transactional_email- Read a transactional email by ID or slug, including body blockscreate_transactional_email- Create a transactional template from a prompt, raw HTML, or Sequenzy blocks. Prompt-generated templates include company branding with no unsubscribe linkupdate_transactional_email- Update transactional email metadata or body contentdelete_transactional_email- Permanently delete a saved transactional template by ID or slug, freeing the slug for reuse. Past deliveries and their stats are kept, and the linked email content stays as a reusable template returned asdeleted.emailId, whichdelete_templatecan remove separately. To stop sends without losing the template, setenabledtofalsewithupdate_transactional_emailinsteadsend_email- Send one email using directsubjectandhtmlcontent (mapped to the transactional API’ssubjectandbodyfields), or pass a saved transactional email API slug through the compatibility-namedtemplateIdfield.to,cc, andbcceach accept a single address or an array of up to 50, so a transactional send delivers one email with a shared recipient list rather than one email per address. Addresses repeated across the fields are dropped from the lower-priority one (tobeatsccbeatsbcc), and the result echoes the accepted lists. Marketing sends still take exactly onetoaddress and rejectccandbcc, because suppression and one-click unsubscribe apply per subscriber. Itsvariablesobject supports nested arrays for repeat blocks, such as{ "event": { "items": [...] } }. Attachments accept Base64contentor a publicpath(up to 10 files / 15MB total); setcontentIdto embed a CID image referenced from the HTML andcontentTypeto override MIME detection. When a single recipient matches a subscriber, saved first and last names fill omitted name variables; explicitvariablesvalues take precedence. The result echoes the acceptedemailType. OptionalfromEmail/fromNameandreplyTo/replyToNamepick an existing verified brand identity for that one send without profile IDs; they do not create profiles.fromEmaillooks up a send-ready sender by address, and if several identities share the address passfromName(orsenderProfileIdfromlist_sender_profiles).senderProfileId/replyProfileIdremain available when you already have them. When those fields are omitted, a template send keeps its saved From and Reply-To identities, while a direct send uses the company defaults.replyToremains a one-off Reply-To string and is mutually exclusive withreplyProfileId.{{viewInBrowserUrl}}becomes a hosted copy link. WhentrackingSettingsis omitted, the account’s Transactional API tracking defaults apply. SetclickTrackingoropenTrackingtofalseto opt out for that send only; these fields cannot enable tracking disabled by the account defaults. The optionalheadersobject adds extra email headers, such as your ownList-Unsubscribeon a transactional send; marketing sends keep Sequenzy’s signed unsubscribe headers, and headers Sequenzy manages are never applied. Header values must be strings. Headers the API does not apply are listed in the result’signoredHeaderswith a reason instead of failing the send.get_transactional_stats- Inspect top clicked links, complaints, replies, bounce classifications, and separate human/machine engagement for one saved templatelist_email_sends- Search recent delivery history and return a dashboard URL on every delivery; every row carriessubscriberId,automationNodeId, andabTestVariantId, and a returned ID withget_email_sendgives the full timeline
Segments
list_segments- List saved segmentscreate_segment- Create a segment from explicit filters, including nested AND/OR groups, event filters, segment filters, Stripe product purchase filters, and optionalfilterJoinOperatorupdate_segment- Update a segment’s name and/or replace its filter rules using the samefiltersplusfilterJoinOperatoror nestedrootshapes ascreate_segmentdelete_segment- Permanently delete a segment; subscribers are not affectedget_segment_count- Preview how many active subscribers match a segment
{"id":"filter-1","field":"stripeProduct","operator":"is","value":"prod_pro"}for “bought product”{"id":"filter-1","field":"stripeProduct","operator":"is_not","value":"prod_pro"}for “didn’t buy product”{"id":"filter-1","field":"stripeProduct","operator":"at_least","value":"prod_pro:3"}for “at least 3 payments”{"id":"filter-1","field":"stripeProduct","operator":"less_than_count","value":"prod_pro:3"}for “fewer than 3 payments”{"id":"filter-1","field":"stripeCurrentProduct","operator":"is","value":"prod_pro"}for “currently has product”{"id":"filter-1","field":"stripeTrialProduct","operator":"is","value":"prod_pro"}for “currently trialing product”{"id":"filter-1","field":"stripeTrialProduct","operator":"is","value":"prod_pro:is_canceled"}for “trialing product is set to cancel”{"id":"filter-1","field":"stripeTrialProduct","operator":"gte","value":"prod_pro:start_at:7 days ago"}for “trial started in the last 7 days”{"id":"filter-1","field":"stripeTrialProduct","operator":"is","value":"prod_pro:end_at:2026-05-26"}for “trial ends on May 26, 2026”
commerceProduct field. The value is provider:productId - product IDs are provider-scoped, so the provider prefix (shopify, woocommerce, or api) tells the filter which catalog the ID belongs to. A bare product ID matches the ID on any provider:
{"id":"filter-1","field":"commerceProduct","operator":"is","value":"api:prod-starter-kit"}for “bought product”{"id":"filter-1","field":"commerceProduct","operator":"is_not","value":"api:prod-starter-kit"}for “didn’t buy product”{"id":"filter-1","field":"commerceProduct","operator":"at_least","value":"shopify:42:2"}for “placed at least 2 orders containing the product”{"id":"filter-1","field":"commerceProduct","operator":"less_than_count","value":"shopify:42:2"}for “fewer than 2 orders containing the product”
commerceCollection field. The value is a collection ID or handle, optionally provider-prefixed, with the same optional order-count threshold:
{"id":"filter-1","field":"commerceCollection","operator":"is","value":"skincare"}for “bought anything from the collection”{"id":"filter-1","field":"commerceCollection","operator":"is_not","value":"skincare"}for “never bought from the collection”{"id":"filter-1","field":"commerceCollection","operator":"at_least","value":"shopify:skincare:2"}for “placed at least 2 orders from the collection”
emailSent, emailDelivered, emailOpened, emailClicked, emailBounced, emailComplained), the value can be a rolling time window (7d, 30d, 90d, 180d, all), a specific sent campaign via campaign:<campaign_id>, an email-type scope via marketing:<timeRange> (marketing-policy campaign, automation, and Send API traffic) or transactional:<timeRange> (transactional-policy sends), or - with the at_least / less_than_count operators - a count with a time window in count:timeRange format:
{"id":"filter-1","field":"emailClicked","operator":"at_least","value":"10:all"}for “clicked 10 or more times ever”{"id":"filter-1","field":"emailOpened","operator":"less_than_count","value":"2:90d"}for “opened fewer than 2 times in the last 90 days”{"id":"filter-1","field":"emailSent","operator":"is_not","value":"marketing:7d"}for “no marketing email in the last 7 days” (email-type values work withis,is_not, and the two bounce-subtype operators; not count operators)
{"id":"filter-1","field":"emailBounced","operator":"is","value":"campaign:cmp_abc"}{"id":"filter-2","field":"emailBounced","operator":"is_not","value":"campaign:cmp_xyz"}
list_campaigns to look up the campaign IDs.
By default, segment filters use AND logic. To match any filter instead of all of them, pass filterJoinOperator: "or" when calling create_segment.
For nested logic, pass a v2 root group instead of filters:
eventName:range for is / is_not and eventName:count:range for at_least / less_than_count. Segment filter values are saved segment IDs.
list_segments returns both:
subscriberCount- all matched contacts, including unsubscribed or bounced contactsactiveSubscriberCount- contacts eligible for campaigns
get_segment_count returns the active count, because campaigns and most send flows only target active subscribers.
Audience Syncs
Push segments to Meta custom audiences for Facebook and Instagram retargeting. Requires the Meta Ads integration to be connected in the dashboard (Settings → Integrations).list_audience_syncs- List segment-to-audience syncs with schedule and last sync statuslist_ad_accounts- List the Meta ad accounts available for syncingcreate_audience_sync- Create a sync from an existing segment (segmentId) or a ready-made template (predefinedSegmentId, for examplezero-ltv,no-purchase-1y,recent-buyers); the first upload runs immediatelyupdate_audience_sync- Change the frequency (hourly,daily,weekly) or pause/resume viaisActivedelete_audience_sync- Remove a sync; the Meta audience itself is keptsync_audience_now- Trigger an immediate upload outside the schedule
Warehouse Sync
Import contacts and events from the user’s Snowflake, BigQuery, Redshift or Postgres. See Warehouse Sync.list_warehouse_connections- List connections with status and number of syncscreate_warehouse_connection- Connect a warehouse with a read-only user; a test query runs before savingupdate_warehouse_connection- Rename, change settings or rotate credentials (re-tested)delete_warehouse_connection- Delete a connection that has no syncstest_warehouse_connection- Re-run the test querypreview_warehouse_query- Run a query with a 20-row limit to see its columnslist_warehouse_syncs/get_warehouse_sync- Syncs with status, cursor position and the latest runcreate_warehouse_sync- Sync contacts (subscribers) or events on existing contacts (events) from a query on a scheduleupdate_warehouse_sync- Change the query, mapping, cursor, schedule or options, or pause/resume viaisEnableddelete_warehouse_sync- Stop a sync; imported data staysrun_warehouse_sync- Run now, optionally withfullResynclist_warehouse_sync_runs- Row counts, sample problems and import progress per run
create_warehouse_connection, update_warehouse_connection and preview_warehouse_query are not available on the OpenAI-reviewed MCP surface.
Data Exports
Stream workspace data to the user’s own S3, Google Cloud Storage or S3-compatible bucket. See Data Exports.list_data_exports- List exports with status, per-dataset progress (exportedThrough) and the last errorget_data_export- Get one exportcreate_data_export- Add a bucket; a test file is written first and the first export starts immediatelyupdate_data_export- Rename, change datasets or frequency, pause/resume viaisEnabled, move, or rotate credentials (accessKeyIdwithsecretAccessKey)delete_data_export- Stop exporting; files already written are kepttest_data_export- Write a test file with the stored credentialsrun_data_export- Export now instead of waiting for the schedulelist_data_export_runs- Recent runs with rows, files, bytes and errors
create_data_export and update_data_export accept storage credentials and are not available on the OpenAI-reviewed MCP surface.
Products & Digital Delivery
list_products- List synced products (Stripe, Shopify, WooCommerce, api) including any attached delivery file. Returns one page; supportslimitandoffset, and reportspagination.totalandpagination.hasMoreso you can tell a truncated page from the full catalogupsert_products- Create or update products in the catalog (Commerce API, keyed by yourproductId, up to 100 per call)delete_product- Delete a product previously pushed viaupsert_productsattach_product_file- Attach a distributable file to a product, delivered after purchase. Passurlfor a hosted file, orfilePathto upload a local file (local MCP server only)remove_product_file- Remove the attached file from a productsync_products- Queue a sync of the Stripe product catalog
saas.purchase event with download.url and download.name, so purchase sequences can deliver the file with {{event.download.url}}. See Digital Product Delivery.
Image Assets
upload_image_asset- Upload a PNG, JPEG, GIF, or WebP image (up to 10MB) to the selected company’s shared media library. The tool returns the hostedasset.urland a completeimageBlockthat can be inserted into campaign, sequence, saved-template, or transactional-email blocks.
filePath when the local stdio MCP server runs on the same machine as the
image. For a remote MCP connector, use imageBase64 plus filename when the
client can expose the attachment bytes. This keeps binary image data out of
create_sequence and update_sequence while still making the resulting URL
available to every block-based email surface.
For a responsive lifecycle screenshot, set displayWidthPercent: 100. Add
cropHeight with objectFit: "cover" for a fixed-height centered crop, or use
"contain" when the full screenshot must remain visible. altText is stored
with the media asset and returned as imageBlock.alt.
For product walkthrough images with focus rings, arrows, and drop shadows, use
the Product Screenshot Workflow to capture and
annotate the screen first, then upload the generated PNG here.
imageBlock into the exact email step’s blocks array
with update_sequence (or the corresponding campaign/template tool). Image
upload alone never changes or sends an email.
Tags
list_tags- List all tags in the accountcreate_tag- Create a tag definition. Names are normalized to lowercase with hyphens (VIP Customerbecomesvip-customer); color defaults tograyupdate_tag- Update a tag’s color; system tags cannot be changeddelete_tag- Permanently delete a tag and remove it from all subscribers; system tags and tags used by sequences cannot be deleted
Templates
list_templates- List email templates newest first, with localization status by locale. PassisTemplate: trueto list only reusable master designs. Templates are the company’s saved email bodies - standalone templates plus the bodies behind campaigns and transactional emails - so dashboard-designed emails appear here, and a campaign’semailIdpoints at its entry. Returns 50 per call by default (limitaccepts up to 100); page withoffsetwhilepagination.hasMoreis true, and readpagination.totalfor the full countget_template- Get a template’s details, content, and localized variants.isTemplateis true for reusable master designscreate_template- Create a template from a prompt, raw HTML, or Sequenzy blocks. PassisTemplate: trueto save it as a reusable master design that sequence steps and campaigns start from (always as an independent copy)create_template_from_example- Remix a public email gallery email into a new template: the example’s exact layout with the text rewritten for your brand and your logo, color and links swapped in, without naming the example brandupdate_template- Update template metadata, inbox preview text, raw HTML, Sequenzy blocks, labels, or theisTemplatemarkset_template_localization- Create or replace a caller-supplied localized variant. PasskeepEdits: trueto protect it like a dashboard edit: automatic on-save translation then keeps it and marks itstalewhen the original changessync_template_localizations- Queue AI translation for selected or all enabled non-primary locales. PassskipEdited: trueto keep edited variants; they come back inskippedLocalesshare_template- Create (or fetch) the public “view in browser” link for an individual email - a transactional email (by ID or slug), a sequence email (by the step’semailId), or a standalone template. The hosted page renders an anonymized copy - sample contact, inert unsubscribe link, no open/click tracking. Idempotent: an already-active link is returned withcreated: false.get_templatereports the current link asshareUrl. Campaign links follow the A/B winning variant, so share campaigns withshare_campaigninsteadunshare_template- Revoke the public link; the shared URL returns 404 immediately, and sharing again later mints a different URL
create_template with prompt generates new content without preserving an
existing layout. Supplied blocks or HTML create a new body; localized variants
must be supplied separately.
For campaign copies, the existing create_campaign tool accepts templateId;
it cannot be combined with prompt for an AI rewrite.
Email Blocks
Every tool that writes email content -create_campaign, create_sequence, create_template, update_sequence_node, create_email_component - takes a blocks array. That parameter is declared as a plain object array because the block schema is a large union that would be larger than the rest of the tool schema put together, so this tool is where you look the shapes up.
get_email_block_schema- Required and optional fields for each block type, the allowed values of every enum field, and the shape of nested item arrays and nested objects. OmitblockTypeto list every type; pass one for its full reference plus a minimal valid example and authoring notes. PasscreatableOnly: trueto hide structural types such asgroupthat the editor manages.conditionFields, the per-field table for block conditions - which operators each condition field accepts, how itsvalueis shaped, and what a preview needs to evaluate it - comes back when you list every type and when you ask forconditional-group; on any other single type passconditionFields: true, since the table is several times the size of one block’s reference
get_email_block_schema is not in the MCP tool list, enable it on the Sequenzy connector rather than inferring field names from live HTML; the same reference is also the sequenzy://email-blocks resource, GET /api/v1/email-blocks, and sequenzy blocks <type>. The one shape worth knowing without looking it up: lists are their own block type rather than a text variant.
Video blocks accept an optional thumbnailUrl. Block updates replace the supplied block array, so omit thumbnailUrl to restore YouTube’s own still; videoUrl remains the click destination.
text block accepts only variant: "paragraph" | "lead" | "html" and never accepts items, so {"type": "text", "variant": "numbered"} is rejected. Use list for a plain numbered or bulleted list, and steps for a visual numbered walkthrough with a title and description per step. List items carry content; steps items carry title and an optional description.
Configuration nested inside a block is described the same way. A field of type object carries its own fields, so get_email_block_schema with blockType: "repeat" is where you read that productSource takes strategy (personalized, bestsellers, newest, recently_viewed) alongside mode - see Product Recommendations.
When a block write is rejected, the error names the block type it was validated against, that type’s required and optional fields, the shape of the nested array entry or object that failed, and any field you sent that the type does not accept - so a rejection is usually fixable without a second lookup.
Email Components
Components are saved block groups you can reuse across emails. The component pinned to thefooter slot is the footer every new sequence, campaign, and AI-generated email is built with, so editing it is how you change the footer everywhere at once - editing one email’s blocks only changes that email.
get_default_email_component- Read the company’s default component for a slot. Call this before changing the footer, then edit the blocks it returnsset_default_email_component- Create or replace the default component for a slot. Replaces the whole component, so read it first when you only mean to change part of itlist_email_components- List reusable components newest first; passdefaultsOnlyto see only the pinned defaultsget_email_component- Get one component’s blocks,version, and default-slot statuscreate_email_component- Save a block group as a reusable component. Names are unique per companyupdate_email_component- Update metadata or replace blocks. Replacing blocks bumps the componentversiondelete_email_component- Delete a component. Emails that already use it keep their copied blocks
{{unsubscribeUrl}}.
A/B Tests
list_ab_tests- List A/B tests and variants, optionally scoped by sequenceget_ab_test- Get effective settings, variants, content, and localization status. Copy the returnedsettingsobject; sequencetestPercentage: 100andtestDurationMinutes: 0values are legacy sentinelsget_ab_test_stats- Get aggregate and per-variant stats, plussignificance: whether the leading variant’s advantage on the winning metric is statistically significant at 95% confidenceselect_ab_test_winner- Select a campaign test winner and queue the winning variant for the remaining audience, which starts external email delivery. On a sequence test, select or change the winner, including one picked automatically, for everyone who reaches the step afterwards; sequence tests needsequences:writeinstead ofcampaigns:send, andconfirmLiveChange: truewhile the sequence is activeresume_ab_test- Clear a sequence test’s winner so contacts are split across the variants again, keeping the results so far. The test then waits forselect_ab_test_winnerinstead of picking automatically;update_ab_testwithautoSelectWinner: trueturns automatic selection back on. PassconfirmLiveChange: truewhile the sequence is activecreate_ab_test- Provide exactly one ofcampaignIdorautomationNodeId. Campaign tests usetestPercentage,testDurationMinutes, andwinnerCriteria; a sequence email node is converted toaction_ab_testwithtestType,winnerThreshold, andwinnerCriteria. An explicit sequencewinnerCriteriaoverrides the test-type default. PassconfirmLiveChange: truewhen converting a node in an active sequence. Control variant A is created automaticallyupdate_ab_test- Update campaign or sequence settings. Campaign tests accept percentage/duration/criteria; sequence tests accept type/threshold/criteria and requireconfirmLiveChange: truefor active or already-used testsadd_ab_test_variant- Add a variant to a draft campaign or sequence A/B test; sequence variants receive independent email templatesupdate_ab_test_variant- Update a variant’s subject, preview text, HTML, or blocks. Campaign variants are editable in draft only; sequence variants stay editable, withconfirmLiveChange: trueonce the sequence is active or the test has activitydelete_ab_test_variant- Permanently remove a variant from a draft campaign or sequence A/B test; variant A is the control and cannot be deleteddelete_ab_test- Permanently delete a campaign A/B test and all of its variants; running tests cannot be deleted
get_sequence (or get_ab_test) to discover variant IDs before editing. update_ab_test_variant accepts either html or blocks, not both. Campaign tests can only be changed while in draft; sequence tests keep sending over time and stay editable, but an edit after the test has started requires confirmLiveChange: true and can make combined results inaccurate. Campaign creation requires a draft or rejected campaign; sequence creation requires an action_email node. Variants can only be added or removed while the test is in draft status. When a sequence test’s parent sequence is active, add_ab_test_variant and delete_ab_test_variant also require confirmLiveChange: true because they immediately change the live rotation.
Editing the content of a sequence A/B step
Converting a sequence email step withcreate_ab_test moves that step’s copy off
the node and onto the test’s variants. From then on:
get_sequencestill lists the step insequence.emailswithnodeType: "action_ab_test", but itssubject,previewText, andblocksare control variant A only. Withab_tests:read, the step’sabTestobject carries the test id, status, and one entry per variant including that variant’s fullblocks, plus acontentEditingpointer at the tools below. Without that scope, test-record fields are redacted andvariantsis empty while the configured id and editing guidance remain available.update_sequence_nodecannot change variant content. It still edits the step’s identity fields (label, sender and reply profile, cc/bcc, transactional flag), and rejectsblocks/subject/previewTextwith a pointer atupdate_ab_test_variant.- A change that should apply to the whole step has to be repeated on every variant - otherwise you are changing what the test measures.
- Never rebuild an
action_ab_teststep as a plain email node to reach its content. That destroys the test and its results.
ab_tests:read, ab_tests:write, and sequences:write on the API key. The variant edit itself requires both write scopes. Safer agent access includes all three. A key holding only the sequence scopes sees the redacted A/B summary from get_sequence; calling an A/B tool returns a 403 naming the missing scope, which can be added to the key you are already using. If update_ab_test_variant is missing from the MCP tool list, enable it on the Sequenzy connector rather than writing through update_template or update_sequence_node.
get_ab_test is still the dedicated A/B read for settings, localization, and stats. A sequence-only MCP allowlist can audit variant copy from get_sequence alone.
When you need recipient-specific content, prefer Sequenzy blocks instead of raw HTML. Every block accepts a conditions array so it renders only when its rules match. To branch on a value passed in a transactional send’s variables or an automation event payload, use field: "variable":
variable condition, the text before the colon in value is a merge-tag path (without {{ }}), including nested paths like order.total or event.plan, and the text after it is the comparison value. field can also be attribute (same name:value form) or email / firstName / lastName (the value is the plain comparison string). Operators: is, is_not, contains, not_contains, gt, gte, lt, lte, is_empty, is_not_empty.
Conditions can also read stored subscriber state - tag, segment, list, status, event, purchases, and engagement - and each of those fields accepts only its own operators. A tag condition is written { "field": "tag", "operator": "contains", "value": "extended" }; operator: "is" is rejected for tag, and the rejection names the operators that field does take. get_email_block_schema returns the whole table as conditionFields: the operators per field, the shape of each field’s value, and what a preview needs before it can evaluate that field. Listing every type includes it, as does asking for conditional-group; for any other single type pass conditionFields: true.
Stored-state conditions are evaluated per recipient at send time, so render_email can only evaluate them for a stored subscriberId, or - for a tag condition - an inline subscriber that carries tags. Anything it cannot evaluate renders as false and comes back in unevaluatedConditions, so check that array before treating a preview as proof of which branch a recipient gets.
conditional-group block with ifBranch and elseBranch:
Team
list_team_members- List the company owner, members with their roles, and pending or expired invitationsinvite_team_member- Invite a teammate asadmin,marketer,viewer, orrestricted. Marketers create, edit, and send campaigns and sequences and manage subscribers but cannot access transactional emails, settings, billing, or the team. Existing Sequenzy users are added immediately; everyone else receives an email invitation. Billing access (canManageBilling) can only be granted by the company owner and is not available for marketer or restricted memberscancel_team_invitation- Cancel a pending invitation; accepted invitations cannot be cancelled
Inbox
list_conversations- List subscriber reply conversations with status, search, unread, and pagination filtersget_conversation- Get a conversation with its full message history, subscriber details, and contextreply_to_conversation- Send an outbound reply (requiresbodyTextorbodyHtml) or add an internal team-only note withtype: "note". PasssenderProfileId(fromlist_sender_profiles) to reply from a specific verified sender. Replying to a closed conversation reopens itupdate_conversation_status- Open or close a conversationbulk_update_conversation_status- Open or close up to 100 conversations in one call withconversationIdsandstatus. ReturnsupdatedIds,unchangedIds(already had the status) andnotFoundIds; retrying is safe because only conversations whose status changes are updatedmark_conversation_read- Mark all unread inbound messages in a conversation as read
Webhooks
list_webhooks- List outbound webhook endpoints and their subscribed event typescreate_webhook- Create an endpoint and return its one-time signing secret on the standard MCP surface. It is omitted from the OpenAI-reviewed surface; create it in the dashboard or local CLI thereupdate_webhook- Update a webhook’s name, URL, subscribed events, or enabled/disabled status; providingeventsreplaces the existing listdelete_webhook- Permanently delete a webhook endpoint and stop all deliveries to ittest_webhook- Send a test event to verify the endpoint is reachable and signatures validatelist_webhook_deliveries- List recent delivery attempts, including status and response codesreplay_webhook_delivery- Re-send a previous delivery’s event payload to the endpoint
email.*, sms.*, subscriber.*, and sequence.* events.
Analytics
get_stats- Overview stats (7d/30d/90d). Counts are a funnel over the sends made inside the period:openedandclickedare unique per email send (not total open events) and include engagement that arrives after the period ends, so they never exceedsent. Rates divide byrateDenominator(delivered, falling back tosent), returned withrateDenominatorBasis. Also returns top-levelsubscriberCount(every stored contact) andactiveSubscriberCount(status=active) as a live audience snapshot, independent of period. SetemailTypetotransactionalfor Send API and transactional SMTP open/click rates, including direct and saved-template sendsget_transactional_stats- Aggregate metrics for one saved transactional email by ID or slug, all-time or within a requested period/rangelist_email_metrics- One row per email across the account: each campaign and each sequence email step, with its own funnel, attributed conversions, andrevenueCents. This is the cross-sequence tool: “how many step-4 emails went out across these sequences” is one call withstep: 4plus the returnedtotals, not oneget_sequence_statsper sequence. Sequence rows carrysequenceId,sequenceName,automationNodeId, andstep. Filter byemailType,sequenceId,campaignId, andstep; sort withsort/order; page withpage/limit.totalscovers every matching email, not just the returned page. Counts come from retained event storage, so unlikelist_email_sendsthey are not limited to 14 days; omitperiod/start/endfor all-time countslist_email_sends- Search and filter the recent dashboard delivery history by subject/title, recipient, status, type, or source ID, includingautomationNodeIdto list the recipients of one sequence step. Each row carriesrecipientEmail,subscriberId,automationNodeId,abTestVariantId, and the sent/delivered/opened/clicked timestamps, so rows join into a recipient-level delivery matrix without re-reading the raw event stream. Rows are retained for 14 days, so useget_sequence_statssteps[]orlist_email_metricsfor send totalsget_email_send- Inspect one delivery’s status, timestamps, failure details, stored HTML, and event timeline. Failed test sends appear here too, flaggedisTestEmail: true- a test send is queued rather than delivered inline, so this is where you find out one never arrivedlist_recipient_suppressions- Every associated recipient the workspace currently cannot reach, newest first, with a stablesuppressionType, the reason, the scope (globalblocks every workspace,companyonly this one), and whether the entry can be removed. Global invalid-recipient rows, company hard bounces without conclusive invalid-inbox evidence, and complaints are protected; company soft-bounce escalations are removable. Start here for “why didn’t this person get my email?”: this is the standing list of who is blocked, whereaslist_email_sendsshows individual attempts (a suppressed send does get a row there, with statussuppressed). Filter withsearch, page withpage/limit, and order withsort(suppressedAt,email,status) plusorder(asc/desc) -sort=statussurfaces the removable escalations first, and the response echoes thesortBy/sortOrderactually appliedget_recipient_suppression- Full suppression check for one exact address, including the regional Amazon SES account-level listremove_recipient_suppression- Clear a company-scoped soft-bounce escalation for one associated address and reactivate the matching bounced subscriber. Global invalid-recipient and Amazon SES account-level suppressions, spam complaints, and unsubscribes are protectedget_campaign_stats- Campaign performance, plus a top-levelclickedLinksarray with the per-link click breakdown, a top-levelgoalsarray when conversion goals are attached to the campaign, and a top-levelpollsarray with answer distributions and NPS score/breakdown when the campaign collected survey responsesget_email_client_stats- Mail client (Apple Mail, Gmail, Outlook, …) and device shares of unique opens, for one campaign withcampaignIdor company-wide for a periodlist_poll_responses- Individual Poll and NPS responses for a campaign: each respondent’s email, their answer and stored value, the attribute the answer was saved to, and the response time, newest first. Scope to one block withblockId. Only each subscriber’s latest answer per block is returned, so counts matchget_campaign_stats. Use this instead of scanning subscribers for the poll attribute - the attribute carries no response time and reflects the latest answer to any emailget_sequence_stats- Sequence performance, including astepsarray with each email step’s own sent/delivered/opened/clicked/replies counts, node ID, and subject - read that instead of countinglist_sequence_events. Also returns live active/waiting enrollment-run counts grouped by current node; historical date filters do not limit the live counts. Uselist_sequence_enrollmentsto get the actual contacts behind those counts, andlist_email_metricsto compare the same step across sequenceslist_sequence_events- Paginated raw per-recipient events for a sequence’s email steps, or one step viaautomationNodeId. Use it to see who received or engaged with a step, not to count sendsget_subscriber_activity- Individual activity
AI Generation
generate_email- Create email blocks from a prompt. Company logo/footer branding is included by default; useapplyBranding: falsefor raw content blocks, oremailType: "transactional"for a footer without an unsubscribe linkgenerate_sequence- Deprecated compatibility alias for goal-basedcreate_sequence; it persists the same disabled draftgenerate_subject_lines- Generate A/B subject variantsgenerate_sms- Generate SMS message variants with encoding and segment counts
create_sequence persists a disabled draft automation that appears in
list_sequences; the deprecated generate_sequence alias does the same.
Email and sequence generation include the company’s configured email branding by
default. Sequence generation supports up to 10 emails.
SMS
get_sms_settings- SMS add-on status: enabled, plan eligibility, credit balance, brand prefix, numbers, and areadyToSendflag that accepts either a paid plan or SMS credits plus an active numberupdate_sms_number_label- Update an SMS number’s label and/or its brand prefix overrideget_sms_usage- Per-number usage: sends, delivered, failed, credits charged, last sent, and test-send countssend_test_sms- Send a real test text (charges credits, max 100 per company per rolling 24 hours, bypasses quiet hours); optionally pick which active number it sends fromrelease_sms_number- Release a toll-free number back to the carrier and free its slot under the workspace’s 100-number cap. IMPORTANT: this is irreversible - only call it when the user explicitly asks to remove or release a number
type: "sms" with a plain-text text field in create_sequence steps or insert_sequence_step, and edit existing SMS steps with update_sequence.smsSteps (targeted by action_sms nodeId). Check get_sms_settings first and warn the user when SMS is not ready - steps added early are stored but skip at runtime until the add-on is enabled and a number is verified.
Push Notifications
get_push_settings- Web push, APNs and Firebase readiness, last credential errors, and active device counts per platformupdate_web_push_settings- Turn web push on or off (the first enable generates VAPID keys) or set the default notification iconset_apns_credentials/remove_apns_credentials- Save or remove the APNs auth key (.p8) for iOS pushset_fcm_credentials/remove_fcm_credentials- Save or remove the Firebase service account for Android pushlist_push_devices/register_push_device/remove_push_device- Manage registered browsers and app installs; tokens are never returned in fullsend_test_push- Send a real test push to one device or a contact’s devices (max 200 per company per rolling 24 hours, excluded from stats)list_push_campaigns,get_push_campaign,create_push_campaign,update_push_campaign,duplicate_push_campaign- Manage push campaign draftsestimate_push_campaign_recipients- Count audience contacts with an active devicesend_push_campaign,unschedule_push_campaign,cancel_push_campaign- Send, schedule, unschedule, or stop a push campaign. Confirm with the user before sendingget_push_campaign_stats- Sent, displayed, clicked, failed and skipped counts with reasons
type: "push" with title and/or body (plus optional url, imageUrl, iconUrl, platforms, and ineligibleAction) in create_sequence steps or insert_sequence_step, and edit existing push steps with update_sequence_node. Check get_push_settings first: push steps and campaigns skip contacts until at least one platform is set up. set_apns_credentials and set_fcm_credentials are not available on the OpenAI-reviewed surface because they take private keys. See Push notifications.
Feedback
submit_feedback- Send product feedback about Sequenzy to the Sequenzy team
submit_feedback only when the user explicitly asks to send product feedback to Sequenzy. Categories: missing_capability, bug, docs, ux, praise, other. Every submission goes straight to the team.
The standard surface can include the structured reproduction fields
userIntent, toolCalls, expected, actual, and resourceIds when they are
needed to investigate a user-requested report. The OpenAI-reviewed surface
accepts only the message, category, and optional generalized workflow context,
and rejects feedback text that contains an email address or resource ID.
Never include unrelated subscriber data, email content, raw API payloads,
debug data, secrets, or API keys.
Interactive email and sequence previews
In clients that support MCP Apps, including compatible ChatGPT and Claude connections, you can review your saved emails and sequences directly in the conversation.render_emailopens the rendered email with Desktop (640px) and Mobile (375px) views, its subject, preview text and personalization warnings. Pass a campaign ID, template ID, or sequence ID plus node ID using the existing tool inputs. It renders your saved content through Sequenzy’s email renderer. Personalization and locale options remain available through the same tool.preview_sequence({ companyId, sequenceId })opens the saved sequence as a connected diagram with triggers, delays, branches and actions. Select an email to render it, switch between available A/B variants, or use the Emails tab to browse the sequence’s emails. Random splits show their configured allocation. Refresh reloads saved content, and failed requests offer an explicit retry.
open_image_upload({ companyId })opens an image picker. Choose a PNG, JPEG, GIF or WebP up to 10 MB, optionally describe it, then select Upload image. Opening the widget does not write anything. Submission usesupload_image_assetwith your existing permissions and returns the saved asset to your assistant. After an uncertain failure, check your image library before retrying; uploads are never automatically retried.monitor_subscriber_import({ companyId, importId })shows counts and progress for an existing import. It pollsget_subscriber_importevery five seconds while running, for up to five minutes. Completion, blocked status, errors or leaving the view stop polling. Refresh status restarts monitoring. This does not start or retry imports.
upload_image_asset and get_subscriber_import directly; the same operations are available through the existing REST API and CLI.
The sequence preview requires an explicit company ID from get_account and keeps every email render pinned to that company. Previews never activate sequences, enroll subscribers or send email. A/B previews require the existing access to variant content; unavailable variants are shown as unavailable instead of being replaced with the control email.
Email content is isolated from the widget. Scripts, forms, nested frames and link navigation are disabled; external stylesheets and fonts are not loaded. HTTPS email images may load from their original hosts, subject to the client’s policy. The widget itself bundles its logo and font and uses authenticated MCP tool calls without exposing credentials. Actual email-client rendering can differ, so use test sends for final inbox verification.
Clients without MCP Apps still receive the existing rendered HTML or sequence data. The same workflows are available through the existing public render and sequence-read endpoints and CLI render/sequence commands. No new REST endpoint or CLI command is needed for this presentation layer.
Resources
MCP also provides read-only resources that AI can access:Workflows
Event-personalized sequences
When your AI assistant creates a sequence withtrigger: "event_received", it can place {{event.*}} merge tags directly into step subjects or body content.
Those values come from the properties payload you send to POST /api/v1/subscribers/events.
Example:
- Trigger payload:
{"event":"weather.wind_alert","properties":{"city":"Tel Aviv","alert":{"maxSpeed":75}}} - Sequence subject:
Wind alert for {{event.city}} - Sequence body:
Winds may reach {{event.alert.maxSpeed}} km/h.
Apply a default footer to existing emails
You can save for future emails only, or preview and apply to selectedsequences,
campaigns, transactional, and templates. Campaigns must be draft or scheduled;
sent and in-progress content stays unchanged. Draft A/B variants and localizations
are included. Customized footers are preserved unless you explicitly include them.
Raw HTML, missing or ambiguous footers, and content shared with a protected owner
are skipped with reasons.
Preview is read-only. Review the affected counts, skipped reasons, and optional
before/after HTML, then apply with the returned token and identical blocks,
metadata, and scope options. If the relevant saved content changes, application
returns 409; preview again. A successful application saves the default and
selected content atomically. It does not send emails.
Layout previews use the email theme and locale, with placeholder personalization.
They are not subscriber-specific inbox previews. You can request a particular
sample by its affected item id and kind (email, ab_variant, or localization).
Use preview_default_email_component with slot: "footer", blocks,
application: { scopes: ["sequences", "campaigns", "transactional", "templates"], includeCustomized: false }, and renderPreview: true. Inspect
renderedPreview.footerHtml and renderedPreview.samples[].beforeHtml/afterHtml.
Pass the identical inputs and previewToken: application.token to
set_default_email_component. You can also supply sample: { id, kind } to
preview an affected version. Omitting application keeps future-only saves.
Campaign audience status
campaigns list --json and MCP list_campaigns include hasAudience. Drafts with this flag have an explicit audience configuration, not a confirmed eligible-recipient count. Use campaigns from-audience / create_campaign_for_audience to save matching contact IDs directly in a blank campaign draft, then update its content. This does not create a list, change list membership or enroll contacts. The dashboard opens the existing campaign template picker for filtered groups; saved lists and segments retain their campaign and sequence actions.
For running campaign A/B tests, use get_ab_test for progress, update_ab_test for audience percentage and total duration from the original start, and select_ab_test_winner to finish early. Retry the same sample target after an interrupted request; cancelSampleUpdate: true discards only a failed sample change. Repeat the same winner ID to repair delivery.