# No-code (n8n, Make, Zapier)

Publish from n8n, Make or Zapier workflows with a generic HTTP request step.


You can publish from any automation tool that can send an HTTP request. There's no dedicated Relaycast app or node in these tools, but you don't need one: their built-in HTTP request steps call the REST API directly.

Typical workflows:

- Publish new blog posts or RSS items to every channel.
- Post a product announcement when a row is added to a spreadsheet or database.
- Schedule a week of posts from a content calendar.
- Notify a team chat when a post fails, using [webhook notifications](/docs/notifications).

## What every request needs

Whichever tool you use, a publish request has the same parts:

| Setting | Value |
| --- | --- |
| Method | `POST` |
| URL | `https://social-publish-api.onrender.com/v1/posts` |
| Header | `x-access-key`: your access key |
| Header | `Content-Type`: `application/json` |
| Header (recommended) | `Idempotency-Key`: a value unique to this post, such as the source item's ID |
| Body | JSON, see below |

```json
{
  "content": "New on the blog: How we cut our build times in half",
  "targets": [
    { "accountId": "8f1c2a4e-5b6d-4e7f-9a0b-1c2d3e4f5a6b" },
    { "accountId": "2b7d9e1f-3a4c-4d5e-8f6a-7b8c9d0e1f2a" }
  ],
  "media": [{ "url": "https://example.com/cover.jpg", "type": "image" }],
  "publishNow": true
}
```

To schedule instead, replace `"publishNow": true` with `"scheduledFor": "2026-10-12T09:00:00Z"`, an ISO 8601 time with a timezone. See [Scheduling](/docs/scheduling).

### Before you start

1. Create an access key at [https://social-publish-kappa.vercel.app/dashboard/api-keys](https://social-publish-kappa.vercel.app/dashboard/api-keys). Use a separate key per tool, so you can revoke it on its own.
2. Get your account IDs from the **Integrations** page, or with `GET https://social-publish-api.onrender.com/v1/accounts` and the same header.
3. Build the post in the [Playground](/docs/playground) and copy the JSON from the **Live request** panel. It's the exact body your workflow should send.

> [!WARNING]
> Store the access key in the tool's credentials or secrets feature, not as plain text in a step, so it isn't exposed when you share or export the workflow.

## n8n

Use the **HTTP Request** node:

1. **Method:** `POST`. **URL:** `https://social-publish-api.onrender.com/v1/posts`.
2. **Authentication:** choose a generic **Header Auth** credential with name `x-access-key` and your key as the value.
3. **Send Headers:** add `Idempotency-Key` with an expression based on the incoming item, such as its ID or link.
4. **Send Body:** body content type **JSON**, then specify the body as JSON and map fields from earlier nodes with expressions, for example `"content": "{{ $json.title }} {{ $json.link }}"`.

The node's output contains `data.id`, which you can pass to a second HTTP Request node calling `GET https://social-publish-api.onrender.com/v1/posts/<id>` after a **Wait** node, to check the results.

## Make

Use the **HTTP → Make a request** module:

1. **URL:** `https://social-publish-api.onrender.com/v1/posts`. **Method:** `POST`.
2. **Headers:** add `x-access-key` with your key, and `Idempotency-Key` mapped from the trigger's item ID.
3. **Body type:** Raw, **Content type:** JSON (application/json).
4. **Request content:** paste the JSON body and map values from earlier modules into it.
5. Turn on **Parse response** so later modules can use `data.id` and `data.targets`.

## Zapier

Use the **Webhooks by Zapier** action with the **Custom Request** event (Webhooks by Zapier may require a paid Zapier plan):

1. **Method:** `POST`. **URL:** `https://social-publish-api.onrender.com/v1/posts`.
2. **Data:** paste the JSON body and insert fields from earlier steps.
3. **Headers:** `x-access-key` with your key, `Content-Type` with `application/json`, and `Idempotency-Key` mapped from the trigger's ID.

The step's output includes the created post, so later steps can use its `id`.

## Watch out for

- **JSON escaping.** Text with quotes or line breaks from earlier steps can break a hand-written JSON body. Use the tool's JSON-safe mapping or a function that escapes values.
- **Character limits.** Each platform has its own limit, for example 300 characters on Bluesky. A long blog title plus a link can exceed it. Use per-account `targets[].content` for short platforms, see [Posts](/docs/posts).
- **Media must be public.** The platform downloads media at publish time, so URLs from the trigger must be publicly reachable. See [Media & Uploads](/docs/media).
- **Errors.** A `400 validation_error` response explains what to fix for each account. Configure the step to continue on error and route failures to an alert, or the workflow may stop silently. See [Errors](/docs/errors).
- **Retries.** If the tool retries failed steps automatically, the `Idempotency-Key` header makes sure a retry never posts twice. See [Idempotency & Retries](/docs/idempotency).
- **Credits.** Each account a post goes to uses one credit. A workflow that fires often can use credits quickly. See [Credits & Usage](/docs/credits).

## React to publish results

To trigger a workflow when a post publishes or fails, create a webhook [notification rule](/docs/notifications) pointing at your workflow's webhook trigger URL (for example an n8n **Webhook** node, a Make **Custom webhook** or a Zapier **Catch Hook**). Each delivery includes the post status and every platform's result.
