Webhooks

Receive real-time notifications when events happen in your TruCustom account.

Overview

Webhooks allow your application to receive HTTP POST notifications when specific events occur, such as when a customer finalizes a design. This enables you to build reactive integrations without polling the API.

Available Events

Event Description
design.created A new design session was started
design.updated A design was saved/updated
design.finalized A design was finalized (customer completed customization)
product.synced Products were synced from your e-commerce platform

Webhook Payload

All webhook payloads follow this structure:

{
  "event": "design.finalized",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "id": "design-uuid",
    "session_token": "abc123...",
    "product_id": "product-uuid",
    "product_name": "Custom T-Shirt",
    "store_id": "store-uuid",
    "status": "finalized",
    "preview_url": "https://...",
    "canvas_data": { ... }
  }
}

Configuring Webhooks

Webhook endpoints are configured per-store in your e-commerce platform settings. The customizer will POST to your platform's webhook endpoint when events occur.

Swell Integration

For Swell stores, webhooks are automatically registered when you connect your store:

POST https://trucustom.net/webhooks/swell

ShopStack Integration

For ShopStack stores:

POST https://trucustom.net/webhooks/shopstack

Verifying Webhooks

All webhook requests include a signature header for verification. Verify this signature to ensure the webhook came from TruCustom.

Signature Header

X-TC-Signature: sha256=abc123...

Verification Example (Ruby)

def verify_webhook(payload, signature, secret)
  expected = "sha256=" + OpenSSL::HMAC.hexdigest(
    "SHA256",
    secret,
    payload
  )
  Rack::Utils.secure_compare(expected, signature)
end

# In your controller
def webhook
  payload = request.raw_post
  signature = request.headers["X-TC-Signature"]

  unless verify_webhook(payload, signature, ENV["WEBHOOK_SECRET"])
    head :unauthorized
    return
  end

  # Process the webhook
  event = JSON.parse(payload)
  # ...
end

Verification Example (Node.js)

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

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

// In your Express route
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-pc-signature'];

  if (!verifyWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);
  // Process the webhook
  res.status(200).send('OK');
});

Responding to Webhooks

Your endpoint should respond with a 2xx status code within 30 seconds.

  • 200 OK - Webhook received and processed
  • 202 Accepted - Webhook received, will process asynchronously

Retry Policy

If your endpoint fails to respond, we'll retry with exponential backoff:

  • 1st retry: 1 minute
  • 2nd retry: 5 minutes
  • 3rd retry: 30 minutes
  • 4th retry: 2 hours
  • 5th retry: 12 hours (final)

Best Practices

  • Respond quickly - Return a 2xx immediately, process async if needed
  • Handle duplicates - Webhooks may be sent more than once
  • Verify signatures - Always validate the webhook signature
  • Use HTTPS - Only HTTPS endpoints are supported
  • Log everything - Keep logs for debugging