# X (Twitter) credits

> Post to X as a pay-per-use add-on of the paid plans: what each post uses, what is left, and top-ups.

Source: https://postwire.io/docs/x/ · Base URL: https://postwire.io · OpenAPI: https://postwire.io/openapi.json

X charges for every post, so posting to X uses X credits: **1 X credit = 1 X post**; a post with a link uses 10 (X charges about 13 times more for links); each image or video adds 1. Each paid plan includes X credits every month (Starter 30, Pro 150, Agency 600, Scale 2,000; they renew on the 1st and do not roll over) and a daily cap of X posts (5, 20, 60, 150). Top-up credits (80 for $5, 340 for $20, one-time) are used after the plan's credits and do not expire. X is not available on Free or during the trial. Connect X like any OAuth network (`POST /api/oauth/x/url`) and publish with `platforms: ["x"]`: the credits are taken before anything is sent to X and come back if X rejects the post. Text is fitted to 280 characters as X counts them (a link counts 23, an emoji 2); up to 4 images or one video.

- [`GET /api/x`](#get-api-x): X (Twitter) credits: what posting to X uses and what this account has left
- [`GET /api/x/quote`](#get-api-x-quote): How many X credits one post would use, before it is published or scheduled
- [`POST /api/x/credits/checkout`](#post-api-x-credits-checkout): A Stripe Checkout link to buy X top-up credits (one-time payment)

## X (Twitter) credits: what posting to X uses and what this account has left

`GET /api/x`

X is a pay-per-use add-on of the paid plans (Starter, Pro, Agency, Scale; not Free, not during a trial). 1 X credit = 1 X post; a post with a link uses 10 (X charges about 13 times more for links); each image or video adds 1. Each paid plan includes X credits every month (Starter 30, Pro 150, Agency 600, Scale 2,000; they renew on the 1st and do not roll over) and a daily cap of X posts (5, 20, 60, 150); top-up credits (80 for $5, 340 for $20, one-time) are used after them and do not expire. An X post without enough credits is not sent to X: its result has code x_credits_required and the links to buy more.

Needs an API key: `Authorization: Bearer pw_live_…`.

**Responses**

| Status | Means |
|---|---|
| `200` | { network: "x", available, mode: paid\|free\|trial\|internal, allowed, killed, pricing: { rule, credits, plans, packs, notes }, credits?: { plan_allowance, allowance_used, allowance_left, topup, total_left, resets_on }, daily?: { used, max }, buy?: [{ pack, usd, credits, url, label }], history: [{ at, kind, what, credits, from_plan, from_topup }], upgrade? (Free), house? (internal: { spent_usd, cap_usd }) } |

```bash
curl "https://postwire.io/api/x" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
```

```js
const res = await fetch("https://postwire.io/api/x", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.get(
    "https://postwire.io/api/x",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())
```

**Example response**

```json
{
  "network": "x",
  "available": true,
  "mode": "paid",
  "allowed": true,
  "credits": {
    "plan_allowance": 150,
    "allowance_used": 12,
    "allowance_left": 138,
    "topup": 80,
    "total_left": 218,
    "resets_on": "2026-11-01"
  },
  "daily": {
    "used": 3,
    "max": 20
  },
  "buy": [
    {
      "pack": "5",
      "usd": 5,
      "credits": 80,
      "url": "https://postwire.io/api/x/credits/go?t=…&pack=5"
    },
    {
      "pack": "20",
      "usd": 20,
      "credits": 340,
      "url": "https://postwire.io/api/x/credits/go?t=…&pack=20"
    }
  ]
}
```

Abridged: it also returns `pricing` (the rule, every plan's X credits and daily cap, the packs) and `history` (the last movements).

## How many X credits one post would use, before it is published or scheduled

`GET /api/x/quote`

Needs an API key: `Authorization: Bearer pw_live_…`.

**Parameters**

| Field | Type | Description |
|---|---|---|
| `text` | query, string | The X post's text. A link anywhere in it (also a bare domain such as postwire.io/x) makes it a post with a link. |
| `images` | query, integer | Images attached (X takes up to 4). |
| `video` | query, boolean | A video attached (one, on its own). |

**Responses**

| Status | Means |
|---|---|
| `200` | { credits, has_link, images, video, sentence } — e.g. sentence "This post uses 10 X credits: it contains a link." |

```bash
curl "https://postwire.io/api/x/quote?text=The+new+docs+are+live%3A+https%3A%2F%2Fpostwire.io%2Fdocs%2F" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
```

```js
const res = await fetch("https://postwire.io/api/x/quote?text=The+new+docs+are+live%3A+https%3A%2F%2Fpostwire.io%2Fdocs%2F", {
  method: "GET",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.get(
    "https://postwire.io/api/x/quote?text=The+new+docs+are+live%3A+https%3A%2F%2Fpostwire.io%2Fdocs%2F",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())
```

**Example response**

```json
{
  "credits": 10,
  "has_link": true,
  "images": 0,
  "video": false,
  "sentence": "This post uses 10 X credits: it contains a link."
}
```

## A Stripe Checkout link to buy X top-up credits (one-time payment)

`POST /api/x/credits/checkout`

Packs: "5" = 80 credits for $5, "20" = 340 credits for $20. Nothing is charged until the person pays on the Stripe page. Paid plans only (403 x_paid_plan_required otherwise, with the plan that has X).

Needs an API key: `Authorization: Bearer pw_live_…`.

**Body (JSON)**

| Field | Type | Description |
|---|---|---|
| `pack` (required) | string | One of: 5, 20. |

**Responses**

| Status | Means |
|---|---|
| `200` | { url } of the Stripe Checkout page |
| `403` | x_paid_plan_required (Free or a running trial) or internal_account |

```bash
curl -X POST "https://postwire.io/api/x/credits/checkout" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "pack": "5"
}'
```

```js
const res = await fetch("https://postwire.io/api/x/credits/checkout", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "pack": "5"
  }),
});
console.log(res.status, await res.json());
```

```python
import os, requests

r = requests.post(
    "https://postwire.io/api/x/credits/checkout",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
    json={
        "pack": "5",
    },
)
print(r.status_code, r.json())
```

**Example response**

```json
{
  "url": "https://checkout.stripe.com/c/pay/cs_live_…"
}
```
