REST API

Post from your own code with a project API key. Create one in the project's Settings → Developers (admins only); it is shown once. Send it as a bearer token to https://your-postwase-domain/api/v1.

bash
curl https://your-postwase-domain/api/v1/channels -H "Authorization: Bearer pw_live_YOUR_KEY"

Endpoints

MethodPathDescription
GET/api/v1/meThe project the key belongs to
GET/api/v1/channelsConnected channels: id, platform, name, status
POST/api/v1/mediaImport a file from a URL: { url, filename? } → 202 { id }
GET/api/v1/media/:idMedia status: uploaded → processing → ready (or failed)
GET/api/v1/postsRecent posts with per-channel status; ?from=&to= filter by scheduled time
POST/api/v1/postsCreate a post (body below)
GET/api/v1/posts/:idOne post with media and channel options
PUT/api/v1/posts/:idReplace a post that hasn't started publishing
POST/api/v1/posts/:id/cancelCancel channels that haven't published

Create a post

Exactly one of publishNow, scheduledAt (ISO 8601 with offset) or addToQueue; with none of them the post is saved as a draft.

bash
curl https://your-postwase-domain/api/v1/posts \
  -H "Authorization: Bearer pw_live_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{
    "content": "New clip is out!",
    "mediaIds": ["MEDIA_ID"],
    "targets": [
      { "channelId": "TIKTOK_CHANNEL_ID", "options": { "privacyLevel": "PUBLIC_TO_EVERYONE" } },
      { "channelId": "YOUTUBE_CHANNEL_ID", "options": { "title": "New clip" }, "contentOverride": "Full story in the description" }
    ],
    "scheduledAt": "2026-11-02T09:00:00+07:00"
  }'

Responses: 201 with the post; 422 with issues when a network's rules aren't met (or media_not_ready); 402 when the owner's plan limit is reached; 409 no_free_slot for a full queue.

Import media, then post

Node.js 20+
const api = (path, init = {}) =>
  fetch("https://your-postwase-domain/api/v1" + path, {
    ...init,
    headers: { Authorization: `Bearer ${process.env.POSTWASE_KEY}`, "Content-Type": "application/json" },
  }).then((r) => r.json());

const { id } = await api("/media", { method: "POST", body: JSON.stringify({ url: "https://example.com/clip.mp4" }) });
let media;
do {
  await new Promise((r) => setTimeout(r, 3000));
  media = await api(`/media/${id}`);
} while (media.status === "uploaded" || media.status === "processing");
if (media.status !== "ready") throw new Error(media.error);

const [tiktok] = (await api("/channels")).filter((c) => c.platform === "tiktok");
await api("/posts", {
  method: "POST",
  body: JSON.stringify({
    content: "New clip!",
    mediaIds: [id],
    targets: [{ channelId: tiktok.id, options: { privacyLevel: "PUBLIC_TO_EVERYONE" } }],
    addToQueue: true,
  }),
});
Prefer AI assistants? The same actions are available as MCP tools: see Connect AI apps.