Signature headers
X-Ordinavo-Event-Id: evt_01JZ8Y4EXAMPLE
X-Ordinavo-Event-Type: visit_report.approved
X-Ordinavo-Delivery-Id: del_01JZ8Y4DELIVERY
X-Ordinavo-Timestamp: 2026-06-18T16:40:00Z
X-Ordinavo-Signature: sha256=...
X-Ordinavo-Webhook-Version: v1
Content-Type: application/json
Ordinavo sends a signature header with every webhook delivery. Consumers should verify the signature before processing the payload.
Webhook delivery is at-least-once. Consumers should deduplicate by eventId. Retries can cause events to arrive later or out of order.
Node.js verification
const crypto = require("crypto");
function verifySignature(rawBody, signatureHeader, secret) {
const expected =
"sha256=" +
crypto
.createHmac("sha256", secret)
.update(rawBody, "utf8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}
C# verification
using System.Security.Cryptography;
using System.Text;
static bool VerifyOrdinavoSignature(string rawBody, string signatureHeader, string secret)
{
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(rawBody));
var expected = "sha256=" + Convert.ToHexString(hash).ToLowerInvariant();
return CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(expected),
Encoding.UTF8.GetBytes(signatureHeader));
}
- Reject timestamps older than 5 minutes.
- Store processed eventIds.
- Ignore duplicate eventIds.
- Return 2xx only after the event was accepted for processing.