> ## Documentation Index
> Fetch the complete documentation index at: https://docs.primevault.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Receive TRANSACTION_STATUS_CHANGED notifications, understand retry behavior, and verify PrimeVault webhook signatures with HMAC-SHA256.

PrimeVault sends webhook notifications when a transaction reaches a terminal state, allowing your application to react to transaction outcomes without continuously polling the API.

Configure one or more endpoint URLs in **Settings → Webhooks**. PrimeVault sends each event to every configured endpoint.

## Webhook event type

### TRANSACTION\_STATUS\_CHANGED

Version 2.0.0 event sent when a transaction reaches `COMPLETED`, `FAILED`, or `DECLINED`. The current transaction is available in `data.transaction`, and `eventId` identifies the webhook delivery.

## Retries and delivery behavior

PrimeVault sends each webhook as an HTTP `POST` request with a JSON body. Return a `2xx` response as soon as the event has been accepted, then perform longer processing asynchronously.

* **Request timeout** — 30 seconds per attempt. If the endpoint does not respond in time, the attempt fails.
* **Attempts** — Up to 4 total: one initial attempt plus up to three retries.
* **Backoff** — 2 seconds before the second attempt, 4 seconds before the third, and 8 seconds before the fourth.
* **Retry conditions** — Network errors, timeouts, and HTTP `4xx` or `5xx` responses are retried.
* **After final failure** — Delivery stops after the fourth failed attempt. Reconcile transaction status through the [Transactions API](/transactions/overview) if delivery is missed.

## Handling recommendations

Retries can produce duplicate deliveries, for example, when your endpoint processes a request but its response is lost. Make webhook handling idempotent and deduplicate using `eventId`.

## Verify webhook signatures

Each delivery includes `X-Signature` and `X-Timestamp` headers. Use the verification key for the configured endpoint to verify the event before accepting or processing it.

Compute HMAC-SHA256 over the canonical JSON body followed immediately by the `X-Timestamp` header value, with no separator. Canonical JSON sorts object keys, removes insignificant whitespace, and preserves Unicode characters. Compare the lowercase hexadecimal digest with `X-Signature` using a constant-time comparison.

Reject missing or invalid signatures. Apply a timestamp tolerance appropriate for your receiver; the example below uses five minutes. Keep the receiver clock synchronized. PrimeVault generates a fresh timestamp and signature for each retry.

```python verify_webhook.py theme={null}
import hashlib
import hmac
import json
import time


def verify_webhook(
    raw_body: bytes,
    timestamp: str,
    signature: str,
    verification_key: str,
    max_age_seconds: int = 300,
) -> bool:
    if (
        len(signature) != 64 or not signature.isascii()
        or not timestamp.isascii() or not timestamp.isdecimal()
    ):
        return False

    try:
        if abs(int(time.time()) - int(timestamp)) > max_age_seconds:
            return False
        payload = json.loads(raw_body)
        canonical_body = json.dumps(
            payload, sort_keys=True, separators=(",", ":"), ensure_ascii=False,
            allow_nan=False,
        )
    except (ValueError, UnicodeDecodeError):
        return False

    expected = hmac.new(
        verification_key.encode("utf-8"),
        f"{canonical_body}{timestamp}".encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature)
```

Pass the original request body bytes and the `X-Timestamp` and `X-Signature` header values into `verify_webhook`. Read missing headers as empty strings. Keep the endpoint verification key in your secret store. A valid signature authenticates the event; your handler must still validate the event version, type, and payload before applying changes.

After verification, durably record or enqueue the event and return `2xx` promptly. Deduplicate retries by `eventId`. Make business updates idempotent by transaction ID and status as well, because a separate notification about the same transaction can have a new `eventId`. Use the Transactions API to reconcile current status.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.