Skip to content

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:

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

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

Verification steps

To verify a webhook signature:

  1. Extract the signature from the X-Gravv-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:

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