Account, keys and billing

Sign up, read usage and limits, manage API keys and the plan.

View as MarkdownOpenAPIBase URL https://postwire.io

Every limit an account has is readable: GET /api/usage gives each one with what is used and what is left. A limit of null means unlimited.

Create an account (the API key is emailed as a confirmation link, not returned here)

POST/api/signup

Signup never returns credentials. We create the account and email a one-time confirmation link; opening it proves you control the mailbox and issues your API key. This prevents anyone from registering an address they do not own and receiving a working key.

No API key needed.

Body (JSON)

FieldTypeDescription
email requiredstring (email)

Responses

StatusMeans
200Account created; pending_verification=true, emailed=true|false
curl
curl -X POST "https://postwire.io/api/signup" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "you@example.com"
}'
Node
const res = await fetch("https://postwire.io/api/signup", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "email": "you@example.com"
  }),
});
console.log(res.status, await res.json());
Python
import os, requests

r = requests.post(
    "https://postwire.io/api/signup",
    json={
        "email": "you@example.com",
    },
)
print(r.status_code, r.json())

Account info, usage and connections

GET/api/me

limits carries posts_this_month, brands, ai_drafts_today, networks_per_post { limit } and scheduled_queue { used, limit, held, left } (null = no limit). A free account created before the 2-Oct-2026 limits also gets grandfathered { until, note } (it keeps the earlier limits until 2026-11-01). Free accounts get insights_teaser: how many What works patterns are ready and how strong each is, without the answer. With teams: `workspace` (id, name, plan, seats, members) and `member` (who is calling: email, role, effective_role, read_only, brand_ids, and `can`: which actions this role may take). The no-card Pro trial (when it is on): `trial` { kind: "reverse", plan, plan_name, until, ends_at, started_at, days_left, active, no_card } while it runs (a card trial is `trial` with kind "card"), `trial_ended` once it is over, `trial_line` (one sentence, no link), and for a free account that can still have it `reverse_trial_offer` { kind, plan, name, days, no_card, starts: "now" | "first_post", unlocks, extras, note } instead of `trial_offer`. A free account that looks like a business (3+ networks, 2+ brands, or a team seat wall) gets `bizcard` { show, dismissed, reasons, networks, brands, title, lead, benefits: [{ key: "approvals" | "team", title, text }], action: { kind: "trial", label, days, note } | { kind: "checkout", plan, label, url, secondary?: { plan, label, url }, note } }: approvals and team with the plans' real limits, and the no-card trial (POST /api/trial/start with from "bizcard") or Starter's signed checkout link. `show` is false once it was dismissed.

Needs an API key: Authorization: Bearer pw_live_….

Responses

StatusMeans
200OK
401Missing/invalid API key
curl
curl "https://postwire.io/api/me" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/me", {
  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/me",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())

Alias of GET /api/me: account info, usage and connections

GET/api/account

Needs an API key: Authorization: Bearer pw_live_….

Responses

StatusMeans
200Same body as /api/me
401Missing/invalid API key
curl
curl "https://postwire.io/api/account" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/account", {
  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/account",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())

This month's posts, today's AI drafts and brands, against the plan's limits

GET/api/usage

{ plan, plan_name, period, posts: { used, limit, left, resets_on }, ai_drafts_today: { used, limit, left, resets_at }, brands: { used, limit }, networks_per_post: { limit }, scheduled_queue: { used, limit, held, left }, grandfathered_until?, upgrade? } — a limit of null means unlimited; upgrade appears at 80 % of a limit.

Needs an API key: Authorization: Bearer pw_live_….

Responses

StatusMeans
200usage
curl
curl "https://postwire.io/api/usage" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/usage", {
  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/usage",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())

Example response

JSON
{
  "plan": "free",
  "plan_name": "Free",
  "period": "2026-10",
  "posts": {
    "used": 6,
    "limit": 20,
    "left": 14,
    "resets_on": "2026-11-01"
  },
  "ai_drafts_today": {
    "used": 1,
    "limit": 5,
    "left": 4
  },
  "brands": {
    "used": 1,
    "limit": 1
  },
  "networks_per_post": {
    "limit": 2
  },
  "scheduled_queue": {
    "used": 2,
    "limit": 3,
    "held": 0,
    "left": 1
  }
}

Abridged. null as a limit means unlimited.

The account's plan, what it includes, current usage and the next plan with a checkout link

GET/api/plan

Needs an API key: Authorization: Bearer pw_live_….

Responses

StatusMeans
200{ plan, name, price_usd_month, includes, limits: { posts_per_month, brands, ai_drafts_per_day, networks_per_post, scheduled_queue }, usage, grandfathered_until?, next? }
curl
curl "https://postwire.io/api/plan" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/plan", {
  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/plan",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())

List plans and limits

GET/api/plans

Each plan: { name, price, brands, limit (posts a month, -1 = unlimited), genDay (AI drafts a day), networksPerPost (-1 = every network in each post), maxQueued (scheduled posts at a time, -1 = unlimited) }.

No API key needed.

Responses

StatusMeans
200OK
curl
curl "https://postwire.io/api/plans"
Node
const res = await fetch("https://postwire.io/api/plans", {
  method: "GET",
});
console.log(res.status, await res.json());
Python
import os, requests

r = requests.get(
    "https://postwire.io/api/plans",
)
print(r.status_code, r.json())

Plan, subscription state and where to manage billing

GET/api/billing

Changing, cancelling or updating a card is done by a person: POST /api/billing/portal returns the portal link.

Needs an API key: Authorization: Bearer pw_live_….

Responses

StatusMeans
200{ plan, name, price_usd_month, subscription: active|none|unknown|null, manage, upgrade, refund }
curl
curl "https://postwire.io/api/billing" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/billing", {
  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/billing",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())

Start a Stripe checkout for a paid plan

POST/api/billing/checkout

Needs an API key: Authorization: Bearer pw_live_….

Body (JSON)

FieldTypeDescription
plan requiredstringOne of: starter, pro, agency, scale.
intervalstringBilling period: month (default) or year (20% off, billed once a year). A running subscription is switched, prorated. One of: month, year.

Responses

StatusMeans
200{ url }
curl
curl -X POST "https://postwire.io/api/billing/checkout" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "plan": "starter"
}'
Node
const res = await fetch("https://postwire.io/api/billing/checkout", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "plan": "starter"
  }),
});
console.log(res.status, await res.json());
Python
import os, requests

r = requests.post(
    "https://postwire.io/api/billing/checkout",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
    json={
        "plan": "starter",
    },
)
print(r.status_code, r.json())

A Stripe customer-portal link to change plan, update the card or cancel

POST/api/billing/portal

Needs an API key: Authorization: Bearer pw_live_….

Responses

StatusMeans
200{ url }
503billing not configured
curl
curl -X POST "https://postwire.io/api/billing/portal" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/billing/portal", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
Python
import os, requests

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

The no-card Pro trial: where it stands, what Pro did for this account, the offer

GET/api/trial

7 days of Pro with no card, once per person, started by the account's first successful post (or, for an account that already published, its next publish or the next free limit it hits). While it runs the account keeps plan "free" and gets Pro's limits, except X (paid per post on paid plans) and an AI budget of Free's month plus Pro's for the trial's days. When it ends nothing is deleted: scheduled posts past Free's queue cap are held (they go out on upgrade), brands made during the trial past Free's count are paused for publishing. Returns { trial: { kind, plan, until, started_at, days_left, active, ended_at? }, line, facts: { posts, network_posts, multi_network_posts, posts_this_month, free_post_limit, posts_over_free, ai_drafts_month_about, queued, held, queued_past_free, brands, brands_past_free }, did[], when_it_ends[], keeps[], paid_offer? } — or { trial: null, available, offer? } for an account that never had one.

Needs an API key: Authorization: Bearer pw_live_….

Responses

StatusMeans
200OK
401Missing/invalid API key
curl
curl "https://postwire.io/api/trial" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/trial", {
  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/trial",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())

Start the no-card Pro trial now (an account that has published)

POST/api/trial/start

For a free account that has published and never had the trial: starts the 7 days now (the dashboard's button on a free limit). An account that has not published yet is told its first post starts it — except `from: "bizcard"` (the dashboard's approvals-and-team card) for an account the server finds business-like (3+ networks connected, 2+ brands, or a team seat wall): it starts before the first post, with the same once-per-person rules. 409 `trial_unavailable` with `reason`: not_posted_yet, trial_used, same_person (another account of the same person had it), card_trial_used, paid_plan, off.

Needs an API key: Authorization: Bearer pw_live_….

Body (JSON)

FieldTypeDescription
fromstringwhere the button was (measurement); "bizcard" may start it before the first post for a business-like account

Responses

StatusMeans
200{ started: true, trial_started: { kind, plan, days, started_at, until, no_card }, trial_note, trial }
401Missing/invalid API key
409trial_unavailable
curl
curl -X POST "https://postwire.io/api/trial/start" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "from": "dashboard"
}'
Node
const res = await fetch("https://postwire.io/api/trial/start", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "from": "dashboard"
  }),
});
console.log(res.status, await res.json());
Python
import os, requests

r = requests.post(
    "https://postwire.io/api/trial/start",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
    json={
        "from": "dashboard",
    },
)
print(r.status_code, r.json())

List your API keys (prefixes only — the secret is never returned)

GET/api/keys

Needs an API key: Authorization: Bearer pw_live_….

Responses

StatusMeans
200keys[]
curl
curl "https://postwire.io/api/keys" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/keys", {
  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/keys",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())

Create a new API key, optionally with an expiry

POST/api/keys

Needs an API key: Authorization: Bearer pw_live_….

Body (JSON)

FieldTypeDescription
namestring
expires_in_daysinteger1 to 3650.

Responses

StatusMeans
200api_key shown once
curl
curl -X POST "https://postwire.io/api/keys" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "n8n production",
  "expires_in_days": 365
}'
Node
const res = await fetch("https://postwire.io/api/keys", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "name": "n8n production",
    "expires_in_days": 365
  }),
});
console.log(res.status, await res.json());
Python
import os, requests

r = requests.post(
    "https://postwire.io/api/keys",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
    json={
        "name": "n8n production",
        "expires_in_days": 365,
    },
)
print(r.status_code, r.json())

Revoke an API key immediately

DELETE/api/keys/{id}

Needs an API key: Authorization: Bearer pw_live_….

Parameters

FieldTypeDescription
id requiredpath, string

Responses

StatusMeans
200revoked
404not found or already revoked
curl
curl -X DELETE "https://postwire.io/api/keys/7c2a6f0e-5b1d-4c8a-9e3f-2d4b6a8c0e1f" \
  -H "Authorization: Bearer $POSTWIRE_API_KEY"
Node
const res = await fetch("https://postwire.io/api/keys/7c2a6f0e-5b1d-4c8a-9e3f-2d4b6a8c0e1f", {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.POSTWIRE_API_KEY}` },
});
console.log(res.status, await res.json());
Python
import os, requests

r = requests.delete(
    "https://postwire.io/api/keys/7c2a6f0e-5b1d-4c8a-9e3f-2d4b6a8c0e1f",
    headers={"Authorization": f"Bearer {os.environ['POSTWIRE_API_KEY']}"},
)
print(r.status_code, r.json())