Zolt AI
API Documentation← Back to site

Webhooks

Two directions: push content into a board from an external trigger (inbound), and get notified from Zolt AI when something finishes (outbound).

Inbound: send content into a board

Point a Zapier/Make/Pabbly "webhook" step (or any HTTP call) at this endpoint to drop new content straight onto a board — the classic “trigger → content lands in my board” automation.

POST
/api/inbound/tiles
Create a tile on a board from an external trigger.
FieldTypeRequiredDescription
board_idstringrequiredThe target board's id.
zone_idstringoptionalZone to place the tile in. Must belong to board_id.
urlstringoptionalA link to ingest (YouTube, TikTok, Instagram, a webpage, etc.) — auto-detected and processed in the background.
contentstringoptionalPlain text to store as a text tile. Provide either url or content.
titlestringoptionalTile title.

If url is given, the tile is created immediately with status: "processing" and ingestion (transcript, scrape, etc.) continues in the background:

{ "tile": { "id": "cldx...", "status": "processing", "type": "YOUTUBE" } }

If content is given instead, the text tile is created synchronously and is immediately ready:

{ "tile": { "id": "cldx...", "status": "ready", "type": "TEXT" } }
400 Bad RequestRequired field: board_id.
400 Bad RequestProvide either content or url.
400 Bad RequestThat zone does not belong to this board.

Outbound: get notified of activity

Set a webhook URL for your business in Settings → Webhook (Owner only). Content Integrator will POST a signed JSON payload to that URL whenever one of the events below happens. Delivery is best-effort — there are no retries, so treat this as a real-time nice-to-have, not a guaranteed delivery queue.

Envelope

Every delivery has the same outer shape:

{
  "event": "tile.ready" | "generation.complete",
  "payload": { /* event-specific, see below */ },
  "sentAt": "2026-08-03T00:00:00.000Z"
}

Verifying the signature

Every request carries an X-CI-Signature header — an HMAC-SHA256 hex digest of the exact raw request body, keyed with your webhook secret (shown once when you set the webhook URL — save it, it can't be re-displayed, only rotated). Verify against the raw bytes you received, not a re-serialized copy:

import crypto from "crypto";

function isValidSignature(rawBody: string, signature: string, secret: string): boolean {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Event: tile.ready

Fired once a tile finishes background ingestion/processing.

{ "tileId": "cldx...", "boardId": "cldx...", "title": "string", "type": "YOUTUBE" }

Event: generation.complete

Fired after a REST API generate/idea call finishes. Shape varies slightly by endpoint:

{ "generationId": "cldx...", "boardId": "cldx...", "endpoint": "/api/v1/generate", "assetType": "video" }
{ "generationId": "cldx...", "boardId": "cldx...", "endpoint": "/api/v1/idea" }