Skip to main content

Webhooks

Webhooks allow your application to receive real-time notifications when fiscalization events occur. Instead of polling for transaction status, configure a webhook endpoint and FiscalAPI will send you HTTP POST requests with event details.

Overview

When a transaction completes fiscalization (or permanently fails), FiscalAPI sends an HTTP POST to your configured webhook URL with the event payload.

Setting up webhooks

1. Create a webhook endpoint

First, create a webhook subscription with the events you want to receive:

curl -X POST https://api.fiscalapi.com/v1/webhooks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"url": "https://example.com/webhooks/fiscalapi",
"events": ["fiscalization.completed", "fiscalization.dead_letter"],
"description": "Production webhook"
}'

The response includes a secret (prefixed with whsec_) that you'll use to verify signatures. Store it securely -- it's only shown on creation and when rotated.

2. Handle webhook deliveries

Your endpoint receives POST requests with a JSON payload:

{
"event": "fiscalization.completed",
"entry_id": "550e8400-e29b-41d4-a716-446655440000",
"transaction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"account_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"status": "completed",
"attempt": 1,
"max_attempts": 50,
"last_error": "",
"timestamp": "2026-03-09T14:30:05Z"
}

3. Verify signatures

Every delivery includes two headers for HMAC-SHA256 signature verification:

HeaderDescription
X-Webhook-TimestampUnix timestamp of the delivery
X-Webhook-Signaturesha256=<hex> HMAC-SHA256 signature

The signature is computed over "{timestamp}.{body}" using your webhook secret:

Python:

import hmac
import hashlib

def verify_webhook(secret, timestamp, body, signature):
expected = hmac.new(
secret.encode(),
f"{timestamp}.{body}".encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)

Node.js:

const crypto = require("crypto");

function verifyWebhook(secret, timestamp, body, signature) {
const expected = crypto
.createHmac("sha256", secret)
.update(`${timestamp}.${body}`)
.digest("hex");
return `sha256=${expected}` === signature;
}

Events

EventDescription
fiscalization.completedA transaction was successfully fiscalized
fiscalization.dead_letterA transaction exceeded max retry attempts and was moved to dead letter

Retry policy

Failed deliveries (non-2xx responses or timeouts) are retried with the following backoff:

AttemptDelay
1st retry10 seconds
2nd retry60 seconds
3rd retry300 seconds (5 min)
4th retry600 seconds (10 min)

Webhook deliveries have a 10-second timeout per attempt.

Managing webhooks

See the Webhooks API reference for full CRUD operations:

Best practices

  • Respond quickly -- return a 200 status within 10 seconds
  • Process asynchronously -- queue webhook payloads for background processing
  • Always verify signatures -- use the X-Webhook-Timestamp and X-Webhook-Signature headers
  • Handle duplicates -- use the entry_id field to deduplicate events
  • Rotate secrets periodically -- use the rotate-secret endpoint to generate new signing keys