---
title: "Automate Chockstone with n8n, Make and Zapier | Chockstone"
description: "Send Chockstone events to n8n, Make, Zapier or your own server as signed webhooks: posts published, comments, DMs, link signups and more."
canonical: https://chockstonelabs.com/integrations/
last_updated: 2026-11-10
source: "The same content as https://chockstonelabs.com/integrations/"
---

Source: the same content as https://chockstonelabs.com/integrations/

# Automate Chockstone with n8n, Make and Zapier

Chockstone calls a web address you choose each time something happens in your workspace: a post goes live, a comment arrives, someone signs up on your link page. n8n, Make, Zapier or your own server can start a workflow from that call.

Checked November 10, 2026 against the events and limits the server uses.

## What you can trigger on

A webhook listens for the events you pick. This table is made from the list the server sends from, so it names every event and nothing else.

*Every event Chockstone sends. Each carries id, type, created_at, workspace_id, api_version (2026-11-01) and data.*

| Event | When it fires | Always in data | Only with include_text |
| --- | --- | --- | --- |
| `post.approved` | A person approved a post for an account. | `post_id`: The post. `target_id`: The post on one account. `account_id`: The connected account. `network`: instagram, tiktok, youtube and so on. `account_handle`: The account's public handle. `state`: The target's state after the change. `scheduled_at`: ISO time it goes out, or null. `links`: app (the post in Chockstone) and live (the network's page for it, once published). | `title`: The post's name, which can be the start of its caption. |
| `post.scheduled` | A post got a time and will go out by itself. | `post_id`: The post. `target_id`: The post on one account. `account_id`: The connected account. `network`: instagram, tiktok, youtube and so on. `account_handle`: The account's public handle. `state`: The target's state after the change. `scheduled_at`: ISO time it goes out, or null. `links`: app (the post in Chockstone) and live (the network's page for it, once published). | `title`: The post's name. |
| `post.published` | A post went live on a network. | `post_id`: The post. `target_id`: The post on one account. `account_id`: The connected account. `network`: instagram, tiktok, youtube and so on. `account_handle`: The account's public handle. `state`: The target's state after the change. `scheduled_at`: ISO time it goes out, or null. `links`: app (the post in Chockstone) and live (the network's page for it, once published). `published_at`: ISO time it went live. `permalink`: The live post's address on the network. | `title`: The post's name. |
| `post.failed` | A post did not go out and needs a retry or a person. | `post_id`: The post. `target_id`: The post on one account. `account_id`: The connected account. `network`: instagram, tiktok, youtube and so on. `account_handle`: The account's public handle. `state`: The target's state after the change. `scheduled_at`: ISO time it goes out, or null. `links`: app (the post in Chockstone) and live (the network's page for it, once published). `error_code`: A code to branch on, such as NETWORK or MEDIA_REJECTED. `error`: A plain sentence about what went wrong. | `title`: The post's name. |
| `edit.ready_for_review` | A video edit finished and waits for a person to look at it. | `edit_job_id`: The edit. `post_id`: The draft post made from it. `status`: Always review. `links`: app: the draft in Chockstone. | `title`: The edit's name. |
| `edit.failed` | A video edit could not be made. | `edit_job_id`: The edit. `post_id`: The draft post, or null. `status`: Always failed. `reason`: A plain sentence about what went wrong. | `title`: The edit's name. |
| `comment.received` | A new comment arrived on a connected account. Chockstone reads an account's comments while the account has a comment reply rule or a saved reply, and sends comments from the last six hours. | `account_id`: The connected account. `network`: Where the comment is. `comment_id`: The network's id for the comment. `network_post_id`: The network's id for the post it is under. `post_id`: The Chockstone post it is under, or null. `commented_at`: ISO time the comment was written. `links`: live: the post's address on the network. | `text`: What the comment says. `author`: The commenter's handle. |
| `message.received` | A new direct message arrived on a connected Instagram account. | `account_id`: The connected account. `network`: instagram. `message_id`: The network's id for the message. `kind`: message, story_reply, story_mention or tap (a button or quick reply). `received_at`: ISO time Chockstone got it. | `text`: What the message says. `sender_id`: The network's id for the sender. |
| `link.signup` | A visitor signed up with the email block on a link page. | `link_id`: The signup block. `page_slug`: The link page. `email_hash`: SHA-256 of the lowercased email, in hex. Match it against your own list without receiving the address. | `email`: The visitor's email address. |
| `account.needs_reconnect` | A network signed an account out, so its posts wait until someone reconnects it. | `account_id`: The connected account. `network`: Which network. `account_handle`: The account's public handle. `reason`: Always signed_out. `links`: app: where to reconnect. | Nothing beyond the always-sent fields. |

- **Sent as:** A POST with a JSON body
- **Signed:** HMAC-SHA256 with your secret
- **Order:** Not guaranteed

## How to connect a tool

1. In your tool, make a trigger that receives POST calls and copy its address. In n8n that is the Webhook node's Production URL. In Make it is a Custom webhook, and in Zapier it is Webhooks by Zapier with a Catch Hook trigger.
2. In the Chockstone app, make an API key under Agents with the admin permission. Owners and admins manage webhooks.
3. Create the webhook with the API, or ask a connected assistant to run `webhook_create`. The answer holds the signing secret. Chockstone shows it once, so store it in your tool now.
4. Send a test. `POST /api/v1/webhooks/{id}/test` sends a `ping` event and returns what your server answered.

```
curl -X POST https://chockstonelabs.com/api/v1/webhooks \
  -H "Authorization: Bearer $CHOCKSTONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-tool.example/webhook/abc","events":["link.signup","post.published"]}'
```

Add `"workspace":"your workspace id"` when the key reaches more than one workspace. Chockstone calls your address on each event from then on. Turn on `include_text` only if you want the words people wrote.

### The webhook endpoints

- `POST /api/v1/webhooks` creates one and returns the secret once.
- `GET /api/v1/webhooks` lists them. The secret is never listed.
- `PATCH /api/v1/webhooks/{id}` changes the address, events, `active` or `include_text`.
- `DELETE /api/v1/webhooks/{id}` removes one and its delivery log.
- `POST /api/v1/webhooks/{id}/test` sends a ping.
- `GET /api/v1/webhooks/{id}/deliveries` shows the last 50 deliveries with their status.
- `POST /api/v1/webhooks/{id}/rotate-secret` makes a new secret and ends the old one at once.

- **Who:** Owners and admins
- **Permission:** admin
- **Address:** A public https address

## Check the signature

Every call has four headers: `Chockstone-Event`, `Chockstone-Delivery`, `Chockstone-Timestamp` (Unix seconds) and `Chockstone-Signature`. The signature is `sha256=` and then the hex HMAC-SHA256 of the timestamp, a dot and the raw request body, with your secret as the key.

Refuse a call when the signature does not match or when the timestamp is more than 300 seconds from your clock. Use the body exactly as received, before a JSON parser touches it.

### JavaScript

```
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyChockstone(rawBody, headers, secret, toleranceSeconds = 300) {
  const timestamp = headers["chockstone-timestamp"];
  const signature = headers["chockstone-signature"] ?? "";
  if (!timestamp || Math.abs(Date.now() / 1000 - Number(timestamp)) > toleranceSeconds) return false;
  const expected = "sha256=" + createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const a = Buffer.from(expected), b = Buffer.from(signature);
  return a.length === b.length && timingSafeEqual(a, b);
}
```

### Python

```
import hashlib
import hmac
import time


def verify_chockstone(raw_body: bytes, headers: dict, secret: str, tolerance_seconds: int = 300) -> bool:
    timestamp = headers.get("Chockstone-Timestamp", "")
    signature = headers.get("Chockstone-Signature", "")
    try:
        if abs(time.time() - int(timestamp)) > tolerance_seconds:
            return False
    except ValueError:
        return False
    message = timestamp.encode() + b"." + raw_body
    expected = "sha256=" + hmac.new(secret.encode(), message, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
```

- **Header:** Chockstone-Signature
- **Signed text:** timestamp, a dot, the raw body
- **Replay window:** 300 seconds

## A recipe for n8n

1. Add a Webhook node, set the HTTP method to POST and copy its Production URL into Chockstone. The Test URL works only while the editor is listening, so use the Production URL and activate the workflow.
2. Add a Code node that checks the signature. n8n Cloud has the Node.js `crypto` module in the Code node. A self-hosted n8n needs `NODE_FUNCTION_ALLOW_BUILTIN=crypto`.
3. Add a Switch node on `{{ $json.type }}` with one output for each event you handle, or an If node when you handle one.

The Code node, ready to paste:

```
const crypto = require('crypto');

// Paste the secret Chockstone showed you when you created the webhook.
const secret = 'whsec_PASTE_YOUR_SECRET_HERE';

const item = $input.first().json;
const timestamp = item.headers['chockstone-timestamp'] || '';
const given = item.headers['chockstone-signature'] || '';
// Chockstone writes the body with JSON.stringify, so writing the parsed body back gives the same bytes.
const body = JSON.stringify(item.body);
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(timestamp + '.' + body).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(given);
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
if (!fresh || a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
  throw new Error('Chockstone signature check failed');
}
return [{ json: item.body }];
```

A finished workflow is ready to import: [n8n-link-signup.json](https://chockstonelabs.com/integrations/n8n-link-signup.json). The workflow receives the call, checks the signature, keeps only `link.signup` and adds a row to a Google Sheet. After importing, paste your secret, set your spreadsheet and choose your Google credential. The row holds the email hash, because the webhook does not send addresses unless `include_text` is on.

- **Trigger:** Webhook node, POST
- **Check:** Code node
- **Branch:** Switch or If on type

## Make and Zapier

In Make, start a scenario with the Webhooks app's Custom webhook, copy its address and give it to Chockstone. In Zapier, start a Zap with Webhooks by Zapier and the Catch Hook trigger, and do the same. Each receives the JSON body and the four headers.

Checking the signature needs the raw body and the headers in one step. Where a step can run code and read both, use the check above. Where it cannot, treat the address as a secret, leave `include_text` off and rotate the webhook if the address leaks.

- **Make:** Custom webhook
- **Zapier:** Webhooks by Zapier, Catch Hook
- **Signature:** The same headers

## Calling Chockstone back

Webhooks send events out. To act on them, call Chockstone. Every action is a REST endpoint under `https://chockstonelabs.com/api/v1/`, described in OpenAPI at [/api/v1/openapi.json](https://chockstonelabs.com/api/v1/openapi.json) and called with an API key as a Bearer token. The HTTP Request node in n8n, Make and Zapier can call any of them.

n8n has an MCP Client node that connects to an MCP server and uses its tools as workflow steps. Point it at `https://chockstonelabs.com/mcp` and use an API key as the Bearer token. The tools are listed on [Chockstone MCP tools](https://chockstonelabs.com/mcp-tools/).

- **REST:** /api/v1, API key
- **OpenAPI:** /api/v1/openapi.json
- **MCP:** https://chockstonelabs.com/mcp

## Limits and retries

- Endpoints per space: Starter 1, Creator 5, Studio 25. An endpoint that is switched off still counts.
- Chockstone waits 10 seconds for your answer. Any 2xx status counts as received. Anything else, a timeout or a redirect is a failure.
- A failed call is tried again after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours: 6 tries in all. After the last one the delivery is marked dead.
- 20 dead deliveries in a row turn the endpoint off and send a notification to the people in the workspace. Turning it back on clears the count.
- One request at a time goes to each endpoint. Order is not guaranteed, so use `created_at` if order matters.
- The last 200 deliveries of each endpoint are kept, with the status your server returned and how long it took.

A call can arrive twice, for example when your server answers after the 10 seconds. `Chockstone-Delivery` is the same on every try of one delivery, so keep the ones you have handled. The event `id` in the body is unique to the event.

- **Success:** Any 2xx answer
- **Redirects:** Not followed
- **Plans:** [Pricing](https://chockstonelabs.com/pricing/)

## What is never sent

Events carry ids, status, times, the network, account handles and links. They leave out captions, post titles, comment and message text, the names of commenters and senders, and email addresses.

A webhook can turn on `include_text` to add the fields the table marks as only with include_text. New webhooks start with it off. `link.signup` always carries a hash of the email, which lets you match a signup against your own list without receiving the address.

- **Default:** include_text off
- **Email:** SHA-256 hash
- **Sent to:** Only the address you set

## Security

- Chockstone encrypts the secret at rest and shows it once. Keep it out of source control and rotate it if it leaks. The old secret stops working at once.
- The address must be a public https address. Chockstone refuses private networks, addresses with a user name or password, and redirects.
- The signature shows that Chockstone sent the call and that nobody changed it. Check it, and check the timestamp, before you act.
- Only owners and admins with the admin permission can create, change or delete webhooks, and every change shows in Activity.

- **Secret:** Encrypted, shown once
- **Transport:** https only
- **Log:** Activity

## Start free, with no card.

Starter is free for one brand. Creator is $19 a month and Studio is $79. Questions? Email [hello@chockstonelabs.com](mailto:hello@chockstonelabs.com).

[Start free](https://chockstonelabs.com/app/start) [See pricing](https://chockstonelabs.com/pricing/)
