API · webhooks
Mama events, pushed to your endpoint in real time.
Subscribe an HTTPS endpoint to events from your Mama workspace. JSON payload, HMAC-signed with a per-subscription secret, retried on 5xx. Same pattern as the status webhooks, scoped to your account.
Available events
brief.created
A new account brief has been generated.
brief.updated
An existing brief was regenerated (signal change, ICP rule change).
brief.shared
A teammate or guest opened the brief URL.
signal.fired
A strong signal landed on a tracked account.
signal.decayed
A previously-active signal dropped below the strength threshold.
opener.generated
Mama drafted a new opener for a brief.
reply.classified
An inbound reply was classified by the reply-loop (positive / not-now / wrong-person / never).
account.scored
An account's ICP score changed by ≥10 points in a single run.
export.completed
A bulk export (CSV / Snowflake push / etc.) finished.
Subscribe
curl -X POST https://api.signalmama.com/v1/webhooks \
-H "Authorization: Bearer $MAMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.your-domain.com/mama",
"events": ["signal.fired", "opener.generated", "reply.classified"]
}'
Response includes a signing_secret. Store it — every delivery is HMAC-signed with it.
Sample payload — signal.fired
{
"event": "signal.fired",
"event_id": "evt_01J5XKQ9Y8M0N3R7W2P4VBHTZ8",
"delivered_at": "2026-05-25T14:12:38Z",
"workspace_id": "ws_outbound_na",
"signal": {
"id": "sig_2026_05_25_acme_funding_series_b",
"type": "funding",
"subtype": "series-b",
"strength": 5,
"recency_days": 2,
"source_url": "https://techcrunch.com/...",
"fired_at": "2026-05-25T14:12:00Z"
},
"account": {
"id": "acc_acme_co",
"domain": "acme.co",
"name": "Acme Co",
"icp_score_before": 64,
"icp_score_after": 81
},
"brief_url": "https://app.signalmama.com/brief/acme.co"
}
Verify the signature
// X-Mama-Signature: sha256=<hex>
const sig = req.headers['x-mama-signature'].slice(7);
const expected = crypto.createHmac('sha256', SIGNING_SECRET)
.update(req.rawBody)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(401).end();
}
Retry behavior + limits
2xx within 10s = delivered. 5xx (or timeout) retries at 1m, 5m, 25m, 2h, 12h. 4xx is treated as permanent rejection. Max 50 subscriptions per workspace; max 1,000 events per minute per subscription before throttling kicks in.