hogsend-webhooks-and-workflows

star 3

Use when adding an inbound webhook source in src/webhook-sources/ (defineWebhookSource — auth as a match|signature discriminated union, optional Zod schema, transform(payload, ctx) -> IngestEvent | null, served at POST /v1/webhooks/:id), reaching for a built-in integration preset (Clerk/Supabase/Stripe/Segment), or a custom Hatchet task in src/workflows/ passed as extraWorkflows (NOT workflows) to createWorker, including the idempotent batched expand→migrate→contract backfill pattern. Outbound signed webhooks are managed separately (hogsend webhooks CLI / hs.webhooks).

dougwithseismic By dougwithseismic schedule Updated 6/8/2026

name: hogsend-webhooks-and-workflows description: Use when adding an inbound webhook source in src/webhook-sources/ (defineWebhookSource — auth as a match|signature discriminated union, optional Zod schema, transform(payload, ctx) -> IngestEvent | null, served at POST /v1/webhooks/:id), reaching for a built-in integration preset (Clerk/Supabase/Stripe/Segment), or a custom Hatchet task in src/workflows/ passed as extraWorkflows (NOT workflows) to createWorker, including the idempotent batched expand→migrate→contract backfill pattern. Outbound signed webhooks are managed separately (hogsend webhooks CLI / hs.webhooks). license: MIT metadata: author: withSeismic version: "1.0.0"

Hogsend webhooks & workflows

This skill covers the two extension points a scaffolded Hogsend app uses to take in external events and run background jobs:

  1. Webhook sources — turn an inbound HTTP payload into an IngestEvent that flows through the engine's ingestion pipeline (and can trigger journeys).
  2. Custom Hatchet tasks — durable background work (one-off jobs, backfills, cron-style maintenance) registered alongside the engine's built-in workflows.

You are editing a content-only consumer: you import everything from @hogsend/engine (and @hogsend/db for tasks). Never edit engine internals. Relative imports use the ESM .js extension.

Capability map / key concepts

  • defineWebhookSource({ meta, auth, schema?, transform }) (from @hogsend/engine) — declares one source served at POST /v1/webhooks/:id. auth is a discriminated union on type: "match" (shared-secret equality against a header/Authorization: Bearer; OPEN when the secret is unset) or "signature" (scheme: "svix" | "stripe" | "hmac-hex", with an envKey, optional header/fallbackMatchHeader; FAILS CLOSED with 401 when the secret is unset). schema is an optional Zod validator; transform(payload, ctx) returns an IngestEvent | null (null = accept-and-skip). Register sources in src/webhook-sources/index.ts and pass them to createApp(client, { webhookSources }) in src/index.ts.
  • Built-in integration presets — the engine ships four ready-made inbound sources (Clerk, Supabase, Stripe, Segment) served at POST /v1/webhooks/{clerk,supabase,stripe,segment} with no code to write. Each mounts only when its secret env var is set AND ENABLED_WEBHOOK_PRESETS allows it ("*"/absent = auto, a csv of ids = exactly those, "none" = off). Defining your own source with the SAME id overrides the preset (you win).
  • IngestEvent — the shape transform must return: { event, userId, userEmail, properties, idempotencyKey? }. The route feeds it straight into ingestEvent(), so a webhook can enroll users into journeys.
  • Custom Hatchet tasks — define with hatchet.task({ name, fn }) (or hatchet.durableTask for event-driven/long-running work), export from src/workflows/index.ts in the extraWorkflows array, and pass it as createWorker({ ..., extraWorkflows }) — the option is extraWorkflows, NOT workflows. Never list the engine's built-ins (send-email, import-contacts, check-alerts, bucket tasks) — those register automatically.
  • JSON-serializable IO — task input AND return value must serialize to JSON. Use specific keys or JsonValue-compatible types; do not use a [key: string]: unknown index signature.
  • Backfill patternrunBatchedBackfill() (from @hogsend/engine) drives a long data migration in small, idempotent, lock-friendly batches from inside a task — the supported home for bulk data changes (never inside a schema migration). Follow expand → migrate → contract across releases.

Task playbooks — load the matching reference

  • Adding / editing an inbound webhook source → load references/webhook-source.md (defineWebhookSource fields, the transformingestEvent contract, auth matching, registration + createApp wiring).
  • Writing a custom Hatchet task (one-off job, cron, event-driven) → load references/custom-workflow.md (hatchet.task/durableTask, JSON-serializable IO, export from index.ts, createWorker({ extraWorkflows })).
  • Backfilling a new column on existing rows → load references/backfill-pattern.md (the idempotent batched expand→migrate→contract job from the template example).

Cross-skill pointers

  • A webhook's transform only needs to emit the right event/properties; whether a journey then enrolls or exits is decided by trigger/exit conditions — see the hogsend-conditions skill for where/exitOn/criteria and duration helpers.
  • To verify a webhook or task against a running instance (events landing, contacts upserted, journeys firing), see the hogsend-cli skill.
  • Inbound vs outbound: this skill is about inbound sources (HTTP → engine). The engine also emits an outbound event stream (contact.*, email.*, journey.completed, bucket.*). Two halves:
    • Subscriber endpoints — manage the webhook_endpoints rows with hogsend webhooks … (hogsend-cli skill) or hs.webhooks.* (hogsend-client-sdk skill); verify signed deliveries with verifyHogsendWebhook. create/update now take a kind + config: the default kind="webhook" is the byte-identical signed whsec_ POST (returns a one-time secret); a keyed destination (kind="posthog"|"segment"|"slack"|…) carries its credentials in config (e.g. { apiKey }) and returns NO secret. Same durable retry/backoff/DLQ spine either way — kind just selects the delivery-time transform.
    • Code-defined destinations — author a delivery-time transform for a new fan-out TARGET (a CRM, a warehouse, a custom shape) with defineDestination() in src/destinations/. This is the symmetric twin of defineWebhookSource on the OUTBOUND side. → the hogsend-authoring-destinations skill. NOTE: outbound is no longer "just code in a journey" — for event fan-out, reach for a destination, not a per-step integration call.
Install via CLI
npx skills add https://github.com/dougwithseismic/hogsend --skill hogsend-webhooks-and-workflows
Repository Details
star Stars 3
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator
dougwithseismic
dougwithseismic Explore all skills →