# Leonardo.Ai Webhooks

Leonardo.Ai (the generative image API) can POST a JSON webhook callback when an image generation
finishes. Callbacks are **not signed**. If you set a webhook callback API key, Leonardo.Ai sends it
in the `Authorization: Bearer <key>` header of every callback, and your endpoint authenticates the
request by comparing it with the key you stored.

Hookdeck's source type is `LEONARDO_AI` (labelled "Leonardo.Ai"). Its setup note is: "Set a webhook callback API key on the production API key, then paste it here."

## When to Use This Skill

* How do I receive Leonardo.Ai webhook callbacks?
* How do I verify the `Authorization: Bearer` header on a Leonardo.Ai webhook?
* Does Leonardo.Ai sign webhook payloads? (No: use the callback API key)
* How do I handle `image_generation.complete` events?
* Why does my Leonardo.Ai webhook endpoint return 401?

## Verification (core)

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

function verifyLeonardoRequest(headers, configured = process.env.LEONARDO_AI_WEBHOOK_SECRET) {
  if (!configured) return false;                          // never accept when unconfigured
  // Store the bare key; tolerate a pasted "Bearer <key>" like Hookdeck does.
  const secret = /^bearer /i.test(configured) ? configured.slice(7) : configured;
  if (!secret) return false; // a configured value of just "Bearer " must not match
  const header = headers['authorization'] || '';
  if (!/^bearer /i.test(header)) return false;           // scheme is case-insensitive (RFC 9110)
  const received = Buffer.from(header.slice(7));
  const expected = Buffer.from(secret);
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

```

* Header: `Authorization: Bearer <webhook callback API key>`. Store only the key in
  `LEONARDO_AI_WEBHOOK_SECRET`; don't trim or alter it.
* Missing header, wrong scheme or mismatch: return `401`. Invalid JSON: `400`. Handled: `200`.
* Read the body raw (`express.raw({ type: '*/*' })`) and authenticate before parsing it.
* **A static shared credential authenticates the sender, not the body, and gives no replay
  protection** (no signature, no timestamp). Use HTTPS only, and rotate the key if it leaks.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/leonardo-ai-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/leonardo-ai-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/leonardo-ai-webhooks/examples/fastapi/).

## Event Types

Dispatch on the `type` field. The payload is `{type, object, timestamp (ms), api_version, data: {object}}`.

| Event | Sent When |
| --- | --- |
| `image_generation.complete` | An image generation made with the production API key finishes; `data.object` is the generation (`id`, `status`, `images`, ...) |

Acknowledge (`200`) any other `type` so new event types don't cause retries or alerts.

## Environment Variables

```bash
LEONARDO_AI_WEBHOOK_SECRET=your-webhook-callback-api-key   # the bare key, without "Bearer "

```

The callback URL and key are optional settings on a production API key. Changing them means
creating a new production API key, so update the variable when you do.

## Local Development

Leonardo.Ai can't reach `localhost`. Tunnel with the Hookdeck CLI (no account required):

```bash
npx hookdeck-cli listen 3000 leonardo-ai --path /webhooks/leonardo-ai

```

Use the printed URL as the webhook callback URL on the production API key.

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/leonardo-ai-webhooks/references/overview.md) - What Leonardo.Ai webhooks are, event and payload shape
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/leonardo-ai-webhooks/references/setup.md) - Set the callback URL and API key
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/leonardo-ai-webhooks/references/verification.md) - Bearer check details, gotchas, debugging 401s
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/leonardo-ai-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests