# Cloudsmith Webhooks

## When to Use This Skill

* How do I receive Cloudsmith webhooks?
* How do I verify the `X-Cloudsmith-Signature` header?
* How do I handle `package.created`, `package.synced` or `package.security_scanned` events?
* Why is my Cloudsmith webhook signature verification failing?
* Why are my Cloudsmith webhook deliveries unsigned?

## Setup note

Set an HMAC signature key on the Cloudsmith webhook. Without one, deliveries are unsigned and fail verification.

## Verification (core)

Cloudsmith signs the **raw request body bytes** with HMAC-SHA1, keyed with the webhook's HMAC Signature Key (UTF-8, used as-is), and sends the bare lowercase hex digest (40 characters) in `X-Cloudsmith-Signature`. There is no prefix and no timestamp; the whole header value is the digest. Validate the format before decoding, then compare in constant time.

Node:

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

function verify(rawBody /* Buffer */, signature, secret) {
  if (!signature || !secret || !/^[0-9a-fA-F]{40}$/.test(signature)) return false;
  const expected = crypto.createHmac('sha1', secret).update(rawBody).digest();
  const received = Buffer.from(signature, 'hex'); // safe: format validated above
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

```

Python:

```python
import hashlib, hmac, re

def verify(raw_body: bytes, signature: str | None, secret: str | None) -> bool:
    if not signature or not secret or not re.fullmatch(r"[0-9a-fA-F]{40}", signature):
        return False
    expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha1).digest()
    return hmac.compare_digest(bytes.fromhex(signature), expected)

```

Read the body as raw bytes (`express.raw({ type: '*/*' })`, `await request.arrayBuffer()`, `await request.body()`) and parse JSON only after the check. A missing, empty, malformed or mismatching signature gets `401`.

> **For complete handlers with route wiring, event dispatch, and tests**, see:
> 
> * [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/cloudsmith-webhooks/examples/express/)
> * [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/cloudsmith-webhooks/examples/nextjs/)
> * [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/cloudsmith-webhooks/examples/fastapi/)

## Event Types

Dispatch on the body's `meta.event_id`. The event is not in a header.

| `meta.event_id` | Triggered when |
| --- | --- |
| `ping` | You send a test from the webhook's page |
| `package.created` | A package is uploaded |
| `package.syncing` | A package starts syncing |
| `package.synced` | A package is fully synchronised and ready |
| `package.security_scanned` | A security scan finishes |
| `package.quarantined` | A package is quarantined |
| `package.failed` | A package fails to sync |
| `package.released` | A package is released |
| `package.restored` | A package is restored |
| `package.tags_updated` | A package's tags change |
| `package.deleted` | A package is deleted |

`meta.event_id` is reliably there only for the default **JSON Object** payload format. The JSON Array format wraps the object in `[...]`, Form Encoded sends `payload=<url-encoded JSON>`, and a Handlebars template sends whatever it emits. Keep the default format unless you handle the others.

> **For payload examples**, see [Cloudsmith webhooks](https://docs.cloudsmith.com/developer-tools/webhooks)

## Important Headers

| Header | Description |
| --- | --- |
| `X-Cloudsmith-Signature` | Bare hex HMAC-SHA1 of the raw body (only when a signature key is set) |
| Secret Header / Secret Value | Optional custom header you define on the webhook, sent with every delivery |

## Environment Variables

```bash
CLOUDSMITH_WEBHOOK_SECRET=your_hmac_signature_key   # "HMAC Signature Key" of the webhook; it can be replaced but not read back

```

## Local Development

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

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/cloudsmith-webhooks/references/overview.md) - Cloudsmith webhook concepts and events
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/cloudsmith-webhooks/references/setup.md) - Creating and configuring a webhook
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/cloudsmith-webhooks/references/verification.md) - Signature verification details