Direct messages actions
44 actions. Every field marked Required must be sent; account, dryRun, idempotencyKey, confirmCredits and quoteId are the control fields every surface adds.
DM overview
Section titled “DM overview”dm.dashboard · read
Direct messages at a glance: sender state (paused, stopped, needs reconnect), today’s usage and limits, active campaigns and unread replies.
- MCP tool:
dm_dashboard. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/dashboard - CLI:
xholic dm dashboard - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Find people to DM
Section titled “Find people to DM”dm.preview_recipients · write
Find people to message from a post’s repliers, a search, handles, an X list, recent interactions or a contact list, with whether each can be messaged. Returns the recipients (with preview tokens) that send_dms takes.
- MCP tool:
dm_preview_recipients. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/preview-recipients - CLI:
xholic dm preview-recipients - Scope:
write - Plan: Pro plan or higher
- Cost: Live X lookup: no credits, counts toward the plan’s X data limits.
- Rate limit bucket:
live_x
Input
| Field | Type | Required | Description |
|---|---|---|---|
type |
“FROM_TWEET” \ | “SEARCH” \ | “HANDLES” \ |
tweetUrl |
string (uri) ≤ 2048 chars | No | |
includeReplies |
boolean | No | |
includeReposts |
boolean | No | |
keyword |
string ≤ 120 chars or null | No | FROM_TWEET: only replies matching one of these comma-separated terms. |
excludeMessagedForPost |
boolean | No | |
continuation |
object or null | No | FROM_TWEET: the continuation from a previous preview, to scan deeper. |
query |
string ≤ 80 chars | No | |
handles |
array of string ≤ 120 chars (min 1, max 500) | No | |
listId |
string ≤ 64 chars or null | No | X_LIST: numeric X list id. CONTACT_LIST: the contact list id. |
listUrl |
string (uri) ≤ 2048 chars or null | No | |
days |
integer 1–7 | No | |
skipQueued |
boolean | No | |
skipCooldown |
boolean | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Send DMs now
Section titled “Send DMs now”dm.quick_send · publish
Send one message to up to 500 people found with dm.preview_recipients, paced safely from the user’s X account. Write the message yourself; variables like [first] personalise it. Only pass confirmedConsent true after the user confirmed these people agreed to or expect the message. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
send_dms. Loaded by default in MCP clients. - REST:
POST /v1/dm/quick-send - CLI:
xholic dm quick-send - Scope:
publish - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
name |
string ≤ 80 chars or null | No | |
messageTemplate |
string ≤ 5000 chars | Yes | The message. Variables: [first], [name], [handle], [location], [followers], list fields such as [first_line], with optional fallbacks like [first|there]; spintax like {Hi|Hey}. Write it yourself in the user’s voice. |
confirmedConsent |
true | Yes | |
recipients |
array of object (min 1, max 500) | Yes | Recipients exactly as dm.preview_recipients returned them. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Pause or resume all DMs
Section titled “Pause or resume all DMs”dm.control_queue · publish
PAUSE_ALL holds every queued DM, RESUME_ALL continues, CANCEL_ALL_PENDING cancels everything not sent yet, ENABLE_SENDING turns DMs back on after a stop. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_control_queue. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/control-queue - CLI:
xholic dm control-queue - Scope:
publish - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
action |
“PAUSE_ALL” \ | “RESUME_ALL” \ | “CANCEL_ALL_PENDING” \ |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Stop all DMs
Section titled “Stop all DMs”dm.stop_all · write
Emergency stop: cancel every pending DM and stop sending until turned back on with dm.control_queue ENABLE_SENDING. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_stop_all. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/stop-all - CLI:
xholic dm stop-all - Scope:
write. Destructive: it can’t be taken back - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
DM campaigns
Section titled “DM campaigns”dm.campaigns · read
The account’s DM campaigns with status and totals, newest first.
- MCP tool:
dm_campaigns. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/campaigns - CLI:
xholic dm campaigns - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
status |
“DRAFT” \ | “QUEUED” \ | “RUNNING” \ |
limit |
integer 1–100 | No | |
offset |
integer 0–9007199254740991 | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Create a DM campaign
Section titled “Create a DM campaign”dm.create_campaign · write
Create a draft DM campaign for a contact list. Then write its steps with dm.update_campaign, check it with dm.review_campaign and launch it with launch_dm_campaign. Write the messages and any per-person first lines with your own model: import the lines as a CSV column (dm.import_csv, e.g. first_line) and use [first_line]. The [ai_line] variable makes Xholic’s AI write a line per recipient at launch and spends AI credits; use it only when the user asks for Xholic to write them. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
create_dm_campaign. Loaded by default in MCP clients. - REST:
POST /v1/dm/create-campaign - CLI:
xholic dm create-campaign - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
name |
string ≤ 80 chars | No | |
contactListId |
string (uuid) or null | No | Contact list to message. |
deliveryMode |
“AUTOMATIC” \ | “ASSISTED” | No |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
DM campaign details
Section titled “DM campaign details”dm.campaign · read
One DM campaign: steps, variants, schedule, rules and totals.
- MCP tool:
dm_campaign. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/campaign - CLI:
xholic dm campaign - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Edit a DM campaign
Section titled “Edit a DM campaign”dm.update_campaign · write
Replace a draft campaign’s settings: send the whole draft (read it with dm.campaign first). Steps are the first message plus up to 2 follow-ups, each with up to three A/B variants. Write the messages and any per-person first lines with your own model: import the lines as a CSV column (dm.import_csv, e.g. first_line) and use [first_line]. The [ai_line] variable makes Xholic’s AI write a line per recipient at launch and spends AI credits; use it only when the user asks for Xholic to write them. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_update_campaign. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/update-campaign - CLI:
xholic dm update-campaign - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
name |
string ≤ 80 chars | Yes | |
deliveryMode |
“AUTOMATIC” \ | “ASSISTED” | Yes |
contactListId |
string (uuid) or null | Yes | |
steps |
array of object (min 1, max 3) | Yes | In order from position 1. Step 1 has delayDays 0; follow-ups wait at least a day. Each variant’s template is the message: [first], [name], list fields like [first_line], {Hi|Hey} spintax. |
schedule |
object | Yes | |
schedule.timezone |
string ≤ 64 chars | Yes | |
schedule.sendDays |
integer 1–127 | Yes | |
schedule.windowStartMinutes |
integer 0–1439 | Yes | |
schedule.windowEndMinutes |
integer 1–1440 | Yes | |
schedule.dailyLimit |
integer 1–100 | Yes | |
schedule.rampStart |
integer 1–100 or null | Yes | |
schedule.rampStep |
integer 1–50 or null | Yes | |
schedule.minGapSeconds |
integer 75–3600 | Yes | |
schedule.maxGapSeconds |
integer 75–3600 | Yes | |
schedule.startsAt |
string (date-time) or null | Yes | |
rules |
object | Yes | |
rules.recontactAfterDays |
30 or 60 or 90 or null | No | Default: null. |
rules.excludeCampaignIds |
array of string (uuid) (max 20) | No | Default: []. |
rules.excludeListIds |
array of string (uuid) (max 20) | No | Default: []. |
rules.skipFollowers |
boolean | No | Default: false. |
rules.skipFollowing |
boolean | No | Default: false. |
rules.skipExistingConversation |
boolean | No | Default: true. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Pause or resume a campaign
Section titled “Pause or resume a campaign”dm.control_campaign · publish
PAUSE or RESUME a running campaign, or CANCEL_PENDING to cancel its unsent messages. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_control_campaign. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/control-campaign - CLI:
xholic dm control-campaign - Scope:
publish - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
action |
“PAUSE” \ | “RESUME” \ | “CANCEL_PENDING” |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Delete a draft campaign
Section titled “Delete a draft campaign”dm.delete_campaign · write
Delete a DM campaign that hasn’t launched. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_delete_campaign. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/delete-campaign - CLI:
xholic dm delete-campaign - Scope:
write. Destructive: it can’t be taken back - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Check a campaign before launch
Section titled “Check a campaign before launch”dm.review_campaign · read
Check a draft campaign before launch: who can be messaged, who is skipped and why, missing variables, and the outreach guidelines the user must accept. Show the guidelines to the user before launching.
- MCP tool:
dm_review_campaign. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/review-campaign - CLI:
xholic dm review-campaign - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Launch a DM campaign
Section titled “Launch a DM campaign”dm.launch_campaign · publish
Launch a reviewed campaign: its messages start sending on its schedule. Run dm.review_campaign first, show the user the outreach guidelines, and pass confirmedConsent true only after they accept. If a template uses [ai_line], launching reserves AI credits for each recipient and needs confirmCredits. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
launch_dm_campaign. Loaded by default in MCP clients. - REST:
POST /v1/dm/launch-campaign - CLI:
xholic dm launch-campaign - Scope:
publish - Plan: Pro plan or higher
- Cost: Xholic AI: up to about 0 credits (Xholic AI first lines ([ai_line]) for each eligible recipient; nothing when no template uses them). Returns a quote first; pass
confirmCreditsafter the user agrees. - Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
confirmedConsent |
boolean | Yes | The user accepted the cold-outreach guidelines shown by dm.review_campaign. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
confirmCredits |
number 0–100000 | No | Xholic AI credits the user agreed to spend. Call first without it to get the quote, show the quote to the user, and pass the amount only after they say yes. |
quoteId |
string ≤ 100 chars | No | The quoteId from the quote the user agreed to. Send it with confirmCredits. |
Preview campaign messages
Section titled “Preview campaign messages”dm.preview_campaign · write
Render a campaign step’s message for a few recipients exactly as it will be sent. With generateAiLine true, Xholic’s AI writes the missing [ai_line] first lines and charges per line: quote first, show it to the user, and pass confirmCredits after they agree. Without it, previews are free.
- MCP tool:
dm_preview_campaign. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/preview-campaign - CLI:
xholic dm preview-campaign - Scope:
write - Plan: Pro plan or higher
- Cost: Xholic AI: up to about 10 credits (Xholic AI first lines ([ai_line]) for up to 5 previewed recipients). Returns a quote first; pass
confirmCreditsafter the user agrees. - Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
offset |
integer 0–9007199254740991 | No | |
limit |
integer 1–5 | No | |
stepPosition |
integer 1–3 | No | |
variantLabel |
“A” \ | “B” \ | “C” or null |
generateAiLine |
boolean | No | Write missing [ai_line] first lines with Xholic’s AI (spends credits). |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
confirmCredits |
number 0–100000 | No | Xholic AI credits the user agreed to spend. Call first without it to get the quote, show the quote to the user, and pass the amount only after they say yes. |
quoteId |
string ≤ 100 chars | No | The quoteId from the quote the user agreed to. Send it with confirmCredits. |
Duplicate a campaign
Section titled “Duplicate a campaign”dm.duplicate_campaign · write
Copy a campaign’s steps and settings into a new draft. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_duplicate_campaign. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/duplicate-campaign - CLI:
xholic dm duplicate-campaign - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Campaign recipients
Section titled “Campaign recipients”dm.campaign_recipients · read
A campaign’s recipients with each one’s status, step and reply.
- MCP tool:
dm_campaign_recipients. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/campaign-recipients - CLI:
xholic dm campaign-recipients - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
status |
“PENDING” \ | “SENDING” \ | “SENT” \ |
step |
integer 1–3 | No | |
q |
string ≤ 50 chars | No | Search by name or handle. |
limit |
integer 1–100 | No | |
offset |
integer 0–9007199254740991 | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
DM campaign results
Section titled “DM campaign results”dm.campaign_stats · read
How a campaign is doing: sent, replied, interested and booked, by step and A/B variant.
- MCP tool:
get_dm_campaign_stats. Loaded by default in MCP clients. - REST:
GET /v1/dm/campaign-stats - CLI:
xholic dm campaign-stats - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Export a campaign
Section titled “Export a campaign”dm.export_campaign · read
A campaign’s recipients and results as CSV.
- MCP tool:
dm_export_campaign. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/export-campaign - CLI:
xholic dm export-campaign - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | DM campaign id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Assisted DMs for today
Section titled “Assisted DMs for today”dm.today · read
Messages from ASSISTED campaigns ready for the user to send by hand today, with the rendered text and a link to each person’s DMs.
- MCP tool:
dm_today. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/today - CLI:
xholic dm today - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Mark an assisted DM sent
Section titled “Mark an assisted DM sent”dm.mark_assisted_sent · write
Record that the user sent an assisted DM by hand. Undo works for a minute. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_mark_assisted_sent. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/mark-assisted-sent - CLI:
xholic dm mark-assisted-sent - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write - Undo: from the activity log, which runs
dm.undo_assisted_sent
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | Campaign recipient id from dm.today or dm.campaign_recipients. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Undo marking an assisted DM sent
Section titled “Undo marking an assisted DM sent”dm.undo_assisted_sent · write
Put an assisted DM back in today’s queue within a minute of marking it sent.
- MCP tool:
dm_undo_assisted_sent. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/undo-assisted-sent - CLI:
xholic dm undo-assisted-sent - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | Campaign recipient id from dm.today or dm.campaign_recipients. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Skip a recipient
Section titled “Skip a recipient”dm.skip_recipient · write
Skip one person in a campaign so they aren’t messaged. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_skip_recipient. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/skip-recipient - CLI:
xholic dm skip-recipient - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | Campaign recipient id from dm.today or dm.campaign_recipients. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Cancel a pending DM
Section titled “Cancel a pending DM”dm.cancel_recipient · write
Cancel a DM that is queued but not sent yet. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_cancel_recipient. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/cancel-recipient - CLI:
xholic dm cancel-recipient - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | Campaign recipient id from dm.today or dm.campaign_recipients. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
DM inbox
Section titled “DM inbox”dm.inbox · read
DM conversations with replies, newest first, with each person’s lead status. Filter by lead status, campaign or unread.
- MCP tool:
get_dm_inbox. Loaded by default in MCP clients. - REST:
GET /v1/dm/inbox - CLI:
xholic dm inbox - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
leadStatus |
“NEW” \ | “REPLIED” \ | “INTERESTED” \ |
campaignId |
string (uuid) | No | |
unread |
“true” \ | “false” | No |
limit |
integer 1–50 | No | |
offset |
integer 0–9007199254740991 | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
DM conversation
Section titled “DM conversation”dm.thread · read
The full DM conversation with one person.
- MCP tool:
dm_thread. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/thread - CLI:
xholic dm thread - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
creatorId |
string | Yes | The person’s numeric X user id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Update a DM conversation
Section titled “Update a DM conversation”dm.update_conversation · write
Set a conversation’s lead status (e.g. INTERESTED, MEETING_BOOKED, DO_NOT_CONTACT) or mark it read or unread. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_update_conversation. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/update-conversation - CLI:
xholic dm update-conversation - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
creatorId |
string | Yes | The person’s numeric X user id. |
leadStatus |
“NEW” \ | “REPLIED” \ | “INTERESTED” \ |
unread |
boolean | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Reply to a DM
Section titled “Reply to a DM”dm.reply · publish
Send a DM reply in a conversation from the user’s X account. Write the reply yourself from the thread (dm.thread) in the user’s voice. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
reply_to_dm. Loaded by default in MCP clients. - REST:
POST /v1/dm/reply - CLI:
xholic dm reply - Scope:
publish - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
creatorId |
string | Yes | The person’s numeric X user id. |
text |
string ≤ 5000 chars | Yes | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Suggest a DM reply with Xholic
Section titled “Suggest a DM reply with Xholic”dm.suggest_reply · write
Have Xholic’s AI suggest a reply in a DM conversation. Use only when the user asks for Xholic to write it; otherwise write the reply yourself. Spends Xholic AI credits: quote first, show it to the user, and pass confirmCredits after they agree. Nothing is sent.
- MCP tool:
dm_suggest_reply. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/suggest-reply - CLI:
xholic dm suggest-reply - Scope:
write - Plan: Pro plan or higher
- Cost: Xholic AI: up to about 8 credits (Xholic AI reply suggestion for this DM conversation). Returns a quote first; pass
confirmCreditsafter the user agrees. - Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
creatorId |
string | Yes | The person’s numeric X user id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
confirmCredits |
number 0–100000 | No | Xholic AI credits the user agreed to spend. Call first without it to get the quote, show the quote to the user, and pass the amount only after they say yes. |
quoteId |
string ≤ 100 chars | No | The quoteId from the quote the user agreed to. Send it with confirmCredits. |
DM lists
Section titled “DM lists”dm.lists · read
Contact lists available for DM campaigns, with sizes, custom fields and how many can be messaged.
- MCP tool:
dm_lists. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/lists - CLI:
xholic dm lists - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Estimate a lead import
Section titled “Estimate a lead import”dm.estimate_import · read
Estimate how many profiles an import (followers, following, keyword posters, X list, post engagers or handles) would bring in and what it uses of the plan’s import pool. Imports nothing.
- MCP tool:
dm_estimate_import. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/estimate-import - CLI:
xholic dm estimate-import - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
source |
object | Yes | Who to import. FOLLOWERS/FOLLOWING {handle}; KEYWORD_POSTERS {query, days?, language?, excludeHandles?}; X_LIST/LIST_FOLLOWERS {listUrl}; POST_ENGAGERS {tweetUrl, includeReplies?, includeReposts?, keyword?}; HANDLES {handles}. |
source.kind |
“FOLLOWERS” \ | “FOLLOWING” \ | “KEYWORD_POSTERS” \ |
filters |
object | No | Optional filters: followersMin, followersMax, bioIncludes, bioExcludes, locationIncludes, verified (any|only|exclude), dmsOpenOnly, excludeProtected, excludeAutomated, minAccountAgeDays. |
maxProfiles |
integer 1–15000 | Yes | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Import leads for DMs
Section titled “Import leads for DMs”dm.queue_import · write
Queue an import of X profiles into a contact list for DM campaigns. Runs in the background and uses the plan’s import pool; estimate it first with dm.estimate_import. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_queue_import. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/queue-import - CLI:
xholic dm queue-import - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
source |
object | Yes | Who to import. FOLLOWERS/FOLLOWING {handle}; KEYWORD_POSTERS {query, days?, language?, excludeHandles?}; X_LIST/LIST_FOLLOWERS {listUrl}; POST_ENGAGERS {tweetUrl, includeReplies?, includeReposts?, keyword?}; HANDLES {handles}. |
source.kind |
“FOLLOWERS” \ | “FOLLOWING” \ | “KEYWORD_POSTERS” \ |
filters |
object | No | Optional filters: followersMin, followersMax, bioIncludes, bioExcludes, locationIncludes, verified (any|only|exclude), dmsOpenOnly, excludeProtected, excludeAutomated, minAccountAgeDays. |
maxProfiles |
integer 1–15000 | Yes | |
listId |
string (uuid) or null | No | Contact list to import into. |
newListName |
string ≤ 80 chars or null | No | Name for a new list instead. Pass exactly one of listId or newListName. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Import a CSV of leads
Section titled “Import a CSV of leads”dm.import_csv · write
Import handles and custom fields from CSV text (up to 200 KB) into a contact list. This is how you hand Xholic first lines you wrote: add a column such as first_line and use [first_line] in the campaign template. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_import_csv. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/import-csv - CLI:
xholic dm import-csv - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
csv |
string | Yes | The CSV text, with a header row. |
handleColumn |
string ≤ 80 chars or null | No | Header of the column holding X handles; detected when left out. |
fieldMap |
object | No | CSV header to field key (lowercase, e.g. first_line), or null to ignore a column. |
listId |
string (uuid) or null | No | Contact list to import into. |
newListName |
string ≤ 80 chars or null | No | Name for a new list instead. Pass exactly one of listId or newListName. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
DM lead imports
Section titled “DM lead imports”dm.imports · read
Lead imports with their progress, optionally for one list.
- MCP tool:
dm_imports. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/imports - CLI:
xholic dm imports - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
listId |
string (uuid) | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Stop a lead import
Section titled “Stop a lead import”dm.cancel_import · write
Stop a running lead import. Profiles already imported stay.
- MCP tool:
dm_cancel_import. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/cancel-import - CLI:
xholic dm cancel-import - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | Import id from dm.imports. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
DM settings
Section titled “DM settings”dm.settings · read
Default delivery mode, schedule and rules for new campaigns, the assisted daily limit and opt-out phrases.
- MCP tool:
dm_settings. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/settings - CLI:
xholic dm settings - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Change DM settings
Section titled “Change DM settings”dm.update_settings · write
Replace the DM settings: send all of them (read them with dm.settings first). Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_update_settings. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/update-settings - CLI:
xholic dm update-settings - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
defaults |
object | Yes | |
defaults.deliveryMode |
“AUTOMATIC” \ | “ASSISTED” | No |
defaults.schedule |
object | No | |
defaults.schedule.timezone |
string ≤ 64 chars | Yes | |
defaults.schedule.sendDays |
integer 1–127 | Yes | |
defaults.schedule.windowStartMinutes |
integer 0–1439 | Yes | |
defaults.schedule.windowEndMinutes |
integer 1–1440 | Yes | |
defaults.schedule.dailyLimit |
integer 1–100 | Yes | |
defaults.schedule.rampStart |
integer 1–100 or null | Yes | |
defaults.schedule.rampStep |
integer 1–50 or null | Yes | |
defaults.schedule.minGapSeconds |
integer 75–3600 | Yes | |
defaults.schedule.maxGapSeconds |
integer 75–3600 | Yes | |
defaults.schedule.startsAt |
string (date-time) or null | Yes | |
defaults.rules |
object | No | Default: {"recontactAfterDays":null,"excludeCampaignIds":[],"excludeListIds":[],"skipFollowers":false,"skipFollowing":false,"skipExistingConversation":true}. |
defaults.rules.recontactAfterDays |
30 or 60 or 90 or null | No | Default: null. |
defaults.rules.excludeCampaignIds |
array of string (uuid) (max 20) | No | Default: []. |
defaults.rules.excludeListIds |
array of string (uuid) (max 20) | No | Default: []. |
defaults.rules.skipFollowers |
boolean | No | Default: false. |
defaults.rules.skipFollowing |
boolean | No | Default: false. |
defaults.rules.skipExistingConversation |
boolean | No | Default: true. |
assistedDailyLimit |
integer 1–100 | Yes | |
optOutPhrases |
array of string ≤ 40 chars (max 20) | Yes | Replies containing one of these stop all messages to that person. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Do-not-message list
Section titled “Do-not-message list”dm.suppressions · read
People the account will never DM.
- MCP tool:
dm_suppressions. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/suppressions - CLI:
xholic dm suppressions - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
q |
string ≤ 50 chars | No | Search by name or handle. |
limit |
integer 1–100 | No | |
offset |
integer 0–9007199254740991 | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Never DM someone
Section titled “Never DM someone”dm.suppress · write
Add a person to the do-not-message list and cancel their pending DMs. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_suppress. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/suppress - CLI:
xholic dm suppress - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write - Undo: from the activity log, which runs
dm.unsuppress
Input
| Field | Type | Required | Description |
|---|---|---|---|
creatorId |
string | Yes | The person’s numeric X user id. |
reason |
string ≤ 1000 chars or null | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Never DM these people
Section titled “Never DM these people”dm.bulk_suppress · write
Add many handles to the do-not-message list at once and cancel their pending DMs. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_bulk_suppress. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/bulk-suppress - CLI:
xholic dm bulk-suppress - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
handles |
array of string ≤ 120 chars (min 1, max 5000) | Yes | |
reason |
string ≤ 200 chars or null | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Allow DMs to someone again
Section titled “Allow DMs to someone again”dm.unsuppress · write
Remove a person from the do-not-message list. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_unsuppress. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/unsuppress - CLI:
xholic dm unsuppress - Scope:
write - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
creatorId |
string | Yes | The person’s numeric X user id. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Keyword auto-replies
Section titled “Keyword auto-replies”dm.inbound_rules · read
Keyword rules that DM people automatically when they message or reply with a word like GUIDE.
- MCP tool:
dm_inbound_rules. Catalog: reach it withfind_actionsandrun_read_action, or turn on the full toolset. - REST:
GET /v1/dm/inbound-rules - CLI:
xholic dm inbound-rules - Scope:
read - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
read
Input
| Field | Type | Required | Description |
|---|---|---|---|
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
Add a keyword auto-reply
Section titled “Add a keyword auto-reply”dm.create_inbound_rule · publish
Add a rule that automatically DMs replyTemplate to anyone who sends the keyword. Write the reply yourself. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_create_inbound_rule. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/create-inbound-rule - CLI:
xholic dm create-inbound-rule - Scope:
publish - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
keyword |
string ≤ 40 chars | Yes | A single word, like GUIDE. |
replyTemplate |
string ≤ 5000 chars | Yes | The message. Variables: [first], [name], [handle], [location], [followers], list fields such as [first_line], with optional fallbacks like [first|there]; spintax like {Hi|Hey}. Write it yourself in the user’s voice. |
active |
boolean | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Edit a keyword auto-reply
Section titled “Edit a keyword auto-reply”dm.update_inbound_rule · publish
Replace a keyword rule’s keyword, reply or active state. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_update_inbound_rule. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/update-inbound-rule - CLI:
xholic dm update-inbound-rule - Scope:
publish - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | Rule id from dm.inbound_rules. |
keyword |
string ≤ 40 chars | Yes | A single word, like GUIDE. |
replyTemplate |
string ≤ 5000 chars | Yes | The message. Variables: [first], [name], [handle], [location], [followers], list fields such as [first_line], with optional fallbacks like [first|there]; spintax like {Hi|Hey}. Write it yourself in the user’s voice. |
active |
boolean | No | |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
Delete a keyword auto-reply
Section titled “Delete a keyword auto-reply”dm.delete_inbound_rule · write
Delete a keyword rule. Call it only when the user asked for this in the conversation; never on your own initiative.
- MCP tool:
dm_delete_inbound_rule. Catalog: reach it withfind_actionsandrun_write_action, or turn on the full toolset. - REST:
POST /v1/dm/delete-inbound-rule - CLI:
xholic dm delete-inbound-rule - Scope:
write. Destructive: it can’t be taken back - Plan: Pro plan or higher
- Cost: Free.
- Rate limit bucket:
write
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes | Rule id from dm.inbound_rules. |
account |
string ≤ 64 chars | No | X account to act on, as @handle. Leave it out to use the connection’s default account. |
dryRun |
boolean | No | Return exactly what would happen without doing it. |
idempotencyKey |
string ≤ 200 chars | No | A unique key for this write. Repeating a call with the same key returns the first result instead of acting twice. |
