Skip to content
Sections

Guides

Webhooks & signatures

Apply the exact signature and replay rules of each integration.

Receive preorder events

In venue fulfillment settings, open Integrations, select a credential with webhooks:manage, and register a public HTTPS endpoint and the required event types. Keep the one-time signing secret on your receiving server.

Events include preorder.quote_issued, preorder.quote_accepted, preorder.confirmed, preorder.changed, preorder.canceled, preorder.ready, preorder.out_for_delivery and preorder.completed. Deliveries carry x-hallify-delivery-id, x-hallify-timestamp and x-hallify-signature. Outbound preorder signatures use v1=<hex>; this is distinct from external-order ingress. Process repeat deliveries idempotently and return a successful response only after durable acceptance.

Outbound preorder signing uses HMAC-SHA256 over unixSeconds + "." + recursively key-sorted stable JSON, the issued secret as UTF-8 text, and v1=<hex> output. The server sends ordinary JSON: parse it and apply the same sorting before verification. The example below chooses a 300-second receiver freshness policy; this is not a universal Hallify outbound-delivery rule.

The envelope contains id, type, occurredAt, data and salesChannelId. Fulfillment data contains venueId, orderId, fulfillmentId, revision, status, serviceMode and scheduledFor. Quote data contains quoteId, nullable orderId, revision, status, serviceMode, scheduledFor, total and currency alongside venueId. Deduplicate by event id; x-hallify-delivery-id identifies the delivery record.

Success is an HTTP 2xx response within the 8-second timeout. Network errors, 408, 429 and 5xx retry with exponential delays starting at 30 seconds, for at most eight attempts. Other 4xx, configuration errors and exhausted attempts move delivery to DEAD_LETTER. Check the endpoint and subscription, credential and channel authorization before an allowed cabinet replay.

Request examples
import { createHmac, timingSafeEqual } from 'node:crypto';

const stable = (value) => Array.isArray(value) ? value.map(stable)
  : value !== null && typeof value === 'object'
    ? Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])]))
    : value;

export function verifyPreorderWebhook(payload, timestamp, signature, now = Date.now()) {
  const fresh = /^\d+$/.test(timestamp)
    && Math.abs(now / 1000 - Number(timestamp)) <= 300;
  const validFormat = /^v1=[0-9a-f]{64}$/.test(signature);
  if (!fresh || !validFormat) return false;
  const expected = createHmac('sha256', process.env.HALLIFY_SIGNING_SECRET)
    .update(timestamp + '.' + JSON.stringify(stable(payload)))
    .digest();
  return timingSafeEqual(Buffer.from(signature.slice(3), 'hex'), expected);
}

Choose the correct HMAC profile

External orders use an RFC3339 timestamp, stable JSON sorted by keys, an issued secret as UTF-8 text, and lowercase hex. Workforce uses recursively sorted JSON and accepts an optional sha256= signature prefix. Guest communications sign JSON.stringify of the parsed DTO and encode the signature as base64url. Payments use stable JSON and v1=<hex>. All of these timestamp windows are 300 seconds.

Audit uses Unix seconds and the exact raw UTF-8 NDJSON. Decode the issued base64url secret to 32 bytes before signing. Repeated audit signatures are rejected; other profiles use domain event IDs, revisions or payload hashes. Copy the profile-specific server example from the operation page.

Provider callbacks

Plaid and Salt Edge callbacks are created by the bank provider and use their own verification keys and signatures. They are not generic HMAC endpoints. Provider configuration and certification are separate from the availability of the documented HTTP contract.

Hallify uses essential cookies and optional analytics.

Essential cookies keep sign-in, locale, and theme preferences working. Analytics is off until you choose to allow it.