Skip to main content

Webhooks

Fuuffy will notify your application when subscribed order events occur. Instead of polling the API for updates, configure an HTTPS endpoint and Fuuffy will send an HTTP POST request when an event is triggered.

How it works

  1. An order event occurs in Fuuffy.
  2. Fuuffy sends a JSON payload to your HTTPS endpoint.
  3. Your endpoint verifies and accepts the request.
  4. Your endpoint returns HTTP 200 to acknowledge receipt.

Endpoint requirements

Your webhook endpoint should:

  • Accept HTTPS POST requests.
  • Respond with HTTP 200 within 15 seconds.
  • Acknowledge the request immediately and process the event asynchronously whenever possible.
  • Implement idempotent event handling, as the same event may be delivered more than once.
  • Return HTTP 200 only after the request has been successfully accepted.

Fuuffy delivers webhooks only to HTTPS endpoints. Treat your webhook endpoint as a production integration and store all related credentials securely.

Delivery & retry policy

If a webhook delivery fails because your endpoint does not return HTTP 200 or cannot be reached, Fuuffy automatically retries the delivery using exponential backoff.

  • Maximum retry attempts: 5
  • Retry strategy: Exponential backoff
  • Duplicate deliveries: The same webhook event may be delivered multiple times.

Your application should process events idempotently.

Delivery behavior


ConditionStatus codeBehavior
Successful acknowledgement200Delivery succeeds.
Failed acknowledgementAny status other than 200Delivery is treated as failed and may be retried.
Timeout or connection failureNo status code receivedDelivery is treated as failed and may be retried.

Securing webhook requests

Fuuffy supports two independent mechanisms for authenticating webhook requests. You may use either or both depending on your security requirements.


MechanismDescriptionExample
Authentication headerA configurable header containing your shared token.Authorization, X-API-Key
HMAC signatureAn HMAC-SHA256 signature generated using your webhook_secret.X-Signature

A unique webhook_secret is generated when your webhook endpoint is configured.

If the secret is ever compromised, contact our Support team to generate a new one.

Treat both your authentication token and webhook_secret as sensitive credentials and store them securely.


Request

Header Parameters


ParameterTypeRequiredExampleDescription
Content-TypestringYesapplication/jsonRequest body content type.
Authorization (or your configured header)stringYesyour-configured-tokenAuthentication token configured for your webhook.
X-SignaturestringYest=1492774577,v1=5257a869e7ecebeda32...HMAC signature for verifying the request.

Example request

Payload fields vary depending on the event type configured for your webhook. The endpoint path is controlled by your application.

curl -X POST "https://your-server.com/webhooks/fuuffy" \
-H "Content-Type: application/json" \
-H "Authorization: your-configured-token" \
-H "X-Signature: t=1492774577,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd" \
-d '{
"invoice_number": "#12345",
"carrier": "UPS",
"tracking_number": "1Z999AA10123456784"
}'

Verifying the signature

When a webhook_secret is configured, every webhook request includes an X-Signature header.

X-Signature: t=<unix_timestamp>,v1=<signature>

Where:

  • t — Unix timestamp indicating when the request was signed.
  • v1 — HMAC-SHA256 signature (hex encoded) generated using {timestamp}.{raw_request_body} and your full webhook_secret (including the whsec_ prefix).

Example signed payload:

1492774577.{"invoice_number":"#12345","carrier":"UPS","tracking_number":"1Z999AA10123456784"}

Verification steps

  1. Read the X-Signature header and extract the t and v1 values.
  2. Read the raw request body exactly as received. The signature is calculated from the exact request body, so any change to whitespace, formatting, or property ordering will cause verification to fail.
  3. Construct the signed payload: {timestamp}.{raw_body}.
  4. Compute the HMAC-SHA256 digest using your webhook_secret.
  5. Compare the computed digest with v1 using a constant-time comparison function.
  6. Reject requests where the timestamp differs from your server time by more than 10 minutes to help prevent replay attacks. Recommended

Code examples

PHP

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

$t = $v1 = null;
foreach (explode(',', $header) as $part) {
[$k, $v] = array_pad(explode('=', trim($part), 2), 2, null);
if ($k === 't') $t = $v;
if ($k === 'v1') $v1 = $v;
}

if ($t === null || $v1 === null) {
http_response_code(401);
exit;
}

$signedPayload = $t . '.' . $rawBody;
$expected = hash_hmac('sha256', $signedPayload, $webhookSecret);

if (!hash_equals($expected, $v1)) {
http_response_code(401);
exit;
}

// Signature verified.
// You may now safely decode and process the payload.
$data = json_decode($rawBody, true);

Node.js

const crypto = require('crypto');

function verifyWebhook(rawBody, signatureHeader, webhookSecret) {
const parts = Object.fromEntries(
signatureHeader.split(',').map((p) => p.trim().split('='))
);

const t = parts.t;
const v1 = parts.v1;

if (!t || !v1) return false;

const signedPayload = `${t}.${rawBody}`;

const expected = crypto
.createHmac('sha256', webhookSecret)
.update(signedPayload, 'utf8')
.digest('hex');

return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(v1)
);
}

Python

import hashlib
import hmac

def verify_webhook(raw_body: bytes, signature_header: str, webhook_secret: str) -> bool:
parts = dict(
p.strip().split("=", 1)
for p in signature_header.split(",")
)

t = parts.get("t")
v1 = parts.get("v1")

if not t or not v1:
return False

signed_payload = f"{t}.".encode() + raw_body

expected = hmac.new(
webhook_secret.encode(),
signed_payload,
hashlib.sha256,
).hexdigest()

return hmac.compare_digest(expected, v1)

Best practices

  • Verify the X-Signature before processing the payload.
  • Acknowledge requests quickly and process events asynchronously.
  • Implement idempotent handlers because webhook deliveries may be retried.
  • Avoid long-running operations before returning HTTP 200.

Enable webhooks

To register a webhook endpoint, contact our Support team at support@fuuffy.com.

After your endpoint is configured, you can:

  • Subscribe to the required event types.
  • Process events as they are delivered.