Hanzo
CommerceAPI Reference

Webhooks API

Configure event notifications, verify signatures, and manage delivery

The Webhooks API lets you register HTTP endpoints to receive real-time notifications when events occur in your store. Webhooks use POST requests with JSON payloads signed for verification.

Webhook Structure

{
  "id": "whk_abc123",
  "url": "https://yourserver.com/webhooks/hanzo",
  "events": [
    "order.created",
    "order.updated",
    "payment.captured"
  ],
  "secret": "whsec_abc123def456ghi789",
  "status": "active",
  "metadata": {
    "environment": "production"
  },
  "createdAt": "2024-01-10T08:00:00Z",
  "updatedAt": "2024-06-15T10:00:00Z"
}

Event Types

Order Events

EventDescription
order.createdNew order placed
order.updatedOrder details changed
order.cancelledOrder cancelled
order.fulfilledOrder fully fulfilled
order.partially_fulfilledSome items fulfilled

Payment Events

EventDescription
payment.authorizedPayment authorized
payment.capturedPayment captured
payment.failedPayment attempt failed
payment.refundedPayment refunded

Product Events

EventDescription
product.createdNew product created
product.updatedProduct details changed
product.deletedProduct deleted

Customer Events

EventDescription
customer.createdNew customer registered
customer.updatedCustomer profile changed

Inventory Events

EventDescription
inventory.low_stockStock below threshold
inventory.out_of_stockStock reached zero
inventory.restockedStock replenished

Endpoints

List Webhooks

GET /webhook

curl "https://api.hanzo.ai/webhook" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{
  "count": 3,
  "models": [
    {
      "id": "whk_abc123",
      "url": "https://yourserver.com/webhooks/hanzo",
      "events": ["order.created", "payment.captured"],
      "status": "active",
      "createdAt": "2024-01-10T08:00:00Z"
    }
  ]
}

Create Webhook

POST /webhook

curl -X POST https://api.hanzo.ai/webhook \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourserver.com/webhooks/hanzo",
    "events": [
      "order.created",
      "order.updated",
      "payment.captured",
      "payment.refunded"
    ],
    "metadata": {
      "environment": "production"
    }
  }'

Response: 201 Created

{
  "id": "whk_abc123",
  "url": "https://yourserver.com/webhooks/hanzo",
  "events": ["order.created", "order.updated", "payment.captured", "payment.refunded"],
  "secret": "whsec_abc123def456ghi789",
  "status": "active",
  "createdAt": "2024-01-10T08:00:00Z"
}

The secret is only returned once at creation time. Store it securely for signature verification. If lost, rotate the secret using the update endpoint.

Update Webhook

PUT /webhook/:id

curl -X PUT https://api.hanzo.ai/webhook/whk_abc123 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      "order.created",
      "order.updated",
      "order.cancelled",
      "payment.captured",
      "payment.refunded"
    ]
  }'

Delete Webhook

DELETE /webhook/:id

curl -X DELETE https://api.hanzo.ai/webhook/whk_abc123 \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response: 204 No Content

Payload Structure

Webhook payloads follow a consistent structure:

{
  "id": "evt_abc123",
  "type": "order.created",
  "timestamp": "2024-06-15T10:00:00Z",
  "data": {
    "id": "order_abc123",
    "displayId": "#1042",
    "status": "confirmed",
    "email": "[email protected]",
    "total": 5638,
    "currency": "USD",
    "createdAt": "2024-06-15T10:00:00Z"
  }
}

Signature Verification

Every webhook request includes a signature header for verification. Always verify signatures to ensure the payload was sent by Hanzo and has not been tampered with.

Headers:

HeaderDescription
X-Hanzo-SignatureHMAC-SHA256 signature of the request body
X-Hanzo-TimestampUnix timestamp of when the event was sent
X-Hanzo-EventEvent type (e.g. order.created)
X-Hanzo-DeliveryUnique delivery ID

Verification Algorithm

The signature is computed as:

HMAC-SHA256(webhook_secret, timestamp + "." + request_body)

Node.js Verification Example

import crypto from 'crypto'

function verifyWebhookSignature(
  body: string,
  signature: string,
  timestamp: string,
  secret: string
): boolean {
  const payload = `${timestamp}.${body}`
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  )
}

// Express middleware
app.post('/webhooks/hanzo', (req, res) => {
  const signature = req.headers['x-hanzo-signature']
  const timestamp = req.headers['x-hanzo-timestamp']

  if (!verifyWebhookSignature(req.body, signature, timestamp, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature')
  }

  const event = JSON.parse(req.body)
  // Process event...

  res.status(200).send('OK')
})

Go Verification Example

func verifySignature(body []byte, signature, timestamp, secret string) bool {
    payload := []byte(timestamp + "." + string(body))
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(payload)
    expected := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(signature), []byte(expected))
}

Retry Policy

Failed webhook deliveries are retried with exponential backoff:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
68 hours
724 hours

A delivery is considered failed if your endpoint:

  • Returns a non-2xx HTTP status code
  • Does not respond within 30 seconds
  • Is unreachable

After 7 failed attempts, the webhook is marked as failing. It will be automatically disabled after 3 consecutive days of failures. You will receive an email notification before disabling.

Rotate Secret

POST /webhook/:id/rotate-secret

Generate a new signing secret. The old secret remains valid for 24 hours to allow for a graceful rotation.

curl -X POST https://api.hanzo.ai/webhook/whk_abc123/rotate-secret \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Response:

{
  "secret": "whsec_new789jkl012mno345",
  "previousSecretExpiresAt": "2024-06-16T10:00:00Z"
}

Test Webhook

POST /webhook/:id/test

Send a test event to verify your endpoint is configured correctly.

curl -X POST https://api.hanzo.ai/webhook/whk_abc123/test \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "order.created"
  }'

SDK Examples

JavaScript

import { Commerce } from '@hanzo/commerce'

const commerce = new Commerce({ apiKey: 'your_key' })

// Create webhook
const webhook = await commerce.webhooks.create({
  url: 'https://yourserver.com/webhooks/hanzo',
  events: ['order.created', 'payment.captured']
})

// List webhooks
const webhooks = await commerce.webhooks.list()

// Update events
await commerce.webhooks.update(webhook.id, {
  events: ['order.created', 'order.cancelled', 'payment.captured']
})

// Send test event
await commerce.webhooks.test(webhook.id, { event: 'order.created' })

// Rotate secret
const rotated = await commerce.webhooks.rotateSecret(webhook.id)

// Delete webhook
await commerce.webhooks.delete(webhook.id)

Go

webhook, err := client.Webhooks.Create(ctx, &sdk.WebhookInput{
    URL:    "https://yourserver.com/webhooks/hanzo",
    Events: []string{"order.created", "payment.captured"},
})

webhooks, err := client.Webhooks.List(ctx, nil)

err = client.Webhooks.Update(ctx, webhook.ID, &sdk.WebhookInput{
    Events: []string{"order.created", "order.cancelled", "payment.captured"},
})

err = client.Webhooks.Test(ctx, webhook.ID, "order.created")

rotated, err := client.Webhooks.RotateSecret(ctx, webhook.ID)

How is this guide?

Last updated on

On this page