Skip to main content
EigenPal sends webhook events as HTTPS POST requests with a JSON body. This page defines the receiver contract, event schemas, signature verification, and delivery behavior. For dashboard setup and testing, see Receive run events with webhooks.

Request contract

Your receiver must:
  1. Accept HTTPS POST requests.
  2. Read and retain the exact request body bytes.
  3. Verify the timestamp and HMAC signature before parsing or processing the event.
  4. Deduplicate events by their stable id.
  5. Durably accept the event and return a 2xx response quickly.
  6. Process expensive work asynchronously.
Requests use Content-Type: application/json and include these headers:
string
required
The stable event ID. It matches the id field in the body and is included in the signed message.
string
required
The Unix timestamp, in seconds, when the delivery attempt was signed.
string
required
The HMAC-SHA256 signature, formatted as v1,<hex digest>.
string
required
Identifies the EigenPal webhook sender and release.
Any custom headers configured for the endpoint are included as well.

Event envelope

Every request has a versioned JSON envelope:

Envelope fields

string
required
Stable event ID with a whev_ prefix. Use this value as the idempotency key.
run.created | run.status_changed
required
Identifies the event schema.
string
required
Version of the webhook wire contract. The current version is 2026-07-01.
string
required
ISO 8601 timestamp for when the event was created.
boolean
required
true for events created with Send test; otherwise false.
When test is true, data.run contains synthetic sample data. Its run and automation IDs do not identify persisted resources. Verify and acknowledge the request normally, but do not fetch or process the sample as a real run.
object
required
Event-specific payload.

Run fields

string
required
Run ID.
string
required
Automation that owns the run.
workflow | agent
required
Runtime used by the automation.
string
required
Current persisted run status.
string
required
How the run was started, such as api, manual, email, or cron.
string
required
ISO 8601 timestamp for when the run was created.
string | null
required
ISO 8601 timestamp for when execution started, or null.
string | null
required
ISO 8601 timestamp for when the run reached a terminal status, or null.
unknown
Public run output, when available and small enough to include.
boolean
true when output was removed to keep the complete event within the payload limit. Retrieve the canonical result with GET /api/v1/runs/{id}.

Event types

run.created

Sent when a top-level workflow or agent run is durably created. data.run contains the initial run snapshot. Most workflow runs are already pending when this event is sent; agent runs can initially be created while preparation completes. This event does not include previousStatus or currentStatus. Test deliveries use the same schema with synthetic run data.

run.status_changed

Sent whenever a top-level run moves from one persisted status to another. Test deliveries simulate this transition with synthetic run data.
string
required
Status the run moved from.
string
required
Status the run moved to. This matches data.run.status.
Runs created internally by an action.invoke-workflow step and evaluation runs do not emit webhook events.

Run statuses

  • created — The run exists and is being prepared before it enters the queue.
  • pending — The run is queued and eligible for a worker.
  • running — A worker is actively executing the run.
  • waiting — The workflow is paused for a human, tool, or step continuation. Not all run types use this status.
  • finalizing — Primary execution has finished, but outputs or other post-run work are still being saved.
  • completed — The run finished successfully. Terminal.
  • failed — The run ended because of an error or timeout. Terminal.
  • cancelled — The run was cancelled before completion. Terminal.
  • rejected — The run was refused before it started, for example because of an inbound email policy. Terminal.
queued is an execution phase, not a run status. The externally visible status for a run waiting in the queue is pending.

Verify webhook signatures

Do not process an event until its signature and timestamp have been verified. EigenPal signs this message with the endpoint’s whsec_... secret:
The signature is an HMAC and is verified, not decrypted. The following Node.js example accepts a five-minute timestamp tolerance and compares the digests in constant time:
Use the raw bytes supplied by your framework. Parsing JSON and serializing it again can change whitespace or key ordering and invalidate the signature. Parse the body only after verification succeeds. Reject missing, malformed, or stale signature headers. Store the signing secret outside source control. If the secret is lost or exposed, disable or delete the endpoint and create a replacement.

Delivery and retries

Delivery is asynchronous and at least once. Duplicate events are expected, and events are not guaranteed to arrive in order.
  • Deduplicate by the event id.
  • Use previousStatus, currentStatus, and createdAt instead of inferring lifecycle order from delivery order.
  • Return 2xx as soon as the event is durably accepted.
  • Process expensive work after acknowledging the request.
Any 2xx response marks a delivery successful. EigenPal retries network failures, timeouts, 408, 425, 429, and 5xx responses with bounded backoff. Other 4xx responses end automatic delivery. A valid Retry-After response header can delay the next retry within EigenPal’s configured limit. Manual redelivery preserves the event ID and payload, so normal deduplication still applies.