acked. Docs Open Acked
DocsDevelopers

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

CredentialUse
Service-scoped ingest URLOne 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 keyCustomer /api/* routes. Send X-Acked-Org: org_….
OAuth MCP grantInteractive 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.