Onboardify
Integrations

Webhooks staging checklist

This checklist is for validating the organization webhook feature in a real staging environment before broader rollout.

Scope

Covered events:

  • client.created
  • process_assignment.accepted

Supported consumers:

  • n8n
  • Make

1. Deploy prerequisites

Before deploying to staging, confirm:

  • Prisma migrations are applied, including the webhook migration.
  • WEBHOOK_SECRET_ENCRYPTION_KEY is set in the staging environment.
  • WEBHOOK_RETRY_TOKEN is set in the staging environment.
  • CRON_SECRET is set in the staging or production environment if Vercel Cron is used.
  • The SaaS project on Vercel has Queues enabled.
  • The queue consumer route is deployed with the queue/v2beta trigger configuration.
  • A Vercel Cron job is configured for /api/internal/webhooks/retry.

Current repository default:

  • On Vercel Hobby, the repair cron runs once per day at 03:00 UTC.
  • If faster recovery is needed, use manual calls to the repair endpoint or upgrade the Vercel plan.

Important:

  • Vercel Cron Jobs run only on Production deployments.
  • Preview deployments do not execute Vercel Cron Jobs automatically.
  • If your staging environment is a Preview deployment, the repair path must be tested manually.
  • For preview or non-production validation, you can still call POST /api/internal/webhooks/retry manually with Authorization: Bearer <WEBHOOK_RETRY_TOKEN>.

2. Staging app setup

In the staging app:

  • Open an organization where your test user is owner or admin.
  • Go to the Webhooks settings page.
  • Create one endpoint for n8n or Make.
  • Subscribe the endpoint to at least one event.
  • Copy the secret shown after creation and store it outside the app. It is not recoverable later.

Recommended staging setup:

  • One endpoint subscribed only to client.created
  • One endpoint subscribed only to process_assignment.accepted

This makes it easier to verify event routing and avoid ambiguity during testing.

3. n8n setup

For n8n:

  • Create a Webhook trigger node.
  • Use POST.
  • Copy the production or test webhook URL from n8n into the organization webhook endpoint.
  • Add downstream logging or persistence so you can inspect headers and body.

Recommended validation in n8n:

  • Store headers["webhook-id"]
  • Store headers["webhook-timestamp"]
  • Store headers["webhook-signature"]
  • Store body.id
  • Store body.type

Important:

  • n8n should deduplicate on webhook-id or body.id.
  • Queue delivery is at-least-once, so duplicate deliveries are possible.

4. Make setup

For Make:

  • Create a Custom webhook.
  • Copy the generated webhook URL into the organization webhook endpoint.
  • Add modules that log the raw body and headers.

Recommended validation in Make:

  • Persist the event id
  • Persist the event type
  • Persist the webhook signature headers
  • Add a deduplication step keyed by event id

5. Functional test cases

Run these in staging.

A. Client created

Steps:

  1. Create a new client in the organization.
  2. Confirm a webhook delivery row appears in the app.
  3. Confirm the consumer receives one event with type = "client.created".
  4. Confirm the payload contains:
    • organization.id
    • organization.name
    • organization.slug
    • data.client.id
    • data.client.name
    • data.client.email
    • data.client.organizationId

Expected result:

  • Delivery status becomes succeeded.
  • Consumer receives the expected payload and headers.

B. Accepted submission

Steps:

  1. Create or reuse a process assignment for a client.
  2. Submit the public form.
  3. Accept the submission from the protected review flow.
  4. Confirm a webhook delivery row appears in the app.
  5. Confirm the consumer receives one event with type = "process_assignment.accepted".
  6. Confirm the payload contains:
    • data.client
    • data.process
    • data.assignment
    • data.submittedSubmission
    • data.acceptedSubmission

Expected result:

  • No webhook is sent on public submit alone.
  • Webhook is sent only when the submission is accepted.

6. Signature checks

Every outbound webhook should include:

  • webhook-id
  • webhook-timestamp
  • webhook-signature

The JSON body should contain:

  • id
  • type
  • createdAt
  • organization
  • data

Minimum verification:

  • webhook-id should match body.id.
  • body.type should match the subscribed event.
  • webhook-signature should be present on every request.

7. Retry behavior

Validate both success and failure behavior.

Success path

  • Configure the consumer to return 200.
  • Confirm the app marks the delivery as succeeded.

Retryable failure path

  • Temporarily configure the consumer to return 500.
  • Trigger an event.
  • Confirm the app marks the delivery as retrying.
  • Confirm attemptCount increases.
  • Confirm a later retry is attempted.

Terminal failure path

  • Temporarily configure the consumer to return 400.
  • Trigger an event.
  • Confirm the app marks the delivery as failed.
  • Confirm no further retry is scheduled.

8. UI checks

Confirm the staging UI shows:

  • endpoint list
  • subscribed events
  • active or paused state
  • secretPreview
  • recent deliveries
  • last error for failed deliveries
  • attempt count and timestamps

Also verify:

  • non-admin users cannot manage webhook endpoints
  • rotating a secret shows the new secret once
  • the full secret is not shown again after refresh

9. Known operational constraints

  • The queue worker is the primary execution path.
  • The internal retry route is a repair path and should stay enabled.
  • Vercel Cron secures its GET call with CRON_SECRET.
  • Delivery is at-least-once, not exactly-once.
  • Consumers must be idempotent.
  • Localhost webhook URLs are allowed only for local development, not for staging.

10. Go or no-go

Ready for broader testing if all are true:

  • staging deploy succeeds
  • migrations are applied
  • queue consumer is active
  • both events are delivered
  • 500 retries work
  • 400 terminal failure works
  • secrets are shown only once
  • ciphertext is never returned to the browser
  • n8n or Make flow deduplicates by event id

Do not proceed if any of these fail:

  • queue trigger is not active
  • deliveries remain stuck in pending with no queue activity
  • accepted submission fires on public submit instead of accept
  • consumer cannot reliably distinguish duplicate events

On this page