Skip to content

Catalog Webhooks

Receive real-time push notifications when your product catalog changes. Instead of polling /v2/catalog, register a webhook endpoint and your backend is notified immediately when products, options, categories, or groups are created, updated, or deleted.

Overview

IIMMPACT ──POST──▶ Your Webhook URL

                     ├── Verify X-Webhook-Signature (HMAC-SHA256)
                     ├── Process event (upsert/delete in your DB)
                     └── Return 200 OK
  • One event per request — each HTTP POST contains a single event
  • Signed with HMAC-SHA256 — verify every request using your webhook secret
  • Automatic retries — failed deliveries are retried with exponential backoff

Webhook Endpoints

MethodEndpointPurpose
GET/v2/reseller/catalog/webhookGet current webhook configuration
POST/v2/reseller/catalog/webhookRegister webhook URL and generate secret
PUT/v2/reseller/catalog/webhookEnable or disable webhook delivery
DELETE/v2/reseller/catalog/webhookRemove webhook configuration and disable delivery
POST/v2/reseller/catalog/webhook/rotateRotate webhook secret

All endpoints require API Key Authentication with HMAC signing.


Registration

Register your HTTPS endpoint to start receiving catalog change notifications:

bash
curl -X POST "https://api.iimmpact.com/v2/reseller/catalog/webhook" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Timestamp: 1704067200" \
  -H "X-Nonce: req-1704067200-a1b2c3d4e5f6" \
  -H "X-Signature: v1=BASE64_HMAC_SIGNATURE" \
  -d '{ "webhook_url": "https://your-api.com/iimmpact/catalog-webhook" }'

The response includes your webhook secret. Store it securely — it cannot be retrieved after this initial response. If lost or compromised, use the rotate endpoint to generate a new one.

HTTPS Required

Your webhook URL must use HTTPS. HTTP endpoints are rejected.


Event Types

Your webhook receives all event types automatically. Each HTTP request contains one event.

EventResourceDescription
product.createdproductsNew product added
product.updatedproductsProduct details changed
product.deletedproductsProduct deactivated
option.createdoptionsNew option added
option.updatedoptionsOption details changed
option.deletedoptionsOption deactivated
category.createdcategoriesNew category added
category.updatedcategoriesCategory details changed
category.deletedcategoriesCategory deactivated
group.createdgroupsNew group added
group.updatedgroupsGroup details changed
group.deletedgroupsGroup deactivated

Payload Format

Each webhook sends a POST request with this JSON structure:

json
{
  "type": "product.updated",
  "resource": "products",
  "id": "CELCOM10",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "data": {
    "product_code": "CELCOM10",
    "product_category_code": "MOBILE_PREPAID",
    "name": "Celcom Prepaid",
    "display_name": "Celcom Prepaid Reload",
    "image_url": "https://dashboard.iimmpact.com/img/CELCOM10.png",
    "processing_time": "instant",
    "is_active": true
  }
}
FieldTypeDescription
typestringEvent type (e.g. product.updated, option.created)
resourcestringResource kind: products, options, categories, groups
idstringIdentifier of the affected resource
timestampstringISO 8601 timestamp of when the change occurred
dataobject|nullFull resource data, or null for delete events

Delete Events

For *.deleted events, the data field is null. Use the id field to remove the resource from your local store.


Signature Verification

All webhook requests include an X-Webhook-Signature header. Always verify the signature before processing the event to confirm it originated from IIMMPACT and was not tampered with.

The header format is sha256=<hex_digest>, computed as HMAC-SHA256 of the raw request body using your webhook secret.

typescript
import crypto from "crypto";

function verifyWebhookSignature(
  rawBody: string,
  signature: string | null,
  secret: string,
): boolean {
  if (!signature) return false;

  const providedSig = signature.startsWith("sha256=")
    ? signature.slice(7)
    : signature;

  const expectedSig = crypto
    .createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");

  try {
    return crypto.timingSafeEqual(
      Buffer.from(providedSig, "hex"),
      Buffer.from(expectedSig, "hex"),
    );
  } catch {
    return false;
  }
}

Use Raw Body

Verify the signature against the raw request body bytes, not a parsed-and-re-serialized JSON object. Re-serializing can change key order or whitespace, causing a mismatch.


Handling Webhooks

A complete webhook handler should: verify the signature, process the event, and return 200 OK.

typescript
app.post("/iimmpact/catalog-webhook", async (req, res) => {
  // 1. Verify signature
  const signature = req.headers["x-webhook-signature"];
  if (!verifyWebhookSignature(req.rawBody, signature, WEBHOOK_SECRET)) {
    return res.status(401).send("Invalid signature");
  }

  // 2. Process event
  const { type, resource, id, data } = req.body;

  switch (type) {
    case "product.created":
    case "product.updated":
      await db.products.upsert({ id, ...data });
      break;

    case "product.deleted":
      await db.products.deactivate(id);
      break;

    case "option.created":
    case "option.updated":
      await db.options.upsert({ id, ...data });
      break;

    case "option.deleted":
      await db.options.deactivate(id);
      break;

    // Handle category.* and group.* similarly
  }

  // 3. Return 200 to acknowledge receipt
  res.status(200).send("OK");
});

Respond Quickly

Return 200 OK as fast as possible. If your processing is slow, accept the webhook, queue the work, and process asynchronously. Slow responses may be treated as failures and trigger retries.


Retry Policy

Failed deliveries are retried with exponential backoff. After 5 failed attempts, the event is dropped.

AttemptDelay After Failure
1Immediate
2~1 minute
3~2 minutes
4~4 minutes
5~8 minutes

What Triggers Retries

ResponseRetried?Reason
5xx (server error)YesTransient failure
408 (request timeout)YesTransient failure
429 (too many requests)YesRate limited
Connection error / DNS failureYesNetwork issue
4xx (except 408, 429)NoPermanent failure

Permanent Failures

4xx responses (except 408 and 429) are treated as permanent failures and are not retried. Ensure your endpoint returns 200 on success and only returns 4xx for genuinely invalid requests (e.g. 401 for bad signatures).


Secret Rotation

Your webhook secret is stored securely and cannot be retrieved after initial registration. If compromised or lost, rotate it:

bash
curl -X POST "https://api.iimmpact.com/v2/reseller/catalog/webhook/rotate" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Timestamp: 1704067200" \
  -H "X-Nonce: req-1704067200-a1b2c3d4e5f6" \
  -H "X-Signature: v1=BASE64_HMAC_SIGNATURE"

After rotation, the old secret is immediately invalidated. Update your webhook handler with the new secret before the next delivery.


Enable / Disable

Temporarily pause webhook delivery without removing your configuration:

bash
# Disable
curl -X PUT "https://api.iimmpact.com/v2/reseller/catalog/webhook" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Timestamp: 1704067200" \
  -H "X-Nonce: req-1704067200-a1b2c3d4e5f6" \
  -H "X-Signature: v1=BASE64_HMAC_SIGNATURE" \
  -d '{ "enabled": false }'

# Re-enable
curl -X PUT "https://api.iimmpact.com/v2/reseller/catalog/webhook" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Timestamp: 1704067200" \
  -H "X-Nonce: req-1704067200-a1b2c3d4e5f6" \
  -H "X-Signature: v1=BASE64_HMAC_SIGNATURE" \
  -d '{ "enabled": true }'

Events During Downtime

Events that occur while webhooks are disabled are not queued. When re-enabled, fetch /v2/catalog to sync any missed changes.


Remove Webhook

Permanently remove your webhook configuration:

bash
curl -X DELETE "https://api.iimmpact.com/v2/reseller/catalog/webhook" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "X-Timestamp: 1704067200" \
  -H "X-Nonce: req-1704067200-a1b2c3d4e5f6" \
  -H "X-Signature: v1=BASE64_HMAC_SIGNATURE"

This deletes the URL, secret, and stops all deliveries. You can re-register at any time with POST.

IIMMPACT API Documentation