أساس · التوثيق

Webhooks

Event catalog, delivery guarantees, and HMAC signature verification for ASAS webhooks.

الويب هوك

تُرسل أساس أحداثاً إلى نقطة النهاية التي تسجّلها، موقّعةً بـ HMAC للتحقق من مصدرها. تحقّق دائماً من التوقيع قبل الوثوق بالحمولة.

Register an HTTPS endpoint and ASAS will POST events to it — job completions, quota alerts, and more — so you don't have to poll. Every delivery is signed; verify the signature before trusting the payload.

Event catalog

EventFires when
pingYou send a test event from the dashboard.
job.completedAn async STT transcription (or RAG indexing) job finishes.
quota.thresholdYour org crosses 80% / 100% of its monthly credits.
invoice.finalizedA billing invoice is finalized.
key.compromisedA leaked key was auto-revoked by secret scanning.

Payload shape

{
  "id": "evt_9f2c1a7b",
  "event": "job.completed",
  "createdAt": "2026-07-11T09:30:00Z",
  "data": { "job_id": "stt_123", "status": "completed" }
}

Delivered with two headers:

HeaderPurpose
ASAS-SignatureHMAC-SHA-256 of ${timestamp}.${rawBody}, hex-encoded.
ASAS-TimestampUnix seconds when the event was signed (replay defense).

Verify the signature

Compute the HMAC over `${timestamp}.${rawBody}` with your endpoint's signing secret and compare in constant time. Reject anything older than a few minutes.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyAsasWebhook(
  rawBody: string,
  signatureHeader: string, // ASAS-Signature
  timestampHeader: string, // ASAS-Timestamp
  secret: string,
): boolean {
  // Replay defense: reject stale timestamps (5 minutes).
  const age = Math.abs(Date.now() / 1000 - Number(timestampHeader));
  if (!Number.isFinite(age) || age > 300) return false;

  const expected = createHmac("sha256", secret)
    .update(`${timestampHeader}.${rawBody}`)
    .digest("hex");

  const a = Buffer.from(expected);
  const b = Buffer.from(signatureHeader);
  return a.length === b.length && timingSafeEqual(a, b);
}

Verify against the raw request body, byte for byte. If you parse JSON first and re-serialize, the bytes change and the signature will not match.

Delivery & retries

  • Respond 2xx within 5 seconds to acknowledge. Anything else is a failure.
  • Failed deliveries are retried with exponential backoff.
  • Deliveries can arrive out of order and more than once — make your handler idempotent by keying on the event id.
  • Inspect recent deliveries and rotate the signing secret from the dashboard.

On this page