Ingest Webhook
The per-source ingest URL your monitoring tools post alerts to: authentication, limits and status codes.
POST /api/im/ingest/:token
Every webhook alert source has its own ingest URL. Your monitoring tool posts its alert JSON there, and the source's mapping turns it into an alert in Incident Management. The setup guides show the configuration for Zabbix, Datadog, Grafana, Prometheus Alertmanager, Sentry and custom webhooks.
To send alerts from your own code with an organization-wide API token instead, use Events Ingest.
Authentication
The token in the URL is the credential: treat the full URL like a password. It is returned once when the source is created and when it is rotated; after a rotation the previous token keeps working until secondaryExpiresAt.
A source can additionally require one or both of:
- Bearer token:
Authorization: Bearer <source bearer token>. - HMAC signature:
X-Uptimeify-Timestamp(Unix seconds) andX-Uptimeify-Signature= hex HMAC-SHA256 of<timestamp>.<raw body>with the source's HMAC secret, optionally prefixedsha256=. The timestamp must be within 5 minutes of the server time.
Every authentication failure, including an unknown token, answers the same 404, so a wrong token cannot be told from a wrong signature.
Request
- Body: JSON, at most 256 KB, nested at most 20 levels deep. An empty body counts as
{}. - Content type is not checked; the body is parsed as JSON.
- Which fields matter is decided by the source's mapping (preset or custom). The body below fits a custom webhook source mapped to these field names.
Example (cURL)
curl -X POST "https://uptimeify.io/api/im/ingest/$INGEST_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"Disk almost full on db-1","severity":"high","status":"firing","dedup_key":"db-1-disk"}'With HMAC:
TS=$(date +%s)
BODY='{"title":"Disk almost full on db-1","status":"firing"}'
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$HMAC_SECRET" -hex | sed 's/^.* //')
curl -X POST "https://uptimeify.io/api/im/ingest/$INGEST_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Uptimeify-Timestamp: $TS" \
-H "X-Uptimeify-Signature: sha256=$SIG" \
-d "$BODY"Response
202 Accepted:
{ "accepted": true }The payload is accepted for processing; mapping, deduplication and paging happen asynchronously. Use the source's stats and recent payloads to see what was made of it.
Limits
- 300 requests per minute per source
- 50 MB of request bodies per hour per organization
Status codes
| Status | Body | Meaning |
|---|---|---|
202 | {"accepted":true} | Accepted. |
404 | {"error":"not_found"} | Unknown or rotated-out token, failed Bearer or HMAC check, or the organization was deleted. |
413 | {"error":"payload_too_large"} | Body larger than 256 KB. |
422 | {"error":"invalid_json"} | Body is not valid JSON. |
422 | {"error":"payload_too_deep"} | JSON nested deeper than 20 levels. |
429 | data.code imIngestRateLimited | More than 300 requests per minute for this source. |
429 | data.code imIngestByteBudgetExceeded | Hourly byte budget of the organization used up. |
503 | {"error":"unavailable"} | Temporarily unable to accept; retry with backoff. Your tool's own retry is the right answer. |