Skip to content

✨ server: webhook api#926

Draft
nfmelendez wants to merge 16 commits intobetter-authfrom
webhook
Draft

✨ server: webhook api#926
nfmelendez wants to merge 16 commits intobetter-authfrom
webhook

Conversation

@nfmelendez
Copy link
Copy Markdown
Contributor

@nfmelendez nfmelendez commented Mar 30, 2026

Summary by CodeRabbit

  • New Features

    • Org-scoped webhook management: create/read/delete webhooks with per-webhook secrets and optional transaction receipt forwarding.
  • Security

    • Outbound webhooks signed with HMAC-SHA256; URL validation requires HTTPS and blocks private/loopback addresses.
  • Reliability

    • Delivery retries with backoff and timeouts; receipt-aware dispatch for transaction flows.
  • Documentation

    • New comprehensive webhook docs and an authenticated webhook flow example.
  • Tests

    • New end-to-end and unit tests for signing, delivery, DNS validation, retries, permissions, and logging.
  • Chores

    • Access-control updated to include webhook permissions; release changelogs added.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 30, 2026

🦋 Changeset detected

Latest commit: 97ac127

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@exactly/server Patch
@exactly/docs Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a webhook subsystem: documentation, a new sources DB table, per-organization CRUD webhook API, URL validation, HMAC-SHA256-signed deliveries with retries/timeouts, publisher integration into event flows (including onReceipt), access-control updates, and tests.

Changes

Cohort / File(s) Summary
Documentation
docs/src/content/docs/webhooks.md, docs/src/content/docs/organization-authentication.md, docs/astro.config.ts
New webhook documentation, SIWE-authenticated webhook example, and sidebar entry added.
API Routes
server/api/webhook.ts, server/api/index.ts
New Hono router exposing GET/POST/DELETE /webhook with auth/permission checks, Valibot validation, per-org mutexed config upsert/delete; route registered in API index.
Database Schema
server/database/schema.ts
Added exported sources table (id: text PK, config: jsonb) and added source one-to-one relation on credentials.
Publisher & Integration
server/hooks/panda.ts
Implemented webhook publish flow: URL validation, HMAC-SHA256 Signature header, 60s timeout, retry/backoff, debug logging and Sentry capture; integrated publish into transaction/card/user flows; adjusted webhook payload shape.
Utilities
server/utils/webhook.ts, cspell.json
Added isValid(raw: string) URL validator (DNS resolution + private-address checks); added "hmac" to spellcheck allowlist.
Access Control & Keeper
server/utils/auth.ts, server/utils/keeper.ts
Added webhook: ["create","delete","read"] permissions to roles; added optional onReceipt callback to exaSend and invoke it after receipt resolution with error capture.
Tests
server/test/api/webhook.test.ts, server/test/hooks/panda.test.ts, server/test/utils/webhook.test.ts
Added E2E tests for webhook CRUD/auth, extended Panda tests to verify HMAC signatures and payloads, and unit tests for URL validation and DNS/private-IP blocking.
Releases / Changesets
.changeset/*
Multiple new Changeset entries added for patch releases documenting webhook-related fixes/features.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as Exactly API
    participant DB as Sources DB
    participant Panda as Panda Publisher
    participant Webhook as External Endpoint
    participant Sentry

    Client->>API: trigger event (e.g., transaction)
    API->>DB: persist state/event
    API->>Panda: invoke publish(payload[, receipt])
    Panda->>DB: load org sources.config
    Panda->>Panda: build JSON body & compute HMAC-SHA256(secret, body)
    loop retry attempts (exponential backoff)
        Panda->>Webhook: POST body with Signature header
        alt 2xx response
            Webhook-->>Panda: response (text/JSON)
            Panda->>Panda: debug log response
        else timeout or non-2xx
            Webhook-->>Panda: error/timeout
            Panda->>Sentry: captureException(error)
            Note right of Panda: wait backoff then retry
        end
    end
    Panda-->>API: publish completed (errors logged)
    API-->>Client: reply to original request
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • cruzdanilo
  • dieguezguille
  • franm91
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title '✨ server: webhook api' directly describes the main change—adding a webhook API to the server, which is the primary focus of this changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch webhook

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.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive webhook system, including a new API for managing webhook configurations, database schema updates, and a publishing mechanism integrated into the transaction lifecycle. The implementation features HMAC SHA256 signing for security, an exponential backoff retry policy, and extensive documentation. Review feedback identifies a critical validation error in the card status schema where the 'INACTIVE' state was omitted, as well as several documentation improvements including a broken markdown tag, a typo, and the need for clearer example URLs.

Comment thread server/hooks/panda.ts Outdated
Comment thread docs/src/content/docs/webhooks.md Outdated
Comment thread docs/src/content/docs/webhooks.md Outdated
Comment thread docs/src/content/docs/webhooks.md Outdated
Comment thread docs/src/content/docs/webhooks.md Outdated
@sentry
Copy link
Copy Markdown

sentry Bot commented Mar 30, 2026

✅ All tests passed.

Copy link
Copy Markdown

@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: 12


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2d79b368-fdf5-44b0-be33-4c4d1d3a8448

📥 Commits

Reviewing files that changed from the base of the PR and between 128b4ec and 8b0564f.

📒 Files selected for processing (19)
  • .changeset/dry-peas-ring.md
  • .changeset/fifty-friends-bet.md
  • .changeset/long-moons-brake.md
  • .changeset/loud-shoes-visit.md
  • .changeset/olive-onions-tan.md
  • .changeset/quick-ants-write.md
  • .changeset/violet-plums-move.md
  • cspell.json
  • docs/astro.config.ts
  • docs/src/content/docs/organization-authentication.md
  • docs/src/content/docs/webhooks.md
  • server/api/index.ts
  • server/api/webhook.ts
  • server/database/schema.ts
  • server/hooks/panda.ts
  • server/test/api/webhook.test.ts
  • server/test/hooks/panda.test.ts
  • server/utils/auth.ts
  • server/utils/keeper.ts

Comment thread docs/src/content/docs/organization-authentication.md
Comment thread docs/src/content/docs/organization-authentication.md
Comment thread docs/src/content/docs/webhooks.md Outdated
Comment thread docs/src/content/docs/webhooks.md Outdated
Comment thread server/api/webhook.ts
Comment thread server/hooks/panda.ts
Comment thread server/hooks/panda.ts Outdated
Comment thread server/test/api/webhook.test.ts
Comment thread server/test/hooks/panda.test.ts
Comment thread server/test/hooks/panda.test.ts
@cruzdanilo cruzdanilo changed the title Webhook ✨ server: webhook Mar 31, 2026
Copy link
Copy Markdown

@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: 6

♻️ Duplicate comments (2)
server/hooks/panda.ts (1)

1322-1328: ⚠️ Potential issue | 🟠 Major

The outbound card webhook schema is narrower than the values you emit.

publish() maps notActivated to "INACTIVE", and the inbound Card schema also allows allTime and perAuthorization, but Webhook only accepts ACTIVE|FROZEN|DELETED and four frequency values. Those legitimate Panda updates will fail v.parse(Webhook, ...) and no webhook will be sent.

🛠️ Proposed fix
       limit: v.object({
         amount: v.number(),
-        frequency: v.picklist(["per24HourPeriod", "per7DayPeriod", "per30DayPeriod", "perYearPeriod"]),
+        frequency: v.picklist([
+          "per24HourPeriod",
+          "per7DayPeriod",
+          "per30DayPeriod",
+          "perYearPeriod",
+          "allTime",
+          "perAuthorization",
+        ]),
       }),
-      status: v.picklist(["ACTIVE", "FROZEN", "DELETED"]),
+      status: v.picklist(["ACTIVE", "FROZEN", "DELETED", "INACTIVE"]),

Also applies to: 1439-1447

server/api/webhook.ts (1)

14-21: ⚠️ Potential issue | 🟠 Major

Validate webhook URLs before storing them.

These fields accept arbitrary strings, and server/hooks/panda.ts later passes them straight to fetch(). That makes it possible to persist malformed or internal destinations and turn webhook delivery into SSRF. Require a valid https:// URL and reject local/private hosts.

Also applies to: 149-161


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 04b5f99d-29af-4493-b6f7-dafe9ae83cba

📥 Commits

Reviewing files that changed from the base of the PR and between 8b0564f and 43424cd.

📒 Files selected for processing (16)
  • .changeset/dry-peas-ring.md
  • .changeset/fifty-friends-bet.md
  • .changeset/long-moons-brake.md
  • .changeset/loud-shoes-visit.md
  • .changeset/olive-onions-tan.md
  • .changeset/quick-ants-write.md
  • docs/astro.config.ts
  • docs/src/content/docs/organization-authentication.md
  • docs/src/content/docs/webhooks.md
  • server/api/index.ts
  • server/api/webhook.ts
  • server/hooks/panda.ts
  • server/test/api/webhook.test.ts
  • server/test/hooks/panda.test.ts
  • server/utils/auth.ts
  • server/utils/keeper.ts

Comment thread docs/src/content/docs/organization-authentication.md
Comment thread docs/src/content/docs/webhooks.md
Comment thread server/api/webhook.ts
Comment thread server/api/webhook.ts
Comment thread server/test/api/webhook.test.ts
Comment thread server/utils/keeper.ts Outdated
@nfmelendez nfmelendez force-pushed the webhook branch 2 times, most recently from a45122d to 149c02f Compare April 1, 2026 20:15
Copy link
Copy Markdown

@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: 3

♻️ Duplicate comments (7)
docs/src/content/docs/organization-authentication.md (1)

163-209: ⚠️ Potential issue | 🟡 Minor

Show the organization prerequisite in this example.

This flow authenticates and then calls GET /api/webhook / POST /api/webhook, but it never creates or selects an organization. Copied in isolation, it will hit 403 { code: "no organization" }. Either add the organization step here or call out the prerequisite explicitly.

server/utils/keeper.ts (1)

151-153: ⚠️ Potential issue | 🟠 Major

Defer onReceipt before wrapping it in a promise.

Promise.resolve(options?.onReceipt?.(receipt)) evaluates the callback before the promise exists, so a synchronous throw escapes this .catch() and can still fail exaSend() after the receipt was already obtained. Queue the callback first, then attach the error handler.

🛠️ Proposed fix
-            Promise.resolve(options?.onReceipt?.(receipt)).catch((error: unknown) =>
-              captureException(error, { level: "error" }),
-            );
+            void Promise.resolve()
+              .then(() => options?.onReceipt?.(receipt))
+              .catch((error: unknown) => captureException(error, { level: "error" }));

Run this to confirm the synchronous-throw behavior difference:

#!/bin/bash
node <<'NODE'
const cb = () => {
  throw new Error("sync throw");
};

try {
  Promise.resolve(cb()).catch(() => console.log("wrapped"));
} catch (error) {
  console.log("escaped:", error.message);
}

Promise.resolve()
  .then(() => cb())
  .catch((error) => console.log("deferred:", error.message));
NODE
server/test/hooks/panda.test.ts (1)

2806-2808: 🧹 Nitpick | 🔵 Trivial

Match the debug mock by namespace instead of call order.

This mockReturnValueOnce() chain only works while server/hooks/panda.ts creates exactly two debug instances in the current order. Adding another namespace or reordering them will silently wire webhookLogger to the wrong logger.

♻️ Suggested refactor
 vi.mock("debug", () => {
-  const createDebug = vi.fn().mockReturnValueOnce(vi.fn()).mockReturnValueOnce(webhookLogger);
+  const createDebug = vi.fn().mockImplementation((namespace: string) =>
+    namespace === "exa:webhook" ? webhookLogger : vi.fn(),
+  );
   return { default: createDebug };
 });

Run this to inspect the current namespace/count assumption:

#!/bin/bash
sed -n '70,75p' server/hooks/panda.ts
sed -n '2804,2809p' server/test/hooks/panda.test.ts
docs/src/content/docs/webhooks.md (1)

393-423: ⚠️ Potential issue | 🟠 Major

Remove authorizedAmount from the force-capture payload.

Force capture is the completed flow without a prior authorization. Keeping authorizedAmount here documents the settlement/over-capture contract instead, so consumers may build the wrong parser.

server/hooks/panda.ts (1)

1249-1257: ⚠️ Potential issue | 🟠 Major

Bound the retry window here.

delay: ({ count }) => 2^count * 500ms with retryCount: 20 pushes the last retry out to ~72 hours and keeps a failed delivery alive for nearly a week. At the same time, plain fetch() network failures still skip retries because only "WebhookFailed" and "TimeoutError" are whitelisted. Cap the delay and include transient network errors if this path is meant to be resilient.

server/api/webhook.ts (2)

14-21: ⚠️ Potential issue | 🟠 Major

Validate webhook targets before persisting them.

These schemas accept any string, and server/hooks/panda.ts later passes the stored value straight to fetch(). That allows webhook configs pointing at localhost, link-local, or other internal hosts. Parse the URL here and reject non-HTTPS/private targets before storing them.

Also applies to: 149-160


175-186: ⚠️ Potential issue | 🟠 Major

This read-modify-write still races across instances.

The in-memory mutex only serializes one process. Two app instances can both read sources.config, apply different mutations, and write whole-document updates that clobber each other. Move this into a DB transaction with row locking or an atomic jsonb update.

Also applies to: 255-266


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d26e278a-58bf-48d3-9902-656e2f07f45c

📥 Commits

Reviewing files that changed from the base of the PR and between 43424cd and a45122d.

📒 Files selected for processing (16)
  • .changeset/dry-peas-ring.md
  • .changeset/fifty-friends-bet.md
  • .changeset/long-moons-brake.md
  • .changeset/loud-shoes-visit.md
  • .changeset/olive-onions-tan.md
  • .changeset/quick-ants-write.md
  • docs/astro.config.ts
  • docs/src/content/docs/organization-authentication.md
  • docs/src/content/docs/webhooks.md
  • server/api/index.ts
  • server/api/webhook.ts
  • server/hooks/panda.ts
  • server/test/api/webhook.test.ts
  • server/test/hooks/panda.test.ts
  • server/utils/auth.ts
  • server/utils/keeper.ts

Comment thread docs/src/content/docs/webhooks.md
Comment thread docs/src/content/docs/webhooks.md
Comment thread server/hooks/panda.ts
Copy link
Copy Markdown

@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

♻️ Duplicate comments (5)
server/hooks/panda.ts (2)

1250-1251: ⚠️ Potential issue | 🟠 Major

Cap the retry backoff.

With retryCount: 20, this reaches 262,144,000ms on the last delay, which is roughly 72 hours. That makes failed deliveries linger for days and ties the retry window to process lifetime.

🛠️ Suggested cap
-          delay: ({ count }) => Math.trunc(1 << count) * 500,
+          delay: ({ count }) => Math.min(Math.trunc(1 << count) * 500, 60_000),

1442-1445: ⚠️ Potential issue | 🟠 Major

Allow the full upstream limit frequency set.

Lines 176-183 accept "allTime" and "perAuthorization" on inbound card.updated events, but the outbound webhook schema rejects both here. v.parse(Webhook, ...) will fail and skip delivery for valid card limit updates.

🛠️ Suggested fix
       limit: v.object({
         amount: v.number(),
-        frequency: v.picklist(["per24HourPeriod", "per7DayPeriod", "per30DayPeriod", "perYearPeriod"]),
+        frequency: v.picklist([
+          "per24HourPeriod",
+          "per7DayPeriod",
+          "per30DayPeriod",
+          "perYearPeriod",
+          "allTime",
+          "perAuthorization",
+        ]),
       }),
docs/src/content/docs/webhooks.md (3)

29-33: ⚠️ Potential issue | 🟠 Major

Use the webhook secret in the verification snippet.

Outbound signatures are generated with the per-webhook secret, not a generic API key. Copying this example as-is will fail against real deliveries.

🛠️ Suggested correction
-const signature = createHmac("sha256", <YOUR_API_KEY>)
+const signature = createHmac("sha256", "<YOUR_WEBHOOK_SECRET>")

393-420: ⚠️ Potential issue | 🟠 Major

Make the force-capture example a true no-authorization settlement.

The force-capture path is the completed flow with no prior authorized hold. Keeping authorizedAmount here models a settled authorization instead of a force capture.

🛠️ Suggested correction
-      "authorizedAmount": 10000,

641-653: ⚠️ Potential issue | 🟠 Major

Document card.updated as a general lifecycle event.

server/hooks/panda.ts forwards generic card updates, including non-wallet states like canceled. Describing this as only digital-wallet provisioning will make consumers ignore valid events.

🛠️ Suggested wording
-This webhook is currently triggered when a user adds their card to a digital wallet.
+This webhook is sent whenever Exa receives a card lifecycle update, including wallet provisioning and status changes such as cancellation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 84db6815-a17c-450d-9e1c-a996d1ceb7db

📥 Commits

Reviewing files that changed from the base of the PR and between a45122d and 149c02f.

📒 Files selected for processing (6)
  • .changeset/dry-peas-ring.md
  • .changeset/fifty-friends-bet.md
  • docs/src/content/docs/webhooks.md
  • server/hooks/panda.ts
  • server/test/api/webhook.test.ts
  • server/test/hooks/panda.test.ts

Comment thread server/hooks/panda.ts
Copy link
Copy Markdown

@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

♻️ Duplicate comments (2)
server/hooks/panda.ts (1)

1252-1254: ⚠️ Potential issue | 🟠 Major

Cap the backoff before one bad webhook hangs around for days.

With retryCount: 20, Math.trunc(1 << count) * 500 reaches 262,144,000ms (~72h) on the last delay. That is long enough to keep this fire-and-forget delivery task alive for multiple days.

⏱️ Minimal fix
         {
-          delay: ({ count }) => Math.trunc(1 << count) * 500,
+          delay: ({ count }) => Math.min(Math.trunc(1 << count) * 500, 60_000),
           retryCount: domain === "base-sepolia.exactly.app" ? 3 : 20,
           shouldRetry: ({ error }) => {
server/api/webhook.ts (1)

29-34: ⚠️ Potential issue | 🟠 Major

This read-modify-write still loses webhook updates across instances.

The Map<string, Mutex> only serializes requests handled by one Node process. Two instances can both read the same sources.config, apply different mutations, and the last write wins; if both see no row, one of the inserts can also fail on the sources.id primary key. Use a database transaction with row locking or an atomic jsonb update instead.

Also applies to: 206-224, 286-300


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 60b544ed-273f-4d14-a251-3274e2013603

📥 Commits

Reviewing files that changed from the base of the PR and between 149c02f and 4b7a21c.

📒 Files selected for processing (6)
  • server/api/webhook.ts
  • server/hooks/panda.ts
  • server/test/api/webhook.test.ts
  • server/test/hooks/panda.test.ts
  • server/test/utils/webhook.test.ts
  • server/utils/webhook.ts

Comment thread server/hooks/panda.ts
Comment thread server/utils/webhook.ts
@nfmelendez
Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 15, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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: 6

♻️ Duplicate comments (5)
docs/src/content/docs/organization-authentication.md (1)

195-209: ⚠️ Potential issue | 🟡 Minor

Example will fail without organization membership.

The webhook endpoints return 403 { code: "no organization" } when the user doesn't belong to an organization. This example only authenticates but doesn't show organization creation/membership. Consider adding a note that the user must be an owner/admin of an organization, or include organization creation (similar to the previous section).

docs/src/content/docs/webhooks.md (3)

22-33: ⚠️ Potential issue | 🟠 Major

Use the webhook secret in the signature example, not an API key.

The delivery code signs with the per-webhook secret, so copied code using <YOUR_API_KEY> will fail against real webhook payloads.


389-425: ⚠️ Potential issue | 🟠 Major

Show a true force-capture payload here.

This example still reads like an authorized settlement: it includes authorizedAt/authorizedAmount and reuses the over-capture shape. A force capture should document the no-prior-authorization contract consumers will actually receive.


643-644: ⚠️ Potential issue | 🟠 Major

Document card.updated as a general card lifecycle event.

The implementation forwards generic card updates as well, not just digital-wallet provisioning. Limiting the description to wallet adds will cause integrators to ignore valid ACTIVE/FROZEN/DELETED/INACTIVE updates.

server/hooks/panda.ts (1)

1224-1235: ⚠️ Potential issue | 🔴 Critical

Revalidate the webhook destination on every retry attempt.

Each fetch() performs a fresh DNS lookup, so validating only when the URL is saved does not protect later retry attempts from DNS rebinding. The public-IP check needs to run inside the retried callback before each outbound request.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bb04b57d-9f3c-4764-af72-559521a52aca

📥 Commits

Reviewing files that changed from the base of the PR and between 149c02f and 43dc358.

📒 Files selected for processing (22)
  • .changeset/dry-peas-ring.md
  • .changeset/fifty-friends-bet.md
  • .changeset/long-moons-brake.md
  • .changeset/loud-shoes-visit.md
  • .changeset/olive-onions-tan.md
  • .changeset/quick-ants-write.md
  • .changeset/shy-foxes-trade.md
  • .changeset/violet-plums-move.md
  • cspell.json
  • docs/astro.config.ts
  • docs/src/content/docs/organization-authentication.md
  • docs/src/content/docs/webhooks.md
  • server/api/index.ts
  • server/api/webhook.ts
  • server/database/schema.ts
  • server/hooks/panda.ts
  • server/test/api/webhook.test.ts
  • server/test/hooks/panda.test.ts
  • server/test/utils/webhook.test.ts
  • server/utils/auth.ts
  • server/utils/keeper.ts
  • server/utils/webhook.ts

Comment thread .changeset/olive-onions-tan.md
Comment thread docs/src/content/docs/webhooks.md Outdated
Comment thread server/api/webhook.ts Outdated
Comment thread server/database/schema.ts
Comment thread server/hooks/panda.ts
Comment thread server/test/utils/webhook.test.ts Outdated
@cruzdanilo cruzdanilo changed the title ✨ server: webhook ✨ server: webhook api Apr 27, 2026
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.

3 participants