API Reference
Complete REST API reference for ProLayer. Everything you need to send internal team alerts and monitoring notifications across six channels with a single, unified API.
https://api.prolayer.iov1Authentication
All API requests require a valid API key passed in the Authorization header.
ProLayer uses API keys to authenticate requests. You can manage your keys in the Dashboard → API Keys. Include your key in every request using the Authorization header.
Authorization: Bearer sk_live_your_api_key_herecurl -X POST https://api.prolayer.io/v1/notifications/send \
-H "Authorization: Bearer sk_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"channel": "slack",
"to": "team_engineering",
"message": "Deploy v2.4.1 completed on production",
"severity": "info"
}'| Key prefix | Environment | Description |
|---|---|---|
sk_live_ | Production | Live key — alerts are delivered to approved team members. |
sk_test_ | Sandbox | Test key — alerts are simulated. No credits consumed. |
Alerts
Send, retrieve, list, and cancel team alerts across all supported channels. All recipients must be approved, opted-in team members.
/v1/notifications/sendRequest Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
channel | string | Required | Delivery channel. One of: whatsapp, telegram, email, push, slack, in-app. |
to | string | Required | Approved team member or team identifier. Team ID (team_xxx), approved contact phone (E.164) for WhatsApp/Telegram, team email for Email, team member ID for Push/In-App, channel name for Slack. |
message | string | Optional | The alert content. Required unless template_id is provided. |
template_id | string | Optional | ID of a predefined template (tpl_xxx). Template variables are populated from metadata. |
severity | string | Optional | Alert severity level. One of: info, warning, critical. Defaults to "info". Critical alerts bypass Do Not Disturb settings for on-call team members. |
metadata | object | Optional | Arbitrary key-value pairs attached to the alert. Used for template variable substitution, incident correlation, and your own tracking. |
schedule_at | string | Optional | ISO 8601 timestamp for scheduled delivery. Must be at least 60 seconds in the future and no more than 30 days ahead. |
priority | string | Optional | Delivery priority. One of: low, normal, high. Defaults to "normal". High-priority messages bypass batching queues. |
idempotency_key | string | Optional | Unique key (max 255 chars) to prevent duplicate sends. Keys are enforced for 24 hours. |
Request Body
{
"channel": "slack",
"to": "team_engineering",
"message": "CPU usage above 90% on prod-server-3",
"severity": "warning",
"template_id": "tpl_cpu_alert",
"metadata": {
"server": "prod-3",
"metric": "cpu",
"value": 92,
"threshold": 90
},
"priority": "high",
"idempotency_key": "cpu_alert_prod3_20260414"
}Response 201 Created
{
"id": "ntf_a1b2c3d4e5f6",
"object": "notification",
"status": "queued",
"channel": "slack",
"to": "team_engineering",
"message": "CPU usage above 90% on prod-server-3",
"severity": "warning",
"template_id": "tpl_cpu_alert",
"metadata": {
"server": "prod-3",
"metric": "cpu",
"value": 92,
"threshold": 90
},
"priority": "high",
"acknowledged": false,
"idempotency_key": "cpu_alert_prod3_20260414",
"credits_used": 1,
"created_at": "2026-04-14T10:30:00Z"
}schedule_at is set, the alert is placed in queued status and can be cancelled before the scheduled time via DELETE /v1/notifications/:id. Non-scheduled notifications are processed immediately./v1/notifications/send-batchRequest Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
notifications | array | Required | Array of notification objects (max 1,000). Each object has the same shape as the /send endpoint body. |
Request Body
{
"notifications": [
{
"channel": "email",
"to": "oncall@company.com",
"template_id": "tpl_incident_report",
"metadata": { "incident_id": "INC-482", "severity": "critical" }
},
{
"channel": "push",
"to": "team_oncall",
"message": "P1 Incident: Payment service degraded. Error rate: 12%.",
"priority": "high",
"severity": "critical"
},
{
"channel": "slack",
"to": "#incidents",
"message": "Deploy v2.4.1 completed successfully on production.",
"metadata": { "service": "api-gateway", "version": "2.4.1" }
},
{
"channel": "telegram",
"to": "team_devops",
"message": "CI/CD Pipeline: Build #4821 passed. Ready for deployment.",
"severity": "info"
},
{
"channel": "in-app",
"to": "team_engineering",
"message": "Scheduled maintenance window starts in 30 minutes.",
"metadata": { "deep_link": "/dashboard/maintenance" }
}
]
}Response 200 OK
{
"object": "batch",
"id": "bat_q1w2e3r4t5",
"total": 5,
"accepted": 5,
"rejected": 0,
"notifications": [
{ "id": "ntf_bat_001", "status": "queued", "channel": "email" },
{ "id": "ntf_bat_002", "status": "queued", "channel": "push" },
{ "id": "ntf_bat_003", "status": "queued", "channel": "slack" },
{ "id": "ntf_bat_004", "status": "queued", "channel": "telegram" },
{ "id": "ntf_bat_005", "status": "queued", "channel": "in-app" }
],
"created_at": "2026-04-14T10:35:00Z"
}422 error. Once accepted, each notification is processed independently and may succeed or fail on its own./v1/notifications/:idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | The notification ID (starts with "ntf_"). |
Response 200 OK
{
"id": "ntf_a1b2c3d4e5f6",
"object": "notification",
"status": "delivered",
"channel": "slack",
"to": "team_engineering",
"message": "CPU usage above 90% on prod-server-3",
"severity": "warning",
"template_id": null,
"metadata": {
"server": "prod-3",
"metric": "cpu",
"value": 92
},
"priority": "high",
"acknowledged": true,
"acknowledged_by": "eng_sarah",
"acknowledged_at": "2026-04-14T10:32:00Z",
"credits_used": 1,
"created_at": "2026-04-14T10:30:00Z",
"sent_at": "2026-04-14T10:30:01Z",
"delivered_at": "2026-04-14T10:30:03Z",
"read_at": null,
"failed_at": null,
"failure_reason": null
}/v1/notificationsQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
channel | string | Optional | Filter by channel: whatsapp, telegram, email, push, slack, in-app. |
status | string | Optional | Filter by delivery status: queued, sent, delivered, read, failed, cancelled. |
from | string | Optional | Start of date range (ISO 8601). Inclusive. |
to | string | Optional | End of date range (ISO 8601). Inclusive. |
cursor | string | Optional | Pagination cursor returned by a previous request. |
limit | integer | Optional | Number of results per page. Min 1, max 100, default 25. |
Example Request
curl "https://api.prolayer.io/v1/notifications?channel=slack&status=delivered&limit=2" \
-H "Authorization: Bearer sk_live_your_api_key_here"Response 200 OK
{
"object": "list",
"data": [
{
"id": "ntf_a1b2c3d4e5f6",
"object": "notification",
"status": "delivered",
"channel": "slack",
"to": "team_engineering",
"message": "CPU usage above 90% on prod-server-3",
"severity": "warning",
"acknowledged": true,
"credits_used": 1,
"created_at": "2026-04-14T10:30:00Z",
"delivered_at": "2026-04-14T10:30:03Z"
},
{
"id": "ntf_g7h8i9j0k1l2",
"object": "notification",
"status": "delivered",
"channel": "telegram",
"to": "team_devops",
"message": "Deploy v2.4.0 completed on staging",
"severity": "info",
"acknowledged": false,
"credits_used": 1,
"created_at": "2026-04-14T10:25:00Z",
"delivered_at": "2026-04-14T10:25:02Z"
}
],
"has_more": true,
"next_cursor": "cur_ntf_g7h8i9j0k1l2"
}/v1/notifications/:idqueued status can be cancelled. Already-sent alerts return a 409 error.Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | The notification ID to cancel (starts with "ntf_"). |
Response 200 OK
{
"id": "ntf_a1b2c3d4e5f6",
"object": "notification",
"status": "cancelled",
"cancelled_at": "2026-04-14T11:00:00Z"
}Alert Templates
Create, manage, and version reusable alert templates with dynamic variable substitution. Ideal for standardized monitoring alerts, incident reports, and deployment notifications.
/v1/templates{{name}}) and are automatically extracted from the body.Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Required | Unique template name. Alphanumeric, underscores, and hyphens only. Max 64 chars. |
channel | string | Required | Target channel: whatsapp, telegram, email, push, slack, in-app. |
body | string | Required | Template content with {{variable}} placeholders. Max 4,096 chars. |
description | string | Optional | Human-readable description for dashboard reference. Max 256 chars. |
metadata | object | Optional | Arbitrary key-value pairs for your own categorization and filtering. |
Request Body
{
"name": "cpu_alert",
"channel": "slack",
"body": "🔴 CPU Alert on {{server}}\nCurrent: {{value}}% | Threshold: {{threshold}}%\nDuration: {{duration}}\nDashboard: {{dashboard_url}}",
"description": "CPU threshold alert for infrastructure monitoring",
"metadata": {
"category": "monitoring",
"team": "infrastructure"
}
}Response 201 Created
{
"id": "tpl_x7y8z9w0",
"object": "template",
"name": "cpu_alert",
"channel": "slack",
"body": "🔴 CPU Alert on {{server}}\nCurrent: {{value}}% | Threshold: {{threshold}}%\nDuration: {{duration}}\nDashboard: {{dashboard_url}}",
"variables": ["server", "value", "threshold", "duration", "dashboard_url"],
"description": "CPU threshold alert for infrastructure monitoring",
"metadata": {
"category": "monitoring",
"team": "infrastructure"
},
"usage_count": 0,
"last_used_at": null,
"created_at": "2026-04-14T08:00:00Z",
"updated_at": "2026-04-14T08:00:00Z"
}/v1/templatesQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
channel | string | Optional | Filter templates by channel. |
cursor | string | Optional | Pagination cursor from a previous response. |
limit | integer | Optional | Results per page. Min 1, max 100, default 25. |
Response 200 OK
{
"object": "list",
"data": [
{
"id": "tpl_x7y8z9w0",
"object": "template",
"name": "cpu_alert",
"channel": "slack",
"description": "CPU threshold alert for infrastructure monitoring",
"variables": ["server", "value", "threshold", "duration", "dashboard_url"],
"usage_count": 1420,
"created_at": "2026-04-14T08:00:00Z"
},
{
"id": "tpl_m3n4o5p6",
"object": "template",
"name": "incident_escalation",
"channel": "email",
"description": "Incident escalation report sent to on-call team",
"variables": ["incident_id", "severity", "summary", "responder"],
"usage_count": 8903,
"created_at": "2026-04-13T15:20:00Z"
},
{
"id": "tpl_a9b8c7d6",
"object": "template",
"name": "deployment_complete",
"channel": "slack",
"description": "Post-deploy alert to engineering team",
"variables": ["service", "version", "environment", "deployer"],
"usage_count": 347,
"created_at": "2026-04-10T11:05:00Z"
}
],
"has_more": false,
"next_cursor": null
}/v1/templates/:idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | The template ID (starts with "tpl_"). |
Response 200 OK
{
"id": "tpl_x7y8z9w0",
"object": "template",
"name": "cpu_alert",
"channel": "slack",
"body": "🔴 CPU Alert on {{server}}\nCurrent: {{value}}% | Threshold: {{threshold}}%\nDuration: {{duration}}\nDashboard: {{dashboard_url}}",
"variables": ["server", "value", "threshold", "duration", "dashboard_url"],
"description": "CPU threshold alert for infrastructure monitoring",
"metadata": {
"category": "monitoring",
"team": "infrastructure"
},
"usage_count": 1420,
"last_used_at": "2026-04-14T09:55:00Z",
"created_at": "2026-04-14T08:00:00Z",
"updated_at": "2026-04-14T08:00:00Z"
}/v1/templates/:idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | The template ID to update. |
Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Optional | New template name. |
body | string | Optional | New template body. Variables are re-extracted automatically. |
description | string | Optional | Updated description. |
metadata | object | Optional | Replaces the entire metadata object (not merged). |
Request Body
{
"body": "🔴 CPU Alert on {{server}}\nCurrent: {{value}}% | Threshold: {{threshold}}%\nDuration: {{duration}}\nRunbook: {{runbook_url}}\nDashboard: {{dashboard_url}}",
"description": "Updated CPU alert with runbook link"
}Response 200 OK
{
"id": "tpl_x7y8z9w0",
"object": "template",
"name": "cpu_alert",
"channel": "slack",
"body": "🔴 CPU Alert on {{server}}\nCurrent: {{value}}% | Threshold: {{threshold}}%\nDuration: {{duration}}\nRunbook: {{runbook_url}}\nDashboard: {{dashboard_url}}",
"variables": ["server", "value", "threshold", "duration", "runbook_url", "dashboard_url"],
"description": "Updated CPU alert with runbook link",
"metadata": {
"category": "monitoring",
"team": "infrastructure"
},
"usage_count": 1420,
"last_used_at": "2026-04-14T09:55:00Z",
"created_at": "2026-04-14T08:00:00Z",
"updated_at": "2026-04-14T12:15:00Z"
}/v1/templates/:idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | The template ID to delete. |
Response 200 OK
{
"id": "tpl_x7y8z9w0",
"object": "template",
"deleted": true
}Account
Retrieve your credit balance and detailed usage analytics.
/v1/balanceResponse 200 OK
{
"object": "balance",
"credits_remaining": 8742,
"credits_used_today": 258,
"credits_used_this_month": 4521,
"plan": "growth",
"credits_included": 10000,
"overage_rate": 0.003,
"overage_credits_used": 0,
"next_reset": "2026-05-01T00:00:00Z",
"last_updated": "2026-04-14T10:30:00Z"
}credits_remaining reaches zero on the Starter plan, subsequent sends will return 402 Payment Required. Growth and Business plans continue sending at the overage_rate per credit./v1/usageQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
from | string | Required | Start of date range (ISO 8601). Example: 2026-04-01T00:00:00Z |
to | string | Required | End of date range (ISO 8601). Example: 2026-04-14T23:59:59Z |
granularity | string | Optional | Time bucket size for the breakdown array. One of: "hour", "day". Defaults to "day". |
channel | string | Optional | Filter stats to a single channel. |
Example Request
curl "https://api.prolayer.io/v1/usage?from=2026-04-01T00:00:00Z&to=2026-04-14T23:59:59Z&granularity=day" \
-H "Authorization: Bearer sk_live_your_api_key_here"Response 200 OK
{
"object": "usage",
"from": "2026-04-01T00:00:00Z",
"to": "2026-04-14T23:59:59Z",
"total_sent": 4521,
"total_delivered": 4389,
"total_failed": 132,
"total_credits_used": 4521,
"delivery_rate": 0.9708,
"by_channel": {
"whatsapp": { "sent": 1823, "delivered": 1790, "failed": 33, "credits": 1823 },
"email": { "sent": 1245, "delivered": 1200, "failed": 45, "credits": 1245 },
"push": { "sent": 876, "delivered": 842, "failed": 34, "credits": 876 },
"telegram": { "sent": 312, "delivered": 305, "failed": 7, "credits": 312 },
"slack": { "sent": 198, "delivered": 192, "failed": 6, "credits": 198 },
"in-app": { "sent": 67, "delivered": 60, "failed": 7, "credits": 67 }
},
"daily": [
{
"date": "2026-04-14",
"sent": 258,
"delivered": 251,
"failed": 7,
"credits": 258
},
{
"date": "2026-04-13",
"sent": 312,
"delivered": 304,
"failed": 8,
"credits": 312
},
{
"date": "2026-04-12",
"sent": 287,
"delivered": 280,
"failed": 7,
"credits": 287
}
]
}daily array is truncated in the example above. The actual response includes one entry per day (or per hour when granularity=hour) for the entire requested range. Maximum queryable range is 90 days.Webhooks
Subscribe to real-time alert delivery and acknowledgment events. Webhook payloads are signed with HMAC-SHA256 for verification. Use webhooks to build automated escalation workflows.
/v1/webhooksPOST requests to your URL for each subscribed event. Failed deliveries are retried with exponential backoff for up to 72 hours.Request Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Required | The HTTPS endpoint URL that will receive webhook events. Must be publicly accessible. |
events | string[] | Required | Array of event types to subscribe to. Use ["*"] for all events. |
secret | string | Optional | Your signing secret for HMAC-SHA256 verification. Auto-generated if omitted. |
description | string | Optional | Human-readable label for this endpoint. |
metadata | object | Optional | Arbitrary key-value pairs for your reference. |
Request Body
{
"url": "https://api.yourapp.com/webhooks/prolayer",
"events": [
"alert.delivered",
"alert.acknowledged",
"alert.failed"
],
"secret": "whsec_k8m2n4p6q8r0s2t4v6w8x0y2z4",
"description": "Production alert webhook endpoint",
"metadata": {
"environment": "production",
"team": "backend"
}
}Response 201 Created
{
"id": "whk_p1q2r3s4t5u6",
"object": "webhook",
"url": "https://api.yourapp.com/webhooks/prolayer",
"events": [
"alert.delivered",
"alert.acknowledged",
"alert.failed"
],
"status": "active",
"description": "Production alert webhook endpoint",
"metadata": {
"environment": "production",
"team": "backend"
},
"signing_secret": "whsec_k8m2n4p6q8r0s2t4v6w8x0y2z4",
"created_at": "2026-04-14T10:00:00Z"
}Webhook Payload Example
{
"id": "evt_v1w2x3y4z5",
"object": "event",
"type": "alert.delivered",
"created_at": "2026-04-14T10:30:03Z",
"data": {
"id": "ntf_a1b2c3d4e5f6",
"object": "notification",
"status": "delivered",
"channel": "slack",
"to": "team_engineering",
"severity": "warning",
"acknowledged": false,
"delivered_at": "2026-04-14T10:30:03Z",
"latency_ms": 2140
}
}HMAC-SHA256(signing_secret, raw_body) and comparing it to the X-ProLayer-Signature header. Always use a constant-time comparison function to prevent timing attacks./v1/webhooksQuery Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | Optional | Filter by status: "active" or "disabled". |
cursor | string | Optional | Pagination cursor. |
limit | integer | Optional | Results per page. Min 1, max 100, default 25. |
Response 200 OK
{
"object": "list",
"data": [
{
"id": "whk_p1q2r3s4t5u6",
"object": "webhook",
"url": "https://api.yourapp.com/webhooks/prolayer",
"events": ["alert.delivered", "alert.acknowledged", "alert.failed"],
"status": "active",
"description": "Production webhook endpoint",
"created_at": "2026-04-14T10:00:00Z"
},
{
"id": "whk_j7k8l9m0n1o2",
"object": "webhook",
"url": "https://staging.yourapp.com/hooks/prolayer",
"events": ["*"],
"status": "active",
"description": "Staging — all events",
"created_at": "2026-03-28T14:20:00Z"
}
],
"has_more": false,
"next_cursor": null
}signing_secret is only returned when creating a webhook. If you need to retrieve it later, rotate the secret from the dashboard./v1/webhooks/:idPath Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Required | The webhook endpoint ID (starts with "whk_"). |
Response 200 OK
{
"id": "whk_p1q2r3s4t5u6",
"object": "webhook",
"deleted": true
}Pagination
All list endpoints use cursor-based pagination for consistent, performant traversal of large datasets.
Unlike offset-based pagination, cursor-based pagination guarantees stable results even when new records are inserted between page requests. Every list response includes:
| Field | Type | Description |
|---|---|---|
data | array | The page of results, ordered by creation time (newest first). |
has_more | boolean | Whether additional pages exist beyond this one. |
next_cursor | string | null | Opaque cursor string to pass as the cursor query parameter on the next request. null when there are no more pages. |
async function fetchAllNotifications(apiKey) {
const results = [];
let cursor = null;
do {
const url = new URL("https://api.prolayer.io/v1/notifications");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const page = await res.json();
results.push(...page.data);
cursor = page.next_cursor;
} while (cursor);
return results;
}Error Codes
All errors follow a consistent JSON structure with a machine-readable code and a human-readable message.
{
"error": {
"type": "invalid_request_error",
"code": "missing_required_field",
"message": "The 'channel' field is required.",
"param": "channel",
"doc_url": "https://prolayer.io/docs/api#send-notification"
}
}| Status | Type | Description |
|---|---|---|
400 | invalid_request_error | The request body is malformed, missing required fields, or contains invalid values. |
401 | authentication_error | No API key provided, or the key is invalid or revoked. |
402 | payment_required | Your credit balance is exhausted and your plan does not allow overage. |
403 | forbidden | The API key does not have permission for this action (e.g., test key used on a production-only endpoint). |
404 | not_found | The requested resource (notification, template, webhook) does not exist. |
409 | conflict | Idempotency key already used for a different request body, or attempting to cancel an already-sent notification. |
422 | validation_error | Request is well-formed but semantically invalid (e.g., invalid phone number format, unknown channel). |
429 | rate_limit_error | Too many requests. Check the Retry-After header for backoff duration in seconds. |
500 | api_error | An unexpected error on our side. These are automatically reported and investigated. |
502 | upstream_error | An upstream delivery provider (WhatsApp Business API, Telegram Bot API, etc.) returned an error. |
503 | service_unavailable | The API is temporarily unavailable due to maintenance or overload. Retry with exponential backoff. |
429 and 503 errors, always respect the Retry-After header. We recommend exponential backoff with jitter: wait min(2^attempt * 1000 + random(0, 1000), 30000) milliseconds between retries, up to 5 attempts.Rate Limits
Rate limits protect the API from abuse and ensure fair usage across all teams.
| Plan | Requests / min | Burst (10s window) | Notifications / day | Batch size |
|---|---|---|---|---|
| Starter | 60 | 15 | 1,000 | 100 |
| Growth | 300 | 75 | 50,000 | 500 |
| Business | 1,000 | 250 | 500,000 | 1,000 |
| Enterprise | Custom | Custom | Unlimited | 1,000 |
Rate limit status is returned in every response via these headers:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed per minute for your plan. |
X-RateLimit-Remaining | Requests remaining in the current window. |
X-RateLimit-Reset | Unix timestamp when the current window resets. |
Retry-After | Seconds to wait before retrying (only present on 429 responses). |
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1745667600
Retry-After: 42
{
"error": {
"type": "rate_limit_error",
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Retry after 42 seconds.",
"doc_url": "https://prolayer.io/docs/api#rate-limits"
}
}Alert Statuses
Every alert progresses through a defined lifecycle. These statuses appear in the status field of alert objects.
| Status | Terminal? | Description |
|---|---|---|
queued | No | Alert accepted and waiting in the processing queue. Scheduled alerts remain in this state until their delivery time. |
sent | No | Handed off to the downstream delivery provider (e.g., Slack API, Telegram Bot API). Awaiting provider confirmation. |
delivered | No | The provider confirmed the alert was delivered to the team member's device, channel, or inbox. |
acknowledged | Yes | A team member acknowledged the alert via an action button, API call, or dashboard. Includes acknowledged_by and acknowledged_at fields. |
read | Yes | The team member opened or viewed the alert. Only available on channels that support read receipts (WhatsApp, In-App, Email with pixel tracking). |
failed | Yes | Delivery failed permanently. Check the "failure_reason" field for details (e.g., unapproved recipient, provider outage, content policy violation). |
cancelled | Yes | The alert was cancelled via DELETE /v1/notifications/:id before it left the queue. |
Status Flow
queued → sent → delivered → acknowledged
↘ read
↘ failed
queued → cancelledread status is best-effort and depends on the channel's support for read receipts. Not all channels or recipients report reads. Do not use read status for critical business logic.Webhook Events
Subscribe to any combination of these events when creating a webhook endpoint.
| Event Type | Category | Description |
|---|---|---|
alert.queued | Alert | An alert was accepted and placed in the processing queue. |
alert.sent | Alert | An alert was handed off to the downstream delivery provider. |
alert.delivered | Alert | An alert was confirmed delivered to the approved team member. |
alert.acknowledged | Alert | An alert was acknowledged by a team member. Includes acknowledged_by in the payload. |
alert.read | Alert | An alert was opened or viewed by the team member. |
alert.failed | Alert | An alert failed to deliver. Includes failure_reason in the payload. |
alert.cancelled | Alert | A scheduled alert was cancelled before delivery. |
template.created | Template | A new template was created. |
template.updated | Template | An existing template was modified. |
template.deleted | Template | A template was permanently deleted. |
balance.low | Account | Credit balance dropped below 10% of your plan's included credits. |
balance.depleted | Account | Credit balance reached zero. Subsequent sends may fail on the Starter plan. |
Example: alert.failed event payload
{
"id": "evt_f1g2h3i4j5",
"object": "event",
"type": "alert.failed",
"created_at": "2026-04-14T10:31:05Z",
"data": {
"id": "ntf_k6l7m8n9o0",
"object": "notification",
"status": "failed",
"channel": "slack",
"to": "team_oncall",
"message": "P1 Incident: Payment service errors above 5%",
"severity": "critical",
"failure_reason": "recipient_not_approved",
"failure_details": "The recipient team_oncall contains members who are not approved contacts. Update your Approved Contacts list.",
"failed_at": "2026-04-14T10:31:05Z",
"created_at": "2026-04-14T10:31:00Z"
}
}Example: balance.low event payload
{
"id": "evt_z9y8x7w6v5",
"object": "event",
"type": "balance.low",
"created_at": "2026-04-14T18:00:00Z",
"data": {
"object": "balance",
"credits_remaining": 847,
"credits_included": 10000,
"percentage_remaining": 8.47,
"plan": "growth",
"next_reset": "2026-05-01T00:00:00Z"
}
}"events": ["*"] when creating a webhook to subscribe to all current and future event types. This is useful for logging and audit trail endpoints.SDKs & Libraries
Official client libraries wrap this REST API with idiomatic interfaces, automatic retries, and type safety.
npm install @prolayer/nodepip install prolayergo get github.com/prolayer/prolayer-gogem install prolayercomposer require prolayer/prolayer-phpimplementation 'io.prolayer:prolayer-java:1.x'Quickstart Snippets
Copy-paste examples to send your first team alert in seconds.
import ProLayer from "@prolayer/node";
const prolayer = new ProLayer("sk_live_your_api_key_here");
const alert = await prolayer.notifications.send({
channel: "slack",
to: "#incidents",
message: "CPU usage above 90% on prod-server-3",
severity: "warning",
metadata: {
server: "prod-3",
metric: "cpu",
value: 92,
},
});
console.log(alert.id); // ntf_a1b2c3d4e5f6
console.log(alert.status); // queuedimport prolayer
client = prolayer.Client("sk_live_your_api_key_here")
alert = client.notifications.send(
channel="email",
to="oncall@company.com",
template_id="tpl_incident_report",
severity="critical",
metadata={
"incident_id": "INC-482",
"severity": "critical",
"summary": "Payment service error rate above 5%",
},
)
print(alert.id) # ntf_a1b2c3d4e5f6
print(alert.status) # queuedcurl -X POST https://api.prolayer.io/v1/notifications/send \
-H "Authorization: Bearer sk_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"channel": "telegram",
"to": "team_devops",
"message": "Deploy v2.4.1 completed. All health checks passing.",
"severity": "info",
"metadata": {
"service": "api-gateway",
"version": "2.4.1",
"environment": "production"
}
}'Idempotency
Safely retry requests without creating duplicate alerts.
Pass an idempotency_key in the request body of any POST endpoint. If a request with the same key was already processed successfully, the API returns the original response with a 200 status instead of creating a duplicate.
| Scenario | Status | Behavior |
|---|---|---|
| First request | 201 | Alert created normally. |
| Retry with same key & body | 200 | Returns the original alert. No duplicate created. |
| Same key, different body | 409 | Conflict — the key is already associated with a different request body. |
curl -X POST https://api.prolayer.io/v1/notifications/send \
-H "Authorization: Bearer sk_live_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"channel": "slack",
"to": "team_engineering",
"message": "Deploy v2.4.1 completed on production",
"severity": "info",
"idempotency_key": "deploy_v241_prod_20260414"
}'cpu_alert_prod3_20260414).Versioning & Stability
How we evolve the API without breaking your integration.
| Version | Status | Notes |
|---|---|---|
v1 | Stable | Current version. All endpoints documented on this page. Breaking changes will only be introduced in a new major version. |
We follow these stability guarantees for v1:
- Existing fields will not be removed or have their type changed.
- New optional fields may be added to response objects at any time.
- New optional query/body parameters may be added to requests.
- New event types may be added to webhooks (use
*to future-proof). - Deprecations are announced at least 6 months before removal via the
Sunsetheader and the changelog.
Support & SLAs
Get help when you need it.
| Channel | Response Time | Availability |
|---|---|---|
| Documentation | Self-serve | 24/7 |
| Community (Discord) | < 4 hours | Business hours |
| Email Support | < 24 hours | All plans |
| Priority Support | < 2 hours | Growth & above |
| Dedicated Slack Channel | < 30 minutes | Enterprise only |
Start building with ProLayer
Create your free account to get API keys and send your first team alert in under 5 minutes.