Answer with a 2xx first, then do the work
Runcrate waits 10 seconds for an answer. Anything slower counts as a failure and is retried, so a slow handler gets the same event again. Check the signature, store the event or put it on a queue, answer200, and do the work in a background worker.
Verify every signature
Your endpoint’s URL is public. CheckRuncrate-Signature on every request before you trust anything in it, compare in constant time, and reject a timestamp more than 5 minutes old. See verifying signatures.
Drop duplicates by event id
The same event can arrive more than once: a retry after an answer that came too late, or a Redeliver from the log. Every copy has the sameid. Record the ids you have processed and skip any you have seen. Keep them for at least as long as the retry window (about 3 hours 40 minutes), longer if you redeliver by hand.
Runcrate-Delivery to trace a single request, not to dedupe: each redelivery gets a new one.
Do not rely on order
Events are sent independently and retried on their own schedule, soinstance.stopped can arrive before the instance.ready that was retried. Order by created_at in the envelope, and ignore an event that is older than the state you already have.
Read current state from the API before acting
An event says what happened atcreated_at. By the time you handle it, things may have changed: a budget was raised, an instance was relaunched. For a decision that costs money or deletes something, read the resource first with the API, the SDKs or the CLI, using the ids in data:
Keep the secret in a secret store
The signing secret is shown once. Put it straight into your secret manager or your platform’s encrypted environment variables. Do not commit it, log it or paste it into chat. If it may have leaked, rotate it: the old one keeps working for 24 hours while you deploy the new one. Rotate it on a schedule too, and whenever someone who had it leaves.Subscribe only to what you use
Under Events, choose Choose events and tick only the types your receiver handles. Fewer events means less traffic, fewer retries to look at, and nothing new arriving unexpectedly when Runcrate adds an event type. Use a separate endpoint for each system that needs different events.Treat Slack and Discord URLs as secrets
Slack and Discord webhooks are not signed: anyone with the URL can post to your channel. Keep them out of repositories and tickets, and if one leaks, replace it in Slack or Discord and update the endpoint. See Slack and Discord.Ignore fields you do not know
data is open: new keys can appear without a new api_version. Read the keys you need and ignore the rest. Do not validate events against a closed schema that rejects unknown keys.
Watch the delivery log
An endpoint that keeps failing is turned off after 3 days with no success. Subscribe a second endpoint (a Slack or Discord channel works) towebhook.disabled, so you hear about it when it happens.