Skip to content

Webhooks — Overview

Webhooks allow your application to receive real-time HTTP notifications whenever events occur in the HappyColis platform. Instead of polling the API, you register an HTTPS endpoint and HappyColis pushes event payloads to it automatically.


How Webhooks Work

  1. You register a webhook endpoint (HTTPS URL) for a specific event type.
  2. When the event fires, HappyColis sends an HTTP POST request to your endpoint.
  3. Your server verifies the HMAC signature and processes the payload.
  4. Your server responds with 2xx to acknowledge receipt.

If delivery fails (non-2xx or timeout), HappyColis retries with exponential backoff.


Integration Types

Webhooks are scoped to an integration context. There are two integration types:

TypeDescription
Integration AppA private or third-party application registered in the HappyColis dashboard. Use integrationWebhookCreate / integrationWebhookRemove.
OAuth ClientAn OAuth application acting on behalf of an organization using the authorization code flow. Use oauthWebhookCreate / oauthWebhookRemove.

Both types use the same IntegrationWebhookInput and produce the same webhook payload format.


Available Webhook Events

Order Events

EventDescription
order/createdA new order has been created.
order/updatedAn order has been updated.
order/completedAn order has reached the COMPLETED state.
order/cancelledAn order has been cancelled.

Delivery Order Events

EventDescription
delivery_order/createdA new delivery order has been created.
delivery_order/updatedA delivery order has been updated.
delivery_order/acceptedA fulfillment service has accepted a delivery order.
delivery_order/refusedA fulfillment service has refused a delivery order.
delivery_order/completedA delivery order has been fully fulfilled.
delivery_order/cancelledA delivery order has been cancelled.
delivery_order/shippedA delivery order has been marked as shipped.

Shipment Events

EventDescription
shipment/createdA new shipment has been created.
shipment/completedA shipment has been delivered or returned (terminal state).
shipment/shipping_eventA new tracking event has been received from the carrier.

Stock Events

EventDescription
stock/createdA new stock reference has been created.
stock/updatedA stock reference has been updated.
stock/adjustedA stock quantity has been adjusted.
stock/reservedStock has been reserved for an order.
stock/releasedPreviously reserved stock has been released.
stock/consumedStock has been consumed (deducted) during fulfillment.
stock/deletedA stock reference has been deleted.

Product Events

EventDescription
product/createdA new product has been created.
product/updatedA product has been updated.
product/deletedA product has been deleted.
product/publishedA product has been published.
product/unpublishedA product has been unpublished.

Variant Events

EventDescription
variant/createdA new product variant has been created.
variant/updatedA variant has been updated.
variant/deletedA variant has been deleted.
variant/linkedA variant has been linked to a bundle.
variant/unlinkedA variant has been unlinked from a bundle.
variant/publishedA variant has been published.
variant/unpublishedA variant has been unpublished.

Location Events

EventDescription
location/createdA new location has been created.
location/updatedA location has been updated.
location/deletedA location has been deleted.
location/activatedA location has been activated.
location/deactivatedA location has been deactivated.
location/service_connectedA fulfillment service has been connected to a location.
location/service_disconnectedA fulfillment service has been disconnected from a location.
location/service_updatedA fulfillment service configuration has been updated.

Transfer Order Events

EventDescription
transfer_order/createdA new transfer order has been created.
transfer_order/updatedA transfer order has been updated.
transfer_order/completedA transfer order has been completed.
transfer_order/cancelledA transfer order has been cancelled.
transfer_order/shippedA transfer order has been marked as shipped.

Webhook Message Format

HTTP Headers

Every webhook request includes the following headers:

HeaderDescription
Content-TypeAlways application/json
X-HappyColis-Hmac-SHA256HMAC-SHA256 signature of the raw request body
X-HappyColis-EventThe event type (e.g. order/created)
X-HappyColis-DeliveryA unique delivery UUID for deduplication

Payload Body

json
{
  "event": "order/created",
  "organizationId": "org_123",
  "occurredAt": "2024-01-15T10:30:00.000Z",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "externalReference": "EXT-2024-001",
    "state": "DRAFT"
  }
}
FieldDescription
eventThe event type string
organizationIdThe organization that owns the resource
occurredAtISO 8601 timestamp of when the event occurred
dataThe event payload — structure varies by event type

HMAC Signature Verification

Always verify the X-HappyColis-Hmac-SHA256 header before processing a webhook payload. The signature is a hex-encoded HMAC-SHA256 of the raw request body using your webhook secret as the key.

js
import crypto from 'crypto';

function verifyWebhookSignature(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(signature, 'hex'),
  );
}

// Express.js example
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-happycolis-hmac-sha256'];
  if (!verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const payload = JSON.parse(req.body.toString());
  console.log('Received event:', payload.event);

  res.sendStatus(200);
});
python
import hashlib
import hmac
import os
from flask import Flask, request, abort

app = Flask(__name__)

def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode('utf-8'),
        raw_body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-HappyColis-Hmac-SHA256', '')
    if not verify_signature(request.get_data(), signature, os.environ['WEBHOOK_SECRET']):
        abort(401)

    payload = request.get_json()
    print(f"Received event: {payload['event']}")
    return '', 200
php
<?php
function verifyWebhookSignature(string $rawBody, string $signature, string $secret): bool
{
    $expected = hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $signature);
}

$rawBody  = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_HAPPYCOLIS_HMAC_SHA256'] ?? '';

if (!verifyWebhookSignature($rawBody, $signature, getenv('WEBHOOK_SECRET'))) {
    http_response_code(401);
    exit('Invalid signature');
}

$payload = json_decode($rawBody, true);
echo 'Received event: ' . $payload['event'];
http_response_code(200);

Best Practices

  1. Always verify the HMAC signature before processing any payload. Reject requests with an invalid or missing signature with HTTP 401.
  2. Respond quickly. Return 200 OK as soon as signature verification passes. Process the payload asynchronously (e.g. enqueue a background job) to avoid timeouts.
  3. Handle duplicates. Use the X-HappyColis-Delivery header as an idempotency key. The same event may be delivered more than once on retry.
  4. Use HTTPS only. Webhook endpoints must use TLS. Plain HTTP endpoints are rejected.
  5. Store your webhook secret securely. Treat the webhook secret like a password — use environment variables or a secrets manager, never hard-code it.
  6. Monitor webhook health. Check the health field on your webhook registration to detect repeated delivery failures.

Operations

OperationTypeDescription
integrationQueryFetch an integration and its webhooks
integrationWebhookCreateMutationSubscribe to a webhook (integration app context)
integrationWebhookRemoveMutationRemove a webhook (integration app context)
oauthWebhookCreateMutationSubscribe to a webhook (OAuth client context)
oauthWebhookRemoveMutationRemove a webhook (OAuth client context)

HappyColis API Documentation