Posting and reading X (Twitter) from Make after the app decommission, full HTTP module setup

The native X app was discontinued (existing scenarios stopped May 30, 2025, and the main thread about it, Make is officially decommissioning X (formerly Twitter) app , is now closed). Since people keep landing on that thread from Google without a working answer, here is the setup that works today with plain HTTP modules.

Reading tweets with the official X API

Reads only need an app-level bearer token, no OAuth dance:

  1. Create a project and app in the X developer console and copy the bearer token.
  2. In Make, add HTTP > Make a request:
    • URL: https://api.x.com/2/users/by/username/make (or any v2 endpoint)
    • Method: GET
    • Headers: Authorization = Bearer YOUR_TOKEN
    • Parse response: yes
  3. Map the JSON output into whatever comes next (Sheets, Slack, a data store).

Note the official API is pay-per-use now: a standard post read is $0.005, so 10,000 reads is $50. Worth estimating volume before you build.

Posting tweets with the official X API

Writes need user-context OAuth 2.0, which is where most people get stuck. The checklist that makes it work:

  1. In the X developer portal, set the app type to Web App, and register the exact redirect URL that Make’s OAuth module shows you. A mismatch here produces the “You weren’t able to give access to the App” error with no further explanation.
  2. Enable scopes: tweet.read, tweet.write, users.read, and offline.access. Without offline.access you get no refresh token and the connection dies after two hours.
  3. Use HTTP > Make an OAuth 2.0 request with authorize URL https://x.com/i/oauth2/authorize, token URL https://api.x.com/2/oauth2/token, and PKCE enabled.
  4. Then POST to https://api.x.com/2/tweets with body {"text": "hello"}.

The simpler route if you do not want a developer account

Third-party Twitter data APIs work with a single bearer token and skip the OAuth setup entirely: same HTTP module, different base URL. I build one of these (GetXAPI), so obvious bias, but the HTTP module pattern is identical whichever provider you use.

Replacing the “watch tweets” trigger

The old trigger was polling anyway, so rebuild it honestly: a scheduled scenario that fetches the account’s recent tweets, a data store holding the last seen tweet ID, a filter that passes only tweets with a higher ID, then an update of the stored ID. One trap that costs people weeks: compare tweet IDs as numbers, not text. A text comparison sorts alphabetically and silently stops matching once IDs grow a digit, and the scenario keeps running green while finding nothing.

Happy to answer questions if anyone gets stuck on the OAuth part, that seems to be where most of the pain is.

this is the thread people actually need, since the closed one still ranks first on google.

two things worth adding for anyone copying it.

  1. the bearer token only covers reads. the moment you want to post you are into oauth with a refresh loop, and that is where most scenarios stall. build the write path as its own scenario with the token refresh isolated, otherwise an expired token takes your reads down with it
    1. budget the reads deliberately. at half a cent each, a scenario polling every five minutes is roughly eight and a half thousand calls a month before it has done anything useful. cache what you can and poll on a schedule that matches how fresh the data actually needs to be
  2. did you get the write path working, or is this read-only so far?

Two answers, since there are two write paths.

Official X OAuth in Make: read-only so far. I have run that flow outside Make but not end to end as a Make scenario, so I did not want to write it up as tested.

Passthrough API: writes work, and they sidestep the problem you are describing. Posting, likes, retweets, follows and DMs are all just another HTTP module with a bearer header plus an account token, so there is no OAuth app, no PKCE, and no refresh loop to isolate. Disclosure again, that is my own API, but the general point holds for any passthrough: the refresh loop is a property of official OAuth, not of writing to X.

Your isolation point is still the right call on the official path, and there is a Make-specific reason it bites: if reads and writes share one OAuth connection, a failed refresh errors every module using it, not just the write. Also worth checking the consent screen actually lists “Post and delete posts for you”, because if the scope was added after the connection was made the token keeps the old scopes and you get a 403 with no useful error.

On the read budget, cadence is the lever rather than the query. Most accounts do not post 288 times a day, so match the schedule to how fast the source actually changes and store the last seen post ID so you compare instead of re-reading.