Skip to main content

Getting Started with Hook0

This tutorial will guide you through creating an application and sending your first webhook event. By the end, you will have a working webhook integration.

Prerequisites

  • For Self-Hosted: Docker and Docker Compose installed. 🚨 You'll need to replace the API base URL with your own domain or http://localhost:8081 in the examples.
  • For Cloud: A Hook0 account at hook0.com
  • Basic understanding of HTTP APIs
  • cURL or similar HTTP client
  • Familiarity with Hook0 Core Concepts

Set Up Environment Variables

# Set your service token (from dashboard)
export HOOK0_TOKEN="YOUR_TOKEN_HERE"
export HOOK0_API="https://app.hook0.com/api/v1" # Replace by your domain (or http://localhost:8081 locally)

# Set your application ID (shown in dashboard URL or application details)
export APP_ID="YOUR_APPLICATION_ID_HERE"

Save these values:

# Save to .env file for later use
cat > .env <<EOF
HOOK0_TOKEN=$HOOK0_TOKEN
HOOK0_API=$HOOK0_API
APP_ID=$APP_ID
EOF

Step 1: Start Hook0 (Self-Hosted Only)

Start Hook0 using Docker Compose:

# Clone the repository
git clone https://github.com/hook0/hook0.git
cd hook0

# Start all services
docker-compose up -d

# Wait for services to be ready
sleep 10

# Verify API is running (check swagger endpoint)
curl -s http://localhost:8081/api/v1/swagger.json | head -c 100

Access the dashboard at http://localhost:8001 and create your first organization account.

Self-Hosted Email Verification

For self-hosted instances, after registering you need to verify your email:

  1. Check Mailpit at http://localhost:8025 for the verification email
  2. Click the verification link in the email

The link signs you in and takes you straight to the dashboard — there is no need to log in again.

Without email verification, you'll see an AuthEmailNotVerified error when trying to access the API.

Keep going?

At this point you have two choices:

  • Use the UI tutorial, displayed on the dashboard, for a quick start. You can stop the tutorial right here and let the UI guides you.
  • Skip it and go to step 2

Step 2: Create Your First Application

Applications represent individual services or projects within your organization.

  1. Select your organization in the left sidebar.
  2. At the end, Click "Create new application"
  3. Fill in the Application Name: My First App
  4. Click "Create"

In the header will be displayed an application ID (App ID) that looks like b676db07-5a75-4359-a6ef-89c79706072e. Please keep it, you'll need it for later.

Step 3: Get Your API Token

To send events to Hook0, you need an API token. Creating an application already provisions one for you, named Default, so there is nothing to create here.

  1. Go to API keys in the sidebar of your application.
  2. Copy the token of the Default key - it looks like this: 49757726-4107-45d4-a262-e438d4f17ab4

The ready-to-run snippets on the Send an event page are already filled in with that token, so you can copy one and run it as is.

If your application was created before this behaviour shipped, it has no Default key: Click "Create new API Key" on that same page, give it a name, and copy the new token. That is also how you add more keys (for example one per environment) or rotate the first one.

Treat this token as a credential

An application secret is not limited to sending events: it can also read and manage everything in this application, including its own list of keys. It is confined to this application, and cannot touch another one or your organization. Keep it server-side and out of source control, and revoke it from the API keys page if it ever leaks.

Self-hosted instances

Sending an API key as a Bearer token relies on Hook0's application-secret compatibility mode, which is on by default. If your instance runs with ENABLE_APPLICATION_SECRET_COMPATIBILITY=false, this key will not authenticate anything: use a service token everywhere this tutorial uses $HOOK0_TOKEN.

Step 4: Create an Event Type

Event types define the structure of events your application can send.

- Using the Dashboard:

  1. Navigate to Event Types in your application
  2. Click "Create Event Type"
  3. Define your event type: user.account.created

- OR using the API:

curl -X POST "$HOOK0_API/event_types" \
-H "Authorization: Bearer $HOOK0_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"application_id": "'"$APP_ID"'",
"service": "user",
"resource_type": "account",
"verb": "created"
}'

Response:

{
"service_name": "user",
"resource_type_name": "account",
"verb_name": "created",
"event_type_name": "user.account.created"
}

This creates an event type named user.account.created (composed from service.resource_type.verb).

Step 5: Create a Webhook Subscription

Subscriptions define where Hook0 should send webhook notifications.

For this tutorial, use webhook.site to create a test endpoint:

  1. Visit webhook.site
  2. Copy your unique URL (e.g., https://webhook.site/abc123)
Test webhooks instantly

Use Hook0 Play to generate a webhook URL in one click — no signup required. Paste the URL as your subscription endpoint to see events arrive in real-time.

Create the Subscription

curl -X POST "$HOOK0_API/subscriptions" \
-H "Authorization: Bearer $HOOK0_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"application_id": "'"$APP_ID"'",
"is_enabled": true,
"event_types": ["user.account.created"],
"description": "Tutorial webhook endpoint",
"labels": {
"environment": "tutorial"
},
"target": {
"type": "http",
"method": "POST",
"url": "https://webhook.site/YOUR_UNIQUE_ID",
"headers": {
"X-Custom-Header": "my-value"
}
}
}'

You'll receive a response with the subscription ID and secret:

{
"subscription_id": "{SUBSCRIPTION_ID}",
"secret": "{SECRET}",
...
}

⚠️ Important: Save the secret - you'll need it to verify webhook signatures.

Keep the subscription_id, you'll need it in step 8.

Step 6: Send Your First Event

Now let's trigger a webhook by sending an event to Hook0:

Labels Required

Every event must include at least one label. Labels are used to route events to the correct subscriptions. An empty labels: {} object will be rejected by the API.

curl -X POST "$HOOK0_API/event" \
-H "Authorization: Bearer $HOOK0_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"application_id": "'"$APP_ID"'",
"event_type": "user.account.created",
"payload": "{\"user_id\": 123, \"email\": \"[email protected]\"}",
"payload_content_type": "application/json",
"labels": {
"environment": "tutorial"
},
"occurred_at": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
}'
Payload Format

The payload field must be a JSON-encoded string, not a raw object. See Understanding Payload Format below for details.

Understanding Payload Format

A common source of confusion is the payload format. The payload field must be a JSON-encoded string, not a JavaScript/JSON object.

Why String Format?

Hook0 forwards payloads exactly as received without re-serialization. This ensures:

  • No data transformation or modification
  • Preserved formatting and whitespace
  • Support for any content type (not just JSON)
  • Zero overhead processing

Correct vs Incorrect Format

✅ Correct - String with escaped quotes:

{
"event_type": "user.account.created",
"payload": "{\"user_id\": \"123\", \"email\": \"[email protected]\"}",
"payload_content_type": "application/json"
}

❌ Incorrect - Raw object:

{
"event_type": "user.account.created",
"payload": {"user_id": "123", "email": "[email protected]"},
"payload_content_type": "application/json"
}

Expected Response

{
"application_id": "{APP_ID}",
"event_id": "{EVENT_ID}",
"received_at": "2024-01-15T10:30:01Z"
}

Step 7: Verify Webhook Delivery

  1. Check webhook.site - you should see a new request containing your event payload.

  2. Check the Hook0 dashboard - navigate to Request Attempts to see:

    • Event details
    • Delivery status
    • Retry attempts (if any)

Step 8: Verify Webhook Signature

Hook0 signs all webhook deliveries with HMAC-SHA256. You should always verify signatures to ensure webhooks are authentic.

Forgot your application secret?

You can get it with:

curl "$HOOK0_API/subscriptions/$SUBSCRIPTION_ID?application_id=$APP_ID" \
-H "Authorization: Bearer $HOOK0_TOKEN"

Note the secret field in the response.

Verify the Signature

See Implementing Webhook Authentication for complete signature verification code in JavaScript, Python, and Go.

🎉 Congrats, you made it to the end!

What You've Learned

✅ Created a Hook0 organization and application
✅ Used the API token that came with your application
✅ Defined event types for your application
✅ Set up webhook subscriptions
✅ Sent events through the Hook0 API
✅ Verified webhook delivery and signatures

Next Steps

Now that you have the basics, try these advanced tutorials:

Common Issues

Event Not Delivered

  • Check subscription is enabled
  • Verify event type and labels match subscription
  • Check that the URL you specified as target in your subscription is accessible

Authentication Errors

  • Ensure token has correct permissions
  • Check token hasn't expired
  • Verify Bearer token format
  • Test with a fresh token

Signature Verification Failed

  • Use the raw request body for signature verification
  • Check secret is correct
  • Ensure consistent character encoding
  • Verify HMAC algorithm (SHA256)

API Reference