Webhooks

Event delivery

Subscribe to Astris events. HMAC-SHA256 signed, with optional adapter shapes for CaseWorthy / Apricot / ETO.

Events

EventFires when
match.createdAstris persists a new match (after runMatches)
match.updatedAn existing match is re-scored (e.g. weights changed)
parse.completedA resume or JD finishes parsing
rating.submittedAn employer or caseworker rates a match
placement.createdA candidate is referred to a job (placement record)
placement.status_changedA placement moves stage (interview → offer → hired → started → 30d)

Subscribe

Super admins manage subscriptions at /admin/webhooks. Tenant admins: contact us until self-serve subscriptions land.

Delivery

  • Method: POST
  • Timeout: 8 seconds
  • Content-Type: application/json
  • Headers:
    • x-astris-event — event name
    • x-astris-signaturesha256=<hmac>
    • x-astris-timestamp — ISO 8601 UTC
    • x-astris-idempotency-keyevent:ts:subscriptionId
  • Retries (v1): none. Delivery status is persisted on the subscription (lastDeliveryAt, lastStatusCode). v2 will add a retry queue.

Verify signatures

HMAC-SHA256 over the raw request body, hex-encoded, prefixed with sha256=.

import crypto from "node:crypto";

export function verifySignature(rawBody, headerValue, secret) {
  const expected = "sha256=" + crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  // Constant-time compare to avoid timing attacks
  const a = Buffer.from(expected);
  const b = Buffer.from(headerValue ?? "");
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Native payload — match.created

{
  "event": "match.created",
  "timestamp": "2026-06-08T17:30:00.000Z",
  "tenantId": "c4fcc511-…",
  "data": {
    "matchId": "…",
    "candidateId": "…",
    "jobId": "…",
    "finalScore": 87,
    "recommendation": "strong_match",
    "retention": {
      "expectedTenureDays": 312,
      "retention180": 0.74
    },
    "gaps": []
  }
}

ATS adapters

Pick one at subscription-create time. Astris reshapes the payload before signing so the HMAC matches your expected shape.

CaseWorthy

{
  "EventType": "MATCH_CREATED",
  "TimestampUtc": "2026-06-08T17:30:00.000Z",
  "TenantId": "c4fcc511-…",
  "Payload": { "matchId": "…", "finalScore": 87, … },
  "SourceSystem": "AstrisHR"
}

Apricot

{
  "kind": "match.created",
  "occurredAt": "2026-06-08T17:30:00.000Z",
  "orgId": "c4fcc511-…",
  "record": { "matchId": "…", "finalScore": 87, … },
  "sender": "astris-hr"
}

ETO (Bonterra)

{
  "event_name": "match_created",
  "sent_at": "2026-06-08T17:30:00.000Z",
  "program_id": "c4fcc511-…",
  "data": { "matchId": "…", "finalScore": 87, … },
  "source": "astris_hr"
}

Sandbox tip

Pointing at https://webhook.site gives you a free inspector for every delivery. Or use httpbin.org/post — it always returns 200 and echoes your payload back so you can confirm signing.

See also