Hooktopus

Anything

a custom source → BigQuery → dbt.
Five minutes from signup.

A single URL your app posts to. Typed BigQuery rows, dbt-ready, nothing to maintain. Hooky generates a typed stg_custom.sql from the events you've already received, and pings you when a custom source changes the shape.

Shape

Whatever JSON your application sends. Hooktopus does not care.

Common events

signup · subscription_started · feature_flag_evaluated · api_key_created

custom.payload.json
{
  "event_id": "01970000-0000-7000-8000-000000000001",
  "event_type": "user.signup",
  "user_id": "u_abc",
  "metadata": {
    "source": "web",
    "experiment_variant": "B"
  },
  "timestamp": "2026-05-16T20:14:30Z"
}

The output

Here's the dbt model Hooky generates for a custom source.

stg_custom.sql
select
  json_value(payload, '$.event_id')             as source_event_id,
  json_value(payload, '$.event_type')           as event_type,
  json_value(payload, '$.user_id')              as user_id,
  json_value(payload, '$.metadata.source')      as source,
  json_value(payload, '$.metadata.experiment_variant') as experiment_variant,
  json_value(payload, '$.timestamp')            as occurred_at,
  payload                                       as raw_payload
from {{ source('hooktopus', 'events') }}
where endpoint_name = 'app_events'

Yes, you can hand-edit it. Yes, regenerate is non-destructive: it produces a diff, doesn't auto-merge. Yes, every column has raw_payload as the escape hatch.

The hard part

Your team controls the payload shape, until they don't.

Even when you own the source, fields creep in. Drift alerts work the same way for your in-house webhooks as for Stripe — you get the early-warning either way.

What you get

Everything you need for a custom source in production.

Signature verification, handled

We use Hookdeck for ingress signature checks. a custom source's scheme works out of the box — paste your signing secret, done.

Drift alerts via Slack + email

New field? Type change? Field disappearing? You hear about it within the hour, with a sample event and a regenerate link.

Replay from R2 archive

Bad BQ window? Re-write any time range from R2 with one click. a custom source retries don't disappear.

Native JSON type, no string-of-JSON

Apostrophes, emojis, special chars in a custom source payloads survive intact. Query with JSON_VALUE, get clean strings.

Partitioned + clustered table

PARTITION BY DATE(received_at) CLUSTER BY endpoint_name so even a chatty a custom source firehose stays cheap to query.

Never blocking writes

Events archive to R2 before the destination write. a custom source sees a 202, you never lose an event during a BQ blip.

Catch a custom source today

Your custom table, ready before lunch.

Free under 10k events/month. Add the URL to a custom source, run dbt, ship a chart.