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

# Webhooks Overview

> Receive real-time event notifications when activity occurs on your Nuvion accounts.

Nuvion delivers event notifications to your server via HTTP POST whenever something significant happens — an account is created, a payment is received, or a transfer completes. Register a webhook endpoint to receive these events in real time rather than polling the API.

## Webhook Security

### Webhook secret

Each webhook endpoint has a unique webhook secret used to verify that webhook events originate from Nuvion.

When you create a webhook endpoint, Nuvion generates a webhook secret and displays it once.

Store this secret securely, as you will need it to verify incoming webhook requests.

### Important

The webhook secret is only displayed once when it is generated.

Be sure to copy and securely store the secret before leaving the page.

If you no longer have access to the secret, you can rotate it and update your integration with the newly generated secret.

## Rotating a webhook secret

When editing a webhook endpoint, you can choose to rotate its webhook secret.

A new webhook secret will be generated and displayed once.

After rotating a secret, update your webhook verification logic to use the new value.

## Verifying webhook signatures

Nuvion signs every webhook request using HMAC-SHA256.

Each request includes the following headers:

| Header                     | Description                                               |
| -------------------------- | --------------------------------------------------------- |
| `x-nuvion-event-id`        | Unique identifier for the webhook event.                  |
| `x-nuvion-event-timestamp` | Timestamp used when generating the signature.             |
| `x-nuvion-event-signature` | HMAC-SHA256 signature used to verify the webhook payload. |

### How signatures are generated

To generate the signature, Nuvion constructs the following payload:

```text theme={null}
{timestamp}.{payload}
```

Nuvion then computes:

```text theme={null}
HMAC_SHA256(
  webhook_secret,
  "{timestamp}.{payload}"
)
```

The resulting hexadecimal digest is included in the `x-nuvion-event-signature` header.

### How to verify a webhook

1. Retrieve your webhook secret.
2. Read the `x-nuvion-event-timestamp` header.
3. Construct `{timestamp}.{payload}` using the webhook payload and timestamp.
4. Generate an HMAC-SHA256 signature using your webhook secret.
5. Compare the generated signature with the value in `x-nuvion-event-signature`.
6. Process the webhook only if the signatures match.

## Registering an endpoint

Register your webhook URL in the [Nuvion Dashboard](https://app.nuvion.co/dashboard/settings). Nuvion sends all enabled events to a single endpoint URL per environment.

<Note>
  Use separate endpoints for sandbox and production. Sandbox events are sent to your sandbox webhook URL; production events go to your production URL.
</Note>

## Delivery

Nuvion sends an HTTP `POST` request to your registered endpoint with a JSON body. Your endpoint must return a `2xx` status code to acknowledge receipt. Any other response is treated as a failure and triggers a retry.

### Request format

```http theme={null}
POST https://your-server.example.com/webhooks
Content-Type: application/json

{
  "event": "inflows.completed",
  "data": { ... }
}
```

All payloads share the same top-level structure:

| Field   | Type   | Description                                                                                    |
| ------- | ------ | ---------------------------------------------------------------------------------------------- |
| `event` | string | The event type. e.g. `inflows.completed`                                                       |
| `data`  | object | Event-specific payload. Shape varies by event type — see [Event types](/webhooks/event-types). |

## Retries

If your endpoint does not return `2xx`, Nuvion retries delivery with exponential backoff for up to **15 minutes**. After the retry window expires, the event is not redelivered.

<Tip>
  Respond with `2xx` immediately and process the event asynchronously. Slow handlers risk timeouts that trigger unnecessary retries.
</Tip>

## Idempotency

Nuvion may deliver the same event more than once — for example, if your server acknowledges receipt after a network timeout that already triggered a retry on Nuvion's side.

Your webhook handler must be idempotent. The recommended approach: store processed event IDs using the `id` field in the event `data`, and skip any event you have already handled.

## Event types

| Event                      | Trigger                                                       |
| -------------------------- | ------------------------------------------------------------- |
| `accounts.created`         | A new account is created for an entity                        |
| `account_details.created`  | Bank account number or wallet address is generated            |
| `account_details.updated`  | Account details are updated (status change, new metadata)     |
| `inflows.completed`        | A payment is received into an account                         |
| `outflows.created`         | A transfer request is received and queued for processing      |
| `outflows.completed`       | A transfer completes successfully                             |
| `outflows.failed`          | A transfer fails                                              |
| `outflows.cancelled`       | A transfer is cancelled before completion                     |
| `payment_intent.completed` | A Payment Intent for card or Apple Pay completes successfully |
| `payment_intent.failed`    | A Payment Intent for card or Apple Pay fails                  |
| `payment_intent.cancelled` | A Payment Intent is cancelled before confirmation             |
| `payment_refund.completed` | A refund request completes successfully                       |
| `payment_refund.failed`    | A refund request fails                                        |
| `funding_sessions_updated` | A funding session is updated (status change, new metadata)    |

See [Event types](/webhooks/event-types) for full payload schemas and examples for each event.
