Skip to content

Webhook Technical Reference

Canonical maker page for inbound and outbound HTTP. Not sure which product? Start with Workflow vs Messaging Webhooks. Admin kill switches, host env files, and internal endpoints stay in repo docs/ — not here.

Direction Meaning NotionApps surface
Inbound An external tool POSTs JSON into NotionApps and starts work Workflow trigger webhook_received, or Messaging inbound that publishes a message
Outbound NotionApps POSTs JSON to a URL you own Notify (fire-and-forget), Call webhook and wait (sync JSON), or a Messaging subscriber of type Webhook

Use webhooks when another system is the first place work begins (CRM, payments, a form tool), when a downstream system must hear the result, or when a button must wait for Make and then refresh the already-open tab.

When not to: you only need email. Use send_notification. You are still exploring — start with the wizard, not HTTP.

  1. Workflow entitlement is on (Messaging External API level if you use Messaging webhooks).
  2. You have the application id from the builder URL.
  3. You can generate a webhook secret in the workflow builder when the trigger is Webhook received. Copy it once — it is not shown again.
  4. You have an outbound catcher (webhook.site, Hookdeck, Zapier Catch Hook) if you will test outbound.
  5. The workflow is published / active. Drafts can accept HTTP and create zero runs.

The secret belongs to this app. Workflow inbound and Messaging inbound both use it.

  1. Open Automation → Workflows.
  2. Select (or create) a workflow whose trigger is Webhook received.
  3. Open External webhook intake.
  4. Enter a name you will recognize later, for example Make production.
  5. Choose an active term: 30, 90, 180, or 365 days, or No expiry.
  6. Click Generate secret.
  7. Copy the value immediately. Paste it into Make, Zapier, or your sender as:
x-notionapps-webhook-token: {PASTE_THE_SECRET}

The builder also accepts Authorization: Bearer {SECRET} and x-workflow-webhook-token: {SECRET}.

The list then shows only a prefix (for example na_wh_8f3a2c1b), the name, status, days left, and last used. The full secret is never shown again.

Rotate

  1. Generate a new secret (you can have up to five active secrets).
  2. Update Make, Zapier, or the sender to the new value.
  3. Confirm a test POST succeeds.
  4. Revoke the old secret.

You cannot revive a revoked secret. Generate a new one instead.

Rules

  • A secret for App A cannot post into App B.
  • Revoked or expired secrets return 401.
  • If inbound webhooks are disabled for the app, generate is blocked.
  • Do not put the secret in a Notion property that guests can open.

Webhook intake template (recommended first route)

Automation → Workflows → Start from a template → Webhook intake, or recreate:

Order Step Purpose
1 Condition e.g. payload.status equals approved
2 Create record Map payload.name, payload.email
3 Notify (channel = Webhook) Outbound proof to your catcher
4 End Done

Trigger: webhook_received on the application.

Replace example field names with your Notion properties. Full step list: Step catalog.

Inbound URL shapes

POST {API_HOST}/v1/webhooks/workflow-events
POST {API_HOST}/v1/application/{APPLICATION_ID}/workflows/webhook-events
POST {API_HOST}/v1/webhooks/messaging-events
POST {API_HOST}/v1/application/{APPLICATION_ID}/messaging/webhook-events

{API_HOST} is the API for your environment (production https://api.notionapps.com unless support tells you otherwise). Prefer the app alias URL from the builder so the event is already scoped.

Auth (maker)

Use the secret you generated above. Do not guess a platform token and do not reuse a secret from another app.

If a request returns 401/403, the secret is wrong, revoked, expired, or bound to a different app. If it returns 503 about a token not configured, that is an environment problem — contact support.

Test inbound

  1. Publish the workflow.
  2. POST JSON with a unique event_id / idempotency_key every try (retries can look like “nothing happened”).
  3. Example body:
{
"application_id": "YOUR_APP_ID",
"event_id": "test-2026-08-31-001",
"payload": {
"status": "approved",
"name": "Sample Lead",
"email": "user@example.com"
}
}
  1. Expect an accepted response and runs_created >= 1 when the trigger matched.
  2. Confirm the Notion row and, if you added Notify, the catcher POST.

Test outbound

  1. Notify step → Channel Webhook → paste the catcher URL.
  2. Subject/body you will recognize.
  3. Fire inbound (or Simulate if Simulate sends outbound in your build).
  4. Confirm the catcher shows headers + body.

Call webhook and wait (open-tab refresh)

Use Call webhook and wait when a button must POST Make (or another webhook), receive JSON, then Refresh or Open screen on the same open tab. This is not fire-and-forget Notify webhook.

  1. Add the step and paste the Make webhook URL.
  2. Leave the sync timeout at 8000 ms unless you need a shorter wait (max 12 seconds on the tap).
  3. In Make, end with Webhook response and return JSON, for example { "ok": true, "cart_record_id": "…" }.
  4. Map a later Open screen record id to context.<this_step_id>.cart_record_id when Make returns one.
  5. Follow with Refresh / Open screen / Show message.

What the user sees:

  • Make answers within 8 seconds: the following UI steps run on the open tab.
  • Make is still going: Working… then the app polls the run for 45 seconds.
  • Still pending: “This is taking longer. Refresh to see the cart.”
  • 4xx / 5xx in the sync window: error, no refresh, no retry.

Live screen updates must be on for the app, or Refresh after this step will not update the open tab. The switch is off by default. NotionApps turns it on from Workflow Operations → Controls.

Inbound webhooks Make fires back at NotionApps still cannot refresh an already-open tab.

Control Where What it does
Trigger Webhook received Workflow Starts a run from HTTP.
Intake URL (central / app alias) Builder Where senders POST.
Generate secret External webhook intake Creates a per-app secret. Plaintext is shown once.
Name + active term External webhook intake Label and 30 / 90 / 180 / 365 days or no expiry.
Revoke External webhook intake Immediately rejects that secret.
Token header Sender (Make / Zapier) x-notionapps-webhook-token.
Condition on payload.* Step Gate.
Create/update record maps Step payload.field → Notion.
Notify channel Webhook Step Fire-and-forget outbound.
Call webhook and wait Step Sync POST; waits for JSON Webhook response.
Messaging inbound / subscriber Messaging Separate product; needs External API level. Uses the same app secret.
Idempotency key Payload Dedupes retries.

Inbound and fire-and-forget Notify usually show nothing to the current tab. Call webhook and wait can Refresh / Open screen / Show message on the open tab when Live screen updates is on. Operators may also see a Work Queue item or Notification if you added those steps. An inbound sender sees only the HTTP status.

  • Messaging webhooks need External API. Workflow Notify webhooks and Call webhook and wait need Workflow on, not Messaging levels.
  • Up to five active secrets per app. Revoke or expire one before generating another if you are at the cap.
  • After the first active secret, the shared platform token no longer works for that app.
  • Call webhook and wait needs a reachable HTTPS URL. Make must return JSON via Webhook response.
  • Unpublished workflows: HTTP may return accepted with runs_created: 0.
  • Payload size and rate limits follow the API. Keep test bodies small.
  • Do not put secrets in Notion properties that guests can open.

You generate a secret named Make production with a 90-day term. Make stores x-notionapps-webhook-token and POSTs { status, name, email } to the app alias URL. Condition requires approved. Create record on Leads. Notify the outbound catcher. The sample lead appears in the app list; the catcher logs the outbound POST.

Symptom Likely cause What to do
401 Wrong, revoked, or expired secret, or a secret from another app Generate a new secret if you lost the value. Confirm the prefix matches this app. Stay on one environment.
401 after you generated a secret Sender still uses the old shared platform token Update Make/Zapier to the new secret.
Generate is blocked Inbound webhooks are disabled for the app Ask NotionApps to turn inbound back on.
At the 5-secret cap Too many active secrets Revoke or expire one, then generate.
Accepted, 0 runs Draft, or trigger not webhook_received Publish. Check trigger.
Condition failed payload.status mismatch Log the raw body. Fix the path.
Outbound missing Notify not Webhook, or URL wrong Catcher URL. Publish.
Open tab stale after Make Used Notify, or Make has no Webhook response, or live screen updates is off Use Call webhook and wait. End Make with Webhook response JSON. Ask NotionApps to turn the switch on.
Messaging 403 Level below External API Request access.

Workflow vs Messaging Webhooks. 31 Aug 2026 Release. Trigger catalog. Which automation.