Documentation

Guides for the Onepostly API, covering authentication, connecting accounts, publishing and scheduling posts, media uploads, comments, analytics, and webhooks.

Onepostly is one API to publish, schedule and measure across every major social platform. This page takes you from API key to your first post in about five minutes.

The free plan includes one connected account with no credit card required.

Base URL

https://api.onepostly.com


Install An SDK

npm install @onepostly/sdk

Prefer raw HTTP? Every example below also shows plain curl, which needs no install at all.

Authentication

All API requests require an API key, passed in the x-api-key header or as an Authorization: Bearer token. The SDKs read it from the ONEPOSTLY_API_KEY environment variable by default.

Get Your API Key

  1. Sign up or log in. The free plan needs no credit card
  2. Go to Settings → API Keys
  3. Click Create
  4. Copy the key immediately. It is shown only once

Set Up The Client

import { Configuration, ConnectionsApi, PostsApi } from "@onepostly/sdk";

const config = new Configuration({
  apiKey: process.env.ONEPOSTLY_API_KEY,
});

const connections = new ConnectionsApi(config);
const posts = new PostsApi(config);

Key format op_ prefix. Keys are shown only once at creation. Store them somewhere safe. Use environment variables and create separate keys per app.


Key Concepts

  • Connections. Your connected social accounts (X, Instagram, TikTok and more), authorized through OAuth. Every publish targets one or more connections
  • Posts. One request creates a post. Each entry in destinations receives its own copy on that platform
  • Destinations. The per-connection results of a post, each with its own status and external URL
  • Media. Images and videos, uploaded through the Media API or referenced from any public HTTPS URL

Every step below returns the ids the next one needs. You get the account id from the list and the post id on create.


Step 1: Connect A Social Account

In Dashboard → Connections, pick a platform and complete the OAuth consent screen. The connection shows up in your dashboard and in the API. Headless connects are available for some platforms. See Connection.

Step 2: List Your Connections

List your connections and grab the id. You pass it as accountId on every publish.

import { Configuration, ConnectionsApi } from "@onepostly/sdk";

const connectionsApi = new ConnectionsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await connectionsApi.listConnections({
  limit: 20,
  page: 2,
  profile: "Business",
  platform: "instagram",
  addedWithinDays: 90,
  sort: "newest",
});
console.log(response);
{
  "connections": [
    {
      "id": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
      "platform": "instagram",
      "displayName": "Onepostly",
      "handle": "@onepostly",
      "avatarUrl": "https://cdn.onepostly.com/avatars/onepostly.jpg",
      "status": "active",
      "tokenExpiresAt": "2026-10-25T10:00:00.000Z",
      "canAutoRenew": true,
      "authHealth": "healthy",
      "profileName": "Business",
      "xSubscriptionType": "Premium",
      "createdAt": "2026-08-25T10:00:00.000Z",
      "updatedAt": "2026-08-25T10:00:00.000Z"
    }
  ],
  "total": 2000,
  "page": 1,
  "hasMore": true
}

Save the account id. The next step targets it.

Step 3: Publish Your First Post

import { Configuration, PostsApi } from "@onepostly/sdk";

const postsApi = new PostsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await postsApi.createPost({
  createPostBody: {
    "text": "Ship day",
    "mediaUrls": [
      "https://cdn.onepostly.com/media/product.jpg"
    ],
    "mediaKind": "image",
    "destinations": [
      {
        "accountId": "YOUR_INSTAGRAM_ACCOUNT_ID"
      }
    ]
  },
});
console.log(response);
{
  "post": {
    "id": "b3e1a7c2-8f4d-4e6a-9c1b-2d3e4f5a6b7c",
    "text": "Ship day",
    "mediaUrls": [
      "https://cdn.onepostly.com/media/product.jpg"
    ],
    "mediaKind": "image",
    "status": "queued",
    "scheduledFor": null,
    "timezone": null,
    "destinations": [
      {
        "id": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
        "accountId": "YOUR_INSTAGRAM_ACCOUNT_ID",
        "platform": "instagram",
        "status": "draft",
        "externalPostId": "17895695668004550",
        "externalUrl": "https://www.instagram.com/p/17895695668004550/",
        "errorCode": null,
        "errorMessage": null,
        "publishedAt": "2026-08-25T10:00:00.000Z",
        "metrics": null
      }
    ],
    "createdAt": "2026-08-25T10:00:00.000Z",
    "updatedAt": "2026-08-25T10:00:00.000Z"
  }
}

The response is 202 Accepted with status queued. Publishing runs in the background. mediaKind is required on every post. Use text for text-only posts. Use image, multi-image, video or stories together with the matching mediaUrls.

Step 4: Confirm It Worked

Poll the post until every destination is published or failed.

import { Configuration, PostsApi } from "@onepostly/sdk";

const postsApi = new PostsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await postsApi.getPost({
  id: "b3e1a7c2-8f4d-4e6a-9c1b-2d3e4f5a6b7c",
});
console.log(response);
{
  "post": {
    "id": "b3e1a7c2-8f4d-4e6a-9c1b-2d3e4f5a6b7c",
    "text": "Ship day",
    "mediaUrls": [
      "https://cdn.onepostly.com/media/product.jpg"
    ],
    "mediaKind": "image",
    "status": "queued",
    "scheduledFor": null,
    "timezone": null,
    "destinations": [
      {
        "id": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
        "accountId": "YOUR_INSTAGRAM_ACCOUNT_ID",
        "platform": "instagram",
        "status": "draft",
        "externalPostId": "17895695668004550",
        "externalUrl": "https://www.instagram.com/p/17895695668004550/",
        "errorCode": null,
        "errorMessage": null,
        "publishedAt": "2026-08-25T10:00:00.000Z",
        "metrics": null
      }
    ],
    "createdAt": "2026-08-25T10:00:00.000Z",
    "updatedAt": "2026-08-25T10:00:00.000Z"
  }
}

Once a destination is published, it carries the live link in externalUrl. Webhooks can push these status changes to you instead of polling.

That's the whole loop. Connect an account, publish and confirm. Everything else is a variation on this.

One Endpoint, Every Posting Mode

The same createPost call covers immediate publishing, scheduling and media.

You setResult
Nothing extraPublishes immediately with 202 Accepted and queued
scheduledFor plus timezonePublishes automatically at that time with 201 Created and scheduled
mediaKind plus mediaUrlsAdds media as image, multi-image, video or stories

And cross-posting is just more entries in the destinations array. Same content, one call, every platform.

await posts.createPost({
  createPostBody: {
    text: "Cross-posting to all my accounts, right now!",
    mediaKind: "text",
    destinations: [
      { accountId: "YOUR_X_ACCOUNT_ID" },
      { accountId: "YOUR_INSTAGRAM_ACCOUNT_ID" },
      { accountId: "YOUR_TIKTOK_ACCOUNT_ID", privacyLevel: "PUBLIC_TO_EVERYONE" },
    ],
  },
});

Per-platform options like TikTok privacy levels and Pinterest boards are covered in each platform guide.


Beyond Posting

Publishing is the entry point. The same API key and connections open comment moderation, analytics and event-driven updates.

Read Analytics

See how a post performs once its destinations are published. Pass post as described in Analytics.

import { Configuration, AnalyticsApi } from "@onepostly/sdk";

const analyticsApi = new AnalyticsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await analyticsApi.getAnalytics({
  post: "1699f415-7fb6-43f4-9d2a-c447491f32a8",
  metrics: "views,reach,profile_views",
  period: "day",
});
console.log(response);
{
  "analytics": {
    "post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
    "status": "ready",
    "fetchedAt": "2026-08-25T10:00:00.000Z",
    "subjects": [
      {
        "scope": "destination",
        "subjectId": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
        "accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
        "platform": "instagram",
        "externalPostId": "17895695668004550",
        "status": "ready",
        "metrics": {
          "impressions": 1234,
          "reach": 987,
          "likes": 123,
          "comments": 12,
          "shares": 4,
          "saves": 2,
          "plays": 456,
          "engagement": 0.14
        },
        "fetchedAt": "2026-08-25T10:00:00.000Z",
        "expiresAt": "2026-09-01T10:00:00.000Z",
        "error": null
      }
    ]
  }
}

Metrics are normalized (likes, comments, shares and so on). Each platform section lists exactly which numbers it returns.

Reply To Comments

List, create and delete comments on published posts. The same endpoints work on every platform that supports them.

import { Configuration, CommentsApi } from "@onepostly/sdk";

const commentsApi = new CommentsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await commentsApi.createComment({
  createCommentBody: {
    "post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
    "text": "Love this!",
    "parentCommentId": "c0"
  },
});
console.log(response);
{
  "comment": {
    "id": "c1",
    "text": "Love this!",
    "username": "jane_doe",
    "likeCount": 12,
    "timestamp": "2026-08-25T10:05:00.000Z"
  }
}

Explore The Rest

X bills through a prepaid wallet

Publishing, replying, liking and analytics reads on X debit your Onepostly wallet at X list prices with no markup. Top up in Dashboard → Settings → Billing.


What's Next?

Going to production? Respect rate limits and listen for webhooks instead of polling.