Skip to content

Webhooks

Webhooks drive the Transfer SNS lifecycle. After POST /v1/transfer/sns is accepted, Gravv sends HTTPS POST events to your configured webhook endpoint as the transfer status changes.

Transfer SNS event types

Transfer status events:

  • transfer.status.pending
  • transfer.status.completed
  • transfer.status.failed

completed and failed are terminal.

Event payload

{
  "event_category": "transfer",
  "event_type": "transfer.status.completed",
  "event_group_id": "7c9e6679-3333-3333-3333-333333333333",
  "timestamp": "2025-10-27T10:11:05Z",
  "event_data": {
    "reference": "5f8d0a11-4444-4444-4444-444444444444",
    "status": "completed",
    "amount": "100.00",
    "client_reference": "wave-2026-06-18-001",
    "remark": null,
    "tx_hash": null,
    "client_metadata": null
  }
}

Field reference

Field Type Description
event_category string Event group. For this flow it is transfer.
event_type string Transition event (pending, completed, failed).
event_group_id string Correlates all events for a single transfer lifecycle.
timestamp string ISO 8601 event timestamp.
event_data object Transfer event payload (reference, status, amount, etc).

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-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:

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 behavior

Return 2xx after successful processing. Non-2xx responses are retried, so webhook handlers should be idempotent.