Skip to main content

Webhooks

Manage webhook subscriptions for real-time event notifications. All endpoints require authentication.

Create a webhook

POST /v1/webhooks

Creates a new webhook subscription. A signing secret is generated automatically.

Request body

FieldTypeRequiredDescription
urlstringYesHTTPS endpoint to receive webhook deliveries
eventsarrayYesEvent types to subscribe to
descriptionstringNoHuman-readable description
enabledbooleanNoWhether the webhook is active (default: true)

Event types

EventDescription
fiscalization.completedA transaction was successfully fiscalized
fiscalization.dead_letterA transaction exceeded max retry attempts

Example

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"
}'

Response 201 Created

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"account_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"url": "https://example.com/webhooks/fiscalapi",
"secret": "whsec_a1b2c3d4e5f6...",
"events": ["fiscalization.completed", "fiscalization.dead_letter"],
"description": "Production webhook",
"enabled": true,
"created_at": "2026-03-09T12:00:00Z"
}
Save your webhook secret

The secret field is returned only on creation (and on secret rotation). Store it securely for verifying webhook signatures.

Errors

StatusErrorCause
400url is requiredMissing URL
400invalid urlMalformed URL
400events is requiredMissing events array
400invalid event typeUnrecognized event type

List webhooks

GET /v1/webhooks

Returns all webhook subscriptions for the authenticated account.

Example

curl https://api.fiscalapi.com/v1/webhooks \
-H "Authorization: Bearer fsk_test_abc123def456..."

Response 200 OK

{
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://example.com/webhooks/fiscalapi",
"events": ["fiscalization.completed", "fiscalization.dead_letter"],
"description": "Production webhook",
"enabled": true,
"created_at": "2026-03-09T12:00:00Z"
}
]
}

Get a webhook

GET /v1/webhooks/{id}

Returns a single webhook subscription by ID.

Example

curl https://api.fiscalapi.com/v1/webhooks/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer fsk_test_abc123def456..."

Response 200 OK

Returns a Webhook object (secret is not included).

Errors

StatusError
404webhook not found

Update a webhook

PATCH /v1/webhooks/{id}

Partially updates a webhook subscription. Only supplied fields are modified.

Request body

FieldTypeDescription
urlstringUpdated endpoint URL
eventsarrayUpdated event types
descriptionstringUpdated description
enabledbooleanEnable or disable the webhook

Example

curl -X PATCH https://api.fiscalapi.com/v1/webhooks/550e8400-e29b-41d4-a716-446655440000 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fsk_test_abc123def456..." \
-d '{
"enabled": false
}'

Response 200 OK

Returns the updated Webhook object.


Delete a webhook

DELETE /v1/webhooks/{id}

Deletes a webhook subscription.

Example

curl -X DELETE https://api.fiscalapi.com/v1/webhooks/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer fsk_test_abc123def456..."

Response 204 No Content

No response body.


Rotate secret

POST /v1/webhooks/{id}/rotate-secret

Generates a new signing secret for the webhook. The old secret is immediately invalidated.

Example

curl -X POST https://api.fiscalapi.com/v1/webhooks/550e8400-e29b-41d4-a716-446655440000/rotate-secret \
-H "Authorization: Bearer fsk_test_abc123def456..."

Response 200 OK

{
"secret": "whsec_f6e5d4c3b2a1..."
}

Webhook object

FieldTypeDescription
iduuidWebhook identifier
account_iduuidOwning account identifier
urlstringDelivery endpoint URL
eventsarraySubscribed event types
descriptionstringHuman-readable description
enabledbooleanWhether the webhook is active
created_atdatetimeCreation timestamp

Webhook signatures

Every webhook delivery includes two headers for signature verification:

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

Verifying signatures

The signature is computed as HMAC-SHA256(secret, "{timestamp}.{body}"):

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)
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;
}

Webhook 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"
}

Retry policy

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

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

After all retries are exhausted, a fiscalization.dead_letter event is emitted.

Webhook deliveries have a 10-second timeout per attempt.