You want a serverless function to wake as soon as a RelayLink package arrives. Inngest can run the durable steps after receipt, but your first boundary still has to authenticate RelayLink's exact bytes and claim the delivery once.
The architecture below uses an explicit adapter you operate. The Inngest event and idempotency features linked here are generic building blocks, not a native RelayLink connector.
Verify RelayLink before emitting an event
Expose a small HTTPS receiver. Before it parses or forwards the request:
- Read the untouched body bytes.
- Compute HMAC-SHA256 over
"{timestamp}.{body}"with the subscription'swhsec_secret. - Compare the expected
sha256=value in constant time. - Reject a signed timestamp outside your replay window.
- Parse the verified JSON and match its event and delivery id to the headers.
- Atomically store the delivery id and a pending handoff.
Only then create an Inngest event. Return 2xx after the receipt and handoff are durable, not after an agent finishes.
Do not point RelayLink at a generic webhook transform unless you have proved that it exposes the exact raw body and lets you perform this verification before parsing or acting. A platform-generated endpoint that can accept JSON is not automatically a RelayLink signature verifier.
Send a minimal, idempotent Inngest event
Inngest events trigger functions with matching event names. Give your internal event an application-owned name and carry references only:
event id: relaylink delivery id
data:
internal account reference
package id
thread id
receiver or subscription reference
credential reference
Do not include the signing secret, OAuth token, API key, note, TL;DR, ask, or context brief. There is no reason to copy the webhook's sender or topic into the event unless a fixed display requirement needs them; the worker can obtain the authoritative package later.
Inngest's idempotency guide says a unique event id prevents duplicate function runs for 24 hours. Use the RelayLink delivery id there, but do not make that time-bounded platform behavior your only record. Keep the receiver inbox under a durable unique constraint and mark the Inngest handoff separately.
That closes the common ambiguity where sending the event succeeds, the receiver crashes before recording success, and a RelayLink retry tries to send it again. The repeat finds the existing inbox row and reconciles the same event id.
Fetch the package in a durable step
The package.received webhook contains an envelope: event, delivery id, package and thread ids, sender, topic, sent time, reply state, and mcp_url. It deliberately omits the correspondence body.
In the function, require mcp_url to match the RelayLink endpoint pinned to the account selected by the receiver route. Only then resolve that account's separate MCP credential from the internal reference and call get_package. Keep each user's credential isolated. Never choose a credential from the sender email or another webhook body field, and never send one to an arbitrary URL supplied by the request.
Use an Inngest step for the fetch and subsequent retryable operations. The platform documents step-level execution and retries, but an external side effect still needs its own idempotency key. A retried step that posts an alert, creates a ticket, or updates another service can otherwise repeat the effect after an uncertain response.
The fetched package remains third-party content. Authentication proves which RelayLink package the account may read; it does not promote the sender's words into application policy. Pass the content to a model as labelled correspondence, not as a system message. Never let sender or topic text select functions, destinations, tools, or approval outcomes.
Keep approval outside automatic retries
An Inngest function can classify, summarize, prepare a draft, or create a review task. It must not interpret event receipt as permission to send a RelayLink package.
Model the review as explicit state: proposal created, waiting for user, approved or refused, then continued by a trusted event from your own interface. If the approved effect is a RelayLink send, use RelayLink's normal draft, preview, and confirmation. Do not build a second “reply from notification” endpoint that turns a click or channel message into delivery.
Retrying the fetch or analysis is operational recovery. Retrying a human decision is not. Store the decision and an operation id before performing the approved effect.
When Inngest fits
This adapter fits teams already using Inngest for event-triggered functions, durable steps, retries, and operational visibility. It is especially useful when the receiver should answer quickly and the rest of the work belongs in serverless execution.
It is not a direct no-code integration, and it does not remove the need for a public receiver, RelayLink HMAC secret, per-user MCP credential, or durable deduplication store. For a private worker with no inbound route, periodic check_inbox polling may be simpler. For a fixed notification, a small queue consumer may need less orchestration than an agent function.