Webhooks
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
- Receive notifications when funds arrive in accounts
Webhook payload structure
All webhook events in Gravv share a 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 |
| 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
Gravv signs all webhook requests with HMAC-SHA256 to verify authenticity and prevent tampering. You should verify the signature before processing webhook events.
How signature verification works
Gravv generates a signature using:
- Your webhook secret key from the Dashboard
- The webhook payload
- HMAC-SHA256 algorithm
The signature appears in the X-Gravv-Signature header of each webhook request.
Verification steps
To verify a webhook signature:
- Extract the signature from the
X-Gravv-Signatureheader - Generate a signature using your secret key and the raw request body
- Compare the generated signature with the received signature
- Process the webhook only if the signatures match
Signature generation
The following code sample in Go shows how to generate webhook signatures for verification:
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
}
Cards events
Card events notify you when transactions occur on issued cards and when funds are withdrawn from cards.
When card events are sent
Gravv sends card events when:
- The card is funded.
- A card transaction is authorized and being processed.
- The transaction completes successfully.
- The transaction fails due to payment issues or validation errors.
- Funds are withdrawn from a card.
Card event types
The following event types are available for cards:
| Event type | Description |
|---|---|
| cards.application.update | card application status changed |
| cards.status.update | card status updated |
| cards.transaction.funding | funds added to card |
| cards.transaction.payment | card transaction completed or failed |
| cards.transaction.withdraw | funds withdrawn from card |
Card event structure
The event_data object for card events contains the following fields:
| Field | Type | Description |
|---|---|---|
| card | object | details about the card used for the transaction |
| transaction | object | details about the transaction |
The structure of the transaction object varies depending on the event type.
Application events (cards.application.update)
For application events, the event_data object contains an application object with details about the card application status change.
The application object contains the following fields:
| Field | Type | Description |
|---|---|---|
| id | string | unique identifier for the application |
| status | string | current status of the card application |
| customer_id | string | ID of the customer who owns the application |
The status field can have the following values:
| Status | Description |
|---|---|
| pending | application is under review |
| approved | application is approved, and you can now create the card |
| needs_information | additional information is required to process the application |
| needs_verification | selfie verification is required to complete intermediate KYC |
| manual_review | application requires manual review by the compliance team |
| denied | application rejected |
| locked | application locked due to security concerns |
| canceled | application canceled |
The following is a sample payload for an application event:
{
"event_id": "2e6c19a1-6a33-47e0-a74b-d9d7bc32e2fe",
"tenant_id": "6acaccaf-d9f2-4ca2-a38b-276012b320fa",
"timestamp": "2026-01-29T10:54:19.932644757Z",
"event_data": {
"application": {
"id": "da977df0-2c08-4b5d-9399-089d4285e9e7",
"status": "approved",
"customer_id": "33485344-9424-43a2-9724-fdb0edfd7c04"
}
},
"event_type": "cards.application.update",
"event_category": "cards",
"event_group_id": "da977df0-2c08-4b5d-9399-089d4285e9e7"
}
Status update events (cards.status.update)
For status update events, the event_data object contains a card object with details about the card status change.
The card object contains the following fields:
| Field | Type | Description |
|---|---|---|
| id | string | unique identifier for the card |
| last4 | string | last 4 digits of the card number |
| expiry | string | card expiration date |
| status | string | current status of the card |
| network | string | card network: visa or mastercard |
| customer_id | string | ID of the customer who owns the card |
| name_on_card | string | name printed on the card |
The status field can have the following values:
| Status | Description |
|---|---|
| active | card is active, and you can use it for transactions |
| freeze | card is temporarily frozen, and you can't use it until it's reactivated |
| blocked | card is permanently blocked, and you can't reactivate it |
The following is a sample payload for a status update event:
{
"event_id": "71deb6c7-19a7-4c74-b73c-be8e36467ba2",
"tenant_id": "6acaccaf-d9f2-4ca2-a38b-276012b320fa",
"timestamp": "2026-02-02T01:09:08.278677733Z",
"event_data": {
"card": {
"id": "da977df0-2c08-4b5d-9399-089d4285e9e7",
"last4": "7600",
"expiry": "1/2032",
"status": "active",
"network": "visa",
"customer_id": "45902344-9424-43a2-9724-fdb0edfd7c04",
"name_on_card": "Ndifreke Jacob"
}
},
"event_type": "cards.status.update",
"event_category": "cards",
"event_group_id": "da977df0-2c08-4b5d-9399-089d4285e9e7"
}
Funding events (cards.transaction.funding)
For funding events, the event_data object contains card and transaction objects with details about the funding transaction.
The card object contains the following fields:
| Field | Type | Description |
|---|---|---|
| id | string | unique identifier for the card |
| last4 | string | last 4 digits of the card number |
| expiry | string | card expiration date |
| status | string | current status of the card |
| network | string | card network: visa or mastercard |
| name_on_card | string | name printed on the card |
The transaction object for funding events contains the following fields:
| Field | Type | Description |
|---|---|---|
| id | string | unique identifier for the funding transaction |
| status | string | transaction status: completed |
| amount | number | amount funded to the card |
| tx_hash | string | blockchain transaction hash for the funding |
The following is a sample payload for a funding event:
{
"event_id": "924bfe34-d926-440e-b020-3e2e00097dc1",
"tenant_id": "31a6fc8d-826c-496c-9e32-7396aed013d2",
"timestamp": "2025-12-09T12:03:36.25772172Z",
"event_type": "cards.transaction.funding",
"event_category": "cards",
"event_group_id": "51bc1a48-d4c5-4f2e-ab0b-1a8c0fcab9f0",
"event_data": {
"card": {
"id": "ac21ddfc-f6ba-432c-abb3-c5e2243e8ef7",
"last4": "9032",
"expiry": "8/2029",
"status": "active",
"network": "visa",
"name_on_card": "Ndifreke Jacob"
},
"transaction": {
"id": "51bc1a48-d4c5-4f2e-ab0b-1a8c0fcab9f0",
"status": "completed",
"amount": 50,
"tx_hash": "0xea0ece02551ae78b16d747d86e176cb59b2b05201de887f9d564626a255e86a3"
}
}
}
Payment events (cards.transaction.payment)
For payment events, the card object within the event_data object contains the following fields:
| Field | Type | Description |
|---|---|---|
| id | string | unique identifier for the card |
| last4 | string | last 4 digits of the card number |
| expiry | string | card expiration date |
| status | string | current status of the card |
| network | string | card network: visa or mastercard |
| customer_id | string | ID of the customer who owns the card |
| name_on_card | string | name printed on the card |
The transaction object for payment events contains the following fields:
| Field | Type | Description |
|---|---|---|
| amount | number | transaction amount |
| user_id | string | unique identifier for the user |
| user_email | string | email address of the user |
| merchant_id | string | unique identifier for the merchant, null if not available |
| merchant_city | string | city where the merchant is located |
| merchant_name | string | name of the merchant |
| user_lastname | string | last name of the user |
| authorize_time | string | timestamp when the transaction was authorized, null if not available |
| user_firstname | string | first name of the user |
| declined_reason | string | reason for transaction decline, null if transaction was successful |
| merchant_country | string | two-letter country code where the merchant is located |
| merchant_category | string | merchant category description |
| merchant_category_code | string | numeric code identifying the merchant category |
| status | string | transaction status: completed or failed |
The following is a sample payload for a payment event:
{
"event_id": "485e8bde-7d51-49de-8dcf-9da925669d60",
"tenant_id": "31a6fc8d-826c-496c-9e32-7396aed013d2",
"timestamp": "2025-12-10T11:44:40.315299561Z",
"event_data": {
"card": {
"id": "ac21ddfc-f6ba-432c-abb3-c5e2243e8ef7",
"last4": "9032",
"expiry": "8/2029",
"status": "active",
"network": "visa",
"customer_id": "1805c3be-abca-4698-9cbd-789fc1d619eb",
"name_on_card": "Ndifreke Jacob"
},
"transaction": {
"amount": 10,
"user_id": "a7bc711c-7b2d-4f47-928e-83db292aca88",
"user_email": "ndifrekeeyak@yopmail.com",
"merchant_id": null,
"merchant_city": "London",
"merchant_name": "aliexpress",
"user_lastname": "JACOB",
"authorize_time": null,
"user_firstname": "NDIFREKE EYAK",
"declined_reason": null,
"merchant_country": "GB",
"merchant_category": "5311 - Department Stores",
"merchant_category_code": "5311",
"status": "completed"
}
},
"event_type": "cards.transaction.payment",
"event_category": "cards",
"event_group_id": "ac21ddfc-f6ba-432c-abb3-c5e2243e8ef7"
}
Withdraw events (cards.transaction.withdraw)
For withdraw events, the card object within the event_data object contains the following fields:
| Field | Type | Description |
|---|---|---|
| id | string | unique identifier for the card |
| last4 | string | last 4 digits of the card number |
| expiry | string | card expiration date |
| status | string | current status of the card |
| network | string | card network: visa or mastercard |
| name_on_card | string | name printed on the card |
The transaction object for withdraw events contains the following fields:
| Field | Type | Description |
|---|---|---|
| id | string | unique identifier for the withdrawal transaction |
| status | string | transaction status: completed |
| amount | number | amount funded to the card |
| tx_hash | string | blockchain transaction hash for the withdrawal |
The following is a sample payload for a withdraw event:
{
"event_id": "924bfe34-d926-440e-b020-3e2e00097dc1",
"tenant_id": "31a6fc8d-826c-496c-9e32-7396aed013d2",
"timestamp": "2025-12-09T12:03:36.25772172Z",
"event_type": "cards.transaction.withdraw",
"event_category": "cards",
"event_group_id": "51bc1a48-d4c5-4f2e-ab0b-1a8c0fcab9f0",
"event_data": {
"card": {
"id": "ac21ddfc-f6ba-432c-abb3-c5e2243e8ef7",
"last4": "9032",
"expiry": "8/2029",
"status": "active",
"network": "visa",
"name_on_card": "Ndifreke Jacob"
},
"transaction": {
"id": "51bc1a48-d4c5-4f2e-ab0b-1a8c0fcab9f0",
"status": "completed",
"amount": 50,
"tx_hash": "0xea0ece02551ae78b16d747d86e176cb59b2b05201de887f9d564626a255e86a3"
}
}
}