---
title: "Overview"
---
Webhooks notify your application when events occur in your Gravv integration. When an event happens, Gravv sends an HTTPS POST request to your webhook endpoint with the event details.

## When to use webhooks

Use webhooks to track the status of operations in real time. For example:

* Monitor transfer completion
* Track customer KYC verification status
* Receive notifications when funds arrive in accounts or wallets

## Webhook payload structure

Most webhook events in Gravv share a common base structure. External account events are the exception and use a leaner envelope, documented in [External account events](/platform/webhooks/external-account-events).

```json title="webhooks common base structure"
{
  "event_id": "53373f52-2b15-469a-822f-69625a2632b9",
  "tenant_id": "dfa96ede-fc13-43cf-8328-8b910d1cd1d2",
  "timestamp": "2025-10-27T10:11:05Z",
  "event_data": {
    "status": "pending",
    "kyc_type": "basic",
    "tenant_id": "dfa96ede-fc13-43cf-8328-8b910d1cd1d2",
    "customer_id": "0ff6cf9a-8da0-466d-a71c-714eb4bde248",
    "customer_type": "individual",
    "customer_email": "marielle@yopmail.com"
  },
  "event_type": "customer.kyc.status.pending",
  "event_category": "customer",
  "event_group_id": "0ff6cf9a-8da0-466d-a71c-714eb4bde248"
}
```

Every webhook request includes these fields:

| Field          | Type   | Description                                                       |
| :------------- | :----- | :---------------------------------------------------------------- |
| event_id       | string | unique identifier for this webhook event                          |
| tenant_id      | string | your account identifier                                           |
| transaction_id | string | identifier of the underlying transaction, when the event relates to one |
| timestamp      | string | ISO 8601 timestamp when the event occurred                        |
| event_data     | object | event-specific data, which varies by event type                   |
| event_type     | string | type of event, for example, when the transfer status is completed |
| event_category | string | category of the event, for example, customer                      |
| event_group_id | string | groups related events together                                    |

## Verify webhook signatures

By default, Gravv signs webhook requests with HMAC-SHA256 so you can verify authenticity and detect tampering. Verify the signature before processing an event. If your endpoint is configured to use a different authentication method (basic auth, bearer token, or API key), Gravv sends that credential in place of a signature.

### How signature verification works

Gravv generates a signature using:

1. Your webhook secret key from the Dashboard
2. The webhook payload
3. HMAC-SHA256 algorithm

The signature appears in the `X-Signature` header of each webhook request.

### Verification steps

To verify a webhook signature:

1. Extract the signature from the `X-Signature` header
2. Generate a signature using your secret key and the raw request body
3. Compare the generated signature with the received signature
4. Process the webhook only if the signatures match

### Signature generation

The following code sample in Go shows how to generate webhook signatures for verification:

```go title="Sample Go function to generate signatures"
func generateSignature(secretKey string, payload []byte) (string, error) {
    // 1. Initialize HMAC with SHA-256 and the Secret Key
    mac := hmac.New(sha256.New, []byte(secretKey))

    // 2. Hash the Payload
    _, err := mac.Write(payload)
    if err != nil {
        return "", fmt.Errorf("failed to write to hmac: %w", err)
    }

    // 3. Compute the signature (HMAC digest) and encode it as a hexadecimal string
    return hex.EncodeToString(mac.Sum(nil)), nil
}
```

## Delivery, retries, and idempotency

Gravv delivers each event as an HTTPS POST and treats any `2xx` response as success. Anything else, including a timeout, is retried.

* **Timeout:** 30 seconds per attempt.
* **Retries:** up to 3, with exponential backoff (roughly 2s, then 4s, then 8s).
* **At-least-once:** your endpoint can receive the same event more than once. Each request carries an `X-Event-ID` header. Dedupe on it and treat repeats as no-ops.
* **Ordering:** not guaranteed. Use `timestamp` and the event's status fields to order events.

## Available event types

The `event_data`  object, which contains the event-specific data, contains different fields depending on the `event_type`. The following are the available event types and their specific data structures:

* **[Inflow events](/platform/webhooks/inflow-events):** Sent when funds are received on-chain into a wallet or account.
* **[Transfer events](/platform/webhooks/transfer-events):** Sent when a transfer is initiated and when it completes successfully.
* **[External account events](/platform/webhooks/external-account-events):** Sent when an external account's asynchronous registration completes, retries, or exhausts its retries.
* **[Card events](/platform/webhooks/card-events):** Sent when card transactions occur, cards are funded or withdrawn from, or card status changes.
* **[Collection events](/platform/webhooks/collections-event):** Sent when a payment collection is initiated, fails, or completes successfully.
* **[Customer KYC events](/platform/webhooks/customer-kyc-events):** Sent when a customer's KYC verification status changes (pending, completed, or failed).

