# API and webhooks

> API keys, what they can do, signed webhooks when posts go out, and Zapier and Make recipes.

Razzle has a small HTTP API and outgoing webhooks. Use them to make drafts from another tool, or to hear when a post goes out or gets approved. They're the same pieces Razzle's MCP server for AI agents uses, so anything an agent can do, a script, Zapier or Make can do too.

## API keys

Open **Settings → AI agents** and make a key. It starts with `rzl_` and is shown once, so copy it somewhere safe. Send it with every request:

```
Authorization: Bearer rzl_…
```

A key acts as you, on your projects, uploads, videos and carousels only. It can't change your account, billing or team, and it never posts: a person approves every post and presses **Schedule all** in the Calendar. Remove a key in Settings → AI agents and it stops working at once. Resetting your password or signing out of other devices ends every key.

Requests go to `https://getrazzle.com`. A team's keys share the agent limits: 60 requests a minute, and up to 50 new drafts a day on Free or 250 on Pro (UTC days; edits don't count). A request over a limit gets an error that says so: wait, don't retry in a loop.

## What a key can do

| Route                                                  | What it's for                                                                        |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| `GET /api/projects`, `POST /api/projects`              | List your projects, or make one.                                                     |
| `GET /api/projects/{id}/folders`                       | A project's folders.                                                                 |
| `GET /api/media`, `POST /api/media`                    | List a project's clips and photos, or start an upload.                               |
| `GET /api/media/{id}`, `POST /api/media/{id}/complete` | One file, and finishing its upload.                                                  |
| `GET /api/items`, `POST /api/items`                    | List videos and carousels, or make a draft (`kind`: `video` or `carousel`).          |
| `POST /api/items/{id}/edit`                            | Change a draft's words, music, look or slides.                                       |
| `POST /api/items/{id}/series`                          | Add a draft to a numbered series.                                                    |
| `GET /api/music`                                       | The music library, to pick a track by id.                                            |
| `GET /api/posts/ready`                                 | Approved posts waiting for a time.                                                   |
| `POST /api/posts/propose`                              | Propose times for approved posts. Nothing posts until a person presses Schedule all. |

The [agent reference](https://getrazzle.com/docs/agent-reference) lists every option these take (templates, styles, script directives, palettes, fonts, limits), since the MCP tools pass them straight through. The quickest draft is a carousel from words:

```
curl https://getrazzle.com/api/items \
  -H "Authorization: Bearer $RAZZLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"kind":"carousel","projectId":"…","script":"Three things we learned\nfrom 100 launches\n\nShip on Tuesdays\n\nFollow for more"}'
```

The reply has the new draft's id. Open it in Razzle to check it, change anything and post. Leave out `projectId` to use your most recent project.

## Webhooks

An admin adds one https address in **Team → Plan → Webhook**. Razzle then sends a JSON POST there for each of these events:

- `post.posted`: a post went out (or went out to some of its accounts). `data` has `postId`, `itemId`, `title`, `projectId`, `status` (`posted` or `partial`) and `results`, one per account with its `status`, the live `url` and any `error`.
- `post.failed`: a post couldn't go out. Same fields, with `status` `failed`.
- `item.approved`: someone approved a video or carousel. `data` has `itemId`, `title`, `kind`, `projectId` and `by`, the approver's name.

Every body looks like `{"event": "post.posted", "at": "2026-11-10T09:30:00.000Z", "team": "…", "data": {…}}`. The `X-Razzle-Event` header names the event. Razzle sends each event once, with an eight-second timeout. A webhook that fails never affects the post, so make your end quick and reply with any 2xx.

### Check the signature

The `X-Razzle-Signature` header is `sha256=` plus the hex HMAC-SHA256 of the raw body, keyed with the secret shown next to your webhook (`whsec_…`). Check it before trusting the body. In Node:

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

function fromRazzle(rawBody, header, secret) {
  const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
  return !!header && header.length === expected.length && timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}
```

Use the body exactly as it arrived, before any JSON parsing. Parsing and re-encoding it changes the bytes and the signature won't match.

## Zapier

To act when a post goes live (log it in a sheet, tell Slack, email a client):

1. In Zapier, make a Zap with the trigger **Webhooks by Zapier → Catch Hook**, and copy the address it gives you.
2. Paste it into **Team → Plan → Webhook** in Razzle.
3. Approve and post something, or wait for the next scheduled post, so Zapier sees a sample.
4. Add a **Filter** step that continues only when `event` is `post.posted`, then add your actions. `data.results[0].url` is the live post's link.

Zapier's catch hook doesn't check the signature. If that matters, point the webhook at your own endpoint and check it there.

## Make

To turn rows, form answers or new products into Razzle drafts:

1. In Make, add an **HTTP → Make a request** module after your trigger (Google Sheets, Typeform, Airtable…).
2. URL `https://getrazzle.com/api/items`, method POST, a header `Authorization` with `Bearer ` and your key, body type raw, content type JSON.
3. Body: `{"kind": "carousel", "projectId": "…", "script": "…"}`, with the script built from your trigger's fields. One slide per paragraph, so separate slides with a blank line.

Each run makes a draft in Razzle for you to review and post. For the other way round, Make's **Webhooks → Custom webhook** trigger works like Zapier's catch hook above.

## Shops

Shopify and WooCommerce don't need the API: a project's **Settings → Shop integrations** (admins) turns new products and price drops into drafts on its own. See [getting started](https://getrazzle.com/docs/getting-started).

---
Source: https://getrazzle.com/docs/api · Markdown: https://getrazzle.com/docs/api.md · Updated 2026-11-10
