Obvious/Help Center

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:

ParameterTypeDescription
connectionIdstringThe Unified.to connection ID (conn_xxx)
objectTypestringObject to watch (e.g., messaging_message, calendar_event)
eventTypestringEvent 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:

ParameterTypeDescription
resourceNamestringHuman-readable name (e.g., "Pylon Support", "Stripe Payments")
eventsstring[]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:

MethodWhen UsedHeader Format
HMAC-SHA256Most providerssha256=<hex> or plain <hex>
StripeStripe-signature headert=<timestamp>,v1=<sig>
TokenverificationMethod: "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 data field if present, otherwise the full payload.

  • Resource type — from object_type in the payload, or the subscription's resourceType.

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 webhookSecret or signatureHeader changes 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:

  1. Subscription status: Confirm the subscription is active using list or get.

  2. Event type match: events array must include the incoming event type, or ["*"].

  3. Authentication: For URL-secret, confirm the full URL is configured; for signature verification, webhookSecret and signatureHeader must match.

  4. Payload format: Obvious requires a JSON body with Content-Type: application/json; non-JSON payloads are rejected.

  5. 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.

Was this helpful?