Skip to main content

Webhooks

Webhooks let Shipbook send your alerts to your own API. When a custom alert or an automatic (Loglytics) alert fires, Shipbook POSTs a signed JSON payload to every webhook endpoint you have configured — so you can route alerts into your own systems alongside Slack and email.

Webhooks for AI agents

A webhook is what lets an AI agent react to production on its own. It's the push half of an autonomous-debugging loop: when an alert fires, Shipbook delivers the event to your endpoint, which wakes the agent — without it, an agent only ever learns about a problem when a human thinks to ask.

The pull half is MCP. Once woken by a webhook, the agent passes the payload's id to the get-alert MCP tool to load the full fired alert, then uses get-logs and get-loglytics-errors to trace the failure to the exact file and line and suggest or apply a fix. The X-Shipbook-Event header and the app.id in the payload give the agent everything else it needs to scope that investigation to the right app and alert.

Together, webhooks and MCP turn Shipbook into both an event source and a queryable knowledge source for agents — letting them go from "alert fired" to "root cause found" to "fix proposed" without a human in the loop. See MCP Integration to connect your assistant.

Add a webhook

In Account Preferences → Webhooks, enter the endpoint and select add:

  • URL (required) — the HTTPS endpoint Shipbook will POST to. Only https:// URLs are accepted.
  • Headers (optional) — static HTTP headers sent with every request, added as name/value pairs (e.g. AuthorizationBearer your-token). Use + add header to add more than one.
  • Apps (optional) — the apps this webhook should receive alerts for. Leave it empty to receive alerts for all apps in the account.

When you create the webhook, Shipbook generates a signing secret and shows it once — it is never displayed again. Every request is signed with it so your endpoint can verify it came from Shipbook. Verifying the signature is optional but recommended — if you plan to verify, copy the secret now (see Verifying the signature); if not, you can ignore it.

Each saved webhook can be:

  • Edited — select the edit (pencil) icon to change its URL, headers, or app scope, or to Regenerate the signing secret. A regenerated secret is shown once and the previous one stops working immediately, so update your endpoint with it.
  • Enabled / disabled — toggle delivery without deleting the configuration.
  • Tested — select the test icon, then choose Custom or Automatic to send a real-shaped sample event of that type to the endpoint and confirm your wiring before relying on it. Test deliveries carry a "test": true flag (see Test events).

Payload

Shipbook sends a POST with Content-Type: application/json. The body has a stable, versioned shape that is the same for both alert types, so a single endpoint can handle all of them.

A custom alert:

{
"version": "1",
"id": "663f1c2a9b1e4a0012ab34cd",
"type": "custom",
"triggeredAt": "2026-06-16T12:00:00.000Z",
"app": { "id": "660a...", "name": "Checkout iOS", "platform": "ios" },
"alert": {
"name": "Checkout errors spike",
"condition": "> 50 logs in 10 minutes",
"count": 73
},
"consoleUrl": "https://console.shipbook.io/<account>/<app>/alerts?alertId=663f1c2a9b1e4a0012ab34cd"
}

An automatic (Loglytics) alert uses the same envelope and adds an issue block:

{
"version": "1",
"id": "663f1d8e9b1e4a0012ab35ef",
"type": "automatic",
"triggeredAt": "2026-06-16T13:00:00.000Z",
"app": { "id": "660a...", "name": "Checkout Android", "platform": "android" },
"issue": {
"severity": "Error",
"message": "NullPointerException in CheckoutViewModel",
"file": "CheckoutViewModel.kt",
"line": 142,
"function": "submit",
"class": "CheckoutViewModel",
"percentSessions": 8.3,
"appVersion": "1.2.3 - 1.2.5"
},
"consoleUrl": "https://console.shipbook.io/<account>/<app>/alerts?alertId=663f1d8e9b1e4a0012ab35ef"
}

Test events

When you select the test icon in the Console and choose Custom or Automatic, Shipbook delivers the same payload shown above for that alert type, with one addition: a top-level "test": true flag. The app block is a real app from your account (the webhook's first scoped app, or your first app if it's scoped to all apps), so app.id is a value you can actually look up.

Use the test to validate your endpoint and parser, and skip any side effects (ticket creation, paging, etc.) when test is true. Real alerts never include the test field.

Headers

HeaderValue
Content-Typeapplication/json
X-Shipbook-Eventalert.custom or alert.automatic
X-Shipbook-Signaturesha256=<hmac> — HMAC-SHA256 of the raw body, signed with the webhook's secret

Any static headers you configured are also included.

Verifying the signature

Verifying the signature is optional but recommended — it lets your endpoint confirm a request genuinely came from Shipbook and wasn't tampered with. If you don't need that assurance, you can skip this and ignore the secret.

Every request includes X-Shipbook-Signature: sha256=<hmac>, where the HMAC is HMAC-SHA256 of the raw request body keyed by your signing secret. Compute the same HMAC and compare:

import crypto from 'crypto';

function isFromShipbook(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(signatureHeader || '');
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Verify against the raw body before parsing it as JSON, and treat the body's app.id as the authoritative source of which app triggered the alert.

Responding and retries

Respond with any 2xx status to acknowledge receipt. Shipbook retries on 5xx and network errors with a short backoff; a 4xx is treated as a configuration error and is not retried. Each delivery is independent — a failure to one webhook never affects email, Slack, or your other webhooks.