@dodopayments/opencode-plugin 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/opencode-plugin/README.md +1 -1
- package/package.json +1 -1
- package/skills/better-auth-integration/SKILL.md +12 -3
- package/skills/billing-sdk/SKILL.md +66 -33
- package/skills/checkout-integration/SKILL.md +26 -20
- package/skills/credit-based-billing/SKILL.md +7 -8
- package/skills/customer-management/SKILL.md +25 -17
- package/skills/discounts-and-promotions/SKILL.md +20 -17
- package/skills/dodo-best-practices/SKILL.md +18 -5
- package/skills/dodo-mcp-usage/SKILL.md +152 -0
- package/skills/framework-adapters/SKILL.md +167 -35
- package/skills/license-keys/SKILL.md +142 -97
- package/skills/localized-pricing/SKILL.md +51 -29
- package/skills/mobile-checkout/SKILL.md +168 -118
- package/skills/product-catalog-management/SKILL.md +39 -16
- package/skills/refunds-and-disputes/SKILL.md +91 -71
- package/skills/subscription-integration/SKILL.md +62 -9
- package/skills/testing-and-go-live/SKILL.md +22 -15
- package/skills/usage-based-billing/SKILL.md +18 -15
- package/skills/webhook-integration/SKILL.md +27 -10
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: webhook-integration
|
|
3
|
-
description:
|
|
3
|
+
description: Dodo Payments webhook handling, covering endpoint setup, Standard Webhooks signature verification on the raw body, payment, subscription, and refund event types, idempotency with webhook-id, retries, and local testing. Use when receiving Dodo events, verifying webhook-signature headers, or syncing your database from payment.succeeded or subscription events.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Dodo Payments Webhook Integration
|
|
@@ -272,7 +272,7 @@ Signature verification requires the exact bytes Dodo sent. If you parse the JSON
|
|
|
272
272
|
|
|
273
273
|
## Webhook Event Catalog
|
|
274
274
|
|
|
275
|
-
Dodo
|
|
275
|
+
Dodo delivers 48 event types across ten families (payment, subscription, refund, dispute, license key, entitlement grant, credit, abandoned checkout, dunning, payout). Subscribe to only the events you need.
|
|
276
276
|
|
|
277
277
|
### Payment events
|
|
278
278
|
|
|
@@ -289,7 +289,10 @@ Dodo sends 40+ event types across nine domains. Subscribe to only the events you
|
|
|
289
289
|
|-------|---|---|
|
|
290
290
|
| `subscription.active` | Subscription becomes active; recurring charges are scheduled | Grant subscription access, send welcome email |
|
|
291
291
|
| `subscription.updated` | Any field on the subscription changes | Sync changes to your database |
|
|
292
|
-
| `subscription.
|
|
292
|
+
| `subscription.past_due` | Renewal failed and the grace period opened; customer keeps access (payload has `past_due_ends_at`) | Prompt for payment before the deadline |
|
|
293
|
+
| `subscription.on_hold` | Failed renewal stops renewals and revokes access | Notify customer, prompt payment method update |
|
|
294
|
+
| `subscription.paused` | Subscription is deliberately paused | Suspend access while paused |
|
|
295
|
+
| `subscription.unpaused` | Paused subscription is resumed | Restore access |
|
|
293
296
|
| `subscription.renewed` | Subscription amount successfully deducted for a billing period | Log renewal, update next billing date |
|
|
294
297
|
| `subscription.plan_changed` | Plan upgraded, downgraded, or modified | Update customer's access level or feature set |
|
|
295
298
|
| `subscription.update_payment_method` | Payment method is updated | Sync the new payment method to your records |
|
|
@@ -320,14 +323,14 @@ Dodo sends 40+ event types across nine domains. Subscribe to only the events you
|
|
|
320
323
|
|
|
321
324
|
| Event | When it fires | What to do |
|
|
322
325
|
|-------|---|---|
|
|
323
|
-
| `license_key.created` | License key is generated |
|
|
326
|
+
| `license_key.created` | License key is generated | Legacy; prefer `entitlement_grant.created` with `status: "Delivered"` |
|
|
324
327
|
|
|
325
328
|
### Entitlement grant events
|
|
326
329
|
|
|
327
330
|
| Event | When it fires | What to do |
|
|
328
331
|
|-------|---|---|
|
|
329
|
-
| `entitlement_grant.created` | Grant row is created |
|
|
330
|
-
| `entitlement_grant.delivered` |
|
|
332
|
+
| `entitlement_grant.created` | Grant row is created. Auto-fulfilled license keys arrive here with `status: "Delivered"` and a `license_key`; no `.delivered` follows | Grant access when `status` is `Delivered`; otherwise prepare for fulfillment |
|
|
333
|
+
| `entitlement_grant.delivered` | An existing grant moves to `Delivered` (manual fulfillment, or a revoked grant restored) | Grant platform, file, or license-key access |
|
|
331
334
|
| `entitlement_grant.failed` | Delivery fails and is no longer retried | Alert team, inspect `error_code` and `error_message` |
|
|
332
335
|
| `entitlement_grant.revoked` | Access is withdrawn | Revoke customer access, inspect `revocation_reason` |
|
|
333
336
|
|
|
@@ -356,6 +359,18 @@ These concern virtual credit entitlements, not monetary wallet balances.
|
|
|
356
359
|
| `dunning.started` | Dunning attempt begins after subscription enters `on_hold` | Monitor dunning progress |
|
|
357
360
|
| `dunning.recovered` | Customer updates payment method and charge succeeds | Reactivate subscription, send confirmation |
|
|
358
361
|
|
|
362
|
+
### Payout events
|
|
363
|
+
|
|
364
|
+
These concern your own funds moving to your bank account - use them for bookkeeping, not customer access.
|
|
365
|
+
|
|
366
|
+
| Event | When it fires | What to do |
|
|
367
|
+
|-------|---|---|
|
|
368
|
+
| `payout.created` | Payout is created (formerly emitted as `payout.not_initiated`) | Record the pending payout |
|
|
369
|
+
| `payout.in_progress` | Payout processing starts | Mark as in transit |
|
|
370
|
+
| `payout.on_hold` | Payout is paused or under review | Check whether more information is required |
|
|
371
|
+
| `payout.success` | Payout settles to your bank account | Reconcile in accounting |
|
|
372
|
+
| `payout.failed` | Payout fails; amount and fees return to your wallet | Alert finance, check bank details |
|
|
373
|
+
|
|
359
374
|
---
|
|
360
375
|
|
|
361
376
|
## Production-Grade Handler Pattern
|
|
@@ -464,7 +479,7 @@ Understand how Dodo delivers webhooks:
|
|
|
464
479
|
|
|
465
480
|
| Property | Behavior |
|
|
466
481
|
|----------|----------|
|
|
467
|
-
| **Timeout** |
|
|
482
|
+
| **Timeout** | 30 seconds for connection and read |
|
|
468
483
|
| **Success** | Any `2xx` response acknowledges delivery. Return `200` immediately after durably recording the event. |
|
|
469
484
|
| **Failure** | Any non-`2xx` response triggers a retry. |
|
|
470
485
|
| **Retries** | Eight attempts: immediately, 5s, 5m, 30m, 2h, 5h, 10h, 10h |
|
|
@@ -483,7 +498,7 @@ If you use a supported framework, use the official adaptor package for built-in
|
|
|
483
498
|
|-----------|---------|---|
|
|
484
499
|
| Next.js | `@dodopayments/nextjs` | `Webhooks({ webhookKey, onPayload })` |
|
|
485
500
|
| Nuxt | `@dodopayments/nuxt` | `Webhooks({ webhookKey, onPayload })` |
|
|
486
|
-
| Express | `@dodopayments/express` |
|
|
501
|
+
| Express | `@dodopayments/express` | `Webhooks({ webhookKey, onPayload })` - register `express.json()` first, **not** `express.raw()` (it verifies against the parsed `req.body`) |
|
|
487
502
|
| Fastify | `@dodopayments/fastify` | `Webhooks({ webhookKey, onPayload })` |
|
|
488
503
|
| Hono | `@dodopayments/hono` | `Webhooks({ webhookKey, onPayload })` |
|
|
489
504
|
| Astro | `@dodopayments/astro` | `Webhooks({ webhookKey, onPayload })` |
|
|
@@ -549,7 +564,7 @@ Forward real test-mode events to localhost:
|
|
|
549
564
|
dodo wh listen http://localhost:3000/webhook
|
|
550
565
|
```
|
|
551
566
|
|
|
552
|
-
This creates a test webhook, opens a WebSocket relay, and forwards events with
|
|
567
|
+
This creates a test webhook, opens a WebSocket relay, and forwards events with the original `webhook-id`/`webhook-signature`/`webhook-timestamp` headers to your local URL. Requires a test-mode API key. The relay and CLI parse and **re-serialize** the JSON body, so if it differs byte-for-byte from the original (for example number formatting), signature verification fails even though the headers are intact - that is a relay artifact, not a bug in your verifier. The URL argument is required in direct mode — bare `dodo wh listen` only works as `/wh listen` inside the TUI.
|
|
553
568
|
|
|
554
569
|
### CLI: Unsigned mock events
|
|
555
570
|
|
|
@@ -561,6 +576,8 @@ dodo wh trigger payment.success http://localhost:3000/webhook
|
|
|
561
576
|
|
|
562
577
|
Use `unsafeUnwrap()` only for these unsigned payloads. Both arguments are required in direct mode.
|
|
563
578
|
|
|
579
|
+
Trigger names are not always the payload `type`: `payment.success` sends `type: "payment.succeeded"`, `refund.success` sends `refund.succeeded`, and `licence.created` sends `license_key.created`. Your handler must switch on the payload types. `subscription.past_due` and `subscription.unpaused` cannot be triggered.
|
|
580
|
+
|
|
564
581
|
### Tunnel
|
|
565
582
|
|
|
566
583
|
Expose localhost with ngrok and register the HTTPS URL in the dashboard:
|
|
@@ -653,7 +670,7 @@ app.post('/webhook', async (req, res) => {
|
|
|
653
670
|
await db.payment.create(...);
|
|
654
671
|
await sendEmail(...);
|
|
655
672
|
|
|
656
|
-
res.json({ received: true }); // Dodo times out after
|
|
673
|
+
res.json({ received: true }); // Dodo times out after 30s
|
|
657
674
|
});
|
|
658
675
|
```
|
|
659
676
|
|