Skip to main content

Webhooks

Webhooks allow you to receive real-time server-side notifications about transactions and catalog changes. Unlike SDK events (which are client-side), webhooks are server-to-server callbacks that are reliable and cannot be missed due to client disconnections.

Overview

If a partner is interested in receiving real-time callbacks from Hubble, they can share a webhook URL with us. Hubble will send POST requests to this URL for supported events.

All webhooks are signed using an HMAC signature, and partners are expected to verify the request authenticity using the X-Verify header.


Transaction Webhooks

Triggered whenever a transaction occurs via the Hubble SDK. Different webhook payloads are sent based on the order status.

Order StatusWhen It FiresVoucher Data
COMPLETEDGift card successfully generatedIncludes voucher codes, PINs, and validity dates
FAILEDOrder failed after paymentEmpty vouchers array; coins are reversed if applicable
REVERSEDManual reversal by Hubble teamEmpty vouchers array; refund has been processed

COMPLETED Status

Triggered by: Successful redemption

{
"transactionReferenceId": "01HRVY38NCAANDYPN3WVGJCDSG",
"partnerCoinTransactionId": "01HZ123EXAMPLE456789",
"partnerCoinReversalTransactionId": null,
"amount": 1000.0,
"discountAmount": 50.0,
"timestamp": "2024-01-15T14:30:22",
"userId": "01HRW71319JNKJS6D3Q85X780R",
"vouchers": [
{
"id": "01HZ46Q0P0242STC8TBV926M8C",
"brandId": "01JRSY42BBMKC2YS9TXMYSYN83",
"brandName": "Swiggy",
"cardType": "CARD_NUMBER_SECURED",
"cardNumber": "5333644476668777",
"cardPin": "123456",
"validTill": "2025-04-04",
"amount": 1000.0,
"shareImageUrl": "https://gullak-assets.s3.ap-south-1.amazonaws.com/share-wa-brand-images/Swiggy.jpg",
"brandRetailModes": ["online", "offline", "app", "website"]
}
],
"brandName": "Swiggy",
"orderStatus": "COMPLETED"
}

FAILED Status

Triggered when orders fail.

{
"transactionReferenceId": "01HRVY38NCAANDYPN3WVGJCDSG",
"partnerCoinTransactionId": "01HZ123EXAMPLE456789",
"partnerCoinReversalTransactionId": "01HZ456REVERSAL789012",
"amount": 1000.0,
"discountAmount": 50.0,
"timestamp": "2024-01-15T14:35:10",
"userId": "01HRW71319JNKJS6D3Q85X780R",
"vouchers": [],
"brandName": "Swiggy",
"orderStatus": "FAILED"
}

REVERSED Status

Triggered during manual reversals.

{
"transactionReferenceId": "01HRVY38NCAANDYPN3WVGJCDSG",
"partnerCoinTransactionId": "01HZ123EXAMPLE456789",
"partnerCoinReversalTransactionId": "01HZ456REVERSAL789012",
"amount": 1000.0,
"discountAmount": 50.0,
"timestamp": "2024-01-15T15:00:00",
"userId": "01HRW71319JNKJS6D3Q85X780R",
"vouchers": [],
"brandName": "Swiggy",
"orderStatus": "REVERSED"
}
note
  • brandRetailModes can be null and must be treated as flexible tags, not a strict enum.
  • partnerCoinReversalTransactionId and partnerCoinTransactionId will be null always if coin module is not integrated.

Brand Update Webhooks

Used to notify partners of catalog changes such as discount updates, new brand additions, or brand deactivation.

USER_DISCOUNT_UPDATED

{
"event": "USER_DISCOUNT_UPDATED",
"details": {
"id": "01GMAVS2CHXR0XP1BZSTA9A44K",
"name": "Amazon shopping",
"discountPercentage": 5
}
}

NEW_BRAND_CREATED

{
"event": "NEW_BRAND_CREATED",
"details": {
"id": "01GMAVS2CHXR0XP1BZSTA9A44K",
"name": "Amazon shopping",
"discountPercentage": 2
}
}

BRAND_DISABLED

{
"event": "BRAND_DISABLED",
"details": {
"id": "01GMAVS2CHXR0XP1BZSTA9A44K",
"name": "Amazon shopping"
}
}

PARTNER_DISCOUNT_UPDATED

{
"event": "PARTNER_DISCOUNT_UPDATED",
"details": {
"brandId": "01HFV6NGBFGATYAKZ3AKASJVM9",
"subventionPercentage": 8,
"validFrom": "2025-12-23",
"validTo": "2026-02-28"
}
}

Webhook Authentication & Security

All webhook requests from Hubble are secured using HMAC-SHA256 signatures.

Signature Verification

Each webhook request includes an X-Verify header containing an HMAC-SHA256 signature of the request body, encoded in Base64.

Verification steps:

  1. Extract the X-Verify header from the incoming request
  2. Read the raw request body as a string (before any JSON parsing)
  3. Compute HMAC-SHA256 of the raw body using your webhook secret key, then Base64-encode the result
  4. Compare your computed signature with the X-Verify header. Only process the request if they match exactly

Example: Node.js

const crypto = require("crypto");

function verifyWebhook(rawBody, signatureHeader, secret) {
const hmac = crypto.createHmac("sha256", secret);
hmac.update(rawBody);
const expected = hmac.digest("base64");
return expected === signatureHeader;
}

// In your webhook handler:
app.post("/hubble-webhook", (req, res) => {
const rawBody = req.rawBody; // Must be the raw string, not parsed JSON
const signature = req.headers["x-verify"];
if (!verifyWebhook(rawBody, signature, WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
// Process the webhook...
res.status(200).send("OK");
});

Example: Kotlin

import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import java.util.Base64

private fun generateSignature(payload: String, secret: String): String {
val algorithm = "HmacSHA256"
val secretKeySpec = SecretKeySpec(secret.toByteArray(), algorithm)
val mac = Mac.getInstance(algorithm).apply { init(secretKeySpec) }
val signatureBytes = mac.doFinal(payload.toByteArray())
return Base64.getEncoder().encodeToString(signatureBytes)
}

fun verifyWebhook(requestBody: String, signatureHeader: String, secret: String): Boolean {
val expectedSignature = generateSignature(requestBody, secret)
return expectedSignature == signatureHeader
}

Important Identifiers

  • transactionReferenceId: Use this as the unique transaction identifier for all webhook callbacks. This ID remains consistent throughout the transaction lifecycle.
  • userId: This corresponds to the customer_id that was provided to Hubble during initialization.

Security Best Practices

  1. Always verify the webhook signature before processing any request
  2. Never log or expose your webhook secret key
  3. Use HTTPS for your webhook endpoint
  4. Implement rate limiting to prevent abuse
  5. Validate all incoming data before processing

IP Whitelisting (Optional)

For additional security, you can whitelist Hubble's production IP addresses:

  • 35.200.156.199
  • 34.47.147.244
  • 34.14.138.52
Common Webhook Issues
  1. Signature validation failure: If you are parsing the JSON body before computing the signature, the whitespace or field ordering may differ from the raw body. Always compute the HMAC on the raw request string.
  2. Webhook endpoint returning 401/400/500: Your webhook endpoint should authenticate using the X-Verify signature, not your app's general auth middleware.
  3. Missing FAILED status handling: Always handle both COMPLETED and FAILED statuses.
  4. Webhooks not being received: Confirm your webhook URL has been registered with the Hubble team for the correct environment.
Webhook Idempotency

Hubble may retry webhook delivery if your endpoint does not return a 200 response. Implement idempotency on your webhook handler using the transactionReferenceId. If you have already processed a webhook for a given transactionReferenceId, return 200 without reprocessing.