Get started

Recipes

Complete scripts for common automations.

Schedule a post with an image

Node.js 18+. Imports an image from a URL, then schedules a post with it.

// Schedule a post with an image from your CMS, e.g. from a cron job or webhook.
const BASE = "https://smanager.mrfirdavs.uz/api/v1";

async function call(path, body) {
  const res = await fetch(BASE + path, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.ONETHREADS_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  });
  const json = await res.json();
  if (!res.ok) throw new Error(`${json.error.code}: ${json.error.message}`);
  return json;
}

const image = await call("/media", { url: "https://example.com/cover.png" });
const post = await call("/posts", {
  account: "yourname",
  text: "New on the blog: how we cut our build time in half",
  media: [{ id: image.id, alt: "Build time chart" }],
  scheduledAt: "2026-11-02T09:00:00Z",
});
console.log("Scheduled", post.id, "for", post.scheduledAt);

Schedule a thread

Node.js 18+. Chains posts with options.replyTo, so each one publishes as a reply to the one before it.

// Schedule a thread: each post replies to the one before it.
const BASE = "https://smanager.mrfirdavs.uz/api/v1";
const parts = [
  "We rebuilt our scheduler from scratch. Here's what we learned 🧵",
  "1/ Queues are state machines. Every step has to survive a crash.",
  "2/ Never publish twice: claim work with a conditional update.",
];

let previous;
let at = Date.parse("2026-11-02T09:00:00Z");
for (const text of parts) {
  const res = await fetch(BASE + "/posts", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.ONETHREADS_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      text,
      options: previous ? { replyTo: previous } : {},
      scheduledAt: new Date(at).toISOString(),
    }),
  });
  const post = await res.json();
  if (!res.ok) throw new Error(post.error.message);
  previous = post.id;
  at += 60_000; // a minute apart; replies never go out before their parent anyway
}

Retry failed posts

Python with requests. Run it on a schedule to republish anything that failed.

# Retry every failed post, e.g. once an hour.
import os, requests

BASE = "https://smanager.mrfirdavs.uz/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['ONETHREADS_KEY']}"

failed = session.get(f"{BASE}/posts", params={"status": "failed"}).json()["data"]
for post in failed:
    r = session.post(f"{BASE}/posts/{post['id']}/publish")
    if r.status_code in (200, 202):
        print("Published", post["id"], r.json()["permalink"])
    else:
        print("Still failing", post["id"], r.json()["error"]["message"])

No-code tools

n8n, Make and Zapier work too: add an HTTP request step, set the Authorization: Bearer … header and send a JSON body like the examples on each endpoint page.