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.
For self-hosted instances, after registering you need to verify your email:
- Check Mailpit at http://localhost:8025 for the verification email
- 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.
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.
- Select your organization in the left sidebar.
- At the end, Click "Create new application"
- Fill in the Application Name: My First App
- 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.
- Go to API keys in the sidebar of your application.
- 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.
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.
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:
- Navigate to Event Types in your application
- Click "Create Event Type"
- 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:
- Visit webhook.site
- Copy your unique URL (e.g.,
https://webhook.site/abc123)
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:
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_content_type": "application/json",
"labels": {
"environment": "tutorial"
},
"occurred_at": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
}'
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_content_type": "application/json"
}
❌ Incorrect - Raw object:
{
"event_type": "user.account.created",
"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
-
Check webhook.site - you should see a new request containing your event payload.
-
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.
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:
- Building Your First Webhook Integration
- Setting up Event Types and Subscriptions
- Implementing Webhook Authentication
- Webhook best practices - Production patterns for payload design, retries, and security
- Webhook retry logic - How Hook0 handles failed deliveries
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)