# Social Media API SDKs in 8 Languages

Official client libraries for the OmniSocials API in 8 languages. Every SDK has the
same shape: resource-based clients (`client.posts.create(...)`), typed requests and
responses, automatic retries with backoff, a shared error hierarchy, and a webhook
signature verification helper. Pick your language and you are posting in five lines.

## Install

Each language has its own page with full examples: install, auth, posting, media,
analytics, the social inbox, Pinterest product tags, webhooks, and error handling.

| Language | Package | Install | Docs |
|----------|---------|---------|------|
| Node.js / TypeScript | `@omnisocials/sdk` | `npm install @omnisocials/sdk` | [Node.js](/sdks/node) |
| Python | `omnisocials` | `pip install omnisocials` | [Python](/sdks/python) |
| Go | `github.com/OmniSocials/omnisocials-go` | `go get github.com/OmniSocials/omnisocials-go` | [Go](/sdks/go) |
| Ruby | `omnisocials` | `gem install omnisocials` | [Ruby](/sdks/ruby) |
| Java | `com.omnisocials:omnisocials-java` | Maven / Gradle dependency | [Java](/sdks/java) |
| PHP | `omnisocials/omnisocials-php` | `composer require omnisocials/omnisocials-php` | [PHP](/sdks/php) |
| .NET | `OmniSocials` | `dotnet add package OmniSocials` | [.NET](/sdks/dotnet) |
| Rust | `omnisocials` | `cargo add omnisocials` | [Rust](/sdks/rust) |

All 8 cover the full v1 surface: posts (including create-and-publish, retrying the
failed platforms of a failed or partially failed post via `posts.retry`, approving or
rejecting a post waiting in an approval workflow via `posts.approve` / `posts.reject`,
reading the review of a post (steps, approvers, the rejection reason and the comment
thread) via `posts.getApproval`,
per-platform options, and thread chains on X, Bluesky, Mastodon, and Threads), media (URL, base64, multipart, PDF
carousels, presigned large-file uploads), folders, hashtag sets (CRUD plus applying
a set at post create via `hashtag_set` / `hashtag_placement`), approval workflows
(`approvalWorkflows.list`), accounts, analytics
(post, bulk, overview, accounts, best times), Instagram locations, Instagram Reel
music search, Pinterest product Pins for product tags (`pinterest.listProducts`,
`pinterest.validateProduct`), the social inbox, and webhooks (CRUD plus secret rotation
and signature verification).

## Social Inbox

Every SDK has an `inbox` resource for the DMs, comments and mentions of your connected
accounts. It needs an API key with the opt-in `inbox:read` / `inbox:write` scopes.

| Method (Node names) | What it does |
|---------------------|--------------|
| `inbox.listConversations()` | Lists conversations. Filters: `platform`, `type`, `unread`, `unanswered`. |
| `inbox.getMessages(conversationId)` | Returns the messages of one conversation. |
| `inbox.reply(conversationId, { text })` | Sends a reply. Pass `message_id` on a comment thread. |
| `inbox.markRead(conversationId)` | Marks the conversation as read. |
| `inbox.hide(messageId)` | Hides or unhides a comment on one of your posts. |
| `inbox.deleteMessage(messageId)` | Deletes a comment on one of your posts. |
| `inbox.next()` | Hands out the next conversation that still needs an answer. |

```ts
let { data: item } = await client.inbox.next();
while (item) {
  const reply = await client.inbox.reply(item.message.conversation_id, {
    text: "Thanks for reaching out!",
    message_id: item.message.id,
    include_next: true,
  });
  item = reply.next ?? null;
}
```

Each language page has the same calls in its own idiom. See the
[Social Inbox guide](/inbox) for the platforms, the reply rules and the error codes.

## Pinterest product tags

Every SDK has a `pinterest` resource for product tagging: it lists the product Pins of
the connected Pinterest account, so you can tag up to 24 of them on a Pin with
`product_tags` in the `pinterest` options of a post. It uses the `posts:read` scope.

| Method (Node names) | What it does |
|---------------------|--------------|
| `pinterest.listProducts()` | Lists product Pins. Filters: `source` (`catalog` or `pins`), `product_group_id`, `bookmark`, `page_size`. |
| `pinterest.validateProduct(id)` | Checks one Pin id or Pin link before you use it as a product tag. |

```ts
const list = await client.pinterest.listProducts();

if (!list.error) {
  await client.posts.create({
    content: "Our summer picks",
    channels: ["pinterest"],
    media_urls: ["https://example.com/summer-look.jpg"],
    pinterest: {
      board_id: "1234567890",
      product_tags: (list.products ?? []).slice(0, 3).map((product) => product.pin_id),
    },
  });
}
```

The list answers with HTTP 200 in both cases: `products` on success, or an `error` object
(`pinterest_not_connected`, `pinterest_catalog_access_required`, `platform_error`) when
it could not be read. Only product Pins of your own account can be tagged; products of
other merchants cannot. The tags are added right after the Pin is published. A product
that Pinterest refuses never fails the post: the post then carries
`pinterest.product_tags_result` with the tagged and the skipped Pin ids. Each language
page has the same calls in its own idiom.

## Authentication

Every SDK reads the `OMNISOCIALS_API_KEY` environment variable, or takes the key in
the constructor. Create a key in the OmniSocials app under **Settings → API**. Keys
start with `omsk_live_` (production) or `omsk_test_` (test mode).

```bash
export OMNISOCIALS_API_KEY="omsk_live_<YOUR_KEY>"
```

## Quickstart

### Node.js / TypeScript

```ts
import { OmniSocials } from "@omnisocials/sdk";

const client = new OmniSocials(); // reads OMNISOCIALS_API_KEY from env
const post = await client.posts.create({
  content: "Hello from the SDK",
  channels: ["instagram", "linkedin"],
  scheduled_at: "2026-08-01T09:00:00Z",
});
```

### Python

```python
from omnisocials import OmniSocials

client = OmniSocials()  # reads OMNISOCIALS_API_KEY from the environment
post = client.posts.create(content="Hello from Python", channels=["instagram", "linkedin"])
print(post["data"]["id"])
```

### SDK names vs REST names

The SDKs use friendlier parameter names than the raw REST body and translate them on the wire. If you move between an SDK and raw HTTP (or read both docs), map them like this:

| SDK parameter | REST field |
|---------------|-----------|
| `channels: ["instagram"]` | `accounts: ["instagram"]` |
| `scheduled_at` | `schedule_at` |
| `content: "one string"` | `content: { "default": "one string" }` |

Everything else passes through under the same name.

A synchronous and an async client (`AsyncOmniSocials`) ship in the Python package.
The Go, Ruby, PHP, Java, .NET, and Rust clients expose the same resources and methods
adapted to each language's idiom. Full runnable examples for every resource live in
each package's README (linked in the table above).

**X link posts use credits.** When a create targets X and the text contains a URL,
the create response carries a top-level `warnings` array next to `data` (code
`x_url_post_credits`): X's link-post fee passed through as prepaid credits. Every
SDK returns it as part of the parsed response body (typed as `PostWarning` in the
Node and Go SDKs). See
[Creating Posts](/creating-posts#x-link-posts-use-credits) for the shape and the
publish-time behavior.

## Configuration

Every client accepts the same options: `apiKey`, `baseUrl`, `timeout` (default 30s),
and `maxRetries` (default 2). Retries use exponential backoff with jitter on `429`,
`5xx`, and network errors, and honor the `Retry-After` header. Other `4xx` responses
are never retried.

## Errors

Non-2xx responses raise a typed error from a shared hierarchy: a base error, an API
error carrying `status` / `code` / `body`, and per-status subclasses (authentication,
permission, not-found, validation, rate-limit with `retry_after`, server), plus a
connection error and a webhook-verification error. See
[Rate limits and errors](/rate-limits-and-errors) for the status codes.

## Webhook verification

Each SDK ships a helper that verifies the `X-OmniSocials-Signature` header (HMAC-SHA256
over `"{timestamp}.{rawBody}"`, constant-time compare, replay-window check) and returns
the parsed event. Node example:

```ts
import { verifyWebhookSignature } from "@omnisocials/sdk";

app.post("/webhooks/omnisocials", express.raw({ type: "application/json" }), (req, res) => {
  const event = verifyWebhookSignature({
    payload: req.body, // raw bytes, not parsed JSON
    signature: req.header("X-OmniSocials-Signature"),
    secret: process.env.OMNISOCIALS_WEBHOOK_SECRET,
  });
  // handle event.type ...
  res.sendStatus(200);
});
```

The events are `post.scheduled`, `post.published`, `post.failed`, `post.approved` and
`post.rejected`. The two approval events carry `data.approval` with `status`,
`decided_by` and `reason`. See [Webhooks](/webhooks) for event types and payloads.

## Prefer a different integration?

- [MCP Server](/mcp-server) for AI assistants (Claude, ChatGPT, Cursor, and more)
- [Agent Skills](/integrations/agent-skills) for AI coding tools without MCP support
- [API Reference](/api) for the raw HTTP endpoints
