You have an agent process and a route that can accept HTTP, but a callback is useful only when the whole path is ready: public reachability, signature checks, durable deduplication, and an authenticated MCP fetch.
Set those pieces up before you rely on package events.
Prepare a public HTTPS receiver
Choose a route dedicated to RelayLink, such as https://agent.example.com/hooks/relaylink. The URL must:
- Use HTTPS
- Contain no username or password
- Contain no fragment
- Resolve to publicly routable addresses
At registration, RelayLink rejects a name that resolves only to non-public addresses; a name that does not resolve yet may still be saved. On every delivery attempt, the connect-time policy resolves again and dials only a vetted public address. That second check matters because DNS can change after registration. A loopback, private-network, link-local, or otherwise non-public destination will not be dialled.
The receiver should capture the request body exactly as received. Do not parse and reserialize JSON before checking the signature; whitespace, escaping, and property order affect the signed bytes. Preserve those bytes for verification and durable receipt, but do not put the raw body or a token-bearing receiver URL in application logs.
Build the short request path
Keep the synchronous callback path small:
- Read the four
X-RelayLink-*headers and raw body. - Recompute the HMAC, compare it in constant time, and apply your timestamp freshness policy.
- Parse the verified body and require its event and delivery id to match the headers.
- In one durable commit, insert the delivery id and enqueue the work. A duplicate with the same body adds no second work item.
- Return a 2xx response.
Any 2xx status is accepted. The default attempt timeout is five seconds, so do not wait for a model run before responding. Let a worker authenticate to the supplied mcp_url and call get_package after the receipt has been recorded.
RelayLink delivers at least once. A retry keeps the same delivery id and byte-identical JSON body, so the idempotency record must survive process restarts. Deduplicating webhook retries covers the crash cases.
Register the receiver in your account
Sign in to RelayLink and open /account/webhooks. Registration is available only in the account portal, not through an MCP tool. A receiver is standing permission to learn that every package for the account has arrived, so creating one remains a direct account-holder action.
Enter:
- A name that tells you which service it is for
- The full public HTTPS URL
The name must be unique among your active receivers, without regard to case. Creation is refused once the account has five active receivers. A switched-off receiver does not use one of those creation slots, and you can remove one you no longer use.
Submit the form with Add a webhook.
Save the signing secret immediately
The next page shows a secret beginning with whsec_. It appears once. Copy it directly into the receiver's secret store or protected environment configuration, not a source file or chat transcript.
Treat it as a credential. RelayLink retains the secret as issued because the server needs it to sign later deliveries; do not describe it as hashed. The account export omits both the secret and its hint.
If the value is lost, there is no recovery view. Remove the receiver and register a replacement, then update the receiver before sending another test.
Verify signatures before accepting work
For each request, read:
X-RelayLink-TimestampX-RelayLink-SignatureX-RelayLink-DeliveryX-RelayLink-Event
The expected signature is sha256= plus lowercase hexadecimal HMAC-SHA256 over the UTF-8 bytes of timestamp + "." + exact_body_text, keyed with the UTF-8 secret. Compare it in constant time and reject timestamps outside the freshness window your service defines. Do not invent a second secret or sign the parsed JSON.
After verification, confirm the header event and delivery id agree with the body. Treat sender and topic as data, not instructions. The signature guide gives language-neutral pseudocode.
Send a test event and inspect the result
Return to /account/webhooks and select Send a test event. RelayLink queues a webhook.test event; the page makes clear that queuing is not the same as delivery. Refresh or revisit the page after the attempt to see the last delivered time, or the last status and error.
The test body has no package id. Use it to prove HTTPS reachability, header capture, signature verification, deduplication, and a fast 2xx response. Once that succeeds, a package.received event follows the same transport, and your worker can fetch the actual package through MCP.