# Guide to CloudSignal Webhooks: Features and Best Practices

CloudSignal webhooks notify your application about print-fulfilment activity: an order is validated, an item is produced, packed, shipped, or errors out. If you're building on Cloudprinter.com, CloudSignal is how you react to order and item status changes without polling.

This guide covers how CloudSignal webhooks work, the events you'll handle, how it authenticates (a body field, not a signature), and the best practices for production.

> This covers CloudSignal, Cloudprinter.com's outbound webhook product. It is not the unrelated cloudsignal.io MQTT platform.

## What are CloudSignal webhooks?

CloudSignal webhooks are JSON POSTs delivered to a URL you configure. Authentication is not an HMAC signature and not Standard Webhooks: each POST carries a plaintext `apikey` field in the JSON body (a per-endpoint Webhook API key, distinct from your account API key). The receiver checks that value. There's no signature header, no timestamp, and no HMAC, so verification is a body-field match.

## CloudSignal webhook features

| Feature | Details |
| --- | --- |
| Configuration | Register an endpoint with a per-endpoint Webhook API key |
| Authentication | Plaintext `apikey` field in the JSON body (not a signature) |
| Acknowledgement | Return HTTP 200 or 204 |
| Retries | Up to 100 times over 7 days until a 200/204 |
| Payload | `type`, `order`, `item`, `order_reference`, `item_reference`, `datetime`, plus type-specific fields |
| Events | PascalCase, case-sensitive |
| SDK | `@cloudprinter/cloudsignal` (npm); no pip |

## Common events

CloudSignal event `type` values are PascalCase and case-sensitive:

| Event | Fires when |
| --- | --- |
| `CloudprinterOrderValidated` | An order is validated |
| `ItemValidated` | An item is validated |
| `ItemProduce` | An item enters production |
| `ItemProduced` | An item is produced |
| `ItemPacked` | An item is packed |
| `ItemShipped` | An item ships (includes `tracking` / `shipping_option`) |
| `ItemError` | An item errors (includes `cause`) |
| `ItemCanceled` | An item is canceled (includes `cause`) |
| `CloudprinterOrderCanceled` | An order is canceled |

Branch on the exact PascalCase `type`, and read the type-specific fields (for example `tracking` on `ItemShipped`).

## Setting up CloudSignal webhooks

Register your endpoint and note the per-endpoint Webhook API key CloudSignal issues, this is the value that arrives in each payload's `apikey` field, and it's distinct from your account API key. Return HTTP 200 or 204 to acknowledge, otherwise CloudSignal retries.

## Securing CloudSignal webhooks

There's no signature to verify. Instead, compare the payload's `apikey` field against the per-endpoint Webhook API key you registered, using a constant-time comparison. Because the key travels in the body, always serve the endpoint over HTTPS and treat the key as a secret.

```javascript
const crypto = require("crypto");

const WEBHOOK_API_KEY = process.env.CLOUDSIGNAL_WEBHOOK_API_KEY;

function verify(body) {
  // Auth is a plaintext apikey field in the body, not a signature. Constant-time compare.
  const a = Buffer.from(body.apikey || "");
  const b = Buffer.from(WEBHOOK_API_KEY);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

app.post("/webhook", express.json(), (req, res) => {
  if (!verify(req.body)) return res.sendStatus(401);

  res.sendStatus(200); // 200 or 204 to acknowledge, else CloudSignal retries
  processQueue.add(req.body); // branch on type, async
});

```

The same check in Python:

```python
import hmac
import os

WEBHOOK_API_KEY = os.environ["CLOUDSIGNAL_WEBHOOK_API_KEY"]

def verify(body: dict) -> bool:
    # Constant-time compare of the body's apikey against the per-endpoint key
    return hmac.compare_digest(body.get("apikey", ""), WEBHOOK_API_KEY)

```

## CloudSignal webhook limitations and pain points

### Authentication is a body field, not a signature

The Problem: There's no signature header. Authenticity rests on a plaintext `apikey` in the body, so anyone who learns the key and your URL can post valid-looking events, and the payload can't be cryptographically verified.

Why It Happens: CloudSignal uses a shared per-endpoint key carried in the body.

Workarounds:

* Serve the endpoint over HTTPS only, treat the key as a secret, rotate it if exposed, and compare it in constant time.

How Hookdeck Can Help: Hookdeck can terminate and check the request at the edge, add its own controls, and give you a managed endpoint in front of your app.

### It's CloudSignal, not cloudsignal.io

The Problem: Two unrelated products share the name. cloudsignal.io is an MQTT platform with no outbound webhooks; applying its model here fails.

Why It Happens: The name collides.

Workarounds:

* Confirm you're integrating Cloudprinter.com's CloudSignal, with the body `apikey` scheme.

How Hookdeck Can Help: Hookdeck verifies each source with its own scheme, so a name collision doesn't lead to the wrong integration.

### The key travels in the body

The Problem: Because the `apikey` is in the payload, it can end up in logs, traces, and stored events, widening its exposure.

Why It Happens: The credential is part of the message.

Workarounds:

* Redact `apikey` from logs and stored payloads, and rotate the key on any suspected exposure.

How Hookdeck Can Help: Hookdeck can handle the credential check centrally, so it isn't spread across every consumer's logs.

### Long retry window

The Problem: CloudSignal retries up to 100 times over 7 days until a 200/204, so a flaky endpoint can receive the same event many times.

Why It Happens: CloudSignal persists retries for a week.

Workarounds:

* Return 200/204 promptly, and dedupe on `item_reference` / `order_reference` so repeats are safe.

How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, so a week of retries doesn't double-process. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

## Best practices

### Compare the body `apikey` in constant time

Match the payload's `apikey` against the per-endpoint Webhook API key with a constant-time comparison, and keep the endpoint HTTPS-only.

### Redact and rotate the key

Keep `apikey` out of logs and stored payloads, and rotate it if exposed.

### Branch on the exact PascalCase type

Handle `ItemShipped`, `ItemError`, and the rest by their exact case-sensitive `type`.

### Return 200/204 and process asynchronously

Acknowledge quickly and defer work to a queue. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

## Conclusion

CloudSignal (Cloudprinter.com) webhooks authenticate with a plaintext `apikey` field in the JSON body, a per-endpoint Webhook API key, not an HMAC signature. Compare it in constant time, keep the endpoint HTTPS-only, redact and rotate the key, branch on the exact PascalCase `type`, and dedupe across the 100-retry, 7-day window.

[Hookdeck](https://hookdeck.com) fronts your endpoint, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique events.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle CloudSignal webhooks reliably in minutes.