WavefrontDevelopers

Reference

Zapier, Make and n8n

Zapier, Make and n8n connect Wavefront to tools it doesn't publish to directly. All three use the REST API with a workspace API key for actions, and event webhooks for triggers.

The API key

An owner creates a key under Settings → API and MCP. Give it the scopes for what your automations do:

To useScopes
Any triggerwebhooks and generations:read
Start a generation, draft a calendar post, message the strategistgenerations:write
Publish an approved versionpublish
Add a workspace documentcontext:write
Export a versiongenerations:read (a draft that isn't approved also needs generations:write)

GET /v1/me with the key returns its scopes and workspace, which is how to test a connection. Approval is never available to a key: a person approves in the web app, and the version.approved trigger fires then.

Triggers

TriggerEventNotes
Draft ready for reviewgeneration.ready_for_reviewA draft or revision finished
Version approvedversion.approvedCarries version_id for publishing and exporting
Publishedpublication.publishedCarries publication.url
Draft needs inputgeneration.needs_inputAnswer in the web app or over the API
New commentcomment.createdCarries comment.excerpt
Plan savedplan.savedCarries strategy and context_version
Suggestions readysuggestions.readyNew strategy suggestions wait for approval

A trigger subscribes the platform's URL with POST …/webhooks and removes it with DELETE …/webhooks/{id}. Owners see these subscriptions in Settings → Integrations and can pause or delete them. For test data, use GET …/webhooks/sample?event=.

Actions

ActionRequest
Start a generationPOST /v1/workspaces/{ws}/generations
Draft a calendar postPOST …/calendar/draft
Message the strategistPOST …/studio/messages
Add a workspace documentPUT …/context/file
Publish an approved versionPOST …/versions/{vid}/publish
Export a versionGET …/versions/{vid}/export?format=json

Generation, drafting and the strategist's reply are asynchronous: the action returns an id at once, and a later trigger (Draft ready for review, Plan saved) picks up the result.

Zapier and Make

Wavefront apps for Zapier and Make are not in their public directories yet. Until they are, connect either platform with its own webhook trigger and HTTP request steps: the same subscription, signature check and requests as the n8n recipe below.

n8n

n8n's Webhook, Code and HTTP Request nodes cover every trigger and action.

  1. Create a Header Auth credential: name Authorization, value Bearer wf_live_…. Every HTTP Request node uses it.
  2. Add a Webhook node (method POST, respond immediately) and turn on Raw Body under Options, so the signature can be checked against the exact bytes. Activate the workflow and copy its public production URL.
  3. Subscribe that URL once:
curl -s -X POST "https://wavefront.adwave.com/v1/workspaces/{ws}/webhooks" \
  -H "Authorization: Bearer $WAVEFRONT_API_KEY" -H "content-type: application/json" \
  -d '{"url":"https://you.app.n8n.cloud/webhook/wavefront-approved","events":["version.approved"],"description":"n8n: approved"}'
  1. Store the returned secret as an n8n variable, WAVEFRONT_WEBHOOK_SECRET.
  2. Add a Code node after the Webhook node that verifies the signature before anything else runs (self-hosted n8n needs NODE_FUNCTION_ALLOW_BUILTIN=crypto):
n8n Code node (JavaScript, run once for all items)
const crypto = require("crypto");

const SECRET = $vars.WAVEFRONT_WEBHOOK_SECRET; // or $env.WAVEFRONT_WEBHOOK_SECRET
const key = Buffer.from(SECRET.replace(/^whsec_/, ""), "base64");
const TOLERANCE_S = 5 * 60;

const out = [];
const items = $input.all();
for (let i = 0; i < items.length; i++) {
  const headers = items[i].json.headers;
  const id = headers["webhook-id"];
  const timestamp = headers["webhook-timestamp"];
  const signatures = String(headers["webhook-signature"] || "").split(" ");
  const raw = (await this.helpers.getBinaryDataBuffer(i, "data")).toString("utf8");

  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > TOLERANCE_S) {
    throw new Error("Wavefront webhook: timestamp too old or in the future");
  }
  const expected = crypto.createHmac("sha256", key).update(`${id}.${timestamp}.${raw}`).digest();
  const ok = signatures.some((part) => {
    const [version, sig] = part.split(",");
    if (version !== "v1" || !sig) return false;
    const given = Buffer.from(sig, "base64");
    return given.length === expected.length && crypto.timingSafeEqual(given, expected);
  });
  if (!ok) throw new Error("Wavefront webhook: signature doesn't match");

  const body = JSON.parse(raw);
  if (body.type === "webhook.test") continue;
  out.push({ json: { id, type: body.type, timestamp: body.timestamp, data: body.data } });
}
return out;
  1. Add HTTP Request nodes for the actions, for example POST https://wavefront.adwave.com/v1/workspaces/{ws}/versions/{{ $json.data.version_id }}/publish with {"destination_id": "dst_…"}. Turn on Retry On Fail for 429 and 5xx.
A retried delivery keeps its webhook-id. If running twice would do harm, deduplicate on id, for example with n8n's Remove Duplicates node.