Webhooks (Developer Setup)
Published February 27, 2026 · Last updated March 7, 2026 · 4 min read
Obvious webhooks deliver real-time event notifications to your project, routing payloads to actions like triggering tasks, starting agents, or running shell commands. This reference covers how webhook subscriptions work, payload authentication, and action type configuration.
Setup Methods
Every webhook subscription uses one of two setup methods.
Unified (Managed Registration)
For services connected through Obvious's integration layer, Obvious handles webhook registration automatically.
Required parameters:
| Parameter | Type | Description |
|---|---|---|
connectionId | string | The Unified.to connection ID (conn_xxx) |
objectType | string | Object to watch (e.g., messaging_message, calendar_event) |
eventType | string | Event to listen for: created, updated, or deleted |
URL (Manual Registration)
Obvious generates a webhook URL you copy into the provider's settings. Key optional parameters include a slug for a custom URL-safe identifier, webhookSecret for provider-supplied signing, and signatureHeader to specify the header containing the signature.
Required parameters:
| Parameter | Type | Description |
|---|---|---|
resourceName | string | Human-readable name (e.g., "Pylon Support", "Stripe Payments") |
events | string[] | Event types to listen for. Use ["*"] for all events. |
URL Routing & Authentication
Obvious exposes two URL patterns for receiving webhooks. The pattern determines the authentication method.
URL-Secret (3-Segment Path)
POST /webhooks/{projectId}/{subscriptionId}/{secret}
The secret is a cryptographically random token embedded in the URL, requiring no signature verification. This is the default for URL-setup subscriptions without a webhookSecret.
Signature Verification (2-Segment Path)
POST /webhooks/{projectId}/{slugOrId}
Used when the provider signs requests with a shared secret. Obvious verifies the signature using the webhookSecret and signatureHeader. slugOrId accepts a subscription ID (wsub_xxx) or a custom slug.
Supported verification methods:
| Method | When Used | Header Format |
|---|---|---|
| HMAC-SHA256 | Most providers | sha256=<hex> or plain <hex> |
| Stripe | Stripe-signature header | t=<timestamp>,v1=<sig> |
| Token | verificationMethod: "token" | Plain token string |
All comparisons use timing-safe functions to prevent timing attacks.
Payload Format
Obvious accepts JSON payloads — both object and array roots.
After authentication, the event processor extracts:
-
Event type — extracted from provider-specific headers (e.g.,
X-GitHub-Event), then payload fields (e.g.,event). Falls back to"unknown". -
Data — the
datafield if present, otherwise the full payload. -
Resource type — from
object_typein the payload, or the subscription'sresourceType.
Event ID & Deduplication
Every incoming event gets a deterministic ID (whevt_<hash>) for deduplication using Redis SET NX with a one-hour TTL. If Redis is unavailable, events are processed anyway, prioritizing processing over strict deduplication.
Action Types
Each subscription has an actionType that determines what happens when an event arrives. The default is task_trigger.
task_trigger
Matches the event to a task in the project and executes it. Setting actionType: "task_trigger" with actionConfig containing a taskId auto-links the task to the subscription.
{
"actionType": "task_trigger",
"actionConfig": { "taskId": "tsk_abc123" }
}
prompt
Renders a template with the webhook payload and dispatches a new agent thread. The {{payload}} placeholder is replaced with event data; modeId is optional.
{
"actionType": "prompt",
"actionConfig": {
"promptTemplate": "New support ticket received: {{payload}}. Summarize and triage.",
"modeId": "auto"
}
}
shell_command
Runs a command in a sandbox. The payload is available as $WEBHOOK_PAYLOAD and at /tmp/webhook-payload.json.
{
"actionType": "shell_command",
"actionConfig": {
"command": "python3 /home/user/work/sync.py",
"workingDir": "/home/user/work"
}
}
Subscription Lifecycle
Subscriptions can be active (receiving events), paused (ignoring events), or failed. Pause or resume a subscription by updating its status.
Updating Subscriptions
For URL subscriptions, resourceName, events, status, slug, actionType, actionConfig, webhookSecret, and signatureHeader can be updated. Unified subscriptions only allow status updates.
Warning: Changing
webhookSecretorsignatureHeaderchanges the webhook URL, requiring an update in your external service.
Deleting Subscriptions
Deleting a subscription soft-deletes it and removes the webhook trigger from any linked tasks. The response includes the count of affected tasks.
Debugging
When a webhook isn't triggering as expected, check these in order:
-
Subscription status: Confirm the subscription is
activeusinglistorget. -
Event type match:
eventsarray must include the incoming event type, or["*"]. -
Authentication: For URL-secret, confirm the full URL is configured; for signature verification,
webhookSecretandsignatureHeadermust match. -
Payload format: Obvious requires a JSON body with
Content-Type: application/json; non-JSON payloads are rejected. -
Deduplication: Identical payloads within one hour are deduplicated; change a field for repeated testing.
The subscription tracks eventCount, lastEventAt, errorCount, and lastError — all visible from the get operation.
Related Resources
-
Webhooks (UI Setup) — configuring webhooks through the Obvious interface
-
Tasks & Schedules — the automation layer that webhooks trigger