# Post to social media from n8n

> Index of all OmniSocials docs pages: https://docs.omnisocials.com/llms.txt

There are two ways to use OmniSocials from n8n:

1. **HTTP Request node.** Your workflow calls the REST API with fixed fields. Use it when every run does the same thing, for example "new RSS item, schedule a LinkedIn post".
2. **AI Agent with the MCP Client Tool node.** An agent gets the OmniSocials MCP tools and decides what to call. Use it when a model should write the caption, pick the accounts, or choose a time.

Both use the same API key and the same n8n credential.

## Before you start

- An OmniSocials account with at least one social account connected (**Settings → Organisation → Workspaces**). Accounts cannot be connected through the API.
- An API key from **Settings → API**. Give it `posts:write` and `accounts:read`, plus `media:write` if the workflow uploads files. See [Authentication](https://docs.omnisocials.com/authentication.md).
- n8n Cloud or a self-hosted n8n instance.

## Store the API key in n8n

Create the credential once. Both nodes on this page use it.

1. In n8n, create a new credential and pick the **Bearer Auth** type.
2. In **Bearer Token**, paste your key: `omsk_live_<YOUR_KEY>`.
3. Name it something like "OmniSocials API" and save.

n8n sends it as `Authorization: Bearer omsk_live_<YOUR_KEY>` on every request. Keep the key in this credential, not in a node's headers or body, so it never shows up in exported workflows.

## Option 1: create a post with the HTTP Request node

Add an **HTTP Request** node after your trigger and set:

| Parameter | Value |
|-----------|-------|
| **Method** | `POST` |
| **URL** | `https://api.omnisocials.com/v1/posts/create` |
| **Authentication** | **Generic Credential Type** |
| **Generic Auth Type** | **Bearer Auth**, then pick the "OmniSocials API" credential |
| **Send Body** | On |
| **Body Content Type** | **JSON** |
| **Specify Body** | **Using JSON** |

Paste this into the **JSON** field:

```json
{
  "content": { "default": "New on the blog: how we plan a month of posts in one hour." },
  "accounts": ["linkedin", "x"],
  "schedule_at": "2026-11-02T09:00:00Z",
  "media_urls": ["https://example.com/cover.jpg"],
  "source": "n8n"
}
```

Run the node. A `201` response returns the new post in `data`, with its `id` and a `status` of `scheduled`.

### Map data from earlier nodes

Switch the **JSON** field to an expression to fill it from the previous node. Wrap text values in `JSON.stringify()`, so quotes and line breaks in a caption cannot break the JSON:

```text
{
  "content": { "default": {{ JSON.stringify($json.caption) }} },
  "accounts": ["linkedin", "x"],
  "schedule_at": "{{ $now.plus({ hours: 1 }).toISO() }}",
  "media_urls": [{{ JSON.stringify($json.image_url) }}],
  "source": "n8n"
}
```

### Body fields

The fields you will use most. The full list, including per-platform options, is in the [API reference](https://docs.omnisocials.com/api) and [Creating posts](https://docs.omnisocials.com/creating-posts.md).

| Field | Type | What it does |
|-------|------|--------------|
| `content` | object | Required. `default` is the text for every account. Add a platform key such as `instagram` or `linkedin` to give that platform its own text. |
| `accounts` | array of strings | Required. Platform names such as `"instagram"`, or account IDs from `GET /v1/accounts` such as `"844008_instagram"`. |
| `schedule_at` | string | ISO 8601 date and time, in the future. The post publishes then. |
| `publish_now` | boolean | `true` publishes right away. It wins over `schedule_at`. |
| `media_urls` | array of URLs | Public image or video URLs. OmniSocials downloads them. Instagram and TikTok posts need at least one. |
| `source` | string | Optional label for where the post came from. |

Leave out both `schedule_at` and `publish_now` to save the post as a draft. Send `publish_now` as a real boolean (`true`), never as the string `"false"`.

:::tip
Run a `GET` on `https://api.omnisocials.com/v1/accounts` with the same credential to see the exact account IDs in your workspace.
:::

## Option 2: let an AI Agent post through MCP

The **MCP Client Tool** node connects an n8n **AI Agent** to the hosted OmniSocials MCP server at `https://mcp.omnisocials.com`. The agent then sees tools like `list_accounts`, `create_post`, `upload_media`, and `get_best_times`. See [MCP server](https://docs.omnisocials.com/mcp-server.md) for the full tool list.

Build the workflow:

1. Add a **Chat Trigger** node. It shows as "When chat message received" on the canvas.
2. Add an **AI Agent** node after it. Leave **Source for Prompt (User Message)** on **Connected Chat Trigger Node**.
3. Connect a chat model sub-node to the agent, for example OpenAI or Anthropic.
4. On the agent's tool connector, add an **MCP Client Tool** node and set:

| Parameter | Value |
|-----------|-------|
| **Endpoint** | `https://mcp.omnisocials.com` |
| **Server Transport** | **HTTP Streamable** |
| **Authentication** | **Bearer Auth**, then pick the "OmniSocials API" credential |
| **Tools to Include** | **Selected**, then pick the tools the agent needs. Or **All**. |

5. Optional: under the agent's **Options**, add a **System Message**, for example:

```text
You manage social media through OmniSocials. Call list_accounts before you create a post.
Create posts as drafts unless the user asks you to schedule or publish them.
```

6. Open the chat and ask: "List my connected social accounts on OmniSocials". The agent should call `list_accounts` and answer with your accounts.

:::caution
OmniSocials only speaks Streamable HTTP. If your MCP Client Tool node shows a field called **SSE Endpoint** and no **Server Transport**, it is the first version of the node. Add a fresh MCP Client Tool node on a current n8n release.
:::

The tools respect the key's scopes. A key without `posts:write` still lists `create_post`, but calling it returns `403`. Pick **Selected** in **Tools to Include** to keep the agent to the tools it needs, for example `list_accounts`, `create_post`, and `list_posts`.

## Troubleshooting

| Response | Cause | Fix |
|----------|-------|-----|
| `401` | The key is wrong or revoked. | Check the Bearer Token in the credential. |
| `402` on the MCP server | The organisation has no active plan. | Check billing in **Settings → Organisation**. |
| `403` | The key misses a scope. | Create a new key with the scope. Scopes cannot be edited. |
| `400` with `validation_error` | A field is missing or invalid, for example an unknown account or a past `schedule_at`. | Read `error.message`, it names the field. |
| `429` | Rate limit. | Wait for `Retry-After` seconds, then retry. |

See [Rate limits and errors](https://docs.omnisocials.com/rate-limits-and-errors.md) for every status code.

## Next steps

- [Creating posts](https://docs.omnisocials.com/creating-posts.md) covers per-platform text, post types, and updates.
- [Media](https://docs.omnisocials.com/media.md) covers uploads, formats, and size limits.
- [Webhooks](https://docs.omnisocials.com/webhooks.md) can start an n8n workflow when a post publishes or fails.
