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

EventWhenCan be turned off
driftA settled Step’s model stopped passing; its backup now serves while it’s re-searched.yes
resettledA re-search finished and the Step has a new winner.with drift
failoverA model failed and a backup served the call.yes
spend_alertSpend this month crossed your alert threshold.no
spend_capSpend reached your monthly cap; calls are paused (402).no
billing_failedAn auto top-up or a subscription renewal couldn’t be charged.no
digestA monthly summary per Workflow.yes

Every event is also listed on the Workflow’s Production tab.

Email

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.