FirmARDigital

Developer documentation

API reference · Webhooks

Events to sync your system

Receive status changes in your backend without relying only on polling. Configure endpoints from the Enterprise panel.

Signed

HMAC SHA-256

Retryable

Up to 8 attempts

Persistent

History per endpoint

Available events

signer.enrolled
signing_session.created
signing_session.signed

Envelope

Events always use this shape. Persist `id` before processing so a retry does not execute your business logic twice.

jsonFirmARDigital API
{
  "id": "evt_01J...",
  "type": "signing_session.signed",
  "api_version": "2026-07-01",
  "created_at": "2026-08-01T12:00:00.000Z",
  "data": { "document_id": "doc_123", "status": "SIGNED" }
}

Request headers

HeaderUso
x-firmar-event-idIdempotent event identifier.
x-firmar-event-typeType of the delivered event.
x-firmar-timestampUnix timestamp in seconds used in the signature.
x-firmar-signatureFormat `t=<timestamp>,v1=<hmac-sha256>`.

Verify the signature

Use the raw body, not serialized JSON, and compare with a constant-time function.

javascriptFirmARDigital API
const rawBody = await request.text();
const signature = request.headers.get("x-firmar-signature") ?? "";
const timestamp = request.headers.get("x-firmar-timestamp") ?? "";
const signed = `${timestamp}.${rawBody}`;
const expected = crypto
  .createHmac("sha256", WEBHOOK_SECRET)
  .update(signed)
  .digest("hex");

const [, version] = signature.split(",");
const received = version?.replace("v1=", "") ?? "";

if (
  received.length !== expected.length ||
  !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))
) {
  throw new Error("Firma de webhook inválida");
}
200

Signing completed event

jsonFirmARDigital API
{
  "id": "7d920246-1d14-4f43-a194-2f0c2dc7018c",
  "type": "signing_session.signed",
  "apiVersion": "2026-07-31",
  "createdAt": "2026-08-01T12:00:00.000Z",
  "data": {
    "documentId": "cme0tc1tw0003s6a1c4g2n8fj",
    "status": "SIGNED"
  }
}