@peable.to/contracts 0.4.0 → 1.1.0
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/dist/cjs/common/address.js +81 -0
- package/dist/cjs/common/envelopes.js +101 -0
- package/dist/cjs/common/objects.js +85 -0
- package/dist/cjs/common/params.js +211 -0
- package/dist/cjs/common/primitives.js +39 -0
- package/dist/cjs/contributions.js +22 -0
- package/dist/cjs/index.js +40 -137
- package/dist/cjs/openapi/document.js +297 -0
- package/dist/cjs/openapi/index.js +7 -0
- package/dist/cjs/openapi/webhooks.js +17 -0
- package/dist/cjs/resources/billingEngine/billingPortal.js +237 -0
- package/dist/cjs/resources/billingEngine/creditNotes.js +189 -0
- package/dist/cjs/resources/billingEngine/customerBalanceTransactions.js +90 -0
- package/dist/cjs/resources/billingEngine/index.js +43 -0
- package/dist/cjs/resources/billingEngine/invoiceItems.js +155 -0
- package/dist/cjs/resources/billingEngine/invoices.js +509 -0
- package/dist/cjs/resources/billingEngine/params.js +43 -0
- package/dist/cjs/resources/billingEngine/public.js +326 -0
- package/dist/cjs/resources/billingEngine/subscriptions.js +476 -0
- package/dist/cjs/resources/catalog/billing.js +755 -0
- package/dist/cjs/resources/catalog/billingSettings.js +131 -0
- package/dist/cjs/resources/catalog/coupons.js +222 -0
- package/dist/cjs/resources/catalog/entitlements.js +257 -0
- package/dist/cjs/resources/catalog/index.js +58 -0
- package/dist/cjs/resources/catalog/meters.js +279 -0
- package/dist/cjs/resources/catalog/prices.js +423 -0
- package/dist/cjs/resources/catalog/products.js +228 -0
- package/dist/cjs/resources/catalog/promotionCodes.js +174 -0
- package/dist/cjs/resources/catalog/shared.js +75 -0
- package/dist/cjs/resources/catalog/testClocks.js +127 -0
- package/dist/cjs/resources/checkout/checkoutSessions.js +582 -0
- package/dist/cjs/resources/checkout/contributions.js +172 -0
- package/dist/cjs/resources/checkout/files.js +133 -0
- package/dist/cjs/resources/checkout/index.js +57 -0
- package/dist/cjs/resources/checkout/merchants.js +290 -0
- package/dist/cjs/resources/checkout/paymentLinks.js +330 -0
- package/dist/cjs/resources/checkout/paymentMethodConfigurations.js +262 -0
- package/dist/cjs/resources/checkout/shared.js +368 -0
- package/dist/cjs/resources/connect/account.js +332 -0
- package/dist/cjs/resources/connect/applicationFees.js +113 -0
- package/dist/cjs/resources/connect/balance.js +212 -0
- package/dist/cjs/resources/connect/connectedAccounts.js +260 -0
- package/dist/cjs/resources/connect/index.js +51 -0
- package/dist/cjs/resources/connect/onboarding.js +82 -0
- package/dist/cjs/resources/connect/payouts.js +196 -0
- package/dist/cjs/resources/connect/reporting.js +235 -0
- package/dist/cjs/resources/connect/requestLogs.js +110 -0
- package/dist/cjs/resources/connect/transfers.js +227 -0
- package/dist/cjs/resources/core/customers.js +194 -0
- package/dist/cjs/resources/core/index.js +23 -0
- package/dist/cjs/resources/core/paymentMethods.js +134 -0
- package/dist/cjs/resources/events/events.js +357 -0
- package/dist/cjs/resources/events/index.js +29 -0
- package/dist/cjs/resources/events/webhookDeliveries.js +93 -0
- package/dist/cjs/resources/events/webhookEndpoints.js +215 -0
- package/dist/cjs/resources/payments/charges.js +157 -0
- package/dist/cjs/resources/payments/disputes.js +204 -0
- package/dist/cjs/resources/payments/index.js +41 -0
- package/dist/cjs/resources/payments/paymentIntents.js +529 -0
- package/dist/cjs/resources/payments/refunds.js +245 -0
- package/dist/cjs/resources/payments/setupIntents.js +158 -0
- package/dist/cjs/resources/payments/social.js +182 -0
- package/dist/cjs/resources/payments/testHelpers.js +39 -0
- package/dist/cjs/resources/tax/assessments.js +217 -0
- package/dist/cjs/resources/tax/businessProfile.js +99 -0
- package/dist/cjs/resources/tax/calculations.js +176 -0
- package/dist/cjs/resources/tax/capabilities.js +42 -0
- package/dist/cjs/resources/tax/codes.js +37 -0
- package/dist/cjs/resources/tax/complianceActions.js +56 -0
- package/dist/cjs/resources/tax/deadlines.js +59 -0
- package/dist/cjs/resources/tax/documents.js +128 -0
- package/dist/cjs/resources/tax/index.js +80 -0
- package/dist/cjs/resources/tax/locationEvidence.js +131 -0
- package/dist/cjs/resources/tax/operatingLocations.js +98 -0
- package/dist/cjs/resources/tax/products.js +67 -0
- package/dist/cjs/resources/tax/registrationDeclarations.js +124 -0
- package/dist/cjs/resources/tax/registrations.js +82 -0
- package/dist/cjs/resources/tax/reports.js +92 -0
- package/dist/cjs/resources/tax/reviewItems.js +116 -0
- package/dist/cjs/resources/tax/ruleSet.js +68 -0
- package/dist/cjs/resources/tax/salesDestinations.js +94 -0
- package/dist/cjs/resources/tax/settings.js +104 -0
- package/dist/cjs/resources/tax/shared.js +62 -0
- package/dist/cjs/resources/tax/transactions.js +102 -0
- package/dist/cjs/route.js +22 -0
- package/dist/cjs/routes.js +31 -0
- package/dist/cjs/vocabulary/billingPortal.js +15 -0
- package/dist/cjs/vocabulary/catalog.js +110 -0
- package/dist/cjs/vocabulary/checkout.js +53 -0
- package/dist/cjs/vocabulary/connect.js +95 -0
- package/dist/cjs/vocabulary/dashboard.js +68 -0
- package/dist/cjs/vocabulary/errors.js +175 -0
- package/dist/cjs/vocabulary/events.js +176 -0
- package/dist/cjs/vocabulary/files.js +44 -0
- package/dist/cjs/vocabulary/identity.js +12 -0
- package/dist/cjs/vocabulary/index.js +39 -0
- package/dist/cjs/vocabulary/invoices.js +52 -0
- package/dist/cjs/vocabulary/lists.js +22 -0
- package/dist/cjs/vocabulary/merchants.js +23 -0
- package/dist/cjs/vocabulary/money.js +104 -0
- package/dist/cjs/vocabulary/paymentMethodConfigurations.js +36 -0
- package/dist/cjs/vocabulary/payments.js +195 -0
- package/dist/cjs/vocabulary/reporting.js +27 -0
- package/dist/cjs/vocabulary/subscriptions.js +60 -0
- package/dist/cjs/vocabulary/tax.js +237 -0
- package/dist/cjs/vocabulary/version.js +12 -0
- package/dist/esm/common/address.js +76 -0
- package/dist/esm/common/envelopes.js +95 -0
- package/dist/esm/common/objects.js +74 -0
- package/dist/esm/common/params.js +203 -0
- package/dist/esm/common/primitives.js +35 -0
- package/dist/esm/contributions.js +5 -0
- package/dist/esm/index.js +26 -134
- package/dist/esm/openapi/document.js +294 -0
- package/dist/esm/openapi/index.js +2 -0
- package/dist/esm/openapi/webhooks.js +14 -0
- package/dist/esm/resources/billingEngine/billingPortal.js +234 -0
- package/dist/esm/resources/billingEngine/creditNotes.js +186 -0
- package/dist/esm/resources/billingEngine/customerBalanceTransactions.js +87 -0
- package/dist/esm/resources/billingEngine/index.js +26 -0
- package/dist/esm/resources/billingEngine/invoiceItems.js +152 -0
- package/dist/esm/resources/billingEngine/invoices.js +506 -0
- package/dist/esm/resources/billingEngine/params.js +39 -0
- package/dist/esm/resources/billingEngine/public.js +323 -0
- package/dist/esm/resources/billingEngine/subscriptions.js +473 -0
- package/dist/esm/resources/catalog/billing.js +752 -0
- package/dist/esm/resources/catalog/billingSettings.js +128 -0
- package/dist/esm/resources/catalog/coupons.js +219 -0
- package/dist/esm/resources/catalog/entitlements.js +254 -0
- package/dist/esm/resources/catalog/index.js +38 -0
- package/dist/esm/resources/catalog/meters.js +276 -0
- package/dist/esm/resources/catalog/prices.js +419 -0
- package/dist/esm/resources/catalog/products.js +225 -0
- package/dist/esm/resources/catalog/promotionCodes.js +171 -0
- package/dist/esm/resources/catalog/shared.js +67 -0
- package/dist/esm/resources/catalog/testClocks.js +124 -0
- package/dist/esm/resources/checkout/checkoutSessions.js +579 -0
- package/dist/esm/resources/checkout/contributions.js +167 -0
- package/dist/esm/resources/checkout/files.js +130 -0
- package/dist/esm/resources/checkout/index.js +25 -0
- package/dist/esm/resources/checkout/merchants.js +287 -0
- package/dist/esm/resources/checkout/paymentLinks.js +327 -0
- package/dist/esm/resources/checkout/paymentMethodConfigurations.js +259 -0
- package/dist/esm/resources/checkout/shared.js +363 -0
- package/dist/esm/resources/connect/account.js +329 -0
- package/dist/esm/resources/connect/applicationFees.js +110 -0
- package/dist/esm/resources/connect/balance.js +209 -0
- package/dist/esm/resources/connect/connectedAccounts.js +257 -0
- package/dist/esm/resources/connect/index.js +34 -0
- package/dist/esm/resources/connect/onboarding.js +79 -0
- package/dist/esm/resources/connect/payouts.js +193 -0
- package/dist/esm/resources/connect/reporting.js +232 -0
- package/dist/esm/resources/connect/requestLogs.js +107 -0
- package/dist/esm/resources/connect/transfers.js +224 -0
- package/dist/esm/resources/core/customers.js +191 -0
- package/dist/esm/resources/core/index.js +6 -0
- package/dist/esm/resources/core/paymentMethods.js +131 -0
- package/dist/esm/resources/events/events.js +353 -0
- package/dist/esm/resources/events/index.js +12 -0
- package/dist/esm/resources/events/webhookDeliveries.js +90 -0
- package/dist/esm/resources/events/webhookEndpoints.js +212 -0
- package/dist/esm/resources/payments/charges.js +154 -0
- package/dist/esm/resources/payments/disputes.js +201 -0
- package/dist/esm/resources/payments/index.js +24 -0
- package/dist/esm/resources/payments/paymentIntents.js +526 -0
- package/dist/esm/resources/payments/refunds.js +242 -0
- package/dist/esm/resources/payments/setupIntents.js +155 -0
- package/dist/esm/resources/payments/social.js +179 -0
- package/dist/esm/resources/payments/testHelpers.js +36 -0
- package/dist/esm/resources/tax/assessments.js +214 -0
- package/dist/esm/resources/tax/businessProfile.js +96 -0
- package/dist/esm/resources/tax/calculations.js +173 -0
- package/dist/esm/resources/tax/capabilities.js +39 -0
- package/dist/esm/resources/tax/codes.js +34 -0
- package/dist/esm/resources/tax/complianceActions.js +53 -0
- package/dist/esm/resources/tax/deadlines.js +56 -0
- package/dist/esm/resources/tax/documents.js +125 -0
- package/dist/esm/resources/tax/index.js +63 -0
- package/dist/esm/resources/tax/locationEvidence.js +128 -0
- package/dist/esm/resources/tax/operatingLocations.js +95 -0
- package/dist/esm/resources/tax/products.js +64 -0
- package/dist/esm/resources/tax/registrationDeclarations.js +121 -0
- package/dist/esm/resources/tax/registrations.js +79 -0
- package/dist/esm/resources/tax/reports.js +89 -0
- package/dist/esm/resources/tax/reviewItems.js +113 -0
- package/dist/esm/resources/tax/ruleSet.js +65 -0
- package/dist/esm/resources/tax/salesDestinations.js +91 -0
- package/dist/esm/resources/tax/settings.js +101 -0
- package/dist/esm/resources/tax/shared.js +58 -0
- package/dist/esm/resources/tax/transactions.js +99 -0
- package/dist/esm/route.js +16 -0
- package/dist/esm/routes.js +27 -0
- package/dist/esm/vocabulary/billingPortal.js +12 -0
- package/dist/esm/vocabulary/catalog.js +106 -0
- package/dist/esm/vocabulary/checkout.js +50 -0
- package/dist/esm/vocabulary/connect.js +92 -0
- package/dist/esm/vocabulary/dashboard.js +64 -0
- package/dist/esm/vocabulary/errors.js +170 -0
- package/dist/esm/vocabulary/events.js +173 -0
- package/dist/esm/vocabulary/files.js +41 -0
- package/dist/esm/vocabulary/identity.js +9 -0
- package/dist/esm/vocabulary/index.js +23 -0
- package/dist/esm/vocabulary/invoices.js +49 -0
- package/dist/esm/vocabulary/lists.js +19 -0
- package/dist/esm/vocabulary/merchants.js +20 -0
- package/dist/esm/vocabulary/money.js +98 -0
- package/dist/esm/vocabulary/paymentMethodConfigurations.js +33 -0
- package/dist/esm/vocabulary/payments.js +192 -0
- package/dist/esm/vocabulary/reporting.js +24 -0
- package/dist/esm/vocabulary/subscriptions.js +57 -0
- package/dist/esm/vocabulary/tax.js +233 -0
- package/dist/esm/vocabulary/version.js +9 -0
- package/dist/types/common/address.d.ts +62 -0
- package/dist/types/common/envelopes.d.ts +88 -0
- package/dist/types/common/objects.d.ts +107 -0
- package/dist/types/common/params.d.ts +156 -0
- package/dist/types/common/primitives.d.ts +56 -0
- package/dist/types/contributions.d.ts +1 -0
- package/dist/types/index.d.ts +16 -171
- package/dist/types/openapi/document.d.ts +16 -0
- package/dist/types/openapi/index.d.ts +2 -0
- package/dist/types/openapi/webhooks.d.ts +15 -0
- package/dist/types/resources/billingEngine/billingPortal.d.ts +742 -0
- package/dist/types/resources/billingEngine/creditNotes.d.ts +655 -0
- package/dist/types/resources/billingEngine/customerBalanceTransactions.d.ts +282 -0
- package/dist/types/resources/billingEngine/index.d.ts +6071 -0
- package/dist/types/resources/billingEngine/invoiceItems.d.ts +502 -0
- package/dist/types/resources/billingEngine/invoices.d.ts +2547 -0
- package/dist/types/resources/billingEngine/params.d.ts +51 -0
- package/dist/types/resources/billingEngine/public.d.ts +1860 -0
- package/dist/types/resources/billingEngine/subscriptions.d.ts +1519 -0
- package/dist/types/resources/catalog/billing.d.ts +1723 -0
- package/dist/types/resources/catalog/billingSettings.d.ts +160 -0
- package/dist/types/resources/catalog/coupons.d.ts +403 -0
- package/dist/types/resources/catalog/entitlements.d.ts +422 -0
- package/dist/types/resources/catalog/index.d.ts +3155 -0
- package/dist/types/resources/catalog/meters.d.ts +474 -0
- package/dist/types/resources/catalog/prices.d.ts +1091 -0
- package/dist/types/resources/catalog/products.d.ts +430 -0
- package/dist/types/resources/catalog/promotionCodes.d.ts +369 -0
- package/dist/types/resources/catalog/shared.d.ts +34 -0
- package/dist/types/resources/catalog/testClocks.d.ts +220 -0
- package/dist/types/resources/checkout/checkoutSessions.d.ts +3207 -0
- package/dist/types/resources/checkout/contributions.d.ts +375 -0
- package/dist/types/resources/checkout/files.d.ts +280 -0
- package/dist/types/resources/checkout/index.d.ts +5678 -0
- package/dist/types/resources/checkout/merchants.d.ts +395 -0
- package/dist/types/resources/checkout/paymentLinks.d.ts +1728 -0
- package/dist/types/resources/checkout/paymentMethodConfigurations.d.ts +2104 -0
- package/dist/types/resources/checkout/shared.d.ts +419 -0
- package/dist/types/resources/connect/account.d.ts +483 -0
- package/dist/types/resources/connect/applicationFees.d.ts +198 -0
- package/dist/types/resources/connect/balance.d.ts +399 -0
- package/dist/types/resources/connect/connectedAccounts.d.ts +494 -0
- package/dist/types/resources/connect/index.d.ts +2094 -0
- package/dist/types/resources/connect/onboarding.d.ts +95 -0
- package/dist/types/resources/connect/payouts.d.ts +527 -0
- package/dist/types/resources/connect/reporting.d.ts +506 -0
- package/dist/types/resources/connect/requestLogs.d.ts +236 -0
- package/dist/types/resources/connect/transfers.d.ts +436 -0
- package/dist/types/resources/core/customers.d.ts +619 -0
- package/dist/types/resources/core/index.d.ts +679 -0
- package/dist/types/resources/core/paymentMethods.d.ts +336 -0
- package/dist/types/resources/events/events.d.ts +731 -0
- package/dist/types/resources/events/index.d.ts +1727 -0
- package/dist/types/resources/events/webhookDeliveries.d.ts +436 -0
- package/dist/types/resources/events/webhookEndpoints.d.ts +1502 -0
- package/dist/types/resources/payments/charges.d.ts +390 -0
- package/dist/types/resources/payments/disputes.d.ts +822 -0
- package/dist/types/resources/payments/index.d.ts +3517 -0
- package/dist/types/resources/payments/paymentIntents.d.ts +2080 -0
- package/dist/types/resources/payments/refunds.d.ts +684 -0
- package/dist/types/resources/payments/setupIntents.d.ts +391 -0
- package/dist/types/resources/payments/social.d.ts +266 -0
- package/dist/types/resources/payments/testHelpers.d.ts +178 -0
- package/dist/types/resources/tax/assessments.d.ts +787 -0
- package/dist/types/resources/tax/businessProfile.d.ts +134 -0
- package/dist/types/resources/tax/calculations.d.ts +261 -0
- package/dist/types/resources/tax/capabilities.d.ts +81 -0
- package/dist/types/resources/tax/codes.d.ts +29 -0
- package/dist/types/resources/tax/complianceActions.d.ts +97 -0
- package/dist/types/resources/tax/deadlines.d.ts +133 -0
- package/dist/types/resources/tax/documents.d.ts +257 -0
- package/dist/types/resources/tax/index.d.ts +1946 -0
- package/dist/types/resources/tax/locationEvidence.d.ts +246 -0
- package/dist/types/resources/tax/operatingLocations.d.ts +170 -0
- package/dist/types/resources/tax/products.d.ts +68 -0
- package/dist/types/resources/tax/registrationDeclarations.d.ts +270 -0
- package/dist/types/resources/tax/registrations.d.ts +103 -0
- package/dist/types/resources/tax/reports.d.ts +129 -0
- package/dist/types/resources/tax/reviewItems.d.ts +226 -0
- package/dist/types/resources/tax/ruleSet.d.ts +219 -0
- package/dist/types/resources/tax/salesDestinations.d.ts +158 -0
- package/dist/types/resources/tax/settings.d.ts +122 -0
- package/dist/types/resources/tax/shared.d.ts +43 -0
- package/dist/types/resources/tax/transactions.d.ts +404 -0
- package/dist/types/route.d.ts +86 -0
- package/dist/types/routes.d.ts +23 -0
- package/dist/types/vocabulary/billingPortal.d.ts +15 -0
- package/dist/types/vocabulary/catalog.d.ts +97 -0
- package/dist/types/vocabulary/checkout.d.ts +49 -0
- package/dist/types/vocabulary/connect.d.ts +62 -0
- package/dist/types/vocabulary/dashboard.d.ts +44 -0
- package/dist/types/vocabulary/errors.d.ts +146 -0
- package/dist/types/vocabulary/events.d.ts +171 -0
- package/dist/types/vocabulary/files.d.ts +30 -0
- package/dist/types/vocabulary/identity.d.ts +9 -0
- package/dist/types/vocabulary/index.d.ts +19 -0
- package/dist/types/vocabulary/invoices.d.ts +39 -0
- package/dist/types/vocabulary/lists.d.ts +9 -0
- package/dist/types/vocabulary/merchants.d.ts +9 -0
- package/dist/types/vocabulary/money.d.ts +59 -0
- package/dist/types/vocabulary/paymentMethodConfigurations.d.ts +22 -0
- package/dist/types/vocabulary/payments.d.ts +117 -0
- package/dist/types/vocabulary/reporting.d.ts +18 -0
- package/dist/types/vocabulary/subscriptions.d.ts +45 -0
- package/dist/types/vocabulary/tax.d.ts +163 -0
- package/dist/types/vocabulary/version.d.ts +10 -0
- package/package.json +51 -11
- package/dist/cjs/openapi.js +0 -165
- package/dist/esm/openapi.js +0 -161
- package/dist/types/openapi.d.ts +0 -148
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { listOf } from '../../common/envelopes.js';
|
|
3
|
+
import { defineComponent, defineObject, resolveObject } from '../../common/objects.js';
|
|
4
|
+
import { idParam, listQuery, queryBoolean, retrieveQuery } from '../../common/params.js';
|
|
5
|
+
import { livemode, unixSeconds } from '../../common/primitives.js';
|
|
6
|
+
import { defineRoute } from '../../route.js';
|
|
7
|
+
import { WEBHOOK_EVENT_OBJECTS, WEBHOOK_EVENT_TYPES, } from '../../vocabulary/events.js';
|
|
8
|
+
/**
|
|
9
|
+
* Events (`evt_…`, ADR 0014 D4) — Stripe's event names (ADR 0019) with the
|
|
10
|
+
* resource nested under `data.object`. Stored once, in the transaction of the
|
|
11
|
+
* change it records, kept 30 days (`/v1/events`), and delivered HMAC-signed to
|
|
12
|
+
* every matching webhook endpoint: a delivery's body and `GET /v1/events/:id`
|
|
13
|
+
* are byte for byte the same object.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* The payload of `billing.observation.updated`: a wake-up, never paid or grant
|
|
17
|
+
* authority. Re-read the owner-bound resource it names.
|
|
18
|
+
*/
|
|
19
|
+
export const billingObservationSchema = defineObject('billing_observation', 'BillingObservation', z
|
|
20
|
+
.object({
|
|
21
|
+
object: z.literal('billing_observation'),
|
|
22
|
+
livemode: livemode.describe('The mode of the billing cohort observed (ADR 0017).'),
|
|
23
|
+
resource_kind: z.enum(['subscription', 'invoice']),
|
|
24
|
+
resource_id: z.string().describe('The provider subscription or invoice observed.'),
|
|
25
|
+
subscription_id: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Owner-scoped wake-up hint only; re-read the subscription before resolving a payer.'),
|
|
29
|
+
revision: z.number().int().describe('The observation revision; later revisions are newer.'),
|
|
30
|
+
observed_at: unixSeconds,
|
|
31
|
+
})
|
|
32
|
+
.strict(), {
|
|
33
|
+
examples: [
|
|
34
|
+
{
|
|
35
|
+
object: 'billing_observation',
|
|
36
|
+
livemode: false,
|
|
37
|
+
resource_kind: 'subscription',
|
|
38
|
+
resource_id: 'sub_1Q2w3E4r5T6y7U8i',
|
|
39
|
+
subscription_id: 'sub_1Q2w3E4r5T6y7U8i',
|
|
40
|
+
revision: 3,
|
|
41
|
+
observed_at: 1793750400,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
});
|
|
45
|
+
/**
|
|
46
|
+
* What caused an event, when an API request did (Stripe's `event.request`).
|
|
47
|
+
* Both `null` for an event caused by something else — the chain watcher, the
|
|
48
|
+
* expiry sweeper, a provider's own notification.
|
|
49
|
+
*/
|
|
50
|
+
export const eventRequestSchema = defineComponent('EventRequest', z
|
|
51
|
+
.object({
|
|
52
|
+
id: z
|
|
53
|
+
.string()
|
|
54
|
+
.nullable()
|
|
55
|
+
.describe('The `Request-Id` of the request whose change produced the event.'),
|
|
56
|
+
idempotency_key: z
|
|
57
|
+
.string()
|
|
58
|
+
.nullable()
|
|
59
|
+
.describe('The `Idempotency-Key` that request carried, if any.'),
|
|
60
|
+
})
|
|
61
|
+
.strict());
|
|
62
|
+
const previousAttributes = z
|
|
63
|
+
.record(z.string(), z.unknown())
|
|
64
|
+
.optional()
|
|
65
|
+
.describe('The fields of `object` that this change moved, with their values BEFORE it. Absent when the event is not a change of an existing object.');
|
|
66
|
+
/**
|
|
67
|
+
* The fields of the envelope that do not depend on its type, in the wire's
|
|
68
|
+
* order around `type` and `data` (`lib/serialize.ts` `toEventDTO`).
|
|
69
|
+
*/
|
|
70
|
+
const head = {
|
|
71
|
+
id: z.string().describe('`evt_…`.'),
|
|
72
|
+
object: z.literal('event'),
|
|
73
|
+
};
|
|
74
|
+
const tail = {
|
|
75
|
+
created: unixSeconds,
|
|
76
|
+
livemode: livemode.describe('The mode of the merchant it was sent to, and of the object it carries (ADR 0017).'),
|
|
77
|
+
api_version: z
|
|
78
|
+
.string()
|
|
79
|
+
.describe('The wire version the event was rendered with — the `Peable-Version` of the deployment that stored it. An event is a stored snapshot; it is not re-rendered when the wire moves on.'),
|
|
80
|
+
account: z
|
|
81
|
+
.string()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe('The connected account (`ca_…`) this event is about (ADR 0012 D7). Present on every event for an on-behalf payment and on `connected_account.updated`; absent otherwise.'),
|
|
84
|
+
};
|
|
85
|
+
/** The envelope around `type` and `data.object`. */
|
|
86
|
+
function envelope(type, object) {
|
|
87
|
+
return z
|
|
88
|
+
.object({
|
|
89
|
+
...head,
|
|
90
|
+
type,
|
|
91
|
+
...tail,
|
|
92
|
+
data: z.object({ object, previous_attributes: previousAttributes }).strict(),
|
|
93
|
+
request: eventRequestSchema,
|
|
94
|
+
})
|
|
95
|
+
.strict();
|
|
96
|
+
}
|
|
97
|
+
/** The schema of the object an event of `type` carries, once its module registered it. */
|
|
98
|
+
const objectOf = (type) => z.lazy(() => resolveObject(WEBHOOK_EVENT_OBJECTS[type]));
|
|
99
|
+
/** Every object type an event can carry, each once. */
|
|
100
|
+
const EVENT_OBJECT_TYPES = [...new Set(Object.values(WEBHOOK_EVENT_OBJECTS))];
|
|
101
|
+
/**
|
|
102
|
+
* An event of any type. `data.object` is the resource `type` names
|
|
103
|
+
* (`WEBHOOK_EVENT_OBJECTS`), checked against THAT object's schema — a
|
|
104
|
+
* `payment_intent.succeeded` carrying a Customer is refused even though a
|
|
105
|
+
* Customer is a valid event object.
|
|
106
|
+
*/
|
|
107
|
+
export const eventSchema = defineObject('event', 'Event', envelope(z.enum(WEBHOOK_EVENT_TYPES), z
|
|
108
|
+
.union(EVENT_OBJECT_TYPES.map((type) => z.lazy(() => resolveObject(type))))
|
|
109
|
+
.describe('The resource the event is about, as the API rendered it at the time.')).superRefine((event, ctx) => {
|
|
110
|
+
const expected = WEBHOOK_EVENT_OBJECTS[event.type];
|
|
111
|
+
const parsed = resolveObject(expected).safeParse(event.data.object);
|
|
112
|
+
if (parsed.success)
|
|
113
|
+
return;
|
|
114
|
+
for (const issue of parsed.error.issues) {
|
|
115
|
+
ctx.addIssue({
|
|
116
|
+
code: 'custom',
|
|
117
|
+
path: ['data', 'object', ...issue.path],
|
|
118
|
+
message: `a ${event.type} event carries a ${expected}: ${issue.message}`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}), {
|
|
122
|
+
examples: [
|
|
123
|
+
{
|
|
124
|
+
id: 'evt_0193b8f2c1a87d3e9f4b',
|
|
125
|
+
object: 'event',
|
|
126
|
+
type: 'webhook_endpoint.test',
|
|
127
|
+
created: 1793750400,
|
|
128
|
+
livemode: false,
|
|
129
|
+
api_version: '2026-11-03',
|
|
130
|
+
data: {
|
|
131
|
+
object: {
|
|
132
|
+
id: 'we_0193b8f2c1a87d3e9f4c',
|
|
133
|
+
object: 'webhook_endpoint',
|
|
134
|
+
livemode: false,
|
|
135
|
+
url: 'https://example.com/peable/webhooks',
|
|
136
|
+
description: null,
|
|
137
|
+
enabled_events: ['*'],
|
|
138
|
+
status: 'enabled',
|
|
139
|
+
disabled_reason: null,
|
|
140
|
+
api_version: '2026-11-03',
|
|
141
|
+
metadata: {},
|
|
142
|
+
created: 1793750000,
|
|
143
|
+
updated_at: 1793750000,
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
request: { id: 'req_0193b8f2c1a87d3e9f4d', idempotency_key: null },
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
});
|
|
150
|
+
/**
|
|
151
|
+
* The envelope of one event type, `data.object` narrowed to its object: the
|
|
152
|
+
* request body of that type's webhook in the OpenAPI document.
|
|
153
|
+
*/
|
|
154
|
+
export function eventSchemaOf(type) {
|
|
155
|
+
return envelope(z.literal(type), objectOf(type));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* `type=payment_intent.settled` (exact) or `type=payment_intent.*` (a dotted
|
|
159
|
+
* prefix). `*` alone is no filter. Lowercase dotted names only, so the value is
|
|
160
|
+
* never a LIKE pattern of the caller's choosing.
|
|
161
|
+
*/
|
|
162
|
+
const TYPE_FILTER_PATTERN = /^(\*|[a-z_]+(\.[a-z_]+)*(\.\*)?)$/;
|
|
163
|
+
function toTypeFilter(value) {
|
|
164
|
+
if (value === '*')
|
|
165
|
+
return undefined;
|
|
166
|
+
if (value.endsWith('.*'))
|
|
167
|
+
return { kind: 'prefix', prefix: value.slice(0, -1) };
|
|
168
|
+
return { kind: 'exact', type: value };
|
|
169
|
+
}
|
|
170
|
+
const typeFilter = z
|
|
171
|
+
.string()
|
|
172
|
+
.max(100)
|
|
173
|
+
.regex(TYPE_FILTER_PATTERN, 'type is an event type, or a prefix ending in .* (payment_intent.*)')
|
|
174
|
+
.transform(toTypeFilter);
|
|
175
|
+
/** The filters `GET /v1/events` adds to the list parameters. */
|
|
176
|
+
export const listEventsFilters = {
|
|
177
|
+
type: typeFilter
|
|
178
|
+
.optional()
|
|
179
|
+
.describe('An exact event type, or a prefix ending in `.*` (`payment_intent.*`).'),
|
|
180
|
+
delivery_success: queryBoolean
|
|
181
|
+
.optional()
|
|
182
|
+
.describe('`true`: only events every delivery of which succeeded. `false`: only events with a delivery still pending or failed.'),
|
|
183
|
+
payment_intent: idParam
|
|
184
|
+
.optional()
|
|
185
|
+
.describe('`pi_…`: only the events about that payment — the timeline of one payment.'),
|
|
186
|
+
};
|
|
187
|
+
export const listEventsQuery = listQuery(listEventsFilters);
|
|
188
|
+
export const retrieveEventQuery = retrieveQuery({});
|
|
189
|
+
/**
|
|
190
|
+
* The stream's `types`: a comma-separated list of the same filters
|
|
191
|
+
* (`payment_intent.settled,connected_account.*`). Absent, or any `*`, is every
|
|
192
|
+
* event.
|
|
193
|
+
*/
|
|
194
|
+
export const streamEventsQuery = z
|
|
195
|
+
.object({
|
|
196
|
+
types: z
|
|
197
|
+
.string()
|
|
198
|
+
.max(2000)
|
|
199
|
+
.transform((value) => value.split(',').map((part) => part.trim()))
|
|
200
|
+
.pipe(z
|
|
201
|
+
.array(z
|
|
202
|
+
.string()
|
|
203
|
+
.max(100)
|
|
204
|
+
.regex(TYPE_FILTER_PATTERN, 'types is a comma-separated list of event types, or prefixes ending in .*')
|
|
205
|
+
.transform(toTypeFilter))
|
|
206
|
+
.min(1)
|
|
207
|
+
.max(32))
|
|
208
|
+
.optional()
|
|
209
|
+
.describe('Comma-separated event types or `prefix.*` patterns (`payment_intent.succeeded,charge.*`). Absent: every event.'),
|
|
210
|
+
})
|
|
211
|
+
.strict();
|
|
212
|
+
/** One line per event type: what happened when it is sent. Total, like the vocabulary. */
|
|
213
|
+
export const WEBHOOK_EVENT_DESCRIPTIONS = {
|
|
214
|
+
'payment_intent.created': 'A PaymentIntent was created.',
|
|
215
|
+
'payment_intent.requires_action': 'A PaymentIntent needs the payer to act (pay, authenticate).',
|
|
216
|
+
'payment_intent.processing': 'A PaymentIntent is processing: a FairCoin payment was broadcast, or a card payment is pending.',
|
|
217
|
+
'payment_intent.amount_capturable_updated': 'A PaymentIntent was authorized and awaits capture (`capture_method: manual`).',
|
|
218
|
+
'payment_intent.succeeded': 'A PaymentIntent succeeded: the payment is final.',
|
|
219
|
+
'payment_intent.payment_failed': 'A payment attempt failed; a card PaymentIntent returns to `requires_payment_method`.',
|
|
220
|
+
'payment_intent.canceled': 'A PaymentIntent was canceled — by the merchant, by expiry, or underpaid.',
|
|
221
|
+
'charge.refunded': 'A Charge was refunded, partially or fully: `amount_refunded` moved.',
|
|
222
|
+
'charge.dispute.created': 'A cardholder disputed a charge. Evidence is due by its deadline.',
|
|
223
|
+
'charge.dispute.updated': 'A Dispute changed: evidence was staged or submitted.',
|
|
224
|
+
'charge.dispute.closed': 'A Dispute closed; `status` carries the outcome.',
|
|
225
|
+
'charge.dispute.funds_withdrawn': 'The network took the disputed amount from the balance.',
|
|
226
|
+
'charge.dispute.funds_reinstated': 'The network returned the disputed amount (the dispute was won, or withdrawn).',
|
|
227
|
+
'refund.created': 'A Refund was created.',
|
|
228
|
+
'refund.updated': 'A Refund changed state.',
|
|
229
|
+
'refund.failed': 'A Refund failed: the bank rejected it.',
|
|
230
|
+
'customer.created': 'A Customer was created.',
|
|
231
|
+
'customer.updated': 'A Customer was updated; `previous_attributes` names what moved.',
|
|
232
|
+
'customer.deleted': 'A Customer was deleted.',
|
|
233
|
+
'payment_method.attached': 'A PaymentMethod was attached to a Customer.',
|
|
234
|
+
'payment_method.detached': 'A PaymentMethod was detached from its Customer.',
|
|
235
|
+
'payment_method.updated': 'A PaymentMethod was updated.',
|
|
236
|
+
'setup_intent.created': 'A SetupIntent was created.',
|
|
237
|
+
'setup_intent.requires_action': 'A SetupIntent needs the customer to authenticate.',
|
|
238
|
+
'setup_intent.succeeded': 'A SetupIntent succeeded: its PaymentMethod is saved.',
|
|
239
|
+
'setup_intent.setup_failed': 'A SetupIntent attempt failed.',
|
|
240
|
+
'setup_intent.canceled': 'A SetupIntent was canceled.',
|
|
241
|
+
'billing.observation.updated': 'A recurring billing resource was observed to change. A wake-up only: re-read the resource.',
|
|
242
|
+
'connected_account.updated': "A seller's connected account changed — its readiness, in practice.",
|
|
243
|
+
'product.created': 'A Product was created.',
|
|
244
|
+
'product.updated': 'A Product was updated; `previous_attributes` names what moved.',
|
|
245
|
+
'product.deleted': 'A Product was deleted (it carries the product as it stood before).',
|
|
246
|
+
'price.created': 'A Price was created.',
|
|
247
|
+
'price.updated': 'A Price was updated (archiving one is `active: false`).',
|
|
248
|
+
'coupon.created': 'A Coupon was created.',
|
|
249
|
+
'coupon.updated': 'A Coupon was updated.',
|
|
250
|
+
'coupon.deleted': 'A Coupon was deleted.',
|
|
251
|
+
'promotion_code.created': 'A PromotionCode was created.',
|
|
252
|
+
'promotion_code.updated': 'A PromotionCode was updated (archiving one is `active: false`).',
|
|
253
|
+
'account.updated': "The merchant's own account changed: readiness, requirements or settings.",
|
|
254
|
+
'application_fee.created': "Orbit's fee was taken on a succeeded charge.",
|
|
255
|
+
'application_fee.refunded': 'Part or all of an application fee went back.',
|
|
256
|
+
'payout.created': 'A Payout was created.',
|
|
257
|
+
'payout.updated': 'A Payout changed.',
|
|
258
|
+
'payout.paid': 'A Payout arrived in the bank account.',
|
|
259
|
+
'payout.failed': 'A Payout failed.',
|
|
260
|
+
'payout.canceled': 'A Payout was canceled.',
|
|
261
|
+
'balance.available': 'Funds became available in the balance.',
|
|
262
|
+
'checkout.session.completed': 'The payer finished a Checkout Session (paid, authorized, or a FairCoin payment confirming).',
|
|
263
|
+
'checkout.session.expired': 'A Checkout Session expired, or the merchant expired it.',
|
|
264
|
+
'checkout.session.async_payment_succeeded': "A completed Checkout Session's FairCoin payment confirmed.",
|
|
265
|
+
'checkout.session.async_payment_failed': "A completed Checkout Session's FairCoin payment failed.",
|
|
266
|
+
'payment_link.created': 'A PaymentLink was created.',
|
|
267
|
+
'payment_link.updated': 'A PaymentLink was updated.',
|
|
268
|
+
'reporting.report_run.succeeded': 'A ReportRun finished: its CSV is `result`.',
|
|
269
|
+
'reporting.report_run.failed': 'A ReportRun could not be produced; `error` says why.',
|
|
270
|
+
'customer.subscription.created': 'A Subscription was created.',
|
|
271
|
+
'customer.subscription.updated': 'A Subscription changed; `previous_attributes` names what moved.',
|
|
272
|
+
'customer.subscription.deleted': 'A Subscription ended.',
|
|
273
|
+
'customer.subscription.trial_will_end': "A Subscription's trial ends in three days.",
|
|
274
|
+
'customer.subscription.paused': 'A Subscription was paused (a trial ended with no payment method).',
|
|
275
|
+
'customer.subscription.resumed': 'A paused Subscription resumed.',
|
|
276
|
+
'invoice.created': 'An Invoice was created.',
|
|
277
|
+
'invoice.updated': 'An Invoice changed.',
|
|
278
|
+
'invoice.deleted': 'A draft Invoice was deleted.',
|
|
279
|
+
'invoice.finalized': 'An Invoice was finalized.',
|
|
280
|
+
'invoice.paid': 'An Invoice was paid.',
|
|
281
|
+
'invoice.payment_failed': 'An attempt to pay an Invoice failed.',
|
|
282
|
+
'invoice.payment_action_required': 'Paying an Invoice needs the customer to act.',
|
|
283
|
+
'invoice.voided': 'An Invoice was voided.',
|
|
284
|
+
'invoice.marked_uncollectible': 'An Invoice was marked uncollectible.',
|
|
285
|
+
'invoice.upcoming': 'A renewal is days away; it carries a preview Invoice (`id` empty).',
|
|
286
|
+
'invoice.sent': 'An Invoice was emailed to the customer.',
|
|
287
|
+
'invoiceitem.created': 'An InvoiceItem was created.',
|
|
288
|
+
'invoiceitem.deleted': 'An InvoiceItem was deleted.',
|
|
289
|
+
'credit_note.created': 'A CreditNote was issued.',
|
|
290
|
+
'credit_note.updated': 'A CreditNote was updated.',
|
|
291
|
+
'credit_note.voided': 'A CreditNote was voided.',
|
|
292
|
+
'test_helpers.test_clock.created': 'A test clock was created.',
|
|
293
|
+
'test_helpers.test_clock.advancing': 'A test clock started advancing.',
|
|
294
|
+
'test_helpers.test_clock.ready': 'A test clock finished advancing.',
|
|
295
|
+
'test_helpers.test_clock.deleted': 'A test clock was deleted.',
|
|
296
|
+
'billing.meter.created': 'A billing Meter was created.',
|
|
297
|
+
'billing.meter.updated': 'A billing Meter was updated.',
|
|
298
|
+
'billing.meter.deactivated': 'A billing Meter was deactivated.',
|
|
299
|
+
'billing.meter.reactivated': 'A billing Meter was reactivated.',
|
|
300
|
+
'entitlements.active_entitlement_summary.updated': "A customer's active entitlements changed — re-read them, then grant or withdraw access.",
|
|
301
|
+
'billing_portal.configuration.created': 'A customer portal configuration was created.',
|
|
302
|
+
'billing_portal.configuration.updated': 'A customer portal configuration was updated.',
|
|
303
|
+
'billing_portal.session.created': 'A customer portal session was created.',
|
|
304
|
+
'tax.assessment.created': 'A tax compliance assessment was run. Nothing was registered, filed or collected.',
|
|
305
|
+
'tax.review_item.created': 'A tax assessment finding opened a review item.',
|
|
306
|
+
'tax.review_item.updated': 'A tax review item was decided, or found again.',
|
|
307
|
+
'webhook_endpoint.test': 'A test event, sent to ONE endpoint when its owner asks. It cannot be subscribed to.',
|
|
308
|
+
};
|
|
309
|
+
export const eventRoutes = [
|
|
310
|
+
defineRoute({
|
|
311
|
+
operationId: 'listEvents',
|
|
312
|
+
method: 'get',
|
|
313
|
+
path: '/v1/events',
|
|
314
|
+
tag: 'Events',
|
|
315
|
+
summary: 'List events',
|
|
316
|
+
description: 'Every event of the last 30 days, newest first, rendered exactly as its webhook deliveries carried it.',
|
|
317
|
+
auth: 'service',
|
|
318
|
+
scope: 'payments:read',
|
|
319
|
+
query: listEventsQuery,
|
|
320
|
+
response: listOf(eventSchema),
|
|
321
|
+
sdk: 'events.list',
|
|
322
|
+
expandable: 'event',
|
|
323
|
+
}),
|
|
324
|
+
defineRoute({
|
|
325
|
+
operationId: 'streamEvents',
|
|
326
|
+
method: 'get',
|
|
327
|
+
path: '/v1/events/stream',
|
|
328
|
+
tag: 'Events',
|
|
329
|
+
summary: 'Stream events',
|
|
330
|
+
description: 'Server-Sent Events: every event of this merchant as it commits, rendered exactly as a webhook delivery carries it (`event: event`, `id:` the `evt_…`). Resumes after `Last-Event-ID`. Test mode only — what `peable listen` forwards to a local server.',
|
|
331
|
+
auth: 'service',
|
|
332
|
+
scope: 'payments:read',
|
|
333
|
+
testModeOnly: true,
|
|
334
|
+
query: streamEventsQuery,
|
|
335
|
+
response: { kind: 'stream', event: eventSchema },
|
|
336
|
+
sdk: 'events.stream',
|
|
337
|
+
}),
|
|
338
|
+
defineRoute({
|
|
339
|
+
operationId: 'retrieveEvent',
|
|
340
|
+
method: 'get',
|
|
341
|
+
path: '/v1/events/{id}',
|
|
342
|
+
tag: 'Events',
|
|
343
|
+
summary: 'Retrieve an event',
|
|
344
|
+
description: 'A `404` once the event is older than 30 days.',
|
|
345
|
+
auth: 'service',
|
|
346
|
+
scope: 'payments:read',
|
|
347
|
+
params: { id: 'The event (`evt_…`).' },
|
|
348
|
+
query: retrieveEventQuery,
|
|
349
|
+
response: eventSchema,
|
|
350
|
+
sdk: 'events.retrieve',
|
|
351
|
+
expandable: 'event',
|
|
352
|
+
}),
|
|
353
|
+
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { eventRoutes } from './events.js';
|
|
2
|
+
import { webhookDeliveryRoutes } from './webhookDeliveries.js';
|
|
3
|
+
import { webhookEndpointRoutes } from './webhookEndpoints.js';
|
|
4
|
+
export * from './events.js';
|
|
5
|
+
export * from './webhookDeliveries.js';
|
|
6
|
+
export * from './webhookEndpoints.js';
|
|
7
|
+
/** Events, the webhook endpoints they are sent to, and the deliveries of them. */
|
|
8
|
+
export const eventsRoutes = [
|
|
9
|
+
...eventRoutes,
|
|
10
|
+
...webhookEndpointRoutes,
|
|
11
|
+
...webhookDeliveryRoutes,
|
|
12
|
+
];
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { listOf } from '../../common/envelopes.js';
|
|
3
|
+
import { defineObject } from '../../common/objects.js';
|
|
4
|
+
import { idParam, listQuery } from '../../common/params.js';
|
|
5
|
+
import { livemode, unixSeconds } from '../../common/primitives.js';
|
|
6
|
+
import { defineRoute } from '../../route.js';
|
|
7
|
+
import { WEBHOOK_DELIVERY_STATUSES, WEBHOOK_EVENT_TYPES } from '../../vocabulary/events.js';
|
|
8
|
+
/**
|
|
9
|
+
* Webhook deliveries (ADR 0014 D4) — one event sent to one webhook endpoint.
|
|
10
|
+
* An event that matches three endpoints is three deliveries, each with its own
|
|
11
|
+
* attempts, retried for about three days (ADR 0001 D7).
|
|
12
|
+
*/
|
|
13
|
+
export const webhookDeliverySchema = defineObject('webhook_delivery', 'WebhookDelivery', z
|
|
14
|
+
.object({
|
|
15
|
+
id: z.string(),
|
|
16
|
+
object: z.literal('webhook_delivery'),
|
|
17
|
+
livemode: livemode.describe('The mode of the merchant it was sent for (ADR 0017).'),
|
|
18
|
+
event_id: z.string().describe('The `evt_…` delivered — `GET /v1/events/:id` returns it.'),
|
|
19
|
+
event_type: z.enum(WEBHOOK_EVENT_TYPES),
|
|
20
|
+
webhook_endpoint_id: z.string().describe('The `we_…` it was sent to.'),
|
|
21
|
+
url: z.string().describe('The URL actually POSTed to, as of the latest attempt.'),
|
|
22
|
+
attempts: z.number().int().nonnegative(),
|
|
23
|
+
delivered: z.boolean(),
|
|
24
|
+
last_status: z
|
|
25
|
+
.enum(WEBHOOK_DELIVERY_STATUSES)
|
|
26
|
+
.describe('`pending`: will be attempted (`next_attempt_at`). `delivered`: terminal success. `failed`: the endpoint refused it (a 4xx, a blocked address) or was disabled first — never retried. `dead`: every attempt failed transiently for three days; it can be redelivered.'),
|
|
27
|
+
last_error: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Why the last attempt did not succeed — operator-facing, never a secret.'),
|
|
31
|
+
next_attempt_at: unixSeconds
|
|
32
|
+
.optional()
|
|
33
|
+
.describe('When the next attempt is due. Absent once the delivery is terminal.'),
|
|
34
|
+
created: unixSeconds,
|
|
35
|
+
updated_at: unixSeconds,
|
|
36
|
+
})
|
|
37
|
+
.strict(), {
|
|
38
|
+
examples: [
|
|
39
|
+
{
|
|
40
|
+
id: '0193b8f2-c1a8-7d3e-9f4a-7d3e0193b8f2',
|
|
41
|
+
object: 'webhook_delivery',
|
|
42
|
+
livemode: false,
|
|
43
|
+
event_id: 'evt_0193b8f2c1a87d3e9f4b',
|
|
44
|
+
event_type: 'payment_intent.succeeded',
|
|
45
|
+
webhook_endpoint_id: 'we_0193b8f2c1a87d3e9f4c',
|
|
46
|
+
url: 'https://example.com/peable/webhooks',
|
|
47
|
+
attempts: 1,
|
|
48
|
+
delivered: true,
|
|
49
|
+
last_status: 'delivered',
|
|
50
|
+
created: 1793750400,
|
|
51
|
+
updated_at: 1793750401,
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
});
|
|
55
|
+
/** The filters `GET /v1/webhook_deliveries` adds to the list parameters. */
|
|
56
|
+
export const listWebhookDeliveriesFilters = {
|
|
57
|
+
event: idParam.optional().describe('Only the deliveries of this event (`evt_…`).'),
|
|
58
|
+
webhook_endpoint: idParam.optional().describe('Only the deliveries to this endpoint (`we_…`).'),
|
|
59
|
+
};
|
|
60
|
+
export const listWebhookDeliveriesQuery = listQuery(listWebhookDeliveriesFilters);
|
|
61
|
+
export const webhookDeliveryRoutes = [
|
|
62
|
+
defineRoute({
|
|
63
|
+
operationId: 'listWebhookDeliveries',
|
|
64
|
+
method: 'get',
|
|
65
|
+
path: '/v1/webhook_deliveries',
|
|
66
|
+
tag: 'Webhook deliveries',
|
|
67
|
+
summary: 'List webhook deliveries',
|
|
68
|
+
description: "The delivery log, newest first: one event's deliveries, or one endpoint's. Both filters are public ids resolved inside your scope.",
|
|
69
|
+
auth: 'service',
|
|
70
|
+
scope: 'payments:read',
|
|
71
|
+
query: listWebhookDeliveriesQuery,
|
|
72
|
+
response: listOf(webhookDeliverySchema),
|
|
73
|
+
sdk: 'webhookDeliveries.list',
|
|
74
|
+
expandable: 'webhook_delivery',
|
|
75
|
+
}),
|
|
76
|
+
defineRoute({
|
|
77
|
+
operationId: 'redeliverWebhookDelivery',
|
|
78
|
+
method: 'post',
|
|
79
|
+
path: '/v1/webhook_deliveries/{id}/redeliver',
|
|
80
|
+
tag: 'Webhook deliveries',
|
|
81
|
+
summary: 'Redeliver a webhook delivery',
|
|
82
|
+
description: "Send the delivery's event to its endpoint again — the SAME stored event, as a NEW delivery, attempted at once; answers that new delivery. Refused while the endpoint is disabled (`webhook_endpoint_disabled`).",
|
|
83
|
+
auth: 'service',
|
|
84
|
+
scope: 'payments:write',
|
|
85
|
+
idempotent: true,
|
|
86
|
+
params: { id: 'The webhook delivery.' },
|
|
87
|
+
response: webhookDeliverySchema,
|
|
88
|
+
sdk: 'webhookDeliveries.redeliver',
|
|
89
|
+
}),
|
|
90
|
+
];
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { deletedOf, listOf } from '../../common/envelopes.js';
|
|
3
|
+
import { defineComponent, defineObject } from '../../common/objects.js';
|
|
4
|
+
import { expandOnlyQuery, listQuery, metadataCreateParam, metadataUpdateParam, } from '../../common/params.js';
|
|
5
|
+
import { livemode, metadata, unixSeconds } from '../../common/primitives.js';
|
|
6
|
+
import { defineRoute } from '../../route.js';
|
|
7
|
+
import { WEBHOOK_ENABLED_EVENTS, WEBHOOK_ENDPOINT_DESCRIPTION_MAX, WEBHOOK_ENDPOINT_DISABLED_REASONS, WEBHOOK_ENDPOINT_STATUSES, WEBHOOK_SECRET_ROLL_MAX_EXPIRES_IN_SECONDS, } from '../../vocabulary/events.js';
|
|
8
|
+
import { webhookDeliverySchema } from './webhookDeliveries.js';
|
|
9
|
+
/**
|
|
10
|
+
* Webhook endpoints (`we_…`, ADR 0014 D4) — one URL a merchant receives events
|
|
11
|
+
* at, with the event types it wants and the secret deliveries to it are signed
|
|
12
|
+
* with. A merchant may hold several; every event fans out to each ENABLED
|
|
13
|
+
* endpoint whose `enabled_events` matches it, as one delivery per endpoint.
|
|
14
|
+
*/
|
|
15
|
+
const enabledEvent = z.enum(WEBHOOK_ENABLED_EVENTS);
|
|
16
|
+
const endpointShape = {
|
|
17
|
+
id: z.string(),
|
|
18
|
+
object: z.literal('webhook_endpoint'),
|
|
19
|
+
livemode: livemode.describe('The mode of the merchant that owns it (ADR 0017).'),
|
|
20
|
+
url: z.string(),
|
|
21
|
+
description: z.string().nullable(),
|
|
22
|
+
enabled_events: z
|
|
23
|
+
.array(enabledEvent)
|
|
24
|
+
.describe('The event types sent to it; `*` is every type, including ones added later.'),
|
|
25
|
+
status: z.enum(WEBHOOK_ENDPOINT_STATUSES),
|
|
26
|
+
disabled_reason: z
|
|
27
|
+
.enum(WEBHOOK_ENDPOINT_DISABLED_REASONS)
|
|
28
|
+
.nullable()
|
|
29
|
+
.describe('`null` exactly when `status` is `enabled`. `delivery_failures`: every delivery failed for three days straight.'),
|
|
30
|
+
api_version: z.string().describe('The wire version events are rendered with for this endpoint.'),
|
|
31
|
+
metadata,
|
|
32
|
+
created: unixSeconds,
|
|
33
|
+
updated_at: unixSeconds,
|
|
34
|
+
};
|
|
35
|
+
const endpointExample = {
|
|
36
|
+
id: 'we_0193b8f2c1a87d3e9f4c',
|
|
37
|
+
object: 'webhook_endpoint',
|
|
38
|
+
livemode: false,
|
|
39
|
+
url: 'https://example.com/peable/webhooks',
|
|
40
|
+
description: 'Order fulfilment',
|
|
41
|
+
enabled_events: ['payment_intent.succeeded', 'charge.refunded'],
|
|
42
|
+
status: 'enabled',
|
|
43
|
+
disabled_reason: null,
|
|
44
|
+
api_version: '2026-11-03',
|
|
45
|
+
metadata: {},
|
|
46
|
+
created: 1793750000,
|
|
47
|
+
updated_at: 1793750000,
|
|
48
|
+
};
|
|
49
|
+
/** An endpoint as every answer but a create and a roll renders it: never the secret. */
|
|
50
|
+
export const webhookEndpointSchema = defineObject('webhook_endpoint', 'WebhookEndpoint', z.object(endpointShape).strict(), { examples: [endpointExample] });
|
|
51
|
+
/**
|
|
52
|
+
* The answer of a create and of a `roll_secret` — the ONLY two that show the
|
|
53
|
+
* signing secret. Peable never shows it again; a lost secret is rolled, not
|
|
54
|
+
* retrieved.
|
|
55
|
+
*/
|
|
56
|
+
export const webhookEndpointWithSecretSchema = defineComponent('WebhookEndpointWithSecret', z
|
|
57
|
+
.object({
|
|
58
|
+
...endpointShape,
|
|
59
|
+
secret: z
|
|
60
|
+
.string()
|
|
61
|
+
.regex(/^whsec_/)
|
|
62
|
+
.describe('The signing secret (`whsec_…`), shown on this answer only.'),
|
|
63
|
+
})
|
|
64
|
+
.strict(), { examples: [{ ...endpointExample, secret: 'whsec_9f4a7d3e0193b8f2c1a87d3e9f4a7d3e' }] });
|
|
65
|
+
/** What `DELETE /v1/webhook_endpoints/:id` answers. */
|
|
66
|
+
export const deletedWebhookEndpointSchema = defineComponent('DeletedWebhookEndpoint', deletedOf('webhook_endpoint'));
|
|
67
|
+
const enabledEventsParam = z
|
|
68
|
+
.array(enabledEvent)
|
|
69
|
+
.min(1, 'enabled_events needs at least one event type, or "*"')
|
|
70
|
+
.max(WEBHOOK_ENABLED_EVENTS.length)
|
|
71
|
+
// A repeated type means nothing more than one; stored once.
|
|
72
|
+
.transform((list) => [...new Set(list)]);
|
|
73
|
+
const descriptionParam = z.string().max(WEBHOOK_ENDPOINT_DESCRIPTION_MAX);
|
|
74
|
+
const urlParam = z
|
|
75
|
+
.string()
|
|
76
|
+
.min(1)
|
|
77
|
+
.describe('An `https` URL (a test-mode endpoint may also use `http`), ports 80/443 only.');
|
|
78
|
+
export const createWebhookEndpointParams = z
|
|
79
|
+
.object({
|
|
80
|
+
url: urlParam,
|
|
81
|
+
enabled_events: enabledEventsParam,
|
|
82
|
+
description: descriptionParam.min(1).optional(),
|
|
83
|
+
metadata: metadataCreateParam.optional(),
|
|
84
|
+
})
|
|
85
|
+
.strict();
|
|
86
|
+
export const updateWebhookEndpointParams = z
|
|
87
|
+
.object({
|
|
88
|
+
url: urlParam.optional(),
|
|
89
|
+
enabled_events: enabledEventsParam.optional(),
|
|
90
|
+
disabled: z
|
|
91
|
+
.boolean()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe('`true` stops deliveries; `false` re-enables an endpoint, whatever disabled it.'),
|
|
94
|
+
description: descriptionParam.optional().describe('`""` clears it.'),
|
|
95
|
+
metadata: metadataUpdateParam.optional(),
|
|
96
|
+
})
|
|
97
|
+
.strict();
|
|
98
|
+
export const rollWebhookEndpointSecretParams = z
|
|
99
|
+
.object({
|
|
100
|
+
expires_in_seconds: z
|
|
101
|
+
.number()
|
|
102
|
+
.int()
|
|
103
|
+
.min(0)
|
|
104
|
+
.max(WEBHOOK_SECRET_ROLL_MAX_EXPIRES_IN_SECONDS)
|
|
105
|
+
.optional()
|
|
106
|
+
.describe('How long the PREVIOUS secret keeps signing beside the new one, in seconds (0–86400, default 0). While both are live every delivery carries two `v1=` signatures, so a receiver can switch secrets without a gap.'),
|
|
107
|
+
})
|
|
108
|
+
.strict();
|
|
109
|
+
export const listWebhookEndpointsQuery = listQuery({});
|
|
110
|
+
const idDoc = { id: 'The webhook endpoint (`we_…`).' };
|
|
111
|
+
export const webhookEndpointRoutes = [
|
|
112
|
+
defineRoute({
|
|
113
|
+
operationId: 'createWebhookEndpoint',
|
|
114
|
+
method: 'post',
|
|
115
|
+
path: '/v1/webhook_endpoints',
|
|
116
|
+
tag: 'Webhook endpoints',
|
|
117
|
+
summary: 'Create a webhook endpoint',
|
|
118
|
+
description: 'The answer is the ONLY one that shows `secret`. A retry with the same `Idempotency-Key` replays it, secret included, for 24 hours. At most 16 endpoints per merchant and mode.',
|
|
119
|
+
auth: 'service',
|
|
120
|
+
scope: 'payments:write',
|
|
121
|
+
idempotent: true,
|
|
122
|
+
body: createWebhookEndpointParams,
|
|
123
|
+
response: webhookEndpointWithSecretSchema,
|
|
124
|
+
sdk: 'webhookEndpoints.create',
|
|
125
|
+
}),
|
|
126
|
+
defineRoute({
|
|
127
|
+
operationId: 'listWebhookEndpoints',
|
|
128
|
+
method: 'get',
|
|
129
|
+
path: '/v1/webhook_endpoints',
|
|
130
|
+
tag: 'Webhook endpoints',
|
|
131
|
+
summary: 'List webhook endpoints',
|
|
132
|
+
description: 'Newest first. Never the secret.',
|
|
133
|
+
auth: 'service',
|
|
134
|
+
scope: 'payments:read',
|
|
135
|
+
query: listWebhookEndpointsQuery,
|
|
136
|
+
response: listOf(webhookEndpointSchema),
|
|
137
|
+
sdk: 'webhookEndpoints.list',
|
|
138
|
+
expandable: 'webhook_endpoint',
|
|
139
|
+
}),
|
|
140
|
+
defineRoute({
|
|
141
|
+
operationId: 'retrieveWebhookEndpoint',
|
|
142
|
+
method: 'get',
|
|
143
|
+
path: '/v1/webhook_endpoints/{id}',
|
|
144
|
+
tag: 'Webhook endpoints',
|
|
145
|
+
summary: 'Retrieve a webhook endpoint',
|
|
146
|
+
description: 'Never the secret: a lost secret is rolled, not retrieved.',
|
|
147
|
+
auth: 'service',
|
|
148
|
+
scope: 'payments:read',
|
|
149
|
+
params: idDoc,
|
|
150
|
+
query: expandOnlyQuery,
|
|
151
|
+
response: webhookEndpointSchema,
|
|
152
|
+
sdk: 'webhookEndpoints.retrieve',
|
|
153
|
+
expandable: 'webhook_endpoint',
|
|
154
|
+
}),
|
|
155
|
+
defineRoute({
|
|
156
|
+
operationId: 'updateWebhookEndpoint',
|
|
157
|
+
method: 'post',
|
|
158
|
+
path: '/v1/webhook_endpoints/{id}',
|
|
159
|
+
tag: 'Webhook endpoints',
|
|
160
|
+
summary: 'Update a webhook endpoint',
|
|
161
|
+
description: '`url`, `enabled_events`, `disabled`, `description` (`""` clears it) and `metadata` (a patch).',
|
|
162
|
+
auth: 'service',
|
|
163
|
+
scope: 'payments:write',
|
|
164
|
+
idempotent: true,
|
|
165
|
+
params: idDoc,
|
|
166
|
+
body: updateWebhookEndpointParams,
|
|
167
|
+
response: webhookEndpointSchema,
|
|
168
|
+
sdk: 'webhookEndpoints.update',
|
|
169
|
+
}),
|
|
170
|
+
defineRoute({
|
|
171
|
+
operationId: 'deleteWebhookEndpoint',
|
|
172
|
+
method: 'delete',
|
|
173
|
+
path: '/v1/webhook_endpoints/{id}',
|
|
174
|
+
tag: 'Webhook endpoints',
|
|
175
|
+
summary: 'Delete a webhook endpoint',
|
|
176
|
+
description: 'Its deliveries go with it, pending ones included.',
|
|
177
|
+
auth: 'service',
|
|
178
|
+
scope: 'payments:write',
|
|
179
|
+
params: idDoc,
|
|
180
|
+
response: deletedWebhookEndpointSchema,
|
|
181
|
+
sdk: 'webhookEndpoints.del',
|
|
182
|
+
}),
|
|
183
|
+
defineRoute({
|
|
184
|
+
operationId: 'rollWebhookEndpointSecret',
|
|
185
|
+
method: 'post',
|
|
186
|
+
path: '/v1/webhook_endpoints/{id}/roll_secret',
|
|
187
|
+
tag: 'Webhook endpoints',
|
|
188
|
+
summary: 'Roll the signing secret',
|
|
189
|
+
description: 'Mint a new secret and show it once. With `expires_in_seconds` (≤ 24h) the previous one keeps signing beside it until then; without, it stops now.',
|
|
190
|
+
auth: 'service',
|
|
191
|
+
scope: 'payments:write',
|
|
192
|
+
idempotent: true,
|
|
193
|
+
params: idDoc,
|
|
194
|
+
body: rollWebhookEndpointSecretParams,
|
|
195
|
+
response: webhookEndpointWithSecretSchema,
|
|
196
|
+
sdk: 'webhookEndpoints.rollSecret',
|
|
197
|
+
}),
|
|
198
|
+
defineRoute({
|
|
199
|
+
operationId: 'sendWebhookEndpointTestEvent',
|
|
200
|
+
method: 'post',
|
|
201
|
+
path: '/v1/webhook_endpoints/{id}/test',
|
|
202
|
+
tag: 'Webhook endpoints',
|
|
203
|
+
summary: 'Send a test event',
|
|
204
|
+
description: 'Send this endpoint a `webhook_endpoint.test` event now and answer the delivery after its first attempt. A disabled endpoint is refused (`webhook_endpoint_disabled`).',
|
|
205
|
+
auth: 'service',
|
|
206
|
+
scope: 'payments:write',
|
|
207
|
+
idempotent: true,
|
|
208
|
+
params: idDoc,
|
|
209
|
+
response: webhookDeliverySchema,
|
|
210
|
+
sdk: 'webhookEndpoints.sendTestEvent',
|
|
211
|
+
}),
|
|
212
|
+
];
|