Last updated: November 1, 2026
Why the X API refused your DM with a 403
A 403 on an X DM means X refused that message. Most of the time the recipient does not accept messages from you, and retrying will not help. Read the error first: since October 26, 2026 the type field names the refusal, such as dm-sender-not-verified, which tells you whether to skip one person or stop the whole batch.
The difference matters for account safety. A sender problem repeats for every recipient, and a loop of refused cold DMs is the pattern you least want on your account. Check your scopes too: a token without dm.write also fails here.
The three messages you will actually see
These are the only refusal messages in the X DM sends we logged in the 30 days to November 1, 2026. It is a small sample: 468 refusals from outreach campaigns on a small number of accounts, so read the shares as a rough guide.
On the middle one, X's changelog says: refusals it cannot explain safely stay about:blank with "This operation is not permitted."
The dm-* problem types
X lists these in the create-message schema under https://api.x.com/2/problems/. It publishes the names but no description or status code for each one, so the groups and actions below are our reading of the names, not X's wording.
The list is not complete: dm-not-delivered, dm-not-found, dm-not-owner, dm-inactive-device and a few formatting types also exist, and so does the older recipient-not-messageable.
Handle refusals in code
Branch on the problem type, so one closed inbox does not stop a run, and one sender problem does not burn through a whole list:
const res = await fetch(
`https://api.x.com/2/dm_conversations/with/${recipientId}/messages`,
{
method: "POST",
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
body: JSON.stringify({ text }),
}
);
if (res.status === 201) return "sent";
const problem = await res.json().catch(() => ({}));
const type = (problem.type ?? "").split("/").pop(); // e.g. "dm-sender-not-verified"
if (res.status === 429 || type === "dm-rate-limited") return "wait_and_retry";
if (res.status >= 500) return "retry_with_backoff";
if (type.startsWith("dm-sender-") || type.startsWith("dm-safety-")) return "pause_campaign";
if (res.status === 401) return "refresh_token";
return "skip_recipient";X says clients that only check the status code are unaffected, so older code keeps working. It just cannot tell a closed inbox from a sender problem. For the full request and OAuth flow, see Send X DMs with the API.
Do not treat every 403 as the recipient's fault
If your code marks all 403s as "unreachable", a sender problem such as a verification requirement quietly marks your entire list as unreachable. Check the type before you update the lead.Getting fewer refusals
- Message people who follow you first. Refusals are mostly about non-followers.
- Check the sending account: verification status, phone number and whether it is limited.
- Request
dm.read,dm.write,tweet.readandusers.readwith a user token. X's guide rules out app-only auth for DMs. - Upload media with the same user, and send it within 24 hours. X names both as causes of failed attachments.
- Write each message for the person. X's rules prohibit unsolicited automated bulk DMs, and
dm-duplicateis its own error.
OpenTweet DM Campaigns covers the sending side: it finds and qualifies leads, drafts a message for each one, and sends only what you approve from your own account, paced and capped. It stops at a refused recipient rather than retrying. It cannot open a closed inbox, and cold outreach still gets refused often. It is on Advanced ($29/mo) and Agency ($49/mo).
7-day free trial with a few limits, or pay now for full limits.
Frequently asked questions
Why does the X API return 403 when I send a DM?
Because X refused that message, which is usually about the recipient and not your code. X's docs name recipient DM settings that block messages from unknown users, or the recipient having blocked you. A 403 can also mean your token lacks a DM scope or your own account cannot send message requests.
What does "You do not have permission to DM one or more participants" mean?
X will not deliver a message from you to that person. The usual cause is that they do not follow you and do not accept messages from people they do not follow. It was the most common refusal in our logs. Retrying the same recipient will not change it until their settings or your relationship change.
What does "This operation is not permitted" mean on a DM?
X refused the message and will not say why. Its October 26, 2026 changelog says refusals it cannot explain safely stay about:blank with this exact text, because a more specific message could reveal a private fact about the recipient. Skip the recipient and move on.
What does "Your account must be verified to send a Direct Message request" mean?
The problem is your account, not the recipient. X requires verification to send that message request. Every other non-follower you try will probably fail the same way, so pause sending and fix the account first. X also lists a dm-sender-not-verified problem type.
What changed in X DM errors on October 26, 2026?
Create-message requests still return HTTP 403 when refused, but the problem type now identifies the refusal, in the form https://api.x.com/2/problems/dm-..., and detail names the cause when that does not reveal something private about the recipient. Code that checks only the status code is unaffected.
Which OAuth scopes do X DMs need?
dm.write, tweet.read and users.read appear on the create-message endpoint. X's integration guide also says dm.read is required with dm.write, so request all four. App-only auth is not supported for DMs, and a Direct Message scope only comes with a user token.
Can any tool get around these refusals?
No. If a recipient's settings refuse your DM, they refuse it through the app, the API and every tool. Be careful with anything that promises otherwise. What a tool can do is check reachability first and stop retrying people who cannot be reached.
Keep exploring
X DMs from code: limits, endpoints and safe outreach.
Send X DMs with the API
The endpoints, OAuth setup and reading replies.
X DM limits in 2026
Daily caps and who you can reach.
Automate X DMs without getting banned
Approval gates, pacing and what gets accounts flagged.
X DM outreach, human-approved
Find and qualify leads, and approve every message.
Why does POST /2/tweets return 403?
The same status code on posts has different causes.
X API error decoder
Paste an X API error and see what it means.
Outreach you approve, one message at a time
Find leads, draft personal DMs and send from your own X account, with pacing and daily caps built in.
7-day free trial with a few limits, or pay now for full limits.