HTTP API
Send alerts and automate Acked configuration with narrow, explicit credentials.
Download the OpenAPI 3.1 document. It covers alert ingest and every customer /api/* operation.
Choose a credential
| Credential | Use |
|---|---|
| Service-scoped ingest URL | One emitter and one service. The URL is the credential. Send no authorization header or service_id. |
| Alert-ingest API key | /v1/alerts when one emitter selects among services. |
| Full-product API key | Customer /api/* routes. Send X-Acked-Org: org_…. |
| OAuth MCP grant | Interactive agent setup using the signed-in person's current role. |
Store every credential as a secret. Never log an ingest URL, authorization header, webhook secret, or protected custom header.
Trigger and recover from a Cloudflare Worker
Store the complete service-scoped URL in the Worker secret ACKED_INGEST_URL. A recovery uses the same event_key as its trigger.
interface Env { ACKED_INGEST_URL: string }
async function send(env: Env, action: "trigger" | "resolve") {
const eventKey = "checkout-health";
const response = await fetch(env.ACKED_INGEST_URL, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
title: "Checkout health check failed",
event_key: eventKey,
priority: "critical",
action,
}),
});
if (response.status !== 202) throw new Error(`Acked returned ${response.status}`);
const receiptId = response.headers.get("x-acked-receipt-id");
console.log(JSON.stringify({ event: "acked_ingest", receipt_id: receiptId, event_key: eventKey }));
}
Manage services from a Cloudflare Worker
A full-product key uses the same customer routes as the dashboard. Keep the key and organization id in Worker secrets or variables.
interface Env {
ACKED_API_KEY: string;
ACKED_ORG_ID: string;
ACKED_SCHEDULE_ID: string;
}
async function createService(env: Env) {
const response = await fetch("https://api.acked.dev/api/services", {
method: "POST",
headers: {
authorization: `Bearer ${env.ACKED_API_KEY}`,
"x-acked-org": env.ACKED_ORG_ID,
"content-type": "application/json",
},
body: JSON.stringify({
name: "Checkout",
schedule_id: env.ACKED_SCHEDULE_ID,
dedupe_mode: "event_key_only",
}),
});
if (!response.ok) throw new Error(`Acked returned ${response.status}`);
return response.json(); // includes default_integration.ingest_url
}
Record ingest receipts
Every successful native ingest response returns the stable accepted-envelope id as receipt_id and X-Acked-Receipt-Id. It stays the same through buffering and retries. alert_id names the resulting alert when one is immediately known and can differ after deduplication.
PagerDuty Events API v2 responses retain their standard body. Read X-Acked-Receipt-Id for the Acked receipt.
Keep the receipt with the source system's event_key. Log every non-202 response. Sample successful receipts when full success logging would be noisy.
Define webhook templates
{
"version": 1,
"body": {
"text": "[{{ event | upper }}] {{ priority | upper }}: {{ title | escape_mrkdwn }}",
"url": "{{ alert_url }}"
}
}
body can be any JSON value. The render context contains event, ts, alert_id, alert_url, title, body, priority, urgency, status, service_name, acked_by_email, and resolved_by_email. Version 1 can gain fields without changing existing ones.
Filters: default(x), lower, upper, truncate(n), join(sep), map({...}), to_string, json, escape_mrkdwn, and escape_html. Templates have no loops, arithmetic, network access, or secret access.
Preview with POST /api/webhooks/preview. Slack, Discord, and Teams have provider-ready defaults. Custom webhooks require a versioned template. Acked-native webhooks accept no template.