Webhooks
Test your webhook endpoint to verify it can receive notifications from meter.
Test webhook delivery
Send a sample webhook payload to verify your endpoint is configured correctly.
Request body
{
"webhook_url": "https://your-app.com/webhooks/meter"
}
| Field | Type | Required | Description |
|---|
webhook_url | string | Yes | The webhook URL to test |
Response
{
"success": true,
"status_code": 200,
"message": "Webhook delivered successfully"
}
| Field | Type | Description |
|---|
success | boolean | Whether the webhook was delivered successfully (2xx response) |
status_code | integer | HTTP status code returned by your endpoint (0 if request failed) |
message | string | Human-readable result message |
Example
curl -X POST https://api.meter.sh/api/webhooks/test \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://my-app.com/webhook"
}'
Meter sends webhooks for both successful and failed jobs. The payload structure differs based on the job status.
Success payload
Sent when a job completes successfully:
{
"job_id": "660e8400-e29b-41d4-a716-446655440000",
"schedule_id": "880e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"url": "https://example.com/products",
"results": [
{"title": "Sample Product A", "price": "$19.99"},
{"title": "Sample Product B", "price": "$29.99"}
],
"item_count": 2,
"has_changes": true,
"content_hash": "7f3d9a2b4c1e5f8a9b0c1d2e3f4a5b6c",
"completed_at": "2025-01-15T10:30:12Z",
"metadata": {"project": "my-project"}
}
| Field | Type | Description |
|---|
job_id | UUID | ID of the scrape job |
schedule_id | UUID | ID of the schedule that triggered the job |
status | string | Always completed for success webhooks |
url | string | The URL that was scraped |
results | array | Extracted data from the page |
item_count | integer | Number of items extracted |
has_changes | boolean | Whether content changed since last run |
content_hash | string | Hash of the extracted content |
completed_at | datetime | When the job completed |
metadata | object | Custom JSON metadata from webhook_metadata (if configured) |
Failure payload
Sent when a job fails:
{
"job_id": "660e8400-e29b-41d4-a716-446655440000",
"schedule_id": "880e8400-e29b-41d4-a716-446655440000",
"status": "failed",
"url": "https://example.com/products",
"error": "Page not accessible: 404 Not Found",
"completed_at": "2025-01-15T10:30:12Z",
"metadata": {"project": "my-project"}
}
| Field | Type | Description |
|---|
job_id | UUID | ID of the scrape job |
schedule_id | UUID | ID of the schedule that triggered the job |
status | string | Always failed for failure webhooks |
url | string | The URL that failed to scrape |
error | string | Error message describing what went wrong |
completed_at | datetime | When the job failed |
metadata | object | Custom JSON metadata from webhook_metadata (if configured) |
Failure webhooks do not include results, item_count, has_changes, or content_hash fields.
Webhook types
Meter supports two webhook formats:
| Type | Description |
|---|
standard | Full JSON payload (default) |
slack | Formatted Slack message text |
The type is auto-detected from the URL — if it contains hooks.slack.com, Meter uses the Slack format. You can also set webhook_type explicitly when creating a schedule.
Webhook secrets
When a schedule has a webhook_url, Meter auto-generates a secret with a whsec_ prefix. The secret is sent in the X-Webhook-Secret header on every webhook delivery. Verify this header to ensure requests are from Meter.
See the Webhooks Guide for verification examples.
Retry behavior
Failed deliveries are retried up to 5 times with exponential backoff: 15 minutes, 30 minutes, 1 hour, 2 hours, 4 hours.
- 2xx: Success, no retry
- 4xx: Permanent failure, no retry
- 5xx / timeout / connection error: Retries with backoff
Error responses
| Status | Description |
|---|
400 | Invalid request (missing webhook_url) |
401 | Invalid or missing API key |
422 | Invalid URL format |
500 | Internal server error |
503 | Service temporarily unavailable |
See REST API Errors for detailed error handling.
Next steps