GET endpoints for task status, register a webhook endpoint and MuleRouter will POST a signed callback to your URL the moment a task transitions.
Every delivery is signed with HMAC-SHA256 so you can verify it came from MuleRouter and the payload has not been tampered with.
Event types
Events follow the{resource}.{action} convention:
You choose which events each endpoint subscribes to. The intermediate task
processing state does not emit an event. balance.low follows a one-shot edge-trigger semantics — see Billing events for details.
Register an endpoint
Webhook endpoints are managed from the MuleRouter Console. Open theWebhooks tab, click Create endpoint, and provide:
- URL — an HTTPS URL that can accept
POSTrequests (max 2048 characters). - Events — one or more of the event types above.
- Description — optional, up to 200 characters.
whsec_...) exactly once. Save it to a secret store immediately — it is never displayed again.
Each user can register up to 5 webhook endpoints. If you need to deliver to more destinations, use a single endpoint that fans out on your side.
Delivery payload
Every delivery is aPOST with Content-Type: application/json. All events share the same envelope:
data shape depends on the event family:
Task events
Task events use the flatdata shape. The inner data.payload is the same JSON you would receive from the synchronous GET /vendors/.../generation/{task_id} endpoint at that point in the task lifecycle. That means your delivery handler can share result-parsing code with your polling handler, if you have one.
task.created
Fired when the task is accepted. payload only contains task_info.
task.succeeded
Fired when the task completes successfully. payload contains the full task response, including whatever fields the endpoint would normally return (e.g. images, videos, audios).
task.failed
Fired when the task fails. Error details live on payload.task_info.error, using the same shape as the MuleRouter error object.
Billing events
Billing events use the nesteddata shape with data.user_id for routing and data.payload for business fields. They cover wallet-state changes that don’t belong to any specific task.
balance.low
Fired when your wallet’s available balance crosses below the system threshold (default $10) following a charge. This is an edge-trigger event — it fires once when the balance drops past the threshold and stays silent until your balance recovers above the threshold and drops below it again.
Trigger semantics
- Low balance detected: when your
available_balancedrops belowtrigger_threshold, you’ll receive abalance.lowdelivery shortly after. - Sustained low: while you remain below threshold without a top-up, deliveries are throttled — you won’t be spammed with repeated notifications.
- Top-up then drop again: if you top up above the threshold and later drop below again, you’ll receive a fresh delivery without waiting out the throttle window.
- Healthy recovery: once your balance stays above the threshold, no further deliveries fire until it drops again.
When balance.low does not fire
- You don’t have an active webhook endpoint subscribed to
balance.low. - Your
available_balanceis at or above thetrigger_threshold. - A recent delivery for the same wallet was already sent and your balance hasn’t recovered above the threshold in between.
- The triggering activity is only a hold (frozen reservation) for an asynchronous task —
balance.lowfires when funds are actually settled, not when they’re held. This avoids false positives if the task later fails and the hold is released.
Recommended client behavior
- Use this event as a hint to surface a low-balance banner in your UI, send your user a “top up” reminder, or pause non-critical workloads — not as the sole source of truth for your wallet balance.
- Always verify the current balance via your wallet’s source of truth before acting on financial decisions, since
available_balancein the payload is a snapshot at trigger time.
Request headers
Each delivery includes the following HTTP headers:Verify the signature
The signed content is three parts joined with.:
Security
Delivery and retries
If the target URL does not return a
2xx within the timeout, MuleRouter retries with exponential backoff:
After 5 retries (6 total attempts), the delivery is marked
failed and no further attempts are made for that event.
Every attempt of the same delivery reuses the same
X-MuleRouter-Webhook-Id. The timestamp and signature are recomputed each time, so your receiver must always recompute the signature from the headers it actually received — do not cache.Idempotency
Two IDs cooperate to make retries safe:evt_...(event ID) — lives on the payload’s top-levelidfield, identifies “something happened in MuleRouter”.whd_...(delivery ID) — lives on theX-MuleRouter-Webhook-Idheader, identifies “an attempt to deliver that event to this endpoint”. It is unique per(event, endpoint)and is reused across retries of the same delivery.
whd_... as your deduplication key: store it when you first successfully process a delivery, and short-circuit if you see it again. This is the standard way to handle retries without double-processing.
Rate limits and quotas
Next steps
- Open the Webhooks tab in the Console to register your first endpoint.
- Use the Send test event button on any endpoint to trigger a synthetic
task.succeededdelivery (idprefixed withevt_test_) and verify your signature-verification logic end-to-end before sending real traffic.

