Skip to main content

Using Shellui webhooks with n8n

email-service can POST signed JSON to an n8n Webhook node when a message changes state. The signing and retry rules match identity-service, storage-service, and hosting-service, so one n8n pattern works for every Shellui webhook.

The event list and envelope are in actions.md and integration.md.

Before you start​

  1. Create a Shellui Actions webhook rule (POST /api/v1/actions/rules on email-service, or the admin app).
  2. Copy the production Webhook URL from n8n when the workflow is active.
  3. Set the rule signing secret to the value n8n shows, or to a whsec_ secret you generate. Plain text and whsec_<base64> both work. The API returns the secret only on create and on rotate.
  4. Optional: if the Webhook node uses Header Auth, store that header only in a system you control. This version of the rule API signs the body. It does not add a separate Authorization header.

Default HTTP timeout from Shellui is 5 seconds (ACTIONS_WEBHOOK_TIMEOUT_SECONDS). In the Webhook node, set Respond to Immediately so n8n answers before the workflow finishes.

n8n Webhook node​

SettingValue
HTTP MethodPOST
PathYour choice (the production URL includes the path)
AuthenticationNone (the signature is enough)
RespondImmediately

Shellui always POSTs to the URL saved on the rule. Use the production URL. n8n returns 404 when the workflow is inactive. Shellui retries 404.

Delivery​

  • At-least-once. Dedupe on header webhook-id.
  • No ordering guarantee between lanes or companies.
  • webhook-id stays stable across retries of the same delivery. X-Shellui-Delivery-Attempt increments.
  • email.message.sent can arrive twice for one message if the provider webhook also reports acceptance. Dedupe on data.message_id plus type if you need one row.

HTTP headers​

HeaderMeaning
Content-Typeapplication/json
webhook-idStable across retries of this delivery
webhook-timestampUnix seconds when signed
webhook-signaturev1,<base64> HMAC-SHA256
X-Shellui-EventEvent type, for example email.message.delivered
X-Shellui-Delivery-AttemptAttempt number (1 on the first try)
User-Agentshellui-email-webhooks/1.0

Verify the raw request body bytes, not a re-encoded pretty print.

Retry behavior​

HTTP resultShellui behavior
2xxDelivered
404, 408, 409, 425, 429, other retryable 4xx, 5xx, timeouts, connection errorsRetry. Backoff 30s * 2^(attempt-1), max 1 hour, up to 8 attempts.
400, 401, 403, 405, 410, 413, 422Dead (no retry)
429 / 503 with Retry-AfterNext attempt respects Retry-After, capped at 1 hour

A verifier that fails the signature should return 401. Shellui will not retry a 401. Fix the secret, then requeue with POST /api/v1/actions/deliveries/{id}/requeue.

Reference verifier​

node docs/examples/verify-shellui-webhook.mjs "$SECRET" /path/to/raw-body.bin

Set WEBHOOK_ID, WEBHOOK_TIMESTAMP, and WEBHOOK_SIGNATURE to the request headers.