Alerts and webhooks
Managed Production tells you when something happens to a Workflow — by email, by
webhook, or both. Configure both under Settings → alerts in the dashboard, or PUT /v1/settings/alerts.
What you’re told about
| Event | When | Can be turned off |
|---|---|---|
drift | A settled Step’s model stopped passing; its backup now serves while it’s re-searched. | yes |
resettled | A re-search finished and the Step has a new winner. | with drift |
failover | A model failed and a backup served the call. | yes |
spend_alert | Spend this month crossed your alert threshold. | no |
spend_cap | Spend reached your monthly cap; calls are paused (402). | no |
billing_failed | An auto top-up or a subscription renewal couldn’t be charged. | no |
| digest | A monthly summary per Workflow. | yes |
Every event is also listed on the Workflow’s Production tab.
On by default, to your account’s address. Add up to ten more recipients — an on-call alias, a shared inbox. Each email links to the Workflow’s Production tab and to the alert settings.
Webhooks
Set a URL and Shimmy POSTs each event as JSON:
{
"type": "failover",
"workflow_id": "099730af-…",
"step_fingerprint": "da4f6f8aa1bc7385",
"detail": { "from": "gpt-4.1", "to": "gpt-5.5", "reason": "unavailable" },
"at": "2026-10-02T20:25:05Z"
} Two headers come with it: x-shimmy-event (the type) and x-shimmy-signature — sha256= and the hex HMAC-SHA256 of the raw body, keyed by your webhook secret.
Verify it before trusting the body:
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(rawBody: Buffer, header: string, secret: string): boolean {
const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
return header.length === expected.length &&
timingSafeEqual(Buffer.from(header), Buffer.from(expected));
} The secret is generated when you first set a webhook; show or rotate it in the alert settings. A failed delivery is retried once.
Spend caps
Set a monthly cap and the percentage at which to warn. At the cap, Shimmy stops
serving the account’s calls with 402 spend_cap_reached until the month turns or
you raise it — a guard against a runaway loop, not a budget you expect to hit.