How events reach you
Integrations work in two layers.- The integration. You create it once for the organisation. It holds the connection — the webhook URL, or the authorised Slack workspace.
- The notification. You attach the integration to a workflow, and choose which events fire it.
Set up a webhook
1
Create the integration
Go to Integrations → Add Integration → Webhook, then set:
- URL — the endpoint that receives the events.
- Headers — optional headers Asteroid adds to every request.
POST with a JSON body.2
Attach it to a workflow
Open the workflow, go to the Notifications tab, and select Add Notification. Then configure:
- Event rules — which event types fire the notification.
- Field filters — match on fields inside the payload.
- Metadata filter — fire only when the execution’s metadata matches.
- Unwrap result — for
EXECUTION_COMPLETED, sendpayload.resultalone instead of the full envelope.
3
Verify the signature
Check
X-Asteroid-Webhook-Signature against the raw request body before you parse or act on
anything. See Verify the signature.Payload structure
Every request body has the same shape, unlessUnwrap result is set on an EXECUTION_COMPLETED rule. That delivery carries the result object on its own.
string
required
The category of the notification.
execution for execution events. Batch events use
execution_batch and a different info shape. See Batch notifications.string
required
Identifier for this delivery.
string
required
ISO 8601 timestamp of the event.
object
required
The execution context and the event-specific payload.
info holds:
string
required
The event name. See Event types.
string
required
Execution UUID.
string
required
Link to the execution in the platform. For batch events it points at the workflow’s batch page.
string
required
workflow UUID.
string
required
workflow display name.
object
The metadata you attached when you started the execution.
object
required
Event-specific data. Its shape depends on
info.event.Event types
Match oninfo.event. The rule picker in the platform lists the same events by name.
Execution lifecycle
EXECUTION_CANCELLED carries the cancel reason. See Debug your workflows for what
each reason means.
Actions and steps
Execution detail
Tests
Batch notifications
A batch is not an execution, so its events arrive withtype: "execution_batch" and a batch info.
Subscribe with the Batch Started and Batch Completed rules. Batch events carry no metadata, so a
notification with a metadata filter never fires for them. Started and Completed can arrive out of
order for a very small batch.
event_id is stable for a batch event. A redelivery repeats it, so you can deduplicate on it.
See Batch executions.
Example: a failed action
Verify the signature
Asteroid signs every delivery. Check the signature against the raw request body before you parse or act on anything. Every request carries these headers:
Each signature is the SHA-256 digest of the raw body bytes, signed with RSA PKCS#1 v1.5, then Base64
encoded. The key set names that algorithm
RS256.
Fetch the public keys
Public keys are published as a JSON Web Key Set. The endpoint is public and needs no credentials.kid matches X-Asteroid-Webhook-Key-Id.
Cache the set and refetch when a delivery names a kid you do not hold. A new key appears in the set
before we sign anything with it. A receiver that refetches on an unknown kid survives every rotation
with no code change and no downtime.
Example
The legacy header
X-Asteroid-Signature predates key ids. It names no key, so it is always signed with one fixed key.
That key cannot be rotated without breaking every receiver that pinned it.
Nothing breaks today. We still send the header on every delivery, and we will announce a removal date
well before we stop. Until then, treat it as read-only history:
- New integrations verify
X-Asteroid-Webhook-Signatureonly. - Existing integrations migrate, then stop reading
X-Asteroid-Signature.
GET /integrations/webhook/public-key endpoint needs a platform session. Its top-level
publicKeyPem and keyId describe this legacy key only. The same response also returns a keys
array with every signing key in the ring. Prefer the unauthenticated JWKS endpoint.
Migrate off the legacy header
The payload, the algorithm, and the raw-bytes rule are unchanged. You are only changing which header you read and where the key comes from.1
Read the key id
Read
X-Asteroid-Webhook-Key-Id from the request.2
Look the key up
Fetch
https://odyssey.asteroid.ai/.well-known/jwks.json and select the key with that kid.
Cache the set, and refetch on a kid you do not hold.3
Verify the new header
Verify
X-Asteroid-Webhook-Signature against the raw body with that key. Your existing
verification call stays the same, because the algorithm has not changed.4
Drop the old header
Stop reading
X-Asteroid-Signature and delete the pinned public key from your configuration.Filter what you receive
Most teams want the failures, not the running commentary.Subscription modes
Field filters
Add one or more field filters to an event type. Filters on one event type combine with OR: the notification fires when any of them match. Two filters —outcome equals failure and outcome equals cancelled — mean “tell me when the
outcome is either one”.
Metadata filters
A metadata filter matches the key-value pairs you attached when you started the execution. All pairs must match, so the filter combines with AND.
Leave the metadata filter empty and the notification fires for every execution.
Metadata filtering runs after event-type filtering. An execution must match the event rules first, then the
metadata filter.
A worked example
One workflow, two environments, two webhooks.
A production failure fires the first. A staging failure fires the second. A staging run that
completes fires neither.
Slack
The Slack integration posts the same events into a channel, formatted for people to read.Install it
You need a Slack workspace where you can install apps.1
Add the integration
In the platform, go to Integrations → Add Integration → Slack. Slack asks you to
authorise the app. Review the permissions, pick the workspace, and select Allow.
2
Set the default channel
Find the new Slack integration in the list and open its Edit dialog. Pick a Default
Channel and save. The Asteroid bot joins the channel you pick.
The dropdown lists public channels. To use a private channel, invite the Asteroid bot to it in
Slack first. The channel then appears in the dropdown, after you refresh the page.
3
Attach it to a workflow
Open the workflow, go to the Notifications tab, and select Add Notification. Pick the Slack
integration, set the event rules, and save.
What a Slack message contains
- Status — a colour and an icon for the event type.
- Context — the workflow name, and a link to the execution in the platform.
- Detail — depends on the event:
EXECUTION_COMPLETED— a snippet of the result and the workflow’s reasoning.EXECUTION_FAILED— the error and the reason.EXECUTION_PAUSED— the reason, such as the question the workflow asked.
Test the integration
Select Test integration in the platform. Asteroid sends anEXECUTION_TEST payload.
Build a reliable endpoint
Answer with 2xx quickly
Answer with 2xx quickly
Return
2xx as soon as you have the body. Do the work afterwards, in your own queue. A slow
endpoint turns into a failed delivery.Expect the same event twice
Expect the same event twice
Delivery is at-least-once. Build your handler so a repeat is harmless.Dedupe on your own business identifiers.
event_id is generated per delivery and changes across
retries, so it cannot carry the whole job.Know the retry budget
Know the retry budget
Asteroid makes up to three send attempts, with a short backoff, before it marks a delivery
failed.
Sweep for what you missed
Sweep for what you missed
Run a periodic sweep with
GET /executions alongside your webhook handler. It catches anything
that arrived while your endpoint was down. See Executions and statuses.Log the context
Log the context
Log
info.event, info.execution_id, info.agent_id, and your own outcome. That is enough to
reconstruct any delivery later.Troubleshooting
No events arrive
No events arrive
- Check the endpoint is reachable from the internet and accepts
POST. - Check the notification’s event rules cover the events you expect.
- Check the metadata filter values match the execution’s metadata exactly.
Signature verification fails
Signature verification fails
- Verify against the raw request bytes, not parsed JSON.
- Use RSA PKCS#1 v1.5 with SHA-256.
- Check you picked the key whose
kidmatchesX-Asteroid-Webhook-Key-Id. - Refetch the key set. A delivery naming a
kidyou do not hold means your cache is stale. - If you still verify the deprecated
X-Asteroid-Signature, see Migrate off the legacy header.
The same event arrives twice
The same event arrives twice
- Handle at-least-once delivery in your own logic.
- Dedupe on stable execution fields, not on
event_idalone. - Return
2xxonce you recognise a duplicate.
Slack messages go nowhere
Slack messages go nowhere
- Check the integration has a default channel.
- For a private channel, invite the Asteroid bot in Slack first.
- Check the integration is attached to the workflow on its Notifications tab.
Next
Call a workflow from your code
Attach the metadata your filters match on
Batch executions
Batch events and why webhooks beat polling
Executions and statuses
The statuses behind each event
Debug your workflows
What to do when an event says the execution failed

