Developers/Webhooks

Alert webhooks

Aepto POSTs signed JSON to your HTTPS URL when subscribed events fire. Manage webhooks in the app or via the Platform API. End-user UI steps: Docs - Alert webhooks.

Auth and scopes

Manage via API

Base path: https://app.aepto.com/api/v1. Full table: Endpoints — Alert webhooks.

MethodPathNotes
POST/alert-webhooksBody: name, url (HTTPS). Response includes signing_secret once.
GET / PATCH / DELETE/alert-webhooks/{id}PATCH may set name, url, is_enabled.
POST/alert-webhooks/{id}/rotate-secretReturns a new signing_secret once. Store it; it is not shown again.
POST/alert-webhooks/{id}/subscriptionsSubscribe to event families (see below).
GET/alert-webhooks/{id}/subscriptionsList subscriptions.
PATCH / DELETE/alert-webhooks/subscriptions/{id}Update or remove a subscription.
curl -sS -X POST "https://app.aepto.com/api/v1/alert-webhooks" \
  -H "Authorization: Bearer aep_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"My receiver","url":"https://example.com/hooks/aepto"}'

Subscriptions

POST /alert-webhooks/{id}/subscriptions JSON fields:

feature_type values include: website_monitoring, content_monitoring, renewal_reminders, domain_notifications, theft_guard, dns_monitoring, email_deliverability_alerts, incident_reminders, pagespeed_alerts, domain_watch, domain_expense_reports, api_rate_limits.

Some features are account-wide only (global): Domain Watch, expense reports, incident reminders, and API Rate Limits. Per-monitor scope applies to website and content monitoring.

Outbound delivery

Aepto sends POST to your URL with JSON body and these headers:

Envelope (schema_version: 1):

{
  "schema_version": 1,
  "event_id": "...",
  "event_type": "monitoring.downtime",
  "occurred_at": "2026-01-15T12:00:00Z",
  "user": { "id": 123, "public_ref": "user:123" },
  "resource": { "type": "monitoring" },
  "data": { }
}

Monitoring events use resource.type monitoring and types such as monitoring.downtime, monitoring.recovery, monitoring.ssl_expiry, monitoring.slow_response (plus sample monitoring.test). Other families use resource.type notification and event_type shaped like {feature_type}.{template_key} (for example dns_monitoring.dns_change_alert, theft_guard.general_security_alert).

Respond with 2xx quickly. Failed deliveries are retried with backoff; repeated failures can pause the endpoint until you fix and re-enable it.

Verify signatures

  1. Read the raw request body (bytes), not a re-serialized JSON object.
  2. Parse X-Aepto-Signature for t (timestamp) and v1 (hex HMAC).
  3. Reject if t is too far from your clock (recommended: a few minutes).
  4. Compute HMAC-SHA256(signing_secret, t + "." + raw_body) as hex.
  5. Compare to v1 with a constant-time equals.
// Node.js sketch
const crypto = require('crypto');
function verify(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((p) => p.trim().split('='))
  );
  const t = parts.t;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${t}.${rawBody}`)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Secrets

App UI

In the dashboard: Domains → Alert webhooks. Use Send sample and the delivery log while wiring your receiver. Product walkthrough: Alert webhooks (Docs).

FAQ

How do I verify Aepto signed the webhook?

HMAC-SHA256 over t + "." + raw_body using the signing secret; compare to v1 in X-Aepto-Signature. Always use the raw body bytes — see Verify signatures above.

When is the signing secret shown?

Once, on create or rotate (POST …/rotate-secret). Store it in a secrets manager; it is not shown again.

Does slow response have a webhook event?

Yes — monitoring.slow_response, alongside downtime, recovery, and SSL expiry events.

Can I manage webhooks in the UI instead of the API?

Yes. Domains → Alert webhooks in the app, with Send sample and a delivery log. Product guide: Alert webhooks.

More answers: FAQ hub.