Agent skill

CloudSignal Webhooks Skill

Receive and verify CloudSignal webhooks from Cloudprinter.com. Use when setting up a CloudSignal Webhooks v2.0 receiver, authenticating deliveries by the plaintext `apikey` field in the JSON body (there is NO HMAC signature header), or handling print order/item status signals like CloudprinterOrderValidated, ItemProduced, ItemShipped, ItemError, and ItemCanceled.

Install this skill

npx skills add hookdeck/webhook-skills --skill cloudsignal-webhooks


CloudSignal is Cloudprinter.com's outbound webhook product. It HTTPS-POSTs JSON signals to an endpoint you register, notifying your app as a print order and its items move through fulfilment (validated → produced → packed → shipped), or when something errors or is canceled.

Not to be confused with the unrelated cloudsignal.io MQTT platform. This skill is for Cloudprinter.com CloudSignal Webhooks v2.0.

When to Use This Skill

  • How do I receive CloudSignal / Cloudprinter.com webhooks?
  • How do I authenticate a CloudSignal webhook without a signature header?
  • Why is there no X-CloudSignal-Signature / HMAC to verify?
  • How do I handle ItemShipped, ItemError, or CloudprinterOrderCanceled signals?
  • What are the CloudSignal event/signal type values?

Verification (core)

CloudSignal has NO signature header, no HMAC, no timestamp, and is NOT Standard Webhooks. Each POST carries a plaintext, per-endpoint Webhook API key in the JSON body's apikey field (this is different from your account API key). Authenticate by comparing that value against the key you configured, using a timing-safe comparison. Because the key lives inside the body, ordinary JSON parsing is the verification step — there is no raw-body signature to protect.

const crypto = require('crypto');

function safeEqual(a, b) {
  const ab = Buffer.from(a), bb = Buffer.from(b);
  // timingSafeEqual throws on length mismatch — guard first
  return ab.length === bb.length && crypto.timingSafeEqual(ab, bb);
}

// `providedKey` is body.apikey; `expectedKey` is CLOUDSIGNAL_WEBHOOK_APIKEY
function verifyApiKey(providedKey, expectedKey) {
  if (!providedKey || !expectedKey) return false;
  return safeEqual(providedKey, expectedKey);
}

Return 200 (or 204) to acknowledge. Any other status makes CloudSignal retry the signal — up to 100 attempts over 7 days. Return 401 for a missing/incorrect apikey.

Official SDK (@cloudprinter/cloudsignal) exists but is a standalone Node HTTP server (new CloudSignal.EventHandler(apikey, port)) that listens on its own port and emits events — it cannot be mounted as an Express/Next.js/FastAPI route. Its internal check is exactly the body.apikey === expectedKey above. The examples below verify manually so the handler fits your existing app; use the SDK only for a greenfield standalone Node receiver.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Signal Types

Nine signal type values (case-sensitive, PascalCase):

typeFires WhenNotable fields
CloudprinterOrderValidatedOrder received and validatedorder, order_reference
ItemValidatedAn item is validated by productionitem, item_reference
ItemProduceProduction of an item startsitem
ItemProducedProduction of an item completesitem
ItemPackedAn item is packeditem
ItemShippedAn item is dispatchedtracking, shipping_option
ItemErrorA production issue occurscause (optional)
ItemCanceledAn item is canceled in productioncause (optional)
CloudprinterOrderCanceledThe whole order is canceledorder, order_reference

Common fields on every signal: apikey, type, order, datetime. Most also carry item, order_reference, and item_reference. See references/overview.md for the full payload.

Environment Variables

CLOUDSIGNAL_WEBHOOK_APIKEY=your_webhook_api_key   # per-endpoint Webhook API key, from the Cloudprinter.com Dashboard

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 cloudsignal --path /webhooks/cloudsignal

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Aug 6, 2026

View on GitHub →