Webhooks & Integrations

Connect CreatorDesk with the tools you already use.

17 events, HMAC-signed, no code required via Zapier, Make, or n8n — or use your own webhook endpoint. Newsletter sync, booking backup, Slack notifications, and more.

Test free of charge

How it works

Three steps from an event in CreatorDesk to an action in your target tool.

1

Create webhook

In the CreatorDesk Dashboard under Integrations → Webhooks: enter the target URL, select events, confirm the DPA.

2

Set up your receiver

Zapier, Make, n8n, or your own backend — as long as the endpoint can accept JSON and verify HMAC.

3

Action is triggered

As soon as an event occurs, CreatorDesk sends the payload. Your tool responds automatically — you don't have to touch anything.

Technical docs

All events, headers, HMAC verification, retry behavior, and troubleshooting — the same snippets we show our existing users.

Step-by-Step Guides

Detailed setup paths for the most important tools. Click a service to open its guide.

Recommended event client.created
Recommended platform Zapier (Make.com / n8n analogous)

Step by step

  1. 1

    Create webhook in CreatorDesk

    Dashboard → Integrations → Webhooks → New Webhook. Select event "client.created", leave the URL blank for now, confirm DPA, save.

  2. 2

    Create a new Zap in Zapier

    Trigger: "Webhooks by Zapier" → "Catch Hook" → Continue. Zapier displays a unique URL — copy it.

  3. 3

    Enter the URL in the CreatorDesk webhook

    Go back to the webhook in CreatorDesk, paste the Zapier URL, save.

  4. 4

    Trigger test webhook

    Click "Test Webhook" in CreatorDesk. Click "Test Trigger" in Zapier — the payload should arrive.

  5. 5

    Configure action: MailerLite → Create/Update Subscriber

    Connect your account once via OAuth, then map the fields (see table below).

  6. 6

    Run Test Action + Publish

    In the Zapier editor, click "Test Action" — make sure everything arrives correctly in the target tool. Then click "Publish" in the top right.

Field Mapping

CreatorDesk Field MailerLite Field
client_email Email (required)
client_first_name Name
client_last_name Custom field: Last name
client_phone Custom field: Phone
(statisch) Tags: creatordesk

Tips

  • Zapier accepts without HMAC verification — the catch hook URL is already secret.
  • Syncing multiple events? Create a separate webhook + separate Zap per event.
  • Works the same way with Make.com or n8n — the trigger there is a "Webhook" / "Generic Webhook" respectively, and the action is MailerLite.

Variant B — via a public form

Newsletter signup directly from a public form — no CRM entry required.

Trigger event form.submitted
Advantage Form fields directly as data.*
CreatorDesk Field MailerLite Field
data.email Email (required)
data.vorname Name
(statisch) Tags: newsletter-signup
Recommended event client.created
Recommended platform Zapier (Make.com / n8n analogous)

Step by step

  1. 1

    Create webhook in CreatorDesk

    Dashboard → Integrations → Webhooks → New Webhook. Select event "client.created", leave the URL blank for now, confirm DPA, save.

  2. 2

    Create a new Zap in Zapier

    Trigger: "Webhooks by Zapier" → "Catch Hook" → Continue. Zapier displays a unique URL — copy it.

  3. 3

    Enter the URL in the CreatorDesk webhook

    Go back to the webhook in CreatorDesk, paste the Zapier URL, save.

  4. 4

    Trigger test webhook

    Click "Test Webhook" in CreatorDesk. Click "Test Trigger" in Zapier — the payload should arrive.

  5. 5

    Configure action: Mailchimp → Add/Update Member to List

    Connect your account once via OAuth, then map the fields (see table below).

  6. 6

    Run Test Action + Publish

    In the Zapier editor, click "Test Action" — make sure everything arrives correctly in the target tool. Then click "Publish" in the top right.

Field Mapping

CreatorDesk Field Mailchimp Field
client_email Email Address (required)
client_first_name Merge field FNAME
client_last_name Merge field LNAME
(statisch) Tags: creatordesk

Tips

  • Mailchimp action requires an audience ID — select it once in the Zap editor.
  • Duplicate sign-ups: Mailchimp automatically deduplicates by email address.
  • Works the same way with Make.com or n8n — the trigger there is a "Webhook" / "Generic Webhook" respectively, and the action is Mailchimp.
Recommended event booking.confirmed
Recommended platform Zapier (Make.com / n8n analogous)

Step by step

  1. 1

    Create webhook in CreatorDesk

    Dashboard → Integrations → Webhooks → New Webhook. Select event "booking.confirmed", leave the URL blank for now, confirm DPA, save.

  2. 2

    Create a new Zap in Zapier

    Trigger: "Webhooks by Zapier" → "Catch Hook" → Continue. Zapier displays a unique URL — copy it.

  3. 3

    Enter the URL in the CreatorDesk webhook

    Go back to the webhook in CreatorDesk, paste the Zapier URL, save.

  4. 4

    Trigger test webhook

    Click "Test Webhook" in CreatorDesk. Click "Test Trigger" in Zapier — the payload should arrive.

  5. 5

    Configure action: Brevo → Add or Update Contact

    Connect your account once via OAuth, then map the fields (see table below).

  6. 6

    Run Test Action + Publish

    In the Zapier editor, click "Test Action" — make sure everything arrives correctly in the target tool. Then click "Publish" in the top right.

Field Mapping

CreatorDesk Field Brevo Field
client_email EMAIL (required)
client_first_name FIRSTNAME
client_last_name LASTNAME
slot_date Custom attribute SHOOTING_DATE

Tips

  • Brevo lists must be created in Brevo beforehand — the Zap references them via list ID.
  • Create the custom attribute SHOOTING_DATE in Brevo as a date field, otherwise it will be stored as text.
  • Works the same way with Make.com or n8n — the trigger there is a "Webhook" / "Generic Webhook" respectively, and the action is Brevo.

Variant B — via a public form

Form submissions as Brevo contacts with all form fields as custom attributes.

Trigger event form.submitted
Advantage Form fields directly as data.*
CreatorDesk Field Brevo Field
data.email EMAIL (required)
data.vorname FIRSTNAME
data.nachname LASTNAME
data.* (alle Felder) Custom attribute per form question
Recommended event booking.created
Recommended platform Zapier (Make.com / n8n analogous)

Step by step

  1. 1

    Create webhook in CreatorDesk

    Dashboard → Integrations → Webhooks → New Webhook. Select event "booking.created", leave the URL blank for now, confirm DPA, save.

  2. 2

    Create a new Zap in Zapier

    Trigger: "Webhooks by Zapier" → "Catch Hook" → Continue. Zapier displays a unique URL — copy it.

  3. 3

    Enter the URL in the CreatorDesk webhook

    Go back to the webhook in CreatorDesk, paste the Zapier URL, save.

  4. 4

    Trigger test webhook

    Click "Test Webhook" in CreatorDesk. Click "Test Trigger" in Zapier — the payload should arrive.

  5. 5

    Configure action: ActiveCampaign → Create/Update Contact + Add Tag

    Connect your account once via OAuth, then map the fields (see table below).

  6. 6

    Run Test Action + Publish

    In the Zapier editor, click "Test Action" — make sure everything arrives correctly in the target tool. Then click "Publish" in the top right.

Field Mapping

CreatorDesk Field ActiveCampaign Field
email email (required)
customer_name firstName + lastName (split)
phone phone
(statisch) Tag: creatordesk-lead

Tips

  • Optional: 2nd Zap step "Add Contact to Automation" starts a welcome funnel.
  • For a clean split: add a Formatter step in Zapier between the webhook and the ActiveCampaign action.
  • Works the same way with Make.com or n8n — the trigger there is a "Webhook" / "Generic Webhook" respectively, and the action is ActiveCampaign.

Variant B — via a public form

Public form directly as an ActiveCampaign lead — with form fields as tags.

Trigger event form.submitted
Advantage Form fields directly as data.*
CreatorDesk Field ActiveCampaign Field
data.email email (required)
data.interesse Tag per interest field
form.title Tag: form-<title>
Recommended event invoice.paid
Recommended platform Zapier (Make.com / n8n analogous)

Step by step

  1. 1

    Create webhook in CreatorDesk

    Dashboard → Integrations → Webhooks → New Webhook. Select event "invoice.paid", leave the URL blank for now, confirm DPA, save.

  2. 2

    Create a new Zap in Zapier

    Trigger: "Webhooks by Zapier" → "Catch Hook" → Continue. Zapier displays a unique URL — copy it.

  3. 3

    Enter the URL in the CreatorDesk webhook

    Go back to the webhook in CreatorDesk, paste the Zapier URL, save.

  4. 4

    Trigger test webhook

    Click "Test Webhook" in CreatorDesk. Click "Test Trigger" in Zapier — the payload should arrive.

  5. 5

    Configure action: Slack → Send Channel Message

    Connect your account once via OAuth, then map the fields (see table below).

  6. 6

    Run Test Action + Publish

    In the Zapier editor, click "Test Action" — make sure everything arrives correctly in the target tool. Then click "Publish" in the top right.

Field Mapping

CreatorDesk Field Slack Field
invoice_number insert in message text
total Amount in message text
client.name Client name in message text

Tips

  • Message template: 💰 Invoice #{invoice_number} ({total}€) paid by {client.name}
  • The channel is selected when connecting the Slack account — one per Zap.
  • Works the same way with Make.com or n8n — the trigger there is a "Webhook" / "Generic Webhook" respectively, and the action is Slack.

Variant B — via a public form

"New Form Submission" notify directly in the channel — very popular for lead capture.

Trigger event form.submitted
Advantage Form fields directly as data.*
CreatorDesk Field Slack Field
form.title Form name in message text
data.email Contact email in message text
submission_id Reference ID

1. Overview

For every subscribed event, CreatorDesk sends an HTTP POST to the configured target URL. The body is JSON with an HMAC-SHA256-signed header. On transient errors (5xx, timeout) it retries with exponential backoff up to five times (1m, 5m, 30m, 2h, 12h).

Currently 17 event types are available. You subscribe only to the ones you need per webhook — none are required.

2. Request Headers

Every POST comes with these headers. Custom headers from the webhook configuration are merged, but cannot override reserved X-CreatorDesk-* headers.

Header Example
Content-Typeapplication/json
X-CreatorDesk-Eventclient.created
X-CreatorDesk-Signaturesha256=a1b2c3...
X-CreatorDesk-Timestamp2026-05-12T09:30:00Z
X-CreatorDesk-Request-ID8d3f2e4a-1c5b-...
User-AgentCreatorDesk-Webhooks/1.0

3. Verify HMAC Signature

The signed string is {timestamp}.{raw_body}. Using the webhook secret you can verify that the message genuinely came from CreatorDesk. Use constant-time comparisons (e.g. hmac.compare_digest), not ==.

Python (Flask / Django)

import hmac, hashlib

WEBHOOK_SECRET = "dein_secret_aus_creatordesk"

def verify(request):
    timestamp = request.headers["X-CreatorDesk-Timestamp"]
    received = request.headers["X-CreatorDesk-Signature"]  # "sha256=..."
    body = request.get_data()  # raw bytes, NICHT request.json

    message = f"{timestamp}.".encode() + body
    expected = "sha256=" + hmac.new(
        WEBHOOK_SECRET.encode(), message, hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(expected, received):
        return "invalid signature", 401

    # Replay-Schutz: Timestamp darf nicht aelter als 5 min sein
    # → return 401 bei zu altem Timestamp

    return "ok", 200

Node.js (Express)

const crypto = require("crypto");
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;

// WICHTIG: raw body capturen, nicht JSON-parsen vor verify
app.post("/webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const ts = req.headers["x-creatordesk-timestamp"];
    const received = req.headers["x-creatordesk-signature"];
    const body = req.body;  // Buffer

    const message = Buffer.concat([Buffer.from(ts + "."), body]);
    const expected = "sha256=" + crypto
      .createHmac("sha256", WEBHOOK_SECRET)
      .update(message).digest("hex");

    if (!crypto.timingSafeEqual(
        Buffer.from(expected), Buffer.from(received))) {
      return res.status(401).send("invalid signature");
    }

    const payload = JSON.parse(body.toString());
    // ... verarbeiten
    res.send("ok");
});

PHP

<?php
$secret = getenv("WEBHOOK_SECRET");
$body = file_get_contents("php://input");  // raw bytes
$ts = $_SERVER["HTTP_X_CREATORDESK_TIMESTAMP"];
$received = $_SERVER["HTTP_X_CREATORDESK_SIGNATURE"];

$message = $ts . "." . $body;
$expected = "sha256=" . hash_hmac("sha256", $message, $secret);

if (!hash_equals($expected, $received)) {
    http_response_code(401);
    exit("invalid signature");
}

$payload = json_decode($body, true);
// ... verarbeiten
echo "ok";

4. Example Payloads

One representative example per event category. Fields vary slightly depending on the event — full reference per event type via the same payload builder; only excerpts shown here.

client.created — New contact in CRM
{
  "id": 42,
  "uuid": "8d3f2e4a-1c5b-4d6e-9a8b-7c5d4e3f2a1b",
  "email": "[email protected]",
  "name": "Anna Beispiel",
  "first_name": "Anna",
  "last_name": "Beispiel",
  "company": null,
  "phone": "+49 123 456789",
  "tags": ["Hochzeit", "2026"],
  "project_count": 0,
  "source": "instagram",
  "client_number": "K-2026-0042",
  "created_at": "2026-05-12T09:30:00Z"
}
booking.confirmed — Appointment confirmed
{
  "id": 17,
  "customer_name": "Anna Beispiel",
  "email": "[email protected]",
  "phone": "+49 123 456789",
  "slot_date": "2026-08-14",
  "slot_time_start": "10:00:00",
  "project_id": 38,
  "quote_id": null,
  "booked_at": "2026-05-12T09:15:00Z",
  "confirmed_at": "2026-05-12T09:30:00Z"
}
invoice.paid — Invoice paid
{
  "id": 89,
  "invoice_number": "R-2026-0089",
  "title": "Hochzeit Anna & Tobias",
  "status": "paid",
  "total": "1450.00",
  "subtotal": "1218.49",
  "issue_date": "2026-05-01",
  "due_date": "2026-05-31",
  "paid_at": "2026-05-12T09:30:00Z",
  "client": {
    "id": 42,
    "email": "[email protected]",
    "name": "Anna Beispiel",
    "first_name": "Anna",
    "last_name": "Beispiel"
  },
  "project_id": 38,
  "quote_id": 23
}
order.paid — Gallery order paid
{
  "id": 156,
  "order_number": "GS-2026-00156",
  "gallery_id": 73,
  "customer_email": "[email protected]",
  "customer_name": "Anna Beispiel",
  "total": "199.00",
  "payment_method": "stripe",
  "status": "paid",
  "items": [
    {"id": 412, "product_type": "digital_image_package",
     "quantity": 1, "unit_price": "199.00"}
  ],
  "paid_at": "2026-05-12T09:30:00Z"
}
gallery.published — Gallery published
{
  "id": 73,
  "uuid": "f6146aa2-0335-4af2-8c0f-cfcbb0f7d3d0",
  "title": "Hochzeit Anna & Tobias",
  "status": "published",
  "distribution_mode": "shop",
  "project_id": 38,
  "image_count": 342,
  "allow_sale": true,
  "published_at": "2026-05-12T09:30:00Z"
}
All 17 event types — complete list
client.created Ein Kontakt wurde im CRM angelegt.
client.updated Felder eines Kontakts wurden geaendert.
client.deleted Ein Kontakt wurde geloescht (DSGVO-Loeschungsrecht — Empfaenger sollte lokale Kopie entfernen).
booking.created Ein Kunde hat ueber den Buchungs-Kalender eine Anfrage gestellt (noch nicht bestaetigt).
booking.confirmed Ein Termin wurde bestaetigt (SlotBooking.confirmed_at gesetzt).
project.created Ein neues Projekt wurde im CRM angelegt.
project.status_changed Der Status eines Projekts hat sich veraendert.
quote.created Ein neues Angebot wurde erstellt.
quote.accepted Der Kunde hat ein Angebot akzeptiert.
invoice.issued Eine Rechnung wurde an den Kunden geschickt.
invoice.paid Eine Rechnung wurde als bezahlt markiert.
contract.signed Ein Vertrag wurde vom Kunden unterschrieben.
gallery.published Eine Galerie hat den Status published erhalten.
gallery.delivered Galerie.delivered_at wurde gesetzt — Lieferschein ist raus.
order.paid Ein Endkunde hat eine Galerie-Bestellung bezahlt.
order.shipped Eine Galerie-Bestellung mit Druck-Artikeln wurde versandt.
form.submitted Ein Public-Formular wurde abgeschickt — Payload enthaelt alle Felder.

5. Zapier / Make / n8n — Quickstart

Zapier

  1. New Zap → Trigger: Webhooks by Zapier
  2. Event: Catch Hook → Continue
  3. Copy generated URL
  4. Create a new webhook in CreatorDesk with this URL
  5. Send a test event from CreatorDesk, trigger the Zap test
Official docs →

Make (Integromat)

  1. New Scenario → Webhook Module
  2. Custom Webhook → Add → Save
  3. Copy webhook URL
  4. Create a new webhook in CreatorDesk with this URL
  5. Make is waiting for the first test POST — send a test event
Official docs →

n8n

  1. New Workflow → Webhook Trigger Node
  2. Method: POST, path of your choice
  3. Copy test URL (or production URL after activation)
  4. Create a new webhook in CreatorDesk with this URL
  5. Trigger test event
Official docs →
Tip: Zapier/Make/n8n do not automatically verify the HMAC signature. For production use, add your own filter/function step that checks the signature — otherwise anyone with the URL can send fake events.

6. Retry Behavior

Response Behavior
2xxSuccess, failure_count = 0
4xx (außer 408)Permanent error, no retry — check receiver configuration
5xx / 408 / TimeoutExponential Backoff: 1m → 5m → 30m → 2h → 12h (max. 5 attempts)
5 consecutive failuresWebhook is automatically deactivated

HTTP timeout per attempt: 10 seconds. Design your receiver endpoint to return a 2xx within 10s — and handle heavy processing asynchronously (queue, background worker).

7. Troubleshooting

Webhook not arriving
  • Check: is the webhook active? (detail view shows status badge)
  • Check: is the relevant event subscribed?
  • In the delivery log: is there any entry for the event at all?
  • If not: your existing code may not have performed the save that triggers the event (e.g. .update() instead of .save()).
Delivery status shows failed
  • Click an entry in the delivery log → the response body excerpt shows the error
  • 401 from receiver: HMAC verification failed — wrong secret or body was parsed instead of verified raw
  • 404: Target URL unreachable or path incorrect
  • 5xx from receiver: your endpoint is crashing — check receiver logs
  • Manual re-trigger via the Retry button in the detail view
Webhook was auto-disabled

After 5 consecutive failures, the webhook is automatically deactivated to prevent endless retries on broken receivers. Fix the issue, then reactivate via Activate in the detail view — failure_count will be reset to 0.

Duplicate events

Normally not possible — for status transitions we only fire on a real change (old != new). If it does happen: check whether multiple webhooks are sending the same event to the same URL.

Idempotency on the receiver side: use the X-CreatorDesk-Request-ID header as a dedup key. A manual re-trigger generates a NEW request ID; this is intentional — you really do want to deliver again.

8. GDPR

Outbound webhooks forward client data (name, email, and possibly phone number) to an external recipient. As a photographer, you are responsible for ensuring that a data processing agreement (DPA) exists with the recipient — or that the recipient is your own system.

When creating a webhook in the CRM, you confirm this via a checkbox. The webhook cannot be activated without DPA confirmation.

Data minimization: payloads contain only what is necessary for each event. Address data and phone numbers are deliberately not included unless they are explicitly part of the event.

End-customer right to erasure: on Client.delete we automatically send client.deleted with the email address to all active webhooks — so the receiver can remove its local copy.

FAQ

What happens if my endpoint is down?

CreatorDesk retries on temporary errors (5xx, timeout) with exponential backoff: 1 minute → 5 minutes → 30 minutes → 2 hours → 12 hours. After 5 consecutive failures, the webhook is automatically disabled so you'll notice.

How do I verify that a webhook really comes from CreatorDesk?

Every request is HMAC-SHA256-signed. You verify the signature using your webhook secret — we provide code snippets for Python, Node.js, and PHP above. Zapier/Make don't verify automatically; there you add a filter step.

Which plan do I need?

Webhooks are included in every plan — even the free tier. No additional add-ons required.

Can I also pull data from CreatorDesk instead of just push?

Currently the integration is push-only (webhooks). A pull REST API is planned — if you specifically need it, let us know and we'll prioritize it.

Which 17 events are available?
client.created — Ein Kontakt wurde im CRM angelegt.
client.updated — Felder eines Kontakts wurden geaendert.
client.deleted — Ein Kontakt wurde geloescht (DSGVO-Loeschungsrecht — Empfaenger sollte lokale Kopie entfernen).
booking.created — Ein Kunde hat ueber den Buchungs-Kalender eine Anfrage gestellt (noch nicht bestaetigt).
booking.confirmed — Ein Termin wurde bestaetigt (SlotBooking.confirmed_at gesetzt).
project.created — Ein neues Projekt wurde im CRM angelegt.
project.status_changed — Der Status eines Projekts hat sich veraendert.
quote.created — Ein neues Angebot wurde erstellt.
quote.accepted — Der Kunde hat ein Angebot akzeptiert.
invoice.issued — Eine Rechnung wurde an den Kunden geschickt.
invoice.paid — Eine Rechnung wurde als bezahlt markiert.
contract.signed — Ein Vertrag wurde vom Kunden unterschrieben.
gallery.published — Eine Galerie hat den Status published erhalten.
gallery.delivered — Galerie.delivered_at wurde gesetzt — Lieferschein ist raus.
order.paid — Ein Endkunde hat eine Galerie-Bestellung bezahlt.
order.shipped — Eine Galerie-Bestellung mit Druck-Artikeln wurde versandt.
form.submitted — Ein Public-Formular wurde abgeschickt — Payload enthaelt alle Felder.
Is this GDPR-compliant?

As a photographer, you are responsible for having a data processing agreement (DPA) in place with the webhook recipient — or the recipient is your own system. When creating a webhook, you confirm this via checkbox. For contact deletions, we automatically send a client.deleted event so the recipient can remove their copy.

Set up in 5 minutes

Create a webhook, subscribe to events, connect an action in Zapier/Make/n8n — done. No consulting needed, the docs are enough.