Webhooks

Subscribe to real-time events and integrate CraftDesk with your workflow.

Webhooks

Webhooks allow your applications to receive real-time notifications when events happen in CraftDesk. Instead of continuously polling the API for changes, subscribe to events and react immediately when they occur.

How Webhooks Work

When you subscribe to a webhook:

  1. You specify an event type (e.g., "project.created")
  2. CraftDesk sends an HTTP POST request to your endpoint with event details
  3. Your application receives the notification and responds with HTTP 200
  4. CraftDesk retries failed deliveries for up to 24 hours

This is much more efficient than polling and enables real-time integrations.

Subscribing to Events

Set up webhooks in SettingsIntegrationsWebhooks:

  1. Click Add Webhook
  2. Enter the URL where you want to receive notifications
  3. Select which events to subscribe to
  4. Optionally, set a custom secret for payload verification
  5. Click Create

Your endpoint should be a publicly accessible HTTPS URL that accepts POST requests.

Supported Events

CraftDesk currently supports these webhook events:

Project Events

  • project.created — A new project was created
  • project.updated — Project settings were modified
  • project.deleted — A project was deleted
  • project.archived — A project was archived
  • project.unarchived — An archived project was restored

Member Events

  • member.invited — A team member was invited
  • member.joined — An invited member accepted and joined
  • member.role_changed — A member's role was updated
  • member.removed — A member was removed from the workspace

Task Events

  • task.created — A new task was created
  • task.updated — A task was modified
  • task.completed — A task was marked complete
  • task.deleted — A task was deleted

Subscription Events

  • subscription.created — A new subscription started
  • subscription.upgraded — A subscription was upgraded
  • subscription.downgraded — A subscription was downgraded
  • subscription.cancelled — A subscription was cancelled

Webhook Payload Structure

Webhook payloads are JSON POST requests with this structure:

{
  "id": "evt_550e8400e29b41d4a716446655440000",
  "event": "project.created",
  "timestamp": "2025-03-23T14:35:21Z",
  "workspace_id": "ws_550e8400e29b41d4a716446655440000",
  "data": {
    "id": "proj_550e8400e29b41d4a716446655440000",
    "name": "Website Redesign",
    "slug": "website-redesign",
    "description": "Modernize our web presence",
    "created_at": "2025-03-23T14:35:21Z"
  }
}

Key Fields

  • id — Unique event identifier
  • event — The event type that triggered this notification
  • timestamp — When the event occurred (ISO 8601 format)
  • workspace_id — The workspace where the event occurred
  • data — Event-specific details

Verifying Webhook Signatures

Verify that webhooks come from CraftDesk by checking the signature. Every webhook includes an X-Webhook-Signature header containing an HMAC-SHA256 hash of the payload:

import hmac
import hashlib
import json

def verify_webhook(payload_body, signature, secret):
    """Verify that a webhook came from CraftDesk."""
    expected_signature = hmac.new(
        secret.encode(),
        payload_body.encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected_signature)

# In your Flask handler
@app.route("/webhooks/craftdesk", methods=["POST"])
def handle_webhook():
    payload = request.get_data()
    signature = request.headers.get("X-Webhook-Signature")

    if not verify_webhook(payload, signature, os.getenv("WEBHOOK_SECRET")):
        return "Unauthorized", 401

    event = json.loads(payload)

    if event["event"] == "project.created":
        # Handle project creation
        project = event["data"]
        print(f"New project: {project['name']}")

    return "OK", 200

Handling Webhook Events

Your endpoint should respond with HTTP 200 within 30 seconds to acknowledge receipt. Process events asynchronously to avoid timeouts:

@app.route("/webhooks/craftdesk", methods=["POST"])
def handle_webhook():
    event = request.json

    # Queue the event for async processing
    background_job.queue("process_webhook", event)

    # Return immediately
    return "OK", 200

def process_webhook(event):
    """Process webhook asynchronously."""
    if event["event"] == "member.joined":
        new_member = event["data"]
        send_welcome_email(new_member["email"])
    # ... handle other events

Retry Policy

CraftDesk retries failed deliveries with exponential backoff:

  • 1st attempt: Immediately
  • 2nd attempt: 5 minutes later
  • 3rd attempt: 30 minutes later
  • 4th attempt: 2 hours later
  • 5th attempt: 24 hours later

If all retries fail after 24 hours, the webhook event is marked failed. Check your webhook status in the dashboard to see delivery history.

Testing Webhooks Locally

Use a tool like ngrok to expose your local development server:

# In one terminal, start your app
python app.py

# In another terminal, expose it to the internet
ngrok http 5000

Then register the ngrok URL (e.g., https://xyz.ngrok.io/webhooks/craftdesk) in the CraftDesk dashboard. Use CraftDesk's webhook testing tools to send test events to your endpoint.

Webhook Best Practices

Always Verify Signatures — Never trust webhooks without signature verification.

Idempotency — Handle duplicate webhook deliveries gracefully. Use the event id to deduplicate.

Fast Responses — Return HTTP 200 quickly. Process events asynchronously.

Error Handling — Log failures and monitor webhook health. Return non-200 to trigger retries for genuine failures.

Rate Limiting — Be prepared for many simultaneous webhook deliveries during large operations.

Monitoring Webhooks

In SettingsIntegrationsWebhooks, you can:

  • View delivery history for each webhook
  • See response status codes and error messages
  • Manually retry failed deliveries
  • Temporarily disable webhooks for debugging

What's Next

  • API Overview — Understand the CraftDesk API
  • Authentication — Manage API keys
  • API Reference — Complete webhook payload documentation (craftdesk.app/api/docs)