Webhook API
Reference for Atisbo's inbound webhook endpoints
Webhook API
Atisbo exposes separate inbound endpoints for signal events, email ingestion, GitHub events, and metric updates. Custom data is split by purpose: signal webhooks create Triage signals, while metric webhooks update map metrics.
Endpoints
Signal Webhook
POST /api/webhooks/custom/{id}
Generic signal webhook for JSON payloads that should become product signals. Your unique id is found in Settings → Sources → Signal Webhook.
Each workspace has one generic signal webhook integration. Multiple systems can send to it; use payload fields like source, source_url, event, and signal_origin to distinguish senders and business meaning.
curl -X POST https://app.atisbo.dev/api/webhooks/custom/<your-id> \
-H "Content-Type: application/json" \
-H "X-Atisbo-Signature: sha256=<hmac>" \
-d '{
"text": "Users report the payment modal freezes on slow connections",
"source": "intercom",
"occurred_at": "2026-05-27T18:30:00Z",
"signal_origin": "customer",
"actor_role": "user"
}'
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | Signal content (max 50,000 chars) |
source | string | No | Source label |
source_url | string | No | Link to original item |
occurred_at | string | number | No | When the event happened in the source system. ISO 8601 recommended; epoch seconds or milliseconds accepted. |
actor_name | string | No | Name of creator |
actor_email | string | No | Email of creator (PII-scrubbed before storage) |
signal_origin | "customer" | "internal" | "operational" | No | Default: "customer" |
actor_role | "user" | "pm" | "designer" | "engineer" | "system" | No | Default: "user" |
metadata | object | No | Arbitrary key-value pairs |
Response:
{ "ok": true, "snippet_id": "uuid" }
Metric Webhook
POST /api/webhooks/metric/{id}
Named endpoint for numeric metric updates. Create as many metric webhooks as you need in Settings → Sources → Metric Webhooks; for example, one for Stripe revenue and another for warehouse activation counts.
curl -X POST https://app.atisbo.dev/api/webhooks/metric/<webhook-id> \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <webhook-secret>" \
-d '{ "value": 1234, "occurred_at": "2026-05-27T18:30:00Z" }'
Metric webhooks update metric bindings on maps. They do not create Triage signals. If you send occurred_at, timestamp, date, or time, Atisbo uses it for the historical metric point; otherwise it uses the receive date.
Email Ingestion
POST /api/webhooks/email-ingest
Receives emails forwarded to your Atisbo ingestion address. This endpoint is called automatically by Atisbo's email infrastructure — you don't call it directly.
GitHub Webhook
POST /api/webhooks/github/{id}
Receives GitHub events (push, pull_request, release, deployment). Your unique id is in Settings → Sources → GitHub.
GitHub requires HMAC signature verification (X-Hub-Signature-256 header). Atisbo handles this automatically when you copy the secret from the setup dialog.
Authentication
Signal webhook endpoints use secret URL authentication plus the shared secret shown in setup. Treat the URL and secret like API keys:
- Don't commit it to public repos
- Regenerate the endpoint if compromised
Metric webhooks use Authorization: Bearer <webhook-secret>. The secret is shown once when the named metric webhook is created.
GitHub uses HMAC-SHA256 signature verification via X-Hub-Signature-256.
Sources connected through your agent arrive on a separate receiver that verifies a Standard Webhooks signature and resolves the tenant from the connection itself — there is nothing for you to configure. See Connect with your agent.
Rate Limits
| Endpoint | Limit | Window |
|---|---|---|
| Signal webhook | 100 requests | per minute per endpoint |
| Metric webhook | 60 requests | per minute per endpoint |
| Email ingest | 50 emails | per hour per tenant |
| GitHub webhook | 500 events | per minute |
Exceeding limits returns 429 Too Many Requests. The pipeline retries automatically within Atisbo's infrastructure — external callers should implement exponential backoff.
Processing Pipeline
Signal-producing inbound webhooks go through the same 9-step pipeline:
1. Validate → schema check, size limit
2. Normalize → source format → canonical PipelineInput
3. PII scrub → redact emails, phones, national IDs, cards, IPs (not names)
4. Cache check → 0.95 cosine similarity → skip if near-duplicate
5. Classify → problem / idea / question / unclassified
6. Embed → Jina v3 vector (1024 dimensions)
7. Dedup → 0.90 cosine cross-channel dedup
8. Insert → create Snippet in database
9. Cluster → group with related evidence, confirmed by a model before merging
Failed steps are logged to the Dead Letter Queue and retried automatically.
Step 9 is not similarity alone. Evidence close enough to be a candidate is passed to a language model, which confirms it is the same root problem before anything merges — two pieces of feedback from one product area share vocabulary without sharing a cause, and distance cannot tell those apart.