Skip to content

Connect Zapier to Atlas Labs

To connect Zapier to Atlas Labs, use Webhooks by Zapier: a Catch Raw Hook trigger receives events at a hooks.zapier.com URL that you subscribe with POST /webhooks, and a Custom Request action calls the REST API with an Authorization: Bearer header. Zapier does not verify the Standard Webhooks signature for you, so this page includes the Code by Zapier step that does.

Reference table — Atlas Labs API fields and Zapier's documented app names, not part of the fictional simulation. Zapier help centre checked 15 Oct 2026.
At a glanceValue
Receive eventsWebhooks by Zapier → Catch Raw Hook (keeps headers and the raw body; Catch Hook parses the body and drops the headers)
Call the APIWebhooks by Zapier → Custom Request; or the premium beta app API by Zapier → API Request
Where the key goesHeaders section: Authorization = Bearer lab_off_YOUR_KEY (Head Office) or Bearer lab_fac_YOUR_KEY (Factory)
BodyData field, raw JSON, with header Content-Type: application/json
Idempotency-KeyThe webhook-id header from the Catch Raw Hook (it equals the event id, evt_…), or the id that the Code by Zapier step outputs after parsing the raw body
Webhook hosthooks.zapier.com is a recognised platform host with a higher delivery allowance
PlanWebhooks by Zapier is on Professional, Team and Enterprise, not Free; API by Zapier is premium and beta (Zapier help)
OpenAPI importNone found in Zapier's documentation; use the HTTP steps
Start a sandbox and your keys are filled in for you. This page uses lab_off_YOUR_KEY and lab_fac_YOUR_KEY. After you start a sandbox, the “Connect it” panel's Zapier tab shows these field values with your real keys and a copy button.
Atlas Labs fictional company API
signed webhook
POST, event JSON
Custom Request
Bearer key
Your Zap Catch Raw Hook → steps
action
Your apps Slack, Sheets, CRM…
Both legs are optional: a Zap can only listen, only call, or do both.

How do I receive Atlas Labs events in a Zap?

  1. Create a Zap → Trigger: Webhooks by Zapier → event Catch Raw Hook → Continue. It hands later steps exactly two things, the unparsed body and the headers, so fields such as id and data.sales_order_id appear only after the Code step in the next section parses the body. Pick Catch Hook instead only if you will not verify the signature: it parses the body for you but discards the headers and the raw bytes.
  2. Copy the webhook URL Zapier shows, of the form https://hooks.zapier.com/hooks/catch/…/…/.
  3. Subscribe that URL in Atlas Labs with either key. Save the whsec_ secret from the response; it is shown once.
    Method
    POST
    URL
    https://automationatlas.io/labs/api/v1/webhooks
    Headers
    Authorization: Bearer lab_off_YOUR_KEY
    Content-Type: application/json
    Body
    {"url": "https://hooks.zapier.com/hooks/catch/…/…/", "events": ["office.sales_order.accepted"], "description": "accepted orders"}

    Subscribe to office.sales_order.accepted when the Zap will bridge the order into a work order, as in the next section: POST /factory/work-orders accepts only an order whose status is accepted and answers 409 invalid_transition for any other. office.sales_order.received fires earlier, when the order arrives, and suits a listen-only Zap or the ping demo.

  4. Send the test ping (POST /webhooks/{id}/test, in the snippet below), then click Test trigger in Zapier. The subscription turns active once Zapier answers 2xx; Zapier's test only shows the 3 most recent webhooks from the past hour.
  5. Publish the Zap. Atlas Labs re-delivers a failed event after 10 s, 60 s and 300 s, then disables the subscription after 5 consecutive failures.
curl snippets/06-subscribe-webhook.sh bash, curl, jq proven against the live API (create, replay, test ping)
#!/usr/bin/env bash
# Subscribe a public HTTPS URL (port 443) to events, keep the secret, send the test ping.
# Up to 3 subscriptions per sandbox. Needs WEBHOOK_URL, for example a Zapier Catch Hook URL.
set -euo pipefail
BASE="${ATLAS_BASE:-https://automationatlas.io/labs/api/v1}"
: "${ATLAS_OFFICE_KEY:?run: source atlas-keys.env}"
: "${WEBHOOK_URL:?set WEBHOOK_URL to your public https:// endpoint}"

created=$(curl -sS -X POST "$BASE/webhooks" \
  -H "Authorization: Bearer $ATLAS_OFFICE_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: subscribe-orders-1" \
  -d "$(jq -n --arg url "$WEBHOOK_URL" '{url: $url, events: ["office.sales_order.received"], description: "new orders"}')")
echo "$created" | jq '.data | {id, status, url_host, events}'

# The whsec_ secret is returned once. Replaying the same Idempotency-Key never repeats it (secret is null).
secret=$(jq -r '.data.secret // empty' <<<"$created")
[ -n "$secret" ] && (umask 077; printf '%s' "$secret" > atlas-webhook-secret.txt; chmod 600 atlas-webhook-secret.txt) || echo "no secret in this response (a replay?)" >&2
ID=$(jq -r '.data.id' <<<"$created")

# The subscription starts as pending_verification and activates when this ping gets a 2xx.
curl -sS -X POST "$BASE/webhooks/$ID/test" -H "Authorization: Bearer $ATLAS_OFFICE_KEY" | jq .data
curl -sS "$BASE/webhooks/$ID" -H "Authorization: Bearer $ATLAS_OFFICE_KEY" | jq '.data | {status, consecutive_failures, last_error_class}'

The tested file is shown unchanged and subscribes to office.sales_order.received, the listen-only case. For the bridge Zap below, set the events value to office.sales_order.accepted as in the field box above.

Does Zapier verify the signature?

No. Add Code by Zapier (Run JavaScript) right after the Catch Raw Hook and map the raw body and the webhook-id, webhook-timestamp and webhook-signature headers into its input data. The step does two jobs. First, paste the verify function below, leaving out its two import lines and the export keyword, replace process.env.ATLAS_WEBHOOK_SECRET with the secret passed in as an input field of the step (never a whsec_ value pasted into the code), and throw when it returns false, so the Zap stops. The excerpt is the tested Node file; how node:crypto is loaded inside Code by Zapier is not something we have confirmed, so check Zapier's Code docs for the form your step accepts. Second, parse the body with JSON.parse and return the fields later steps will map, for example id, type and data.sales_order_id; without this step a Catch Raw Hook offers no id or sales_order_id fields, only the raw body and the headers. The function needs the raw bytes, which is why the trigger must be Catch Raw Hook.

JavaScript snippets/07-verify-webhook.mjs excerpt: the header comment and the verify function, as in the tested file; the server part is cut where // … stands verified against the repo's own signer: good, rotated, tampered, wrong-secret, stale
// Receive and verify an Atlas Labs webhook (Node 20+, no dependencies).
// Standard Webhooks: headers webhook-id, webhook-timestamp, webhook-signature.
// signature = "v1," + base64(HMAC-SHA256(key, `${id}.${timestamp}.${rawBody}`)), where key is
// the base64-decoded part of your whsec_ secret. During the 24 h after rotate-secret the header
// holds two space-separated values ("v1,<new> v1,<old>"); accept either.
import { createHmac, timingSafeEqual } from "node:crypto";
import { createServer } from "node:http";

const SECRET = process.env.ATLAS_WEBHOOK_SECRET; // whsec_...
const TOLERANCE_S = 300;

export function verify(secret, headers, rawBody, nowS = Math.floor(Date.now() / 1000)) {
  const id = headers["webhook-id"];
  const timestamp = headers["webhook-timestamp"];
  const header = headers["webhook-signature"];
  if (!id || !timestamp || !header) return false;
  if (Math.abs(nowS - Number(timestamp)) > TOLERANCE_S) return false; // stale or replayed
  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const expected = createHmac("sha256", key).update(`${id}.${timestamp}.${rawBody}`, "utf8").digest();
  return header.split(" ").some((part) => {
    const [version, value] = part.split(",");
    if (version !== "v1" || !value) return false;
    const given = Buffer.from(value, "base64");
    return given.length === expected.length && timingSafeEqual(given, expected);
  });
}

// …

How do I call the Atlas Labs API from a Zap?

  1. Add an action → Webhooks by Zapier → event Custom Request. Use Custom Request rather than the plain POST event so the JSON in the Data field is sent exactly as typed.
  2. Fill the request. This example bridges an accepted sales order into a Factory work order, so it uses the Factory key. Look the order up first with a Custom Request GET https://automationatlas.io/labs/api/v1/office/sales-orders/<id> (Head Office key), with <id> mapped from the Code step's sales_order_id output, to get quantity and due_sim_day.
    Method
    POST
    URL
    https://automationatlas.io/labs/api/v1/factory/work-orders
    Headers
    Authorization: Bearer lab_fac_YOUR_KEY
    Content-Type: application/json
    Idempotency-Key: insert the webhook-id header from the trigger (it equals the event id), or the Code step's id output
    Data (raw JSON)
    {"sales_order_id": "<sales_order_id from the Code step>", "quantity": <quantity from the order>, "due_date": <due_sim_day from the order>}
    Response fields
    After a test, Zapier offers the step's HTTP status field and the response body to later steps. Their exact names are not given in the help page we read (unverified), so pick them from the list Zapier shows.

    Preset matters. Pick a preset with a manual bridge (Standard or Full) or this write returns 409 already_bridged, because Starter bridges automatically.

  3. Treat 409 already_bridged as success in a Filter or Paths step: continue when the step's HTTP status field is 201, or is 409 and the response body's error.code is already_bridged (a second delivery of the same event, or an order the sandbox bridged itself). Send yourself anything else, including 409 invalid_transition: that one is a real error and means the order's status is not accepted, usually because the Zap was triggered by office.sales_order.received instead of office.sales_order.accepted.
  4. Prefer to keep the key out of the Zap? Apps → Add connection → API by Zapier → authentication type Static Headers (API key) → one header per line: Authorization: Bearer lab_fac_YOUR_KEY. Then use its API Request action; Zapier adds the header itself. API by Zapier is premium and in beta.

Idempotency and retries

  • Use the event id as the Idempotency-Key: the webhook-id header from the Catch Raw Hook, or the id the Code step returns after parsing. A replayed Zap run then returns the original Atlas Labs response (Idempotency-Replayed: true) instead of creating a second record.
  • On 429 rate_limited, wait the seconds in Retry-After and send the same request. Zapier's own retry behaviour for Webhooks by Zapier is not described in the help pages we read, so do not rely on it.
  • Leaving Data blank in a Custom Request sends every field from previous steps as the body; always type the JSON.

Common errors

Reference table — Atlas Labs error codes as seen from Zapier, not part of the fictional simulation.
You seeWhy, and the fix
403 wrong_systemThe key prefix does not match the route. /factory/* wants lab_fac_, /office/* wants lab_off_; the hint says which.
409 already_bridgedNot an error for this Zap: the order already has a work order (a second delivery of the same event, or a Starter sandbox bridged it itself). Treat it as success, as the Filter step above does.
409 invalid_transition“only accepted sales orders can be bridged”: the order's status is not accepted. The Zap fired on office.sales_order.received, or the order was never accepted. Subscribe to office.sales_order.accepted, or accept it first with POST/office/sales-orders/{id}/accept.
401 unauthorizedThe key is unknown (a typo), revoked (for example after it appeared in a URL) or deleted with its sandbox. An expired sandbox is different: its writes return 423 sandbox_expired. Start a new sandbox and update the header.
415 unsupported_media_typeThe body arrived without Content-Type: application/json. Add the header (see the gotcha below).
422 idempotency_key_reusedSame key, different body or path. Map a value that is stable per event, never one that changes between runs.
422 webhook_url_rejectedThe URL was not public https:// on port 443; details.reason names the rule. Paste the full Zapier URL including https://.
Test trigger finds nothingSend the test ping and click Test trigger within the hour; only the 3 newest requests are offered.

Gotchas

  • Plan gating. Webhooks by Zapier (send and catch) is not available on the Free plan; API by Zapier is a premium, beta app (Zapier help centre, checked 15 Oct 2026).
  • Raw body, no fields. Signature verification needs the exact bytes. Catch Raw Hook keeps them (up to 2 MB) and includes the headers, but offers nothing parsed: map id, type and data.sales_order_id from the Code step's output, never from the trigger. Catch Hook is the reverse: parsed fields, no raw bytes, no headers.
  • Content-Type. Zapier's help says not to set a custom Content-Type on Webhooks by Zapier, while a community thread reports that adding application/json fixed a failing request. Test your Zap once with the header; Atlas Labs requires it on writes.
  • Per-app API Request is not for Atlas Labs. The built-in “API Request” action inside other apps only reaches apps that already have a Zapier integration. Use Webhooks by Zapier or API by Zapier.
  • Underscored headers. A community thread reports Catch Raw Hook dropping headers whose names contain an underscore (unverified). Atlas Labs headers use hyphens, so this should not affect you.

Download the recipe

Bridge an accepted sales order into a work order (Markdown recipe)
Catch Hook (parsed fields, no signature check) → look up the order → Custom Request POST /factory/work-orders → Filter on 201 or 409 already_bridged. Needs a manual-bridge preset (Standard or Full).
Written from vendor docs, never built in a live Zapier account
Download .md

Questions people ask

Will Atlas Labs deliver webhooks to a Zapier URL?
Yes. hooks.zapier.com is public HTTPS on port 443, which is all a subscription needs, and it is one of the shared platform hosts that get a higher delivery allowance.
Does Zapier verify the Standard Webhooks signature?
No. Use Catch Raw Hook and the Code by Zapier step above. For a fictional sandbox you may decide to skip it; the payload is only ever simulation data.
Which Zapier plan do I need?
Webhooks by Zapier is on Professional, Team and Enterprise (Zapier help centre, checked 15 Oct 2026). Without it, use Make, n8n or the REST snippets.
Can Zapier import the Atlas Labs OpenAPI file?
We found no OpenAPI or Swagger import in Zapier's documentation. Build the two HTTP steps by hand; it takes under a minute.
What should I use as the Idempotency-Key in a Zap?
The event id (evt_…): the webhook-id header on a Catch Raw Hook, or the parsed id field on a Catch Hook. Never a timestamp or a random value.
Why can't I find id or sales_order_id in the Catch Raw Hook's fields?
Because Catch Raw Hook keeps the body unparsed. Either parse it in the Code by Zapier step and map that step's outputs, or switch the trigger to Catch Hook, which parses the body but drops the headers, so the signature cannot be checked.
Why does my Zap get 403 wrong_system?
You sent the Head Office key to a Factory route, or the other way round. Both keys appear once, when the sandbox is created; keep them labelled.

Sources (checked 15 Oct 2026): Zapier help centre, “Send webhooks in Zaps” (8496326446989), “Trigger Zaps from webhooks” (8496288690317), “Send API requests in Zap workflows” (44391650357005), “How to get started with API by Zapier” (44391660158733). Atlas Labs facts from the API source, observed live.