Solia Direct DocsControl Plane
⌘K

Partner APIReference

Webhooks

Registration, signature verification, delivery and retry semantics.

Registration

The laboratory registers your HTTPS endpoint in Integrations → Webhooks, selects the event types to deliver, and the subscription is bound to one API client and one environment. A subscription never spans environments or clients.

  • Registering, rotating and disabling a subscription is a laboratory administrator action in the Control Plane.
  • A webhook can only be configured once an eligible integration and an active key exist in the same environment; until then the Control Plane shows that prerequisite instead of an endpoint form.
  • Delivery logs, the event catalog and activity default to the currently selected environment, so a Production view never mixes in Sandbox deliveries.
  • A signing secret is shown once at creation or rotation and is not recoverable afterwards; only its algorithm and rotation generation are recorded.
  • Rotation invalidates the previous secret immediately, so deploy the new secret before rotating.

Delivery headers

  • x-solia-signaturev1=<hex HMAC-SHA256>.
  • x-solia-timestamp — Unix seconds used in the signed material.
  • x-solia-event-id — the event identifier to deduplicate on.
  • x-solia-delivery-id — this delivery attempt's identifier.
  • x-solia-api-version — the API version of the payload.

Signature verification

The signed material is exactly <x-solia-timestamp>.<raw request body>. Compute HMAC-SHA256 with your signing secret over that string, compare in constant time against the presented signature, and reject a timestamp outside a 300-second tolerance. Verify before parsing the body.

javascript
import crypto from "node:crypto";

export function verify(rawBody, headers, secret) {
  const timestamp = headers["x-solia-timestamp"];
  const presented = headers["x-solia-signature"];
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
  const expected =
    "v1=" +
    crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(presented));
}

A delivery identifier that has already been processed must be ignored. Replay protection is your responsibility as the subscriber.

Test delivery versus normal delivery

Send test event is an immediate configuration check from the Control Plane. Normal operational events are persisted to the canonical event stream and delivery outbox, then claimed by the scheduled delivery process. A successful test proves endpoint reachability and signing configuration; it does not prove that a later operational event traversed the scheduled path.

Delivery and retries

  • Each attempt uses a 10-second request timeout; respond 2xx quickly and process asynchronously.
  • A failed attempt is retried on a bounded schedule of 1m, 5m, 30m, 2h, 12h, 24h, for at most 7 attempts in total.
  • A Retry-After response header is honoured up to 60 minutes.
  • Timeouts, network failures, 408, 409, 425, 429 and 5xx responses are temporary. Other 4xx responses are permanent failures; blocked destinations are never retried.
  • Once attempts are exhausted the delivery is dead-lettered and stays visible. Supported replay creates an auditable new attempt rather than rewriting history.
  • The event itself remains readable through the reconciliation stream.
  • Delivery is at-least-once: the same event may arrive more than once.
  • Events may arrive out of order; use sequence from GET /v1/events to order them.
  • Subscribers must be idempotent on event_id and ignore a delivery id already seen.
  • Verify the HMAC-SHA256 signature over <timestamp>.<raw body> before parsing.
  • Reject a delivery whose timestamp is outside a 5 minute tolerance.
  • The Partner API is authoritative: reconcile with GET /v1/events after any gap.

Endpoint safety

  • Endpoints must use public HTTPS and cannot contain user information in the URL.
  • Localhost, private, link-local, reserved and documentation address ranges are blocked.
  • DNS is resolved again at delivery time; any non-public destination is refused, and redirects are not followed.

Payload boundary

A delivery body is the same event object returned by GET /v1/events. Only an allow-listed set of identifier and coarse-state fields can appear in data: order_id, external_order_id, program_id, client_id, environment, lifecycle, next_action, specimen_state, result_id, result_version, result_provenance, result_is_critical, action_required_code, links.

Analyte values, demographics, report documents, headers and secrets are never delivered in an event, and no permanent or signed document URL is ever included.