> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twexapi.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Write Actions

> Post, like, follow, and send DMs with TwexAPI — cookie and auth_token setup, duplicate-write checks, and 403 credit recovery.

Read-only routes need a TwexAPI API key. Write routes also need a **Twitter cookie or `auth_token`** on the request so TwexAPI can act as the logged-in account.

Use this page for posting, replies, likes, retweets, bookmarks, follows, and DMs. Preview payloads with the [CLI](/sdks/cli) `--dry-run` before sending from agents or production jobs.

## What counts as a write

| Action        | Route                                  | Required fields             |
| ------------- | -------------------------------------- | --------------------------- |
| Post or reply | `POST /twitter/tweets/create`          | `tweet_content`, `cookie`   |
| Like          | `POST /twitter/tweets/{tweet_id}/like` | `cookie`                    |
| Follow        | `POST /twitter/user/follow`            | `username`, `cookie`        |
| Send DM       | `POST /twitter/send-dm`                | `username`, `msg`, `cookie` |

Related writes use the same cookie rule: retweet, bookmark, unfollow, unlike, thread create, and XChat DM. MCP marks these endpoints `read_only: false`. Require human approval before any agent calls them. See [Create a Tweet or Reply](/api-reference/tweet-actions-endpoints/create-a-tweet-or-reply).

<Warning>
  Never put cookies, `auth_token` values, or API keys in agent chat, handoff JSON, logs that leave your vault, or public repositories.
</Warning>

## Credentials you need

<Steps>
  <Step title="TwexAPI API key">
    Create a key in the [dashboard](https://twexapi.io/dashboard). Send it as `Authorization: Bearer YOUR_API_KEY` (REST/SDK) or `x-api-key` (MCP).
  </Step>

  <Step title="Twitter session">
    Supply a cookie string **or** an `auth_token`. Most write bodies accept either in the `cookie` field.
  </Step>

  <Step title="Optional cookie lookup">
    If you only have `auth_token`, convert it with [Get cookie by auth token](/api-reference/cookie-endpoints/get-cookie-by-auth-token) (`GET /twitter/{auth_token}/cookie`), then store the returned cookie as a secret.
  </Step>
</Steps>

### Cookie vs `auth_token`

| Value             | Typical contents                                            | Use                                                                                                      |
| ----------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| Cookie string     | Includes `auth_token` and `ct0` (and other session cookies) | Preferred for writes. Pass the whole header-style string in `cookie`.                                    |
| `auth_token` only | Single token from the same session                          | Accepted on write `cookie` fields. Convert to a full cookie when an endpoint rejects a token-only value. |

Export the session from a browser that is already logged into X/Twitter. Copy at least `auth_token` and `ct0`. Treat the export as a password: it can post, follow, and DM as that account.

### Store secrets

```bash theme={null}
export X_API_SCRAPER_KEY="YOUR_API_KEY"
export TWITTER_COOKIE="auth_token=...; ct0=..."
```

CLI named profiles keep the same values off the command line:

```bash theme={null}
x-api-scraper auth apps add --name prod --api-key "YOUR_API_KEY"
x-api-scraper auth profiles add --name founder --cookie "$TWITTER_COOKIE"
x-api-scraper auth apps use prod
x-api-scraper auth profiles use founder
```

Default CLI config is plain JSON in `~/.x-api-scraper/config.json`. Restrict file permissions and do not commit that directory.

SDK pattern (Python):

```python theme={null}
tweet = client.tweets.actions.create(
    tweet_content="Hello from TwexAPI.",
    cookie=os.getenv("TWITTER_COOKIE"),
)
```

REST pattern:

```bash theme={null}
curl --request POST \
  --url 'https://api.twexapi.io/twitter/tweets/create' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "tweet_content": "Hello from TwexAPI.",
    "cookie": "auth_token=...; ct0=..."
  }'
```

MCP agents still send the API key on the MCP connection. Pass `cookie` only inside the `twexapi_request` body after a human approves the exact text, target, and media URLs.

## Preview before you send

```bash theme={null}
x-api-scraper --app prod --profile founder --dry-run tweet create --text "hello from cli"
```

Dry-run validates the payload without creating the tweet. Use it from n8n, Zapier, and agent pipelines before the live call.

Local file upload is not supported. Attach public `--media-url` values (up to 4 images, or 1 GIF, or 1 MP4 up to 100 MB).

## Did the write succeed?

TwexAPI does not expose a separate write-action polling API. HTTP `200` with a tweet ID, message ID, or success envelope is the primary confirmation. Timeouts and `5xx` are ambiguous: the write might have landed.

### Persist an audit row

Store these fields **before** retrying:

| Field                             | Why                                              |
| --------------------------------- | ------------------------------------------------ |
| `method` and `path`               | Identifies the action                            |
| Request fingerprint               | Hash of text, target ID/username, and media URLs |
| Returned `tweet_id` / `messageId` | Proof the side effect exists                     |
| HTTP status and body              | Distinguishes credit errors from cookie errors   |
| Approval record                   | Who confirmed a `read_only: false` MCP call      |

### Check with a read before duplicating

| If you tried to… | Confirm with…                                                        | Retry only if…              |
| ---------------- | -------------------------------------------------------------------- | --------------------------- |
| Post a tweet     | User timeline or tweet lookup for the same text and timestamp window | No matching `tweet_id`      |
| Reply            | Thread/replies for `reply_tweet_id`                                  | Your reply ID is missing    |
| Like             | Tweet detail / favorited state                                       | The tweet is not liked      |
| Follow           | Following relationship for `username`                                | The account is not followed |
| Send DM          | DM history / status for that user                                    | The `messageId` is missing  |

Do not fire the same write again because the client timed out. Look up first, then retry once with the same fingerprint.

## Credits and `403`

Metered writes spend account credits. `403` often means **no available credits** or the action is not allowed for the key/account.

<Steps>
  <Step title="Stop write traffic">
    Pause agents, n8n batches, and CLI loops. Retrying a failed post can create duplicates after credits return.
  </Step>

  <Step title="Check balance">
    Call [Get Balance](/api-reference/balance-endpoints/get-balance):

    ```bash theme={null}
    curl --request GET \
      --url 'https://api.twexapi.io/balance' \
      --header 'Authorization: Bearer YOUR_API_KEY'
    ```
  </Step>

  <Step title="Top up, then resume once">
    Restore credits in the [dashboard](https://twexapi.io/dashboard). Re-run only writes that failed the read-back check.
  </Step>
</Steps>

| Status                         | Likely cause                        | Action                                            |
| ------------------------------ | ----------------------------------- | ------------------------------------------------- |
| `401`                          | Bad API key                         | Replace `X_API_SCRAPER_KEY`                       |
| `403`                          | Credits exhausted or action blocked | Check balance; do not duplicate writes            |
| `401`/`403` with cookie errors | Expired session                     | Export a fresh cookie / `auth_token`              |
| `429`                          | Rate limit                          | Back off — see [Rate Limits](/guides/rate-limits) |
| `5xx` or timeout               | Ambiguous                           | Read-back, then retry at most once                |

Full HTTP recovery: [Error Handling](/guides/error-handling).

## Agent rules

1. Call MCP `explore` with `include_writes: true` only when the user asked for a write.
2. Stop before `read_only: false`. Show path, body preview, and target IDs.
3. After approval, send `cookie` from a secret store, not from the model.
4. Keep cookies out of the handoff JSON. Store `tweet_id`, `route_used`, and approval metadata only.

See [Agent MCP Handoff](/mcp/agent-handoff) and [MCP Tools](/mcp/tools).

## Related pages

* [Authentication](/authentication)
* [CLI](/sdks/cli)
* [Error Handling](/guides/error-handling)
* [Rate Limits](/guides/rate-limits)
* [Create a Tweet or Reply](/api-reference/tweet-actions-endpoints/create-a-tweet-or-reply)
* [Send DM](/api-reference/dm-endpoints/send-dm)
