Skip to content

webhooks sdk for receiving and managing webhooks#2646

Merged
dwwoelfel merged 17 commits into
webhooks-dashfrom
webhooks-sdk
May 13, 2026
Merged

webhooks sdk for receiving and managing webhooks#2646
dwwoelfel merged 17 commits into
webhooks-dashfrom
webhooks-sdk

Conversation

@dwwoelfel
Copy link
Copy Markdown
Contributor

@dwwoelfel dwwoelfel commented May 11, 2026

Creates a new webhooks sdk for processing and managing webhooks.

The SDK is included in both the admin sdk and the platform sdk, but you can use it standalone if you like.

For processing webhooks, we include two main helpers: processRequest for modern frameworks that use Request (I tested against nextjs app router and cloudflare), and processNodeRequest for frameworks like express and the nextjs pages api (I've tested against express, raw httpRequest, koa, and nestjs).

Here is what it looks like with nextjs app router:

import { init, InstantError } from '@instantdb/admin';

const db = init({ appId: process.env.INSTANT_APP_ID! });

const { typedHandlers, combineHandlers } = db.webhooks.helpers();

const handlers = combineHandlers(
  typedHandlers('$users', 'create', (record) => {
    console.log('We got a new user!', record.after.email);
  }),
  typedHandlers('$default', (record) => {
    console.log('unhandled record', record);
  }),
);

// You could also define the handlers like this, but typedHandlers make it easier to get intellisense
const _handlers = {
  $users: {
    create: (record) => console.log('new user!')
  },
  $default: (record) => console.log('unhandled record')   
};

export const POST = async (req: Request) => {
  try {
    await db.webhooks.processRequest(handlers, req);
  } catch (err) {
    if (err instanceof InstantError) {
      console.warn('[webhooks] rejected', err.message, err.hint);
      return Response.json(
        { ok: false, error: err.message, details: err.hint },
        { status: 400 },
      );
    }
    throw err;
  }
};

If you want to handle the request on your own, we also include all of the necessary pieces to validate and fetch the payloads on the webhooks class.

We also include management functions so that you can create/update/delete webhooks, fetch webhook events, and retry events. We'll use those helpers when building out the cli for webhooks.

Next up is docs, and then I think we'll be ready to deploy everything before building out the CLI.

Also includes a couple of fixes for the backend.

Limitations

  1. I left off the UseDates param and it's always false. We allow it with the admin sdk, but then we just ignore it--I felt it was better to make the types correct for the webhooks for now. We can add support for it when we make useDateObjects work in the admin sdk (I think we'll want better client-side date parsing first, playing around with some ideas for that here https://github.com/instantdb/instant/tree/claude/fix-postgres-timestamp-dEmit)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title directly summarizes the main change: adding a webhooks SDK for receiving and managing webhooks, which is the primary focus across all changeset modifications.
Description check ✅ Passed The PR description clearly explains the webhooks SDK implementation, its integration points, usage examples, and includes management functions. It directly addresses the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch webhooks-sdk

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

View Vercel preview at instant-www-js-webhooks-sdk-jsv.vercel.app.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/packages/webhooks/src/index.ts`:
- Around line 995-1014: processPayload currently collects handler promises into
results and awaits Promise.allSettled(results), which swallows rejections so
processRequest never sees failures; change processPayload (the async function
processPayload and its results array) to propagate handler errors by using
Promise.all(results) or by inspecting the settled results and throwing on any
rejection so the returned promise rejects, ensuring processRequest receives the
failure and webhook retry semantics work correctly.
- Line 477: The key cache currently uses only `kid` (keyCache: Record<string, {
alg: ImportAlgorithm; key: CryptoKey }>) which can collide across different
issuers; change the cache to be namespaced by `apiURI` (e.g., use a composite
key like `${apiURI}:${kid}` or a nested map `Record<string, Record<string,
...>>`) and update all usages (the `keyCache` declaration and every read/write
site, including the other occurrences referenced around the 874-893 block) so
keys are stored and looked up with the apiURI namespace to prevent
cross-environment key collisions.
- Line 921: The defaulting for tolerance incorrectly uses || which treats 0 as
falsy; change the assignment in index.ts so that the value from opts?.tolerance
is preserved when explicitly set (including 0) by using the nullish coalescing
operator (??) instead of || for the expression that assigns to tolerance
(referencing tolerance, opts, and defaultTolerance).

In `@client/sandbox/react-nextjs/pages/play/webhooks.tsx`:
- Around line 77-93: The component currently calls initAdmin once via useRef, so
adminDb keeps stale appId/adminToken; change this to recreate the admin client
whenever appId or adminToken (and other config/schema) change by replacing the
useRef(initAdmin(...)) pattern with a memoized or effect-driven initializer
(e.g., useMemo or useEffect) that calls initAdmin({ ...config, appId,
adminToken, schema }) with [config, appId, adminToken, schema] as dependencies,
then expose the live client (adminDb or adminClient) and update all usages
(previously adminDb.current and manager = adminDb.current.webhooks.manager) to
read from the current memoized client (e.g., adminDb or adminClient and
adminDb.webhooks.manager) so webhooks/data calls always use the up-to-date appId
and token.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cf6f9edd-8a5d-4f3c-8698-0a09a6b604e0

📥 Commits

Reviewing files that changed from the base of the PR and between 9ecaf56 and 3c0a6ed.

⛔ Files ignored due to path filters (1)
  • client/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • client/README.md
  • client/package.json
  • client/packages/admin/package.json
  • client/packages/admin/src/index.ts
  • client/packages/platform/package.json
  • client/packages/platform/src/api.ts
  • client/packages/platform/src/index.ts
  • client/packages/webhooks/README.md
  • client/packages/webhooks/package.json
  • client/packages/webhooks/src/index.ts
  • client/packages/webhooks/tsconfig.dev.json
  • client/packages/webhooks/tsconfig.json
  • client/packages/webhooks/tsconfig.test.json
  • client/sandbox/react-nextjs/app/api/webhooks/route.ts
  • client/sandbox/react-nextjs/pages/api/webhooks-pages.ts
  • client/sandbox/react-nextjs/pages/play/webhooks.tsx
  • client/scripts/publish_packages.clj
  • server/src/instant/model/webhook.clj
  • server/src/instant/webhook_routes.clj

Comment thread client/packages/webhooks/src/index.ts
Comment thread client/packages/webhooks/src/index.ts Outdated
Comment thread client/packages/webhooks/src/index.ts
Comment thread client/sandbox/react-nextjs/pages/play/webhooks.tsx
@dwwoelfel dwwoelfel changed the title WIP on webhooks sdk for receiving and managing webhooks webhooks sdk for receiving and managing webhooks May 12, 2026
@dwwoelfel dwwoelfel marked this pull request as ready for review May 12, 2026 20:56
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/packages/webhooks/src/index.ts`:
- Around line 455-467: The signature header parsing loop fails when segments
contain extra spaces; in the loop over h.split(',') (the part variable) trim
whitespace before splitting and normalize the key/value (trim both k and v) so
the switch on k ('t', 'kid', 'v1') matches correctly; update the code around the
for (const part of h.split(',')) block to use trimmedPart = part.trim(), then
derive [k, v] from trimmedPart and trim k and v before the switch/assignments to
t, kid, and v1.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6bd9e28f-75e1-406a-bdbd-35718deb8250

📥 Commits

Reviewing files that changed from the base of the PR and between 3c0a6ed and 6dfc043.

📒 Files selected for processing (5)
  • client/packages/webhooks/README.md
  • client/packages/webhooks/src/__types__/typeUtils.ts
  • client/packages/webhooks/src/__types__/typesTests.ts
  • client/packages/webhooks/src/index.ts
  • client/sandbox/react-nextjs/pages/play/webhooks.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • client/sandbox/react-nextjs/pages/play/webhooks.tsx

Comment thread client/packages/webhooks/src/index.ts
Copy link
Copy Markdown
Contributor

@nezaj nezaj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

One suggestion from claude was to add a runtime test for the dispatch precedence logic (etype.action → etype.$default → $default).

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
client/packages/webhooks/README.md (2)

245-245: 💤 Low value

Minor: Inconsistent header casing in documentation.

Line 245 uses lowercase instant-signature, while the rest of the documentation consistently uses capitalized Instant-Signature (lines 108, 231, 75). HTTP headers are case-insensitive, so this isn't a functional issue, but for documentation consistency it would be clearer to match the casing used elsewhere.

✏️ Suggested change
-Convenience wrapper around `validate`: pulls `instant-signature` and the body off a Web `Request` for you.
+Convenience wrapper around `validate`: pulls `Instant-Signature` and the body off a Web `Request` for you.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/packages/webhooks/README.md` at line 245, The README line describing
the convenience wrapper around `validate` uses lowercase `instant-signature`;
update that header text to `Instant-Signature` to match the rest of the docs
(e.g., other occurrences around `validate`) so casing is consistent across the
documentation.

115-136: ⚡ Quick win

Unused import could confuse readers.

Line 116 imports Webhooks from @instantdb/admin, but the code that follows uses db.webhooks, and db is neither imported nor defined in this snippet. The Webhooks import is not used. This might confuse readers about what imports are actually needed for a webhook handler route.

Consider either:

  1. Removing the import and adding a comment like // Assumes db is initialized per the setup section above, or
  2. Showing the minimal imports needed: import { init } from '@instantdb/admin'; followed by a brief db initialization, or
  3. Assuming db is imported from a shared module: import { db } from './instant';
📝 Example fix removing the unused import
 // app/api/instant-webhook/route.ts
-import { Webhooks } from '@instantdb/admin';
+// Assumes db is initialized per the admin SDK setup section above
 
 const { typedHandlers, combineHandlers } = db.webhooks.helpers();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@client/packages/webhooks/README.md` around lines 115 - 136, The snippet
imports Webhooks but never uses it and references an undefined db; remove the
unused import Webhooks and either (A) add a brief comment like "// Assumes db is
initialized per the setup section above" to clarify that db is provided
elsewhere, or (B) replace the unused import with the minimal real
initialization/import for db (e.g., import init from the SDK and initialize db,
or import { db } from your shared module) so that symbols used in the snippet
(db, db.webhooks.processRequest, typedHandlers, combineHandlers) are actually
defined and the example is self-consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/src/instant/model/webhook.clj`:
- Around line 277-289: The duplicate check currently calls sql/select-one with
check-webhook-duplicate-q and only filters out ignore-id after the query, which
can miss duplicates if the ignored row is returned first; update the SQL binding
used by uhsql/formatp in check-webhook-duplicate! to pass an :ignore-id param
(with appropriate pgtype metadata, e.g., {:pgtype "uuid"} or uuid[] as needed)
and add a WHERE clause in check-webhook-duplicate-q to exclude rows with id =
:ignore-id when :ignore-id is provided so sql/select-one never returns the
ignored webhook; keep existing bindings (id-attr-ids/actions/sink) and ensure
the symbol names check-webhook-duplicate-q, check-webhook-duplicate!, ignore-id,
id, sql/select-one, and uhsql/formatp are used to locate and update the code.
- Around line 383-388: The duplicate-check currently calls
get-by-app-id-and-webhook-id! which drops non-read (transactional) conns and
re-reads from the default pool, exposing stale data; change this to use a
version that honors the passed write/transactional conn (either add a new arity
or modify get-by-app-id-and-webhook-id! so it does not drop non-read conns) and
call that here (and at the other site around lines 425-433) so
check-webhook-duplicate! is built from the transaction-local row rather than a
new pooled read.

---

Nitpick comments:
In `@client/packages/webhooks/README.md`:
- Line 245: The README line describing the convenience wrapper around `validate`
uses lowercase `instant-signature`; update that header text to
`Instant-Signature` to match the rest of the docs (e.g., other occurrences
around `validate`) so casing is consistent across the documentation.
- Around line 115-136: The snippet imports Webhooks but never uses it and
references an undefined db; remove the unused import Webhooks and either (A) add
a brief comment like "// Assumes db is initialized per the setup section above"
to clarify that db is provided elsewhere, or (B) replace the unused import with
the minimal real initialization/import for db (e.g., import init from the SDK
and initialize db, or import { db } from your shared module) so that symbols
used in the snippet (db, db.webhooks.processRequest, typedHandlers,
combineHandlers) are actually defined and the example is self-consistent.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 449367ce-8c99-4276-9854-b5b334e8eedb

📥 Commits

Reviewing files that changed from the base of the PR and between 3c0a6ed and ecc7309.

📒 Files selected for processing (11)
  • client/packages/webhooks/README.md
  • client/packages/webhooks/__tests__/src/helpers.test.ts
  • client/packages/webhooks/__tests__/src/processPayload.test.ts
  • client/packages/webhooks/__tests__/src/validate.test.ts
  • client/packages/webhooks/package.json
  • client/packages/webhooks/src/__types__/typeUtils.ts
  • client/packages/webhooks/src/__types__/typesTests.ts
  • client/packages/webhooks/src/index.ts
  • client/sandbox/react-nextjs/pages/play/webhooks.tsx
  • server/src/instant/model/webhook.clj
  • server/test/instant/model/webhook_test.clj
🚧 Files skipped from review as they are similar to previous changes (3)
  • client/packages/webhooks/package.json
  • client/sandbox/react-nextjs/pages/play/webhooks.tsx
  • client/packages/webhooks/src/index.ts

Comment thread server/src/instant/model/webhook.clj
Comment thread server/src/instant/model/webhook.clj
@dwwoelfel dwwoelfel merged commit 53af807 into webhooks-dash May 13, 2026
33 checks passed
@dwwoelfel dwwoelfel deleted the webhooks-sdk branch May 13, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants