Skip to main content

EDI webhooks

Register HTTPS webhook endpoints to receive document validation results, routing updates, and partner acknowledgement signals without polling.

Quick answer

What HTTP status should handlers return?

Return 2xx quickly after enqueueing async work. Timeouts cause retries — respond fast and process in a background queue.

More common questions

Event types

Typical events include document.validated, document.routed, document.partner_ack, and document.error. Payloads are documented in /docs.

  • JSON envelopes with documentId + partnerId
  • Retry with exponential backoff on 5xx

Signature headers

Every delivery carries X-SignalEDI-Signature (sha256=<hex>), X-SignalEDI-Timestamp (unix seconds), X-SignalEDI-Event, and X-SignalEDI-Delivery-ID. The signature is an HMAC-SHA256 over the string timestamp + '.' + rawBody, using your webhook signing secret.

  • Reject deliveries whose X-SignalEDI-Timestamp skews more than ~5 minutes (replay protection)
  • During key rotation a second X-SignalEDI-Signature-Legacy header lets you accept both secrets

Verification

Verify webhook signatures using the shared secret configured in the developer console. See the verify-signed-webhooks guide for code samples.

import crypto from "node:crypto";

function verifySignalEdiWebhook(input: {
  rawBody: string;
  signatureHeader: string;
  timestampHeader: string;
  secret: string;
}): boolean {
  const provided = input.signatureHeader.replace(/^sha256=/i, "").toLowerCase();
  const expected = crypto
    .createHmac("sha256", input.secret)
    .update(`${input.timestampHeader}.${input.rawBody}`, "utf8")
    .digest("hex");
  // Use a timing-safe compare so signature checks do not leak partial matches.
  return crypto.timingSafeEqual(Buffer.from(provided, "hex"), Buffer.from(expected, "hex"));
}

Idempotency

Use X-SignalEDI-Delivery-ID to dedupe retries. Your handler should be safe to run twice for the same logical transition.

Common questions

© 2026 SignalEDI Inc. All rights reserved.