@volter/twin-stripe 2.0.38 → 3.0.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/README.md +82 -207
- package/dist/generated/pack-facts.json +94 -0
- package/dist/spec/SOURCE.md +14 -0
- package/dist/spec/fixtures3.json.gz +0 -0
- package/dist/spec/openapi.json.gz +0 -0
- package/dist/spec/patches.json +34 -0
- package/dist/spec/sources.json +378 -0
- package/dist/src/cli.js +12 -30
- package/dist/src/engine/after-payment.d.ts +9 -0
- package/dist/src/engine/after-payment.js +28 -0
- package/dist/src/engine/apps-secrets.d.ts +1 -0
- package/dist/src/engine/apps-secrets.js +3 -0
- package/dist/src/engine/balance.d.ts +5 -0
- package/dist/src/engine/balance.js +15 -0
- package/dist/src/engine/billing.d.ts +5 -0
- package/dist/src/engine/billing.js +6 -0
- package/dist/src/engine/charges.d.ts +6 -0
- package/dist/src/engine/charges.js +13 -0
- package/dist/src/engine/checkout.d.ts +24 -0
- package/dist/src/engine/checkout.js +30 -0
- package/dist/src/engine/common.d.ts +19 -0
- package/dist/src/engine/common.js +32 -0
- package/dist/src/{screens → engine}/connect-settings.d.ts +1 -7
- package/dist/src/engine/connect-settings.js +26 -0
- package/dist/src/engine/connect.d.ts +66 -0
- package/dist/src/engine/connect.js +189 -0
- package/dist/src/engine/coupons.d.ts +0 -0
- package/dist/src/engine/coupons.js +5 -0
- package/dist/src/engine/credit-notes.d.ts +1 -0
- package/dist/src/engine/credit-notes.js +5 -0
- package/dist/src/engine/customers.d.ts +12 -0
- package/dist/src/engine/customers.js +30 -0
- package/dist/src/engine/display.d.ts +14 -0
- package/dist/src/engine/display.js +16 -0
- package/dist/src/engine/disputes.d.ts +0 -0
- package/dist/src/engine/disputes.js +9 -0
- package/dist/src/engine/entitlements.d.ts +1 -0
- package/dist/src/engine/entitlements.js +4 -0
- package/dist/src/engine/ephemeral-keys.d.ts +0 -0
- package/dist/src/engine/ephemeral-keys.js +4 -0
- package/dist/src/engine/files.d.ts +18 -0
- package/dist/src/engine/files.js +33 -0
- package/dist/src/engine/front.d.ts +5 -0
- package/dist/src/engine/front.js +25 -0
- package/dist/src/engine/invoices.d.ts +24 -0
- package/dist/src/engine/invoices.js +57 -0
- package/dist/src/engine/issuing.d.ts +35 -0
- package/dist/src/engine/issuing.js +45 -0
- package/dist/src/engine/ledger.d.ts +9 -0
- package/dist/src/engine/ledger.js +9 -0
- package/dist/src/engine/oauth.d.ts +4 -0
- package/dist/src/engine/oauth.js +25 -0
- package/dist/src/engine/onboarding.d.ts +13 -0
- package/dist/src/engine/onboarding.js +42 -0
- package/dist/src/{stripe-params.d.ts → engine/params.d.ts} +20 -3
- package/dist/src/{stripe-params.js → engine/params.js} +7 -60
- package/dist/src/engine/payment-intents.d.ts +10 -0
- package/dist/src/engine/payment-intents.js +27 -0
- package/dist/src/engine/payment-links.d.ts +1 -0
- package/dist/src/engine/payment-links.js +5 -0
- package/dist/src/engine/payment-methods.d.ts +16 -0
- package/dist/src/engine/payment-methods.js +22 -0
- package/dist/src/engine/plans.d.ts +6 -0
- package/dist/src/engine/plans.js +26 -0
- package/dist/src/engine/platform.d.ts +39 -0
- package/dist/src/engine/platform.js +34 -0
- package/dist/src/engine/products.d.ts +0 -0
- package/dist/src/engine/products.js +4 -0
- package/dist/src/engine/radar.d.ts +2 -0
- package/dist/src/engine/radar.js +5 -0
- package/dist/src/engine/refunds.d.ts +1 -0
- package/dist/src/engine/refunds.js +28 -0
- package/dist/src/engine/renewals.d.ts +36 -0
- package/dist/src/engine/renewals.js +65 -0
- package/dist/src/engine/setup-intents.d.ts +1 -0
- package/dist/src/engine/setup-intents.js +4 -0
- package/dist/src/{stripe-twin.d.ts → engine/stripe.d.ts} +11 -39
- package/dist/src/{stripe-twin.js → engine/stripe.js} +25 -310
- package/dist/src/engine/subscription-schedules.d.ts +3 -0
- package/dist/src/engine/subscription-schedules.js +1 -0
- package/dist/src/engine/subscriptions.d.ts +12 -0
- package/dist/src/engine/subscriptions.js +31 -0
- package/dist/src/engine/tax.d.ts +7 -0
- package/dist/src/engine/tax.js +28 -0
- package/dist/src/engine/terminal.d.ts +4 -0
- package/dist/src/engine/terminal.js +20 -0
- package/dist/src/engine/test-clocks.d.ts +5 -0
- package/dist/src/engine/test-clocks.js +9 -0
- package/dist/src/engine/tokens.d.ts +7 -0
- package/dist/src/engine/tokens.js +20 -0
- package/dist/src/engine/transfers.d.ts +2 -0
- package/dist/src/engine/transfers.js +1 -0
- package/dist/src/engine/treasury.d.ts +23 -0
- package/dist/src/engine/treasury.js +45 -0
- package/dist/src/{stripe-version.js → engine/version.js} +4 -3
- package/dist/src/engine/webhook-endpoints.d.ts +1 -0
- package/dist/src/engine/webhook-endpoints.js +12 -0
- package/dist/src/engine/webhooks.d.ts +31 -0
- package/dist/src/engine/webhooks.js +68 -0
- package/dist/src/fetch.d.ts +2 -0
- package/dist/src/fetch.js +26 -0
- package/dist/src/generated/surface.gen.json +1 -1
- package/dist/src/generated/ui.gen.json +1 -1
- package/dist/src/index.d.ts +5 -14
- package/dist/src/index.js +8 -75
- package/dist/src/manifest.js +232 -758
- package/dist/src/screens/billing-portal.d.ts +3 -0
- package/dist/src/screens/{portal.js → billing-portal.js} +28 -54
- package/dist/src/screens/checkout.d.ts +2 -31
- package/dist/src/screens/checkout.js +32 -121
- package/dist/src/screens/connect-oauth.d.ts +3 -27
- package/dist/src/screens/connect-oauth.js +51 -132
- package/dist/src/screens/connect-onboarding.d.ts +3 -0
- package/dist/src/screens/{onboarding.js → connect-onboarding.js} +36 -102
- package/dist/src/screens/dashboard.d.ts +3 -0
- package/dist/src/screens/dashboard.js +117 -0
- package/dist/src/screens/shared.d.ts +27 -0
- package/dist/src/screens/shared.js +87 -0
- package/dist/src/screens/stripe-js.d.ts +3 -0
- package/dist/src/screens/stripe-js.js +135 -0
- package/dist/src/semantics/account_links.d.ts +2 -0
- package/dist/src/semantics/account_links.js +22 -0
- package/dist/src/semantics/accounts.d.ts +4 -0
- package/dist/src/semantics/accounts.js +38 -0
- package/dist/src/semantics/apps.d.ts +4 -0
- package/dist/src/semantics/{apps-secrets.js → apps.js} +14 -26
- package/dist/src/semantics/around.d.ts +2 -0
- package/dist/src/semantics/around.js +16 -0
- package/dist/src/semantics/balance.d.ts +2 -11
- package/dist/src/semantics/balance.js +3 -194
- package/dist/src/semantics/balance_transactions.d.ts +2 -0
- package/dist/src/semantics/balance_transactions.js +15 -0
- package/dist/src/semantics/billing_portal.d.ts +5 -0
- package/dist/src/semantics/billing_portal.js +42 -0
- package/dist/src/semantics/charges.d.ts +3 -28
- package/dist/src/semantics/charges.js +5 -202
- package/dist/src/semantics/checkout.d.ts +3 -20
- package/dist/src/semantics/checkout.js +8 -261
- package/dist/src/semantics/clock.d.ts +2 -0
- package/dist/src/semantics/clock.js +21 -0
- package/dist/src/semantics/coupons.d.ts +2 -6
- package/dist/src/semantics/coupons.js +2 -60
- package/dist/src/semantics/customers.d.ts +6 -6
- package/dist/src/semantics/customers.js +27 -387
- package/dist/src/semantics/disputes.d.ts +2 -2
- package/dist/src/semantics/disputes.js +3 -49
- package/dist/src/semantics/doors.d.ts +23 -0
- package/dist/src/semantics/doors.js +73 -0
- package/dist/src/semantics/entitlements.d.ts +2 -2
- package/dist/src/semantics/entitlements.js +5 -50
- package/dist/src/semantics/events.d.ts +12 -0
- package/dist/src/semantics/events.js +36 -0
- package/dist/src/semantics/index.d.ts +2 -0
- package/dist/src/semantics/index.js +107 -0
- package/dist/src/semantics/invoice_payments.d.ts +2 -0
- package/dist/src/semantics/invoice_payments.js +12 -0
- package/dist/src/semantics/invoiceitems.d.ts +3 -0
- package/dist/src/semantics/invoiceitems.js +59 -0
- package/dist/src/semantics/invoices.d.ts +16 -18
- package/dist/src/semantics/invoices.js +118 -444
- package/dist/src/semantics/payment_intents.d.ts +4 -0
- package/dist/src/semantics/payment_intents.js +79 -0
- package/dist/src/semantics/payment_methods.d.ts +5 -0
- package/dist/src/semantics/payment_methods.js +39 -0
- package/dist/src/semantics/payouts.d.ts +2 -0
- package/dist/src/semantics/payouts.js +21 -0
- package/dist/src/semantics/prices.d.ts +4 -0
- package/dist/src/semantics/prices.js +37 -0
- package/dist/src/semantics/products.d.ts +6 -2
- package/dist/src/semantics/products.js +15 -130
- package/dist/src/semantics/promotion_codes.d.ts +3 -0
- package/dist/src/semantics/promotion_codes.js +35 -0
- package/dist/src/semantics/radar.d.ts +2 -2
- package/dist/src/semantics/radar.js +5 -74
- package/dist/src/semantics/refunds.d.ts +3 -9
- package/dist/src/semantics/refunds.js +6 -192
- package/dist/src/semantics/setup_intents.d.ts +3 -0
- package/dist/src/semantics/{setup-intents.js → setup_intents.js} +10 -53
- package/dist/src/semantics/shared.d.ts +822 -47
- package/dist/src/semantics/shared.js +3044 -78
- package/dist/src/semantics/states.d.ts +531 -0
- package/dist/src/semantics/states.js +852 -0
- package/dist/src/semantics/subscription_items.d.ts +5 -0
- package/dist/src/semantics/subscription_items.js +55 -0
- package/dist/src/semantics/subscription_schedules.d.ts +4 -0
- package/dist/src/semantics/subscription_schedules.js +60 -0
- package/dist/src/semantics/subscriptions.d.ts +7 -11
- package/dist/src/semantics/subscriptions.js +44 -415
- package/dist/src/semantics/test_helpers.d.ts +6 -0
- package/dist/src/semantics/{test-clocks.js → test_helpers.js} +14 -40
- package/dist/src/semantics/transfers.d.ts +2 -2
- package/dist/src/semantics/transfers.js +6 -101
- package/dist/src/server.d.ts +7 -0
- package/dist/src/server.js +7 -0
- package/generated/pack-facts.json +94 -0
- package/package.json +10 -20
- package/spec/SOURCE.md +14 -0
- package/spec/fixtures3.json.gz +0 -0
- package/spec/openapi.json.gz +0 -0
- package/spec/patches.json +34 -0
- package/spec/sources.json +378 -0
- package/src/cli.ts +12 -26
- package/src/engine/after-payment.ts +31 -0
- package/src/engine/apps-secrets.ts +4 -0
- package/src/engine/balance.ts +33 -0
- package/src/engine/billing.ts +16 -0
- package/src/engine/charges.ts +19 -0
- package/src/engine/checkout.ts +40 -0
- package/src/engine/common.ts +47 -0
- package/src/engine/connect-settings.ts +23 -0
- package/src/engine/connect.ts +184 -0
- package/src/engine/coupons.ts +5 -0
- package/src/engine/credit-notes.ts +6 -0
- package/src/engine/customers.ts +35 -0
- package/src/engine/display.ts +19 -0
- package/src/engine/disputes.ts +9 -0
- package/src/engine/entitlements.ts +5 -0
- package/src/engine/ephemeral-keys.ts +3 -0
- package/src/engine/files.ts +41 -0
- package/src/engine/front.ts +31 -0
- package/src/engine/invoices.ts +71 -0
- package/src/engine/issuing.ts +61 -0
- package/src/engine/ledger.ts +50 -0
- package/src/engine/oauth.ts +19 -0
- package/src/engine/onboarding.ts +54 -0
- package/src/{stripe-params.ts → engine/params.ts} +8 -56
- package/src/engine/payment-intents.ts +33 -0
- package/src/engine/payment-links.ts +6 -0
- package/src/engine/payment-methods.ts +25 -0
- package/src/engine/plans.ts +42 -0
- package/src/engine/platform.ts +47 -0
- package/src/engine/products.ts +3 -0
- package/src/engine/radar.ts +6 -0
- package/src/engine/refunds.ts +29 -0
- package/src/engine/renewals.ts +73 -0
- package/src/engine/setup-intents.ts +5 -0
- package/src/{stripe-twin.ts → engine/stripe.ts} +28 -323
- package/src/engine/subscription-schedules.ts +10 -0
- package/src/engine/subscriptions.ts +40 -0
- package/src/engine/tax.ts +39 -0
- package/src/engine/terminal.ts +23 -0
- package/src/engine/test-clocks.ts +11 -0
- package/src/engine/tokens.ts +22 -0
- package/src/engine/transfers.ts +23 -0
- package/src/engine/treasury.ts +47 -0
- package/src/{stripe-version.ts → engine/version.ts} +4 -3
- package/src/engine/webhook-endpoints.ts +14 -0
- package/src/engine/webhooks.ts +72 -0
- package/src/fetch.ts +27 -0
- package/src/generated/surface.gen.json +1 -1
- package/src/generated/ui.gen.json +1 -1
- package/src/index.ts +8 -116
- package/src/manifest.ts +234 -786
- package/src/screens/{portal.tsx → billing-portal.tsx} +32 -37
- package/src/screens/checkout.tsx +33 -95
- package/src/screens/connect-oauth.tsx +64 -88
- package/src/screens/{onboarding.tsx → connect-onboarding.tsx} +38 -82
- package/src/screens/dashboard.tsx +198 -0
- package/src/screens/shared.tsx +84 -0
- package/src/screens/stripe-js.ts +170 -0
- package/src/semantics/account_links.ts +21 -0
- package/src/semantics/accounts.ts +43 -0
- package/src/semantics/{apps-secrets.ts → apps.ts} +17 -32
- package/src/semantics/around.ts +20 -0
- package/src/semantics/balance.ts +6 -207
- package/src/semantics/balance_transactions.ts +20 -0
- package/src/semantics/billing_portal.ts +51 -0
- package/src/semantics/charges.ts +12 -211
- package/src/semantics/checkout.ts +13 -268
- package/src/semantics/clock.ts +26 -0
- package/src/semantics/coupons.ts +5 -67
- package/src/semantics/customers.ts +29 -392
- package/src/semantics/disputes.ts +9 -59
- package/src/semantics/doors.ts +80 -0
- package/src/semantics/entitlements.ts +9 -56
- package/src/semantics/events.ts +44 -0
- package/src/semantics/index.ts +111 -0
- package/src/semantics/invoice_payments.ts +18 -0
- package/src/semantics/invoiceitems.ts +59 -0
- package/src/semantics/invoices.ts +109 -443
- package/src/semantics/payment_intents.ts +83 -0
- package/src/semantics/payment_methods.ts +43 -0
- package/src/semantics/payouts.ts +23 -0
- package/src/semantics/prices.ts +42 -0
- package/src/semantics/products.ts +18 -142
- package/src/semantics/promotion_codes.ts +39 -0
- package/src/semantics/radar.ts +8 -77
- package/src/semantics/refunds.ts +9 -212
- package/src/semantics/setup_intents.ts +45 -0
- package/src/semantics/shared.ts +3092 -106
- package/src/semantics/states.ts +883 -0
- package/src/semantics/subscription_items.ts +54 -0
- package/src/semantics/subscription_schedules.ts +66 -0
- package/src/semantics/subscriptions.ts +49 -432
- package/src/semantics/{test-clocks.ts → test_helpers.ts} +23 -47
- package/src/semantics/transfers.ts +11 -131
- package/src/server.ts +8 -0
- package/client/dashboard-api.ts +0 -286
- package/client/stripe-mirror.css +0 -277
- package/client/stripe-mirror.tsx +0 -1559
- package/dist/client/dashboard-api.d.ts +0 -107
- package/dist/client/dashboard-api.js +0 -238
- package/dist/client/dashboard-api.ts +0 -286
- package/dist/client/stripe-mirror.bundle.js +0 -236
- package/dist/client/stripe-mirror.css +0 -277
- package/dist/client/stripe-mirror.d.ts +0 -134
- package/dist/client/stripe-mirror.js +0 -859
- package/dist/client/stripe-mirror.tsx +0 -1559
- package/dist/src/screens/connect-settings.js +0 -103
- package/dist/src/screens/consent-skin.d.ts +0 -4
- package/dist/src/screens/consent-skin.js +0 -18
- package/dist/src/screens/financial-connections.d.ts +0 -5
- package/dist/src/screens/financial-connections.js +0 -90
- package/dist/src/screens/identity.d.ts +0 -5
- package/dist/src/screens/identity.js +0 -86
- package/dist/src/screens/onboarding.d.ts +0 -13
- package/dist/src/screens/portal.d.ts +0 -5
- package/dist/src/screens/public-details.d.ts +0 -5
- package/dist/src/screens/public-details.js +0 -90
- package/dist/src/semantics/after-payment.d.ts +0 -22
- package/dist/src/semantics/after-payment.js +0 -99
- package/dist/src/semantics/apps-secrets.d.ts +0 -2
- package/dist/src/semantics/billing.d.ts +0 -2
- package/dist/src/semantics/billing.js +0 -220
- package/dist/src/semantics/connect.d.ts +0 -5
- package/dist/src/semantics/connect.js +0 -493
- package/dist/src/semantics/credit-notes.d.ts +0 -2
- package/dist/src/semantics/credit-notes.js +0 -172
- package/dist/src/semantics/ephemeral-keys.d.ts +0 -2
- package/dist/src/semantics/ephemeral-keys.js +0 -34
- package/dist/src/semantics/files.d.ts +0 -2
- package/dist/src/semantics/files.js +0 -125
- package/dist/src/semantics/issuing.d.ts +0 -13
- package/dist/src/semantics/issuing.js +0 -575
- package/dist/src/semantics/ledger.d.ts +0 -59
- package/dist/src/semantics/ledger.js +0 -200
- package/dist/src/semantics/payment-intents.d.ts +0 -18
- package/dist/src/semantics/payment-intents.js +0 -452
- package/dist/src/semantics/payment-links.d.ts +0 -2
- package/dist/src/semantics/payment-links.js +0 -133
- package/dist/src/semantics/payment-methods.d.ts +0 -20
- package/dist/src/semantics/payment-methods.js +0 -140
- package/dist/src/semantics/plans.d.ts +0 -5
- package/dist/src/semantics/plans.js +0 -121
- package/dist/src/semantics/platform.d.ts +0 -9
- package/dist/src/semantics/platform.js +0 -206
- package/dist/src/semantics/renewals.d.ts +0 -47
- package/dist/src/semantics/renewals.js +0 -281
- package/dist/src/semantics/setup-intents.d.ts +0 -2
- package/dist/src/semantics/subscription-schedules.d.ts +0 -2
- package/dist/src/semantics/subscription-schedules.js +0 -119
- package/dist/src/semantics/tax.d.ts +0 -2
- package/dist/src/semantics/tax.js +0 -197
- package/dist/src/semantics/terminal.d.ts +0 -5
- package/dist/src/semantics/terminal.js +0 -182
- package/dist/src/semantics/test-clocks.d.ts +0 -6
- package/dist/src/semantics/tokens.d.ts +0 -4
- package/dist/src/semantics/tokens.js +0 -44
- package/dist/src/semantics/treasury.d.ts +0 -2
- package/dist/src/semantics/treasury.js +0 -377
- package/dist/src/semantics/webhook-endpoints.d.ts +0 -3
- package/dist/src/semantics/webhook-endpoints.js +0 -85
- package/dist/src/stripe-budget.d.ts +0 -55
- package/dist/src/stripe-budget.js +0 -155
- package/dist/src/stripe-capabilities.d.ts +0 -3
- package/dist/src/stripe-capabilities.js +0 -5836
- package/dist/src/stripe-conformance.d.ts +0 -43
- package/dist/src/stripe-conformance.js +0 -105
- package/dist/src/stripe-connector.d.ts +0 -161
- package/dist/src/stripe-connector.js +0 -414
- package/dist/src/stripe-emit.d.ts +0 -2
- package/dist/src/stripe-emit.js +0 -145
- package/dist/src/stripe-events.d.ts +0 -93
- package/dist/src/stripe-events.js +0 -392
- package/dist/src/stripe-js.d.ts +0 -4
- package/dist/src/stripe-js.js +0 -70
- package/dist/src/stripe-mirror-ui.d.ts +0 -15
- package/dist/src/stripe-mirror-ui.js +0 -87
- package/dist/src/stripe-perform-harness.d.ts +0 -9
- package/dist/src/stripe-perform-harness.js +0 -26
- package/dist/src/stripe-server.d.ts +0 -33
- package/dist/src/stripe-server.js +0 -429
- package/dist/src/stripe-shared.d.ts +0 -109
- package/dist/src/stripe-shared.js +0 -276
- package/dist/src/stripe-ui-conformance.d.ts +0 -5
- package/dist/src/stripe-ui-conformance.js +0 -79
- package/dist/src/stripe-ui-structure.d.ts +0 -3
- package/dist/src/stripe-ui-structure.js +0 -168
- package/dist/test-fixtures/stripe-known-deviations.json +0 -110
- package/dist/test-fixtures/stripe-openapi-operations.SOURCE.md +0 -14
- package/dist/test-fixtures/stripe-openapi-operations.json +0 -4717
- package/dist/test-fixtures/stripe-schemas.SOURCE.md +0 -35
- package/dist/test-fixtures/stripe-schemas.json +0 -3813
- package/src/screens/connect-settings.tsx +0 -121
- package/src/screens/consent-skin.ts +0 -20
- package/src/screens/financial-connections.tsx +0 -101
- package/src/screens/identity.tsx +0 -96
- package/src/screens/public-details.tsx +0 -105
- package/src/semantics/after-payment.ts +0 -118
- package/src/semantics/billing.ts +0 -216
- package/src/semantics/connect.ts +0 -487
- package/src/semantics/credit-notes.ts +0 -168
- package/src/semantics/ephemeral-keys.ts +0 -34
- package/src/semantics/files.ts +0 -143
- package/src/semantics/issuing.ts +0 -590
- package/src/semantics/ledger.ts +0 -253
- package/src/semantics/payment-intents.ts +0 -463
- package/src/semantics/payment-links.ts +0 -148
- package/src/semantics/payment-methods.ts +0 -145
- package/src/semantics/plans.ts +0 -131
- package/src/semantics/platform.ts +0 -220
- package/src/semantics/renewals.ts +0 -279
- package/src/semantics/setup-intents.ts +0 -87
- package/src/semantics/subscription-schedules.ts +0 -129
- package/src/semantics/tax.ts +0 -220
- package/src/semantics/terminal.ts +0 -195
- package/src/semantics/tokens.ts +0 -52
- package/src/semantics/treasury.ts +0 -383
- package/src/semantics/webhook-endpoints.ts +0 -87
- package/src/stripe-budget.ts +0 -181
- package/src/stripe-capabilities.ts +0 -5651
- package/src/stripe-conformance.ts +0 -124
- package/src/stripe-connector.ts +0 -462
- package/src/stripe-emit.ts +0 -157
- package/src/stripe-events.ts +0 -434
- package/src/stripe-js.ts +0 -70
- package/src/stripe-mirror-ui.ts +0 -90
- package/src/stripe-perform-harness.ts +0 -29
- package/src/stripe-server.ts +0 -393
- package/src/stripe-shared.ts +0 -297
- package/src/stripe-ui-conformance.ts +0 -88
- package/src/stripe-ui-structure.ts +0 -182
- package/test-fixtures/stripe-known-deviations.json +0 -110
- package/test-fixtures/stripe-openapi-operations.json +0 -4717
- package/test-fixtures/stripe-schemas.json +0 -3813
- /package/dist/src/{screens → engine}/industries.d.ts +0 -0
- /package/dist/src/{screens → engine}/industries.js +0 -0
- /package/dist/src/{semantics → engine}/test-cards.d.ts +0 -0
- /package/dist/src/{semantics → engine}/test-cards.js +0 -0
- /package/dist/src/{stripe-version.d.ts → engine/version.d.ts} +0 -0
- /package/src/{screens → engine}/industries.ts +0 -0
- /package/src/{semantics → engine}/test-cards.ts +0 -0
package/src/manifest.ts
CHANGED
|
@@ -1,474 +1,10 @@
|
|
|
1
1
|
// Stripe's manifest: the vendor facts its published spec does not carry, and the resources the
|
|
2
2
|
// derived core serves (docs/contributing/architecture.md, "Protocol 3"). The surface itself is
|
|
3
3
|
// generated (./generated/surface.gen.json, from ../spec by scripts/derive-pack.ts).
|
|
4
|
-
import type { DerivedManifest
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
status: 400,
|
|
9
|
-
code: 'payment_intent_unexpected_state',
|
|
10
|
-
message: `This PaymentIntent could not be ${verb} because it has a status of {from}. ${allowed}`,
|
|
11
|
-
});
|
|
12
|
-
const OPEN = ['requires_payment_method', 'requires_confirmation', 'requires_action', 'requires_capture', 'processing'];
|
|
13
|
-
|
|
14
|
-
/** A move no API call makes: Stripe's own (`vendor`), the clock's (`time`), or the person on a
|
|
15
|
-
* Stripe-hosted page (`external`: Checkout, the billing portal, a hosted invoice or 3DS page). */
|
|
16
|
-
const by = (actor: 'vendor' | 'time' | 'external', from: string[], to: string, source: string): Transition => ({ actor, from, to, source });
|
|
17
|
-
/** A bank account's `status` as a payout or payment destination. Stripe validates its routing number,
|
|
18
|
-
* verifies it (micro-deposits, or instantly) and marks it errored when a payout or debit to it fails
|
|
19
|
-
* (the page each machine cites); no call the twin serves does any of that (the customer-source verify is
|
|
20
|
-
* a gap), so no move of it is the twin's. */
|
|
21
|
-
const bankAccountStatus = (_doc: string): StateField => ({ initial: 'new', transitions: [] });
|
|
22
|
-
|
|
23
|
-
/** A flag an update sets either way. */
|
|
24
|
-
const flag = (operation: string, source: string): Transition[] => ['true', 'false'].map((to) => ({ operation, from: '*' as const, to, source }));
|
|
25
|
-
|
|
26
|
-
/** A PaymentIntent's `status`: which operation may move it from where, and what Stripe answers otherwise. */
|
|
27
|
-
const paymentIntentStatus: StateField = {
|
|
28
|
-
// "After you create the PaymentIntent, its status is `requires_payment_method` until you attach a payment method"
|
|
29
|
-
// (docs.stripe.com/payments/paymentintents/lifecycle)
|
|
30
|
-
initial: 'requires_payment_method',
|
|
31
|
-
transitions: [
|
|
32
|
-
// created with its payment method, it "enters the `requires_confirmation` status and is ready to confirm" (the same page)
|
|
33
|
-
{ operation: 'PostPaymentIntents', from: ['requires_payment_method'], to: 'requires_confirmation', source: 'https://docs.stripe.com/payments/paymentintents/lifecycle' },
|
|
34
|
-
// confirm lands on one of its outcomes, decided by the payment method and the capture method
|
|
35
|
-
...['requires_payment_method', 'requires_action', 'requires_capture', 'succeeded'].map((to) => ({
|
|
36
|
-
operation: 'PostPaymentIntentsIntentConfirm',
|
|
37
|
-
from: ['requires_payment_method', 'requires_confirmation', 'requires_action'],
|
|
38
|
-
to,
|
|
39
|
-
refusal: { status: 400, code: 'payment_intent_unexpected_state', message: 'You cannot confirm this PaymentIntent because it has a status of {from}.' },
|
|
40
|
-
source: 'https://docs.stripe.com/api/payment_intents/confirm',
|
|
41
|
-
})),
|
|
42
|
-
// a bank debit confirmed (created with `confirm`, confirmed, or verified by micro-deposits) is submitted and
|
|
43
|
-
// processes: "The PaymentIntent you create initially has a status of `processing`"; "When the bank account is
|
|
44
|
-
// successfully verified, Stripe returns the PaymentIntent object with a status of `processing`"
|
|
45
|
-
...['PostPaymentIntents', 'PostPaymentIntentsIntentConfirm'].map((operation) => ({
|
|
46
|
-
operation, from: ['requires_payment_method', 'requires_confirmation', 'requires_action'], to: 'processing',
|
|
47
|
-
source: 'https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment?payment-ui=direct-api',
|
|
48
|
-
})),
|
|
49
|
-
// and succeeds: "After the payment has succeeded, the PaymentIntent status is updated from `processing`
|
|
50
|
-
// to `succeeded`" (semantics/payment-intents.ts settleBankDebits)
|
|
51
|
-
by('vendor', ['processing'], 'succeeded', 'https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment?payment-ui=direct-api'),
|
|
52
|
-
// creating one with `confirm` confirms it at once, landing where a confirm lands
|
|
53
|
-
...['requires_payment_method', 'requires_action', 'requires_capture', 'succeeded'].map((to) => ({
|
|
54
|
-
operation: 'PostPaymentIntents',
|
|
55
|
-
from: ['requires_payment_method', 'requires_confirmation'],
|
|
56
|
-
to,
|
|
57
|
-
source: 'spec:PostPaymentIntents "Set to `true` to attempt to [confirm this PaymentIntent](https://docs.stripe.com/api/payment_intents/confirm) immediately."',
|
|
58
|
-
})),
|
|
59
|
-
{
|
|
60
|
-
operation: 'PostPaymentIntentsIntentCapture',
|
|
61
|
-
from: ['requires_capture'],
|
|
62
|
-
to: 'succeeded',
|
|
63
|
-
refusal: unexpected('captured', 'Only a PaymentIntent with one of the following statuses may be captured: requires_capture.'),
|
|
64
|
-
source: 'https://docs.stripe.com/api/payment_intents/capture',
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
operation: 'PostPaymentIntentsIntentIncrementAuthorization',
|
|
68
|
-
from: ['requires_capture'],
|
|
69
|
-
to: 'requires_capture',
|
|
70
|
-
refusal: unexpected('incremented', 'Only a PaymentIntent with a status of requires_capture may be incremented.'),
|
|
71
|
-
source: 'https://docs.stripe.com/api/payment_intents/increment_authorization',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
operation: 'PostPaymentIntentsIntentCancel',
|
|
75
|
-
from: OPEN,
|
|
76
|
-
to: 'canceled',
|
|
77
|
-
refusal: unexpected('canceled', 'Only a PaymentIntent with one of the following statuses may be canceled: requires_payment_method, requires_capture, requires_confirmation, requires_action, processing.'),
|
|
78
|
-
source: 'https://docs.stripe.com/api/payment_intents/cancel',
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
operation: 'PostPaymentIntentsIntentVerifyMicrodeposits',
|
|
82
|
-
from: ['requires_action'],
|
|
83
|
-
to: 'processing',
|
|
84
|
-
refusal: { status: 400, code: 'payment_intent_unexpected_state', message: 'This PaymentIntent could not be verified because it has a status of {from}.' },
|
|
85
|
-
source: 'https://docs.stripe.com/payments/ach-direct-debit/accept-a-payment?payment-ui=direct-api',
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
// paying the invoice an intent collects for settles the intent
|
|
89
|
-
operation: 'PostInvoicesInvoicePay',
|
|
90
|
-
from: OPEN,
|
|
91
|
-
to: 'succeeded',
|
|
92
|
-
source: 'https://docs.stripe.com/api/invoices/pay',
|
|
93
|
-
},
|
|
94
|
-
...['succeeded', 'requires_action'].map((to) => ({
|
|
95
|
-
operation: 'PostPaymentIntentsIntentApplyCustomerBalance',
|
|
96
|
-
from: OPEN,
|
|
97
|
-
to,
|
|
98
|
-
refusal: { status: 400, code: 'payment_intent_unexpected_state', message: 'This PaymentIntent could not be updated because it has a status of {from}.' },
|
|
99
|
-
source: 'https://docs.stripe.com/api/payment_intents/apply_customer_balance',
|
|
100
|
-
})),
|
|
101
|
-
// a card presented to the Terminal reader processing an intent pays it (held, under manual capture)
|
|
102
|
-
...['succeeded', 'requires_capture'].map((to) => ({
|
|
103
|
-
operation: 'PostTestHelpersTerminalReadersReaderPresentPaymentMethod', from: ['requires_payment_method', 'requires_confirmation'], to,
|
|
104
|
-
source: 'https://docs.stripe.com/api/terminal/readers/present_payment_method',
|
|
105
|
-
})),
|
|
106
|
-
// the customer pays, in the billing portal, the invoice an intent collects for after its charge was declined
|
|
107
|
-
by('external', ['requires_payment_method'], 'succeeded', 'https://docs.stripe.com/customer-management'),
|
|
108
|
-
// Stripe also fails a bank debit back to needing a payment method, completes 3-D Secure on the bank's page and
|
|
109
|
-
// cancels a hold left uncaptured; the twin's bank debits succeed unless their test account stays processing, it has no 3-D Secure page, and it keeps
|
|
110
|
-
// holds until they are captured or canceled
|
|
111
|
-
],
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
/** A charge's `captured`: an authorization (capture=false) is captured once. */
|
|
115
|
-
const chargeCaptured: StateField = {
|
|
116
|
-
initial: true,
|
|
117
|
-
transitions: [
|
|
118
|
-
{
|
|
119
|
-
operation: 'PostChargesChargeCapture',
|
|
120
|
-
from: ['false'],
|
|
121
|
-
to: 'true',
|
|
122
|
-
refusal: { status: 400, code: 'charge_already_captured', message: 'Charge ch_xxx has already been captured.' },
|
|
123
|
-
source: 'https://docs.stripe.com/api/charges/capture',
|
|
124
|
-
},
|
|
125
|
-
// a manual-capture intent's capture captures the charge its confirm authorized
|
|
126
|
-
{ operation: 'PostPaymentIntentsIntentCapture', from: ['false'], to: 'true', source: 'https://docs.stripe.com/api/payment_intents/capture' },
|
|
127
|
-
],
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
/** A charge's `refunded`: true once refunds take its whole amount, false again when a refund that made it so is
|
|
131
|
-
* canceled. A capture or a cancel never makes it so: "`refunded` will no longer be `true` for payment cancellation
|
|
132
|
-
* flows", and a partial capture makes no Refund (docs.stripe.com/changelog/basil/2025-03-31/remove-refund-from-partial-
|
|
133
|
-
* capture-and-payment-cancellation-flow). */
|
|
134
|
-
const chargeRefunded: StateField = {
|
|
135
|
-
initial: false,
|
|
136
|
-
transitions: [
|
|
137
|
-
...['PostRefunds', 'PostChargesChargeRefunds', 'PostCreditNotes'].map((operation) => ({ operation, from: ['false'], to: 'true', source: 'https://docs.stripe.com/api/charges/object#charge_object-refunded' })),
|
|
138
|
-
{ operation: 'PostRefundsRefundCancel', from: ['true'], to: 'false', source: 'https://docs.stripe.com/api/refunds/cancel' },
|
|
139
|
-
// (an authorization left uncaptured is canceled after seven days, "Uncaptured PaymentIntents are cancelled a set
|
|
140
|
-
// number of days (7 by default) after their creation", docs.stripe.com/api/payment_intents/capture; the twin keeps it)
|
|
141
|
-
],
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
/** A charge's `status`: the twin settles a charge when it is made (a declined one is never
|
|
145
|
-
* stored); an asynchronous one settles later, on the network's word. */
|
|
146
|
-
const chargeStatus: StateField = {
|
|
147
|
-
initial: 'succeeded',
|
|
148
|
-
transitions: [
|
|
149
|
-
// (an asynchronous charge is pending at Stripe until it settles or fails; the twin's settle when made)
|
|
150
|
-
],
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
/** A charge's `paid`: true once it succeeded or was authorized; a pending one becomes paid when it settles. */
|
|
154
|
-
const chargePaid: StateField = {
|
|
155
|
-
initial: true,
|
|
156
|
-
// (a charge is paid when it settles; the twin's settle when made)
|
|
157
|
-
transitions: [],
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
/** A refund's `status`: only one waiting on the customer (requires_action) may be canceled; the
|
|
161
|
-
* rest is the network's. */
|
|
162
|
-
const refundStatus: StateField = {
|
|
163
|
-
initial: 'succeeded',
|
|
164
|
-
transitions: [
|
|
165
|
-
{
|
|
166
|
-
operation: 'PostRefundsRefundCancel',
|
|
167
|
-
from: ['requires_action'],
|
|
168
|
-
to: 'canceled',
|
|
169
|
-
refusal: { status: 400, code: 'refund_status_invalid', message: 'Refund {id} cannot be canceled because its status is {from}.' },
|
|
170
|
-
source: 'https://docs.stripe.com/api/refunds/cancel',
|
|
171
|
-
},
|
|
172
|
-
// a card refund the available balance does not cover is held pending, and made once the balance covers it: "Stripe
|
|
173
|
-
// holds the refund as pending for card transactions ... until your Stripe balance becomes sufficient"
|
|
174
|
-
// (docs.stripe.com/refunds; semantics/refunds.ts)
|
|
175
|
-
// (a paid invoice's credit note makes its refund as a refund call does: "Refunds: create a new refund (using
|
|
176
|
-
// refund_amount)", docs.stripe.com/api/credit_notes/create)
|
|
177
|
-
...['PostRefunds', 'PostChargesChargeRefunds', 'PostCreditNotes'].map((operation) => ({ operation, from: ['succeeded'], to: 'pending', source: 'https://docs.stripe.com/refunds' })),
|
|
178
|
-
by('vendor', ['pending'], 'succeeded', 'https://docs.stripe.com/refunds'),
|
|
179
|
-
// a bank-transfer payment's refund waits in requires_action for the customer's bank details, and is made so
|
|
180
|
-
// (semantics/refunds.ts); (Stripe also fails some refunds; the twin's do not fail)
|
|
181
|
-
],
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const SETUP_OPEN = ['requires_payment_method', 'requires_confirmation', 'requires_action'];
|
|
185
|
-
const setupUnexpected = (verb: string) => ({ status: 400, code: 'setup_intent_unexpected_state', message: `You cannot ${verb} this SetupIntent because it has a status of {from}.` });
|
|
186
|
-
|
|
187
|
-
/** A SetupIntent's `status`: confirm settles it (or leaves a bank account awaiting micro-deposits),
|
|
188
|
-
* cancel ends an open one, and verification completes the micro-deposit wait. */
|
|
189
|
-
const setupIntentStatus: StateField = {
|
|
190
|
-
// "After you create the SetupIntent, it has a status of `requires_payment_method` until you attach a payment method"
|
|
191
|
-
// (docs.stripe.com/payments/paymentintents/lifecycle)
|
|
192
|
-
initial: 'requires_payment_method',
|
|
193
|
-
transitions: [
|
|
194
|
-
// created with its payment method, it "enters the `requires_confirmation` status and is ready to confirm" (the same page)
|
|
195
|
-
{ operation: 'PostSetupIntents', from: ['requires_payment_method'], to: 'requires_confirmation', source: 'https://docs.stripe.com/payments/paymentintents/lifecycle' },
|
|
196
|
-
...['requires_action', 'succeeded'].map((to) => ({
|
|
197
|
-
operation: 'PostSetupIntentsIntentConfirm',
|
|
198
|
-
from: SETUP_OPEN,
|
|
199
|
-
to,
|
|
200
|
-
refusal: setupUnexpected('confirm'),
|
|
201
|
-
source: 'https://docs.stripe.com/api/setup_intents/confirm',
|
|
202
|
-
})),
|
|
203
|
-
{
|
|
204
|
-
operation: 'PostSetupIntentsIntentCancel',
|
|
205
|
-
from: SETUP_OPEN,
|
|
206
|
-
to: 'canceled',
|
|
207
|
-
refusal: setupUnexpected('cancel'),
|
|
208
|
-
source: 'https://docs.stripe.com/api/setup_intents/cancel',
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
operation: 'PostSetupIntentsIntentVerifyMicrodeposits',
|
|
212
|
-
from: ['requires_action'],
|
|
213
|
-
to: 'succeeded',
|
|
214
|
-
refusal: { status: 400, code: 'setup_intent_unexpected_state', message: 'This SetupIntent could not be verified because it has a status of {from}.' },
|
|
215
|
-
source: 'https://docs.stripe.com/api/setup_intents/verify_microdeposits',
|
|
216
|
-
},
|
|
217
|
-
// (Stripe completes 3-D Secure on the bank's page and settles an asynchronous method from processing; the
|
|
218
|
-
// twin has no such page and settles every method at once)
|
|
219
|
-
],
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
const invoiceRefusal = (message: string) => ({ status: 400, code: 'invoice_not_editable', message });
|
|
223
|
-
|
|
224
|
-
/** An invoice's `status`: a draft is finalized (or sent, which finalizes it) into open, an open one
|
|
225
|
-
* is paid, written off or voided. Sending leaves any other status where it is. */
|
|
226
|
-
const invoiceStatus: StateField = {
|
|
227
|
-
initial: 'draft',
|
|
228
|
-
transitions: [
|
|
229
|
-
{
|
|
230
|
-
operation: 'PostInvoicesInvoiceFinalize',
|
|
231
|
-
from: ['draft'],
|
|
232
|
-
to: 'open',
|
|
233
|
-
refusal: invoiceRefusal('This invoice cannot be finalized because it has status {from}.'),
|
|
234
|
-
source: 'https://docs.stripe.com/api/invoices/finalize',
|
|
235
|
-
},
|
|
236
|
-
// docs.stripe.com/invoicing/integration: "To finalize a draft invoice, use the Dashboard, send it to the customer, or pay it."
|
|
237
|
-
{ operation: 'PostInvoicesInvoiceSend', from: ['draft'], to: 'open', source: 'https://docs.stripe.com/invoicing/integration' },
|
|
238
|
-
{ operation: 'PostInvoicesInvoiceSend', from: ['open', 'paid', 'uncollectible', 'void'], source: 'https://docs.stripe.com/api/invoices/send' },
|
|
239
|
-
{
|
|
240
|
-
operation: 'PostInvoicesInvoicePay',
|
|
241
|
-
from: ['open', 'uncollectible'],
|
|
242
|
-
to: 'paid',
|
|
243
|
-
refusal: invoiceRefusal('This invoice cannot be paid because it has status {from}.'),
|
|
244
|
-
refusals: { paid: { status: 400, code: 'invoice_payment_intent_requires_action', message: 'This invoice has already been paid.' } },
|
|
245
|
-
source: 'https://docs.stripe.com/api/invoices/pay',
|
|
246
|
-
},
|
|
247
|
-
{
|
|
248
|
-
operation: 'PostInvoicesInvoiceMarkUncollectible',
|
|
249
|
-
from: ['open'],
|
|
250
|
-
to: 'uncollectible',
|
|
251
|
-
refusal: invoiceRefusal('Only open invoices can be marked uncollectible (this one is {from}).'),
|
|
252
|
-
source: 'https://docs.stripe.com/api/invoices/mark_uncollectible',
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
// only a finalized invoice is voided; a draft is deleted
|
|
256
|
-
operation: 'PostInvoicesInvoiceVoid',
|
|
257
|
-
from: ['open', 'uncollectible'],
|
|
258
|
-
to: 'void',
|
|
259
|
-
refusal: invoiceRefusal('This invoice cannot be voided because it has status {from}.'),
|
|
260
|
-
source: 'https://docs.stripe.com/api/invoices/void',
|
|
261
|
-
},
|
|
262
|
-
// confirming or capturing the PaymentIntent an invoice collects through pays the invoice
|
|
263
|
-
...['PostPaymentIntentsIntentConfirm', 'PostPaymentIntentsIntentCapture'].map((operation) => ({
|
|
264
|
-
operation, from: ['draft', 'open', 'uncollectible'], to: 'paid', source: 'https://docs.stripe.com/billing/subscriptions/build-subscriptions',
|
|
265
|
-
})),
|
|
266
|
-
// as does its bank debit succeeding once submitted (semantics/payment-intents.ts settleBankDebits)
|
|
267
|
-
by('vendor', ['draft', 'open', 'uncollectible'], 'paid', 'https://docs.stripe.com/billing/subscriptions/build-subscriptions'),
|
|
268
|
-
// a bank transfer that arrives in the customer's cash balance pays an open invoice that takes transfers
|
|
269
|
-
// (automatic reconciliation; in test mode the funding helper stands in for the transfer)
|
|
270
|
-
{ operation: 'PostTestHelpersCustomersCustomerFundCashBalance', from: ['open'], to: 'paid', source: 'https://docs.stripe.com/payments/customer-balance/reconciliation' },
|
|
271
|
-
// a subscription's first invoice is paid on the Checkout page that started it
|
|
272
|
-
by('external', ['draft'], 'paid', 'https://docs.stripe.com/payments/checkout/how-checkout-works'),
|
|
273
|
-
// a subscription's renewal, drafted at its period's end, is finalized about an hour later and charged: paid, or
|
|
274
|
-
// open when the charge is declined (semantics/renewals.ts)
|
|
275
|
-
by('time', ['draft'], 'paid', 'https://docs.stripe.com/invoicing/integration/workflow-transitions#finalized'),
|
|
276
|
-
by('time', ['draft'], 'open', 'https://docs.stripe.com/billing/subscriptions/overview#payment-status'),
|
|
277
|
-
// an update that ends a subscription's trial invoices its new period and attempts payment at once: paid, or open
|
|
278
|
-
// when the charge is declined or not attempted (semantics/subscriptions.ts applyTrialEnd)
|
|
279
|
-
{ operation: 'PostSubscriptionsSubscriptionExposedId', from: ['draft'], to: 'paid', source: 'https://docs.stripe.com/billing/subscriptions/upgrade-downgrade#immediate-payment' },
|
|
280
|
-
// a trialing subscription's first invoice, for nothing, is paid as it is made ("An immediate invoice is still
|
|
281
|
-
// created, but the amount is 0", docs.stripe.com/billing/subscriptions/trials/free-trials)
|
|
282
|
-
{ operation: 'PostSubscriptions', from: ['draft'], to: 'paid', source: 'https://docs.stripe.com/billing/subscriptions/trials/free-trials' },
|
|
283
|
-
{ operation: 'PostSubscriptionsSubscriptionExposedId', from: ['draft'], to: 'open', source: 'https://docs.stripe.com/billing/subscriptions/upgrade-downgrade#immediate-payment' },
|
|
284
|
-
// the customer pays an open invoice in the billing portal
|
|
285
|
-
by('external', ['open'], 'paid', 'https://docs.stripe.com/customer-management'),
|
|
286
|
-
// (Stripe also finalizes any other auto-advancing draft after an hour, retries an open invoice on its schedule
|
|
287
|
-
// and, retries exhausted, may write it off, and takes payment on the hosted invoice page; the twin's other
|
|
288
|
-
// invoices move only by the calls above)
|
|
289
|
-
],
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
/** A subscription's `status` as the twin's own operations move it; canceling ends any subscription. */
|
|
293
|
-
const subscriptionStatus: StateField = {
|
|
294
|
-
initial: 'active',
|
|
295
|
-
transitions: [
|
|
296
|
-
{ operation: 'DeleteSubscriptionsSubscriptionExposedId', from: '*', to: 'canceled', source: 'https://docs.stripe.com/api/subscriptions/cancel' },
|
|
297
|
-
// (a test clock's advance moves no subscription itself: when the clock reaches its target, a trial that ended there
|
|
298
|
-
// ends by time's move below, on the next request; semantics/test-clocks.ts finishClockAdvances)
|
|
299
|
-
// "Deleting the simulation also deletes the test customers associated with the clock and cancels their
|
|
300
|
-
// subscriptions" (docs.stripe.com/billing/testing/test-clocks/api-advanced-usage)
|
|
301
|
-
{ operation: 'DeleteTestHelpersTestClocksTestClock', from: '*', to: 'canceled', source: 'https://docs.stripe.com/billing/testing/test-clocks/api-advanced-usage' },
|
|
302
|
-
// "Cancels a subscription schedule and its associated subscription immediately" (docs.stripe.com/api/subscription_schedules/cancel)
|
|
303
|
-
{ operation: 'PostSubscriptionSchedulesScheduleCancel', from: ['active', 'trialing', 'past_due', 'incomplete'], to: 'canceled', source: 'https://docs.stripe.com/api/subscription_schedules/cancel' },
|
|
304
|
-
// confirming or capturing the first invoice's PaymentIntent, or paying the invoice itself, pays it and
|
|
305
|
-
// activates the subscription
|
|
306
|
-
...['PostPaymentIntentsIntentConfirm', 'PostPaymentIntentsIntentCapture'].map((operation) => ({
|
|
307
|
-
operation, from: ['incomplete'], to: 'active', source: 'https://docs.stripe.com/billing/subscriptions/build-subscriptions',
|
|
308
|
-
})),
|
|
309
|
-
// or when its bank debit succeeds once submitted (semantics/payment-intents.ts settleBankDebits)
|
|
310
|
-
by('vendor', ['incomplete'], 'active', 'https://docs.stripe.com/billing/subscriptions/build-subscriptions'),
|
|
311
|
-
// paying the invoice a subscription waits on (its first, or a renewal that failed) makes it active
|
|
312
|
-
{ operation: 'PostInvoicesInvoicePay', from: ['incomplete', 'past_due'], to: 'active', source: 'https://docs.stripe.com/billing/subscriptions/overview#payment-status' },
|
|
313
|
-
// an update's `trial_end`: `now` ends a trial at once and charges the new period, active when paid and past_due when
|
|
314
|
-
// not; a future timestamp starts a trial on a subscription out of one (semantics/subscriptions.ts applyTrialEnd)
|
|
315
|
-
{ operation: 'PostSubscriptionsSubscriptionExposedId', from: ['trialing'], to: 'active', source: 'https://docs.stripe.com/api/subscriptions/update#update_subscription-trial_end' },
|
|
316
|
-
{ operation: 'PostSubscriptionsSubscriptionExposedId', from: ['trialing'], to: 'past_due', source: 'https://docs.stripe.com/billing/subscriptions/upgrade-downgrade#immediate-payment' },
|
|
317
|
-
{
|
|
318
|
-
operation: 'PostSubscriptionsSubscriptionExposedId', from: ['active', 'past_due'], to: 'trialing',
|
|
319
|
-
// (Where the documentation stops and the twin decides: the wording of the refusal for a subscription neither
|
|
320
|
-
// active nor past_due; a canceled one answers what Stripe answers any update of a canceled subscription.)
|
|
321
|
-
refusal: { status: 400, message: 'A trial can only be added to an active or past_due subscription; this one is {from}.' },
|
|
322
|
-
refusals: { canceled: { status: 400, message: 'A canceled subscription can only update its cancellation_details and metadata.' } },
|
|
323
|
-
source: 'https://docs.stripe.com/billing/subscriptions/trials/free-trials#adding-a-new-trial-to-a-subscription-previously-in-a-trial',
|
|
324
|
-
},
|
|
325
|
-
// a trial ends on its own clock (Stripe pauses one that ends with no payment method to bill; the twin's
|
|
326
|
-
// trials end active), and a renewal whose charge is declined leaves the subscription past_due
|
|
327
|
-
// (semantics/renewals.ts)
|
|
328
|
-
by('time', ['trialing'], 'active', 'https://docs.stripe.com/billing/subscriptions/trials'),
|
|
329
|
-
by('time', ['active'], 'past_due', 'https://docs.stripe.com/billing/subscriptions/overview#payment-status'),
|
|
330
|
-
// one set to cancel at its period's end is canceled when the period ends
|
|
331
|
-
by('time', ['active', 'trialing', 'past_due'], 'canceled', 'https://docs.stripe.com/billing/subscriptions/cancel#cancel-at-end-of-cycle'),
|
|
332
|
-
// the customer pays the invoice it waits on in the billing portal
|
|
333
|
-
by('external', ['past_due'], 'active', 'https://docs.stripe.com/customer-management'),
|
|
334
|
-
// (Stripe also expires an incomplete subscription after 23 hours, and retries a failed renewal on its schedule,
|
|
335
|
-
// the settings ending the retries unpaid or canceled; the twin makes no retry)
|
|
336
|
-
// the customer cancels in the billing portal
|
|
337
|
-
by('external', ['active', 'trialing', 'past_due', 'unpaid', 'paused'], 'canceled', 'spec:/components/schemas/portal_subscription_cancel "Whether to cancel subscriptions immediately or at the end of the billing period."'),
|
|
338
|
-
],
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
const notOpen = (verb: string) => ({ status: 400, code: 'checkout_session_not_open', message: `You may only ${verb} a Checkout Session that is currently in the \`open\` state.` });
|
|
342
|
-
|
|
343
|
-
/** A Checkout Session's `status`: an open session expires (asked to, or 24 hours on), or completes
|
|
344
|
-
* when the customer pays on the hosted page. Completion is the external actor's move, the one the
|
|
345
|
-
* hosted Checkout page (src/screens/checkout.tsx) performs. */
|
|
346
|
-
const checkoutStatus: StateField = {
|
|
347
|
-
initial: 'open',
|
|
348
|
-
transitions: [
|
|
349
|
-
{ operation: 'PostCheckoutSessionsSessionExpire', from: ['open'], to: 'expired', refusal: notOpen('expire'), source: 'https://docs.stripe.com/api/checkout/sessions/expire' },
|
|
350
|
-
{ actor: 'external', from: ['open'], to: 'complete', refusal: notOpen('complete'), source: 'https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-status' },
|
|
351
|
-
// (Stripe expires an open session at expires_at; the twin keeps it open until asked)
|
|
352
|
-
],
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
/** A Checkout Session's `payment_status`: the customer completing a payment or subscription session
|
|
356
|
-
* pays it; a delayed payment method settles later. */
|
|
357
|
-
const checkoutPaymentStatus: StateField = {
|
|
358
|
-
initial: 'unpaid',
|
|
359
|
-
transitions: [
|
|
360
|
-
{ actor: 'external', from: '*', to: 'paid', source: 'https://docs.stripe.com/api/checkout/sessions/object#checkout_session_object-payment_status' },
|
|
361
|
-
// (a delayed method settles a session later at Stripe; the twin's settle on the page)
|
|
362
|
-
],
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
/** A dispute's `status`: closing concedes it; the bank decides the rest, and an unanswered one is
|
|
366
|
-
* lost when its evidence is due. */
|
|
367
|
-
const disputeStatus: StateField = {
|
|
368
|
-
initial: 'warning_needs_response',
|
|
369
|
-
transitions: [
|
|
370
|
-
{ operation: 'PostDisputesDisputeClose', from: '*', to: 'lost', source: 'https://docs.stripe.com/api/disputes/close' },
|
|
371
|
-
// submitting evidence puts a dispute (or an inquiry) under review; in test mode the evidence decides it
|
|
372
|
-
{ operation: 'PostDisputesDispute', from: ['needs_response'], to: 'under_review', source: 'https://docs.stripe.com/api/disputes/update#update_dispute-submit' },
|
|
373
|
-
{ operation: 'PostDisputesDispute', from: ['warning_needs_response'], to: 'warning_under_review', source: 'https://docs.stripe.com/api/disputes/update#update_dispute-submit' },
|
|
374
|
-
by('vendor', ['under_review'], 'won', 'https://docs.stripe.com/testing#evidence'),
|
|
375
|
-
by('vendor', ['under_review'], 'lost', 'https://docs.stripe.com/testing#evidence'),
|
|
376
|
-
// (the bank decides a dispute under review, escalates an inquiry and loses one left unanswered; the twin
|
|
377
|
-
// decides none)
|
|
378
|
-
// Stripe also closes an inquiry the bank drops (warning_closed); no inquiry the twin holds is dropped
|
|
379
|
-
],
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
/** A payout's `status`: cancel ends it; reversing cancels it and pays a reversal, never twice. */
|
|
383
|
-
const payoutStatus: StateField = {
|
|
384
|
-
initial: 'pending',
|
|
385
|
-
transitions: [
|
|
386
|
-
// only a pending payout can be canceled (docs.stripe.com/api/payouts/cancel); reversing a paid one makes a new
|
|
387
|
-
// payout and leaves the original paid (semantics/balance.ts)
|
|
388
|
-
{ operation: 'PostPayoutsPayoutCancel', from: ['pending'], to: 'canceled', source: 'https://docs.stripe.com/api/payouts/cancel' },
|
|
389
|
-
// it arrives in the bank on its arrival date
|
|
390
|
-
by('time', ['pending'], 'paid', 'https://docs.stripe.com/payouts#payout-statuses'),
|
|
391
|
-
// (a bank may fail a payout at Stripe; the twin's arrive)
|
|
392
|
-
],
|
|
393
|
-
};
|
|
394
|
-
|
|
395
|
-
/** A credit note's `status`: issued, then voided once. */
|
|
396
|
-
const creditNoteStatus: StateField = {
|
|
397
|
-
initial: 'issued',
|
|
398
|
-
transitions: [
|
|
399
|
-
{
|
|
400
|
-
operation: 'PostCreditNotesIdVoid',
|
|
401
|
-
from: ['issued'],
|
|
402
|
-
to: 'void',
|
|
403
|
-
refusal: { status: 400, code: 'credit_note_already_voided', message: 'This credit note has already been voided.' },
|
|
404
|
-
source: 'https://docs.stripe.com/api/credit_notes/void',
|
|
405
|
-
},
|
|
406
|
-
],
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
const scheduleEnded = (verb: string) => ({ status: 400, code: 'subscription_schedule_status_invalid', message: `This subscription schedule has status {from} and cannot be ${verb}.` });
|
|
410
|
-
|
|
411
|
-
/** A subscription schedule's `status`: canceling or releasing ends it; an ended one refuses both. */
|
|
412
|
-
const scheduleStatus: StateField = {
|
|
413
|
-
initial: 'active',
|
|
414
|
-
transitions: [
|
|
415
|
-
// "A subscription schedule can only be canceled if its status is not_started or active"; "A schedule can only be
|
|
416
|
-
// released if its status is not_started or active" (the cancel and release pages)
|
|
417
|
-
{ operation: 'PostSubscriptionSchedulesScheduleCancel', from: ['active', 'not_started'], to: 'canceled', refusal: scheduleEnded('canceled'), source: 'https://docs.stripe.com/api/subscription_schedules/cancel' },
|
|
418
|
-
{ operation: 'PostSubscriptionSchedulesScheduleRelease', from: ['active', 'not_started'], to: 'released', refusal: scheduleEnded('released'), source: 'https://docs.stripe.com/api/subscription_schedules/release' },
|
|
419
|
-
// its phases run on the clock: it starts at its start date and ends with its last phase
|
|
420
|
-
// (a schedule whose end_behavior is cancel completes at its end at Stripe; the twin's release)
|
|
421
|
-
// (Stripe starts a schedule at its start date and ends it with its last phase; the twin's start at once
|
|
422
|
-
// and end when canceled or released)
|
|
423
|
-
],
|
|
424
|
-
};
|
|
425
|
-
|
|
426
|
-
const quoteRefusal = (verb: string) => ({ status: 400, code: 'quote_invalid_status', message: `This quote cannot be ${verb} because it has status {from}.` });
|
|
427
|
-
|
|
428
|
-
/** A quote's `status`: a draft is finalized into open, an open one accepted, and either canceled. */
|
|
429
|
-
const quoteStatus: StateField = {
|
|
430
|
-
initial: 'draft',
|
|
431
|
-
transitions: [
|
|
432
|
-
{ operation: 'PostQuotesQuoteFinalize', from: ['draft'], to: 'open', refusal: quoteRefusal('finalized'), source: 'https://docs.stripe.com/api/quotes/finalize' },
|
|
433
|
-
{ operation: 'PostQuotesQuoteAccept', from: ['open'], to: 'accepted', refusal: quoteRefusal('accepted'), source: 'https://docs.stripe.com/api/quotes/accept' },
|
|
434
|
-
{ operation: 'PostQuotesQuoteCancel', from: ['draft', 'open'], to: 'canceled', refusal: quoteRefusal('canceled'), source: 'https://docs.stripe.com/api/quotes/cancel' },
|
|
435
|
-
// an open quote not accepted by its expires_at is canceled
|
|
436
|
-
// (Stripe cancels an open quote at its expires_at; the twin keeps it open)
|
|
437
|
-
],
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
const setBy = (operation: string, values: string[], source: string): Transition[] => values.map((to) => ({ operation, from: '*' as const, to, source }));
|
|
441
|
-
|
|
442
|
-
/** An Issuing authorization's `status`: approve and decline close a pending one, once; a capture
|
|
443
|
-
* closes it, or leaves it pending when told not to close. */
|
|
444
|
-
const issuingAuthorizationStatus: StateField = {
|
|
445
|
-
initial: 'pending',
|
|
446
|
-
transitions: [
|
|
447
|
-
// approving keeps it pending (approved) until the merchant captures; declining closes it
|
|
448
|
-
{ operation: 'PostIssuingAuthorizationsAuthorizationApprove', from: ['pending'], refusal: { status: 400, code: 'authorization_already_finalized', message: 'This authorization has already been finalized (status {from}).' }, source: 'https://docs.stripe.com/issuing/purchases/authorizations' },
|
|
449
|
-
{ operation: 'PostIssuingAuthorizationsAuthorizationDecline', from: ['pending'], to: 'closed', refusal: { status: 400, code: 'authorization_already_finalized', message: 'This authorization has already been finalized (status {from}).' }, source: 'https://docs.stripe.com/api/issuing/authorizations/decline' },
|
|
450
|
-
{ operation: 'PostTestHelpersIssuingAuthorizationsAuthorizationCapture', from: ['pending'], to: 'closed', source: 'https://docs.stripe.com/api/issuing/authorizations/test_mode_capture' },
|
|
451
|
-
{ operation: 'PostTestHelpersIssuingAuthorizationsAuthorizationCapture', from: ['pending'], source: 'https://docs.stripe.com/api/issuing/authorizations/test_mode_capture' },
|
|
452
|
-
// a real-time request no one answered is decided when its window ends: "If Stripe doesn't receive your approve or
|
|
453
|
-
// decline response within 2 seconds, the Authorization is automatically approved or declined based on your timeout
|
|
454
|
-
// settings" (semantics/issuing.ts lapseRealtimeRequests)
|
|
455
|
-
by('time', ['pending'], 'closed', 'https://docs.stripe.com/issuing/controls/real-time-authorizations'),
|
|
456
|
-
// (Stripe also closes, reverses and expires one as the merchant and the clock act; in test mode the
|
|
457
|
-
// capture helper above closes it, and the twin serves no other)
|
|
458
|
-
],
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
/** A Treasury flow's `status` as the twin's own operations move it: only a processing flow cancels. */
|
|
462
|
-
const flowCancel = (operation: string, code: string, name: string, network: Transition[]): StateField => ({
|
|
463
|
-
initial: 'processing',
|
|
464
|
-
transitions: [
|
|
465
|
-
{ operation, from: ['processing'], to: 'canceled', refusal: { status: 400, code, message: `This ${name} cannot be canceled because it is no longer processing.` }, source: 'https://docs.stripe.com/api/treasury' },
|
|
466
|
-
...network,
|
|
467
|
-
],
|
|
468
|
-
});
|
|
469
|
-
/** An outbound flow on the network: Stripe posts or fails it and a posted one may come back returned (in
|
|
470
|
-
* test mode by test helpers the twin does not serve), so none of those moves is the twin's. */
|
|
471
|
-
const outbound = (_doc: string): Transition[] => [];
|
|
4
|
+
import type { DerivedManifest } from '@volter/world-core';
|
|
5
|
+
import { data, values } from './semantics/events.ts';
|
|
6
|
+
import { STRIPE_EVENTS } from './semantics/shared.ts';
|
|
7
|
+
import { states } from './semantics/states.ts';
|
|
472
8
|
|
|
473
9
|
export const manifest: DerivedManifest = {
|
|
474
10
|
vendor: 'stripe',
|
|
@@ -477,6 +13,90 @@ export const manifest: DerivedManifest = {
|
|
|
477
13
|
ids: { template: '{prefix}_twin_{n}', acceptProvided: true },
|
|
478
14
|
// on declared resources, but never served by the twin: Stripe's unknown-URL answer
|
|
479
15
|
unmodeled: [
|
|
16
|
+
// served by the core on a declared resource, but no application's demand (../journeys/demand.json) names them: the gap
|
|
17
|
+
'DeleteWebhookEndpointsWebhookEndpoint',
|
|
18
|
+
'GetAccountsAccountPersons',
|
|
19
|
+
'GetApplicationFees',
|
|
20
|
+
'GetApplicationFeesId',
|
|
21
|
+
'GetBillingAlertsId',
|
|
22
|
+
'GetBillingCreditGrants',
|
|
23
|
+
'GetBillingCreditGrantsId',
|
|
24
|
+
'GetBillingPortalConfigurationsConfiguration',
|
|
25
|
+
'GetClimateOrders',
|
|
26
|
+
'GetClimateOrdersOrder',
|
|
27
|
+
'GetCoupons',
|
|
28
|
+
'GetCreditNotes',
|
|
29
|
+
'GetEntitlementsFeaturesId',
|
|
30
|
+
'GetFiles',
|
|
31
|
+
'GetFilesFile',
|
|
32
|
+
'GetFinancialConnectionsAccountsAccount',
|
|
33
|
+
'GetForwardingRequests',
|
|
34
|
+
'GetForwardingRequestsId',
|
|
35
|
+
'GetIdentityVerificationReports',
|
|
36
|
+
'GetIdentityVerificationReportsReport',
|
|
37
|
+
'GetIdentityVerificationSessionsSession',
|
|
38
|
+
'GetIssuingCardholders',
|
|
39
|
+
'GetIssuingCardholdersCardholder',
|
|
40
|
+
'GetIssuingCardsCard',
|
|
41
|
+
'GetIssuingDisputes',
|
|
42
|
+
'GetIssuingDisputesDispute',
|
|
43
|
+
'GetIssuingPersonalizationDesignsPersonalizationDesign',
|
|
44
|
+
'GetIssuingTokens',
|
|
45
|
+
'GetIssuingTokensToken',
|
|
46
|
+
'GetIssuingTransactions',
|
|
47
|
+
'GetIssuingTransactionsTransaction',
|
|
48
|
+
'GetMandatesMandate',
|
|
49
|
+
'GetPaymentLinksPaymentLink',
|
|
50
|
+
'GetQuotes',
|
|
51
|
+
'GetQuotesQuote',
|
|
52
|
+
'GetRadarValueListItemsItem',
|
|
53
|
+
'GetRadarValueLists',
|
|
54
|
+
'GetRadarValueListsValueList',
|
|
55
|
+
'GetReportingReportRuns',
|
|
56
|
+
'GetReportingReportRunsReportRun',
|
|
57
|
+
'GetReviews',
|
|
58
|
+
'GetReviewsReview',
|
|
59
|
+
'GetSetupIntentsIntent',
|
|
60
|
+
'GetSourcesSource',
|
|
61
|
+
'GetSubscriptionSchedules',
|
|
62
|
+
'GetTaxCalculationsCalculation',
|
|
63
|
+
'GetTaxRatesTaxRate',
|
|
64
|
+
'GetTaxRegistrations',
|
|
65
|
+
'GetTaxRegistrationsId',
|
|
66
|
+
'GetTaxTransactionsTransaction',
|
|
67
|
+
'GetTerminalConfigurations',
|
|
68
|
+
'GetTerminalConfigurationsConfiguration',
|
|
69
|
+
'GetTerminalLocations',
|
|
70
|
+
'GetTerminalLocationsLocation',
|
|
71
|
+
'GetTerminalReaders',
|
|
72
|
+
'GetTerminalReadersReader',
|
|
73
|
+
'GetTestHelpersTestClocks',
|
|
74
|
+
'GetTokensToken',
|
|
75
|
+
'GetTopups',
|
|
76
|
+
'GetTopupsTopup',
|
|
77
|
+
'GetTransfersTransfer',
|
|
78
|
+
'GetTreasuryFinancialAccounts',
|
|
79
|
+
'GetTreasuryFinancialAccountsFinancialAccount',
|
|
80
|
+
'GetTreasuryInboundTransfers',
|
|
81
|
+
'GetTreasuryInboundTransfersId',
|
|
82
|
+
'GetTreasuryOutboundPayments',
|
|
83
|
+
'GetTreasuryOutboundPaymentsId',
|
|
84
|
+
'GetTreasuryOutboundTransfers',
|
|
85
|
+
'GetTreasuryOutboundTransfersOutboundTransfer',
|
|
86
|
+
'GetTreasuryReceivedCredits',
|
|
87
|
+
'GetTreasuryReceivedCreditsId',
|
|
88
|
+
'GetTreasuryReceivedDebits',
|
|
89
|
+
'GetTreasuryReceivedDebitsId',
|
|
90
|
+
'GetTreasuryTransactionEntriesId',
|
|
91
|
+
'GetTreasuryTransactionsId',
|
|
92
|
+
'GetWebhookEndpoints',
|
|
93
|
+
'GetWebhookEndpointsWebhookEndpoint',
|
|
94
|
+
'PostCouponsCoupon',
|
|
95
|
+
'PostPaymentIntentsIntent',
|
|
96
|
+
'PostPaymentLinksPaymentLink',
|
|
97
|
+
'PostRefundsRefund',
|
|
98
|
+
'PostSetupIntentsIntent',
|
|
99
|
+
'PostTransfersTransfer',
|
|
480
100
|
'DeleteAccountsAccountBankAccountsId',
|
|
481
101
|
'DeleteAccountsAccountPeoplePerson',
|
|
482
102
|
'DeleteCustomersCustomerSubscriptionsSubscriptionExposedId',
|
|
@@ -548,6 +168,65 @@ export const manifest: DerivedManifest = {
|
|
|
548
168
|
message: 'Keys for idempotent requests can only be used with the same parameters they were originally used with. Provide a new idempotency key, or use the original parameters that were used with this key.',
|
|
549
169
|
},
|
|
550
170
|
},
|
|
171
|
+
// the pack as the World registers it (world-core packRegistry)
|
|
172
|
+
// the fail-closed ceiling on live calls against Stripe (world-core rateBudget.ts, architecture D8)
|
|
173
|
+
rateBudget: {
|
|
174
|
+
windowMs: 60_000,
|
|
175
|
+
ceiling: 120,
|
|
176
|
+
defaultWeight: 1,
|
|
177
|
+
maxRetryAfterSeconds: 300,
|
|
178
|
+
rules: [
|
|
179
|
+
{ match: '^POST /v1/payouts$', weight: 5 },
|
|
180
|
+
{ match: '^(POST|DELETE) ', weight: 2 },
|
|
181
|
+
],
|
|
182
|
+
reason:
|
|
183
|
+
'Stripe documents scalar limits (docs.stripe.com/rate-limits, read 2026-07-26): 100 requests/second in live mode, 25/second in ' +
|
|
184
|
+
'sandbox, 25/second for an individual endpoint unless noted, 15 payout creates/second; over it, 429 with a Stripe-Rate-Limited-Reason ' +
|
|
185
|
+
'header. 120 weighted units / 60s is 2 requests/second, 2% of live mode and 8% of the tightest general limit. POST/DELETE cost 2, a ' +
|
|
186
|
+
'judgement about blast radius (a write creates a charge, refund or receipt e-mail and cannot be taken back), not a published ratio; ' +
|
|
187
|
+
"POST /v1/payouts costs 5 because payout creation is documented at 15/second. Stripe's own window is a second, so an intra-second " +
|
|
188
|
+
'burst reaches its limiter first; the 429 cooldown is the backstop for that shape.',
|
|
189
|
+
},
|
|
190
|
+
descriptor: {
|
|
191
|
+
protocol: '3',
|
|
192
|
+
transport: 'rest',
|
|
193
|
+
archetype: 'crud',
|
|
194
|
+
bin: 'world-stripe',
|
|
195
|
+
resources: ['charge', 'customer', 'payment_intent', 'setup_intent', 'payment_method', 'subscription', 'price', 'product', 'invoice', 'invoiceitem', 'refund', 'event'],
|
|
196
|
+
specSource: "Stripe's OpenAPI document (spec/, provenance in spec/SOURCE.md)",
|
|
197
|
+
description: 'Stripe REST twin — spec-correct shapes, signed events, and the hosted pages an application sends people through.',
|
|
198
|
+
// Stripe.js calls the same-origin '/v1/…' and loads from api.stripe.com — the dev proxy forwards '/v1/' to the twin
|
|
199
|
+
// and strips the absolute host so calls come back same-origin
|
|
200
|
+
browserRouting: { apiPathPrefix: '/v1/', loaderHost: 'https://api.stripe.com' },
|
|
201
|
+
// the official server SDK and its Python bindings, and the STRIPE_* credential stems (NEXT_PRIVATE_STRIPE_* too);
|
|
202
|
+
// `stripeconnect` is deliberately not claimed: no Connect-only credential stem is modelled
|
|
203
|
+
adoption: { pypi: ['stripe'], sdks: ['stripe'], envStems: ['STRIPE', 'NEXTPRIVATESTRIPE'] },
|
|
204
|
+
// the API and the screens' hosts, each claimed for the paths its screens serve: an application that sends a person
|
|
205
|
+
// to one of their urls lands in the World; any other path on a claimed host is refused in a World rather than sent
|
|
206
|
+
// to the real Stripe
|
|
207
|
+
// a World's applications hold the platform's keys the dashboard shows (the credential door), never fixtures: the API
|
|
208
|
+
// refuses a key Stripe did not issue
|
|
209
|
+
credentialDoor: { path: '/_twin/app-credentials', body: {}, fill: { STRIPE_SECRET_KEY: 'secret_key', STRIPE_API_KEY: 'secret_key', STRIPE_PRIVATE_KEY: 'secret_key', BILLING_STRIPE_API_KEY: 'secret_key', STRIPE_PUBLISHABLE_KEY: 'publishable_key', NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: 'publishable_key', NEXT_PUBLIC_STRIPE_PUBLIC_KEY: 'publishable_key', NEXT_PUBLIC_STRIPE_KEY: 'publishable_key', STRIPE_WEBHOOK_SECRET: 'webhook_secret', STRIPE_WEBHOOK_SIGNING_SECRET: 'webhook_secret', STRIPE_ENDPOINT_SECRET: 'webhook_secret', STRIPE_WEBHOOK_SECRET_KEY: 'webhook_secret', NEXT_PRIVATE_STRIPE_WEBHOOK_SECRET: 'webhook_secret', BILLING_STRIPE_WEBHOOK_SECRET: 'webhook_secret', STRIPE_CONNECT_WEBHOOK_SECRET: 'connect_webhook_secret', STRIPE_WEBHOOK_SECRET_CONNECT: 'connect_webhook_secret', STRIPE_CONNECT_WEBHOOK_SIGNING_SECRET: 'connect_webhook_secret' } },
|
|
210
|
+
hosts: [
|
|
211
|
+
{ host: 'api.stripe.com' }, { host: 'checkout.stripe.com', pathPattern: '^/c/pay/' }, { host: 'billing.stripe.com', pathPattern: '^/p/session/' },
|
|
212
|
+
{ host: 'connect.stripe.com', pathPattern: '^/setup/|^/oauth/(authorize|token|deauthorize)/?$' },
|
|
213
|
+
{ host: 'dashboard.stripe.com', pathPattern: '^/settings/public/?$|^/(test/)?settings/connect(/onboarding-options/oauth)?/?$' },
|
|
214
|
+
{ host: 'verify.stripe.com', pathPattern: '^/start/' },
|
|
215
|
+
{ host: 'js.stripe.com', pathPattern: '^/v3/financial-connections/|^/v3/?$|^/(v3|[a-z]+)/stripe\\.js$' },
|
|
216
|
+
],
|
|
217
|
+
},
|
|
218
|
+
// what GET /twin says this twin is
|
|
219
|
+
discovery: {
|
|
220
|
+
twinOf: 'the Stripe REST API, its hosted pages (Checkout, the customer portal, Connect onboarding and OAuth, Identity, Financial Connections) and Stripe.js',
|
|
221
|
+
stores: 'customers, payment objects, checkout sessions, products and prices, subscriptions and invoices, Connect accounts, Issuing, Treasury, and webhook endpoints (signed events)',
|
|
222
|
+
},
|
|
223
|
+
// the World's doors (./semantics/doors.ts): what stands in for an act Stripe's API does not have
|
|
224
|
+
doors: [
|
|
225
|
+
{ id: 'account', method: 'POST', path: '/_twin/account', note: "the platform's own account settings, as the Dashboard changes them" },
|
|
226
|
+
{ id: 'appCredentials', method: 'POST', path: '/_twin/app-credentials', note: 'the platform\'s API keys (secret and publishable), as the runtime issues them' },
|
|
227
|
+
{ id: 'webhookEndpoints', method: 'POST', path: '/_twin/webhook-endpoints', note: '{ url, events, connect? }: an endpoint added on the Dashboard\'s Webhooks page, signed with the secret the World\'s application holds' },
|
|
228
|
+
{ id: 'drain', method: 'POST', path: '/_twin/drain', note: "time's events, sent when a runner drives them: payouts paid and funds made available" },
|
|
229
|
+
],
|
|
551
230
|
// The screens applications and people reach (docs/contributing/architecture.md, "Screens"). Demand is the
|
|
552
231
|
// ladder's 85 applications: the code that sends a customer to the page.
|
|
553
232
|
screens: [
|
|
@@ -563,63 +242,51 @@ export const manifest: DerivedManifest = {
|
|
|
563
242
|
source: 'https://docs.stripe.com/customer-management',
|
|
564
243
|
},
|
|
565
244
|
{
|
|
566
|
-
|
|
245
|
+
// an Account Link's url (/setup/{account_link}) opens the onboarding session the page is (/setup/s/{session})
|
|
246
|
+
id: 'connect-onboarding', kind: 'flow', host: 'connect.stripe.com', path: '/setup', status: 'done',
|
|
567
247
|
demand: '3 of 85 applications onboard connected accounts with Account Links', controls: ['Agree and submit', '← Return to platform'],
|
|
568
248
|
source: 'https://docs.stripe.com/connect/hosted-onboarding',
|
|
569
249
|
},
|
|
570
250
|
{
|
|
571
|
-
|
|
251
|
+
// the authorize page, and the token and deauthorize endpoints the platform's server calls (not in Stripe's spec)
|
|
252
|
+
id: 'connect-oauth', kind: 'flow', host: 'connect.stripe.com', path: '/oauth', status: 'done',
|
|
572
253
|
demand: "Cal.com's Stripe app connects each organizer's Standard account through Connect OAuth", controls: ['Skip this form', 'Deny access'],
|
|
573
254
|
source: 'https://docs.stripe.com/connect/oauth-reference',
|
|
574
255
|
},
|
|
575
256
|
{
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
{
|
|
581
|
-
id: 'financial-connections', kind: 'flow', host: 'js.stripe.com', path: '/v3/financial-connections/{client_secret}', status: 'done',
|
|
582
|
-
demand: 'a linked bank account exists only once its holder links it here', controls: ['Link accounts', 'Cancel'],
|
|
583
|
-
source: 'https://docs.stripe.com/js/financial_connections/collect_financial_connections_accounts',
|
|
257
|
+
// Stripe.js, the client library an application's page loads: /v3/, /v3/stripe.js and /<release train>/stripe.js
|
|
258
|
+
id: 'stripe-js', kind: 'content', host: 'js.stripe.com', path: '/', status: 'done',
|
|
259
|
+
demand: "Dub's upgrade button loads Stripe.js and calls redirectToCheckout",
|
|
260
|
+
source: 'https://docs.stripe.com/js',
|
|
584
261
|
},
|
|
585
262
|
{
|
|
586
|
-
id: 'dashboard', kind: 'workspace', host: 'dashboard.stripe.com', path: '/
|
|
587
|
-
demand: '
|
|
263
|
+
id: 'dashboard', kind: 'workspace', host: 'dashboard.stripe.com', path: '/', status: 'done',
|
|
264
|
+
demand: 'an operator sets the business name Checkout shows (Public details: /settings/public) and a Connect platform its OAuth client_id and redirect URIs (/settings/connect/onboarding-options/oauth)',
|
|
588
265
|
controls: ['Business name', 'Save', 'Enable OAuth for Standard accounts', 'Redirect URIs'], source: 'https://docs.stripe.com/dashboard/basics',
|
|
589
266
|
},
|
|
590
267
|
],
|
|
591
268
|
resources: {
|
|
592
269
|
'billing.meter': {
|
|
593
|
-
storedAs: 'billing_meter', idPrefix: 'mtr', notFound: "No such meter: '{id}'",
|
|
594
|
-
notState: ['event_time_window'], filters: ['status'],
|
|
595
|
-
state: { status: { initial: 'active', transitions: [
|
|
596
|
-
{ operation: 'PostBillingMetersIdDeactivate', from: '*', to: 'inactive', source: 'https://docs.stripe.com/api/billing/meter/deactivate' },
|
|
597
|
-
{ operation: 'PostBillingMetersIdReactivate', from: '*', to: 'active', source: 'https://docs.stripe.com/api/billing/meter/reactivate' },
|
|
598
|
-
] } },
|
|
270
|
+
storedAs: 'billing_meter', idPrefix: 'mtr', notFound: "No such meter: '{id}'", ...states["billing.meter"], filters: ['status'],
|
|
599
271
|
},
|
|
600
272
|
'billing.meter_event': { storedAs: 'billing_meter_event', idPrefix: 'mtr_evt' },
|
|
601
|
-
'billing.credit_grant': { storedAs: 'credit_grant', idPrefix: 'credgr',
|
|
273
|
+
'billing.credit_grant': { storedAs: 'credit_grant', idPrefix: 'credgr', ...states["billing.credit_grant"], filters: ['customer'], notFound: "No such credit grant: '{id}'" },
|
|
602
274
|
'billing.alert': {
|
|
603
|
-
storedAs: 'billing_alert', idPrefix: 'alert', notFound: "No such alert: '{id}'",
|
|
604
|
-
state: { status: { initial: 'active', transitions: [
|
|
605
|
-
{ operation: 'PostBillingAlertsIdActivate', from: '*', to: 'active', source: 'https://docs.stripe.com/api/billing/alert/activate' },
|
|
606
|
-
{ operation: 'PostBillingAlertsIdDeactivate', from: '*', to: 'inactive', source: 'https://docs.stripe.com/api/billing/alert/deactivate' },
|
|
607
|
-
{ operation: 'PostBillingAlertsIdArchive', from: '*', to: 'archived', source: 'https://docs.stripe.com/api/billing/alert/archive' },
|
|
608
|
-
] } },
|
|
275
|
+
storedAs: 'billing_alert', idPrefix: 'alert', notFound: "No such alert: '{id}'", ...states["billing.alert"],
|
|
609
276
|
},
|
|
610
277
|
payment_intent: {
|
|
611
|
-
idPrefix: 'pi',
|
|
612
|
-
state: { status: paymentIntentStatus },
|
|
613
|
-
notState: ['cancellation_reason', 'capture_method', 'confirmation_method', 'setup_future_usage'],
|
|
278
|
+
idPrefix: 'pi', ...states["payment_intent"],
|
|
614
279
|
embeds: { customer: 'customer', latest_charge: 'charge', payment_method: 'payment_method', invoice: 'invoice' },
|
|
615
280
|
filters: ['customer'],
|
|
616
281
|
},
|
|
617
282
|
// an update stores what it is given, nested objects whole, as the twin always has (Stripe merges
|
|
618
283
|
// metadata keys; `update: 'replace'` keeps the twin's answer)
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
284
|
+
// next_invoice_sequence, "The suffix of the customer's next invoice number" (docs.stripe.com/api/customers/object): one
|
|
285
|
+
// past its numbered invoices (a finalized invoice is never deleted)
|
|
286
|
+
customer: { idPrefix: 'cus', update: 'replace', ...states["customer"], filters: ['email'], counts: { next_invoice_sequence: { of: 'invoice', by: 'customer', present: 'number', plus: 1 } } },
|
|
287
|
+
tax_id: { idPrefix: 'txi', ...states["tax_id"], filters: ['customer'] },
|
|
288
|
+
customer_balance_transaction: { idPrefix: 'cbtxn', ...states["customer_balance_transaction"], },
|
|
289
|
+
customer_cash_balance_transaction: { storedAs: 'cash_balance_transaction', idPrefix: 'ccsbtxn', ...states["customer_cash_balance_transaction"], },
|
|
623
290
|
// a card is chargeable at once; any other source waits for its owner to authorize it through its
|
|
624
291
|
// flow, and is used up (single-use) or lapses
|
|
625
292
|
// what a customer's sources list answers (a card, a bank account, a Source, an account) as one
|
|
@@ -627,69 +294,46 @@ export const manifest: DerivedManifest = {
|
|
|
627
294
|
// attributes. A customer's bank account verifies as a payout account does.
|
|
628
295
|
payment_source: {
|
|
629
296
|
storedAs: 'source',
|
|
630
|
-
idPrefix: 'src',
|
|
631
|
-
state: { status: bankAccountStatus('https://docs.stripe.com/api/customer_bank_accounts/object#customer_bank_account_object-status') },
|
|
632
|
-
notState: ['allow_redisplay', 'business_type', 'regulated_status', 'type'],
|
|
297
|
+
idPrefix: 'src', ...states["payment_source"],
|
|
633
298
|
},
|
|
634
299
|
source: {
|
|
635
|
-
idPrefix: 'src',
|
|
636
|
-
state: {
|
|
637
|
-
status: {
|
|
638
|
-
initial: 'chargeable',
|
|
639
|
-
transitions: [
|
|
640
|
-
// (Stripe makes a redirect source chargeable when the customer authorizes it on the bank's page;
|
|
641
|
-
// the twin has no such page, so a non-card source stays pending)
|
|
642
|
-
// Stripe also fails a source the customer abandons, consumes a single-use one once charged and
|
|
643
|
-
// cancels one left unused; the twin's sources stay chargeable
|
|
644
|
-
],
|
|
645
|
-
},
|
|
646
|
-
},
|
|
647
|
-
notState: ['allow_redisplay', 'type'],
|
|
300
|
+
idPrefix: 'src', ...states["source"],
|
|
648
301
|
},
|
|
302
|
+
// Connect OAuth's authorization codes: the row's id minted, the code's value drawn from the World's secret
|
|
303
|
+
_oauth_code: { idPrefix: '', ids: '{n}' },
|
|
649
304
|
charge: {
|
|
650
|
-
idPrefix: 'ch',
|
|
651
|
-
state: { status: chargeStatus, captured: chargeCaptured, paid: chargePaid, refunded: chargeRefunded },
|
|
305
|
+
idPrefix: 'ch', ...states["charge"],
|
|
652
306
|
embeds: { customer: 'customer', payment_intent: 'payment_intent', invoice: 'invoice', balance_transaction: 'balance_transaction' },
|
|
653
307
|
filters: ['customer', 'payment_intent'],
|
|
654
308
|
},
|
|
655
309
|
refund: {
|
|
656
310
|
idPrefix: 're',
|
|
657
|
-
update: 'replace',
|
|
658
|
-
state: { status: refundStatus },
|
|
659
|
-
notState: ['pending_reason', 'reason'],
|
|
311
|
+
update: 'replace', ...states["refund"],
|
|
660
312
|
embeds: { charge: 'charge', payment_intent: 'payment_intent', balance_transaction: 'balance_transaction' },
|
|
661
313
|
filters: ['charge', 'payment_intent'],
|
|
662
314
|
},
|
|
663
315
|
setup_intent: {
|
|
664
316
|
idPrefix: 'seti',
|
|
665
|
-
update: 'replace',
|
|
666
|
-
state: { status: setupIntentStatus },
|
|
667
|
-
notState: ['cancellation_reason'],
|
|
317
|
+
update: 'replace', ...states["setup_intent"],
|
|
668
318
|
embeds: { customer: 'customer', payment_method: 'payment_method' },
|
|
669
319
|
filters: ['customer', 'payment_method'],
|
|
670
320
|
},
|
|
671
|
-
payment_method: { idPrefix: 'pm',
|
|
321
|
+
payment_method: { idPrefix: 'pm', ...states["payment_method"], embeds: { customer: 'customer' }, filters: ['customer', 'type'] },
|
|
672
322
|
subscription: {
|
|
673
|
-
idPrefix: 'sub',
|
|
674
|
-
state: { status: subscriptionStatus },
|
|
675
|
-
notState: ['collection_method'],
|
|
323
|
+
idPrefix: 'sub', ...states["subscription"],
|
|
676
324
|
embeds: { customer: 'customer', latest_invoice: 'invoice', default_payment_method: 'payment_method', schedule: 'subscription_schedule' },
|
|
677
325
|
filters: ['customer'],
|
|
678
326
|
},
|
|
679
327
|
subscription_item: { idPrefix: 'si' },
|
|
680
328
|
invoice: {
|
|
681
|
-
idPrefix: 'in',
|
|
682
|
-
state: { status: invoiceStatus },
|
|
683
|
-
notState: ['billing_reason', 'collection_method', 'customer_tax_exempt'],
|
|
329
|
+
idPrefix: 'in', ...states["invoice"],
|
|
684
330
|
embeds: { customer: 'customer', subscription: 'subscription', charge: 'charge', payment_intent: 'payment_intent' },
|
|
685
331
|
filters: ['customer', 'status', 'subscription'],
|
|
686
332
|
},
|
|
687
333
|
invoiceitem: { idPrefix: 'ii', embeds: { customer: 'customer', price: 'price' }, filters: ['customer', 'invoice'], order: { field: 'date', direction: 'desc' } },
|
|
688
334
|
'checkout.session': {
|
|
689
335
|
storedAs: 'checkout_session',
|
|
690
|
-
idPrefix: 'cs',
|
|
691
|
-
state: { status: checkoutStatus, payment_status: checkoutPaymentStatus },
|
|
692
|
-
notState: ['billing_address_collection', 'customer_creation', 'locale', 'mode', 'origin_context', 'payment_method_collection', 'redirect_on_completion', 'submit_type', 'ui_mode'],
|
|
336
|
+
idPrefix: 'cs', ...states["checkout.session"],
|
|
693
337
|
filters: ['customer', 'payment_intent', 'subscription', 'status'],
|
|
694
338
|
// the objects a session links to, as its x-expandableFields name them
|
|
695
339
|
embeds: { customer: 'customer', invoice: 'invoice', payment_intent: 'payment_intent', payment_link: 'payment_link', setup_intent: 'setup_intent', subscription: 'subscription' },
|
|
@@ -697,120 +341,61 @@ export const manifest: DerivedManifest = {
|
|
|
697
341
|
ephemeral_key: { idPrefix: 'ephkey' },
|
|
698
342
|
// a mandate's status is the network's to move; nothing here moves it
|
|
699
343
|
mandate: {
|
|
700
|
-
idPrefix: 'mandate',
|
|
701
|
-
state: {
|
|
702
|
-
status: {
|
|
703
|
-
initial: 'active',
|
|
704
|
-
transitions: [
|
|
705
|
-
// a single-use mandate is spent by its payment: inactive "The mandate was rejected, revoked, or previously
|
|
706
|
-
// used, and may not be used to initiate future payments" (semantics/payment-intents.ts settleBankDebits)
|
|
707
|
-
by('vendor', ['active'], 'inactive', 'https://docs.stripe.com/api/mandates/object'),
|
|
708
|
-
// (Stripe also activates a pending mandate and deactivates one revoked; the twin's are active when made)
|
|
709
|
-
],
|
|
710
|
-
},
|
|
711
|
-
},
|
|
712
|
-
notState: ['type'],
|
|
344
|
+
idPrefix: 'mandate', ...states["mandate"],
|
|
713
345
|
},
|
|
714
|
-
dispute: { idPrefix: 'dp', update: 'replace',
|
|
715
|
-
payout: { idPrefix: 'po',
|
|
346
|
+
dispute: { idPrefix: 'dp', update: 'replace', ...states["dispute"], embeds: { charge: 'charge', payment_intent: 'payment_intent' }, filters: ['charge', 'payment_intent'] },
|
|
347
|
+
payout: { idPrefix: 'po', ...states["payout"], embeds: { balance_transaction: 'balance_transaction', destination: 'account' } },
|
|
716
348
|
// the twin's ledger is seeded available; Stripe holds funds pending until their available_on
|
|
717
349
|
balance_transaction: {
|
|
718
|
-
idPrefix: 'txn',
|
|
719
|
-
state: { status: { initial: 'available', vendorInitial: 'pending', transitions: [by('time', ['pending'], 'available', 'https://docs.stripe.com/api/balance_transactions/object#balance_transaction_object-status')] } },
|
|
720
|
-
notState: ['balance_type', 'type'],
|
|
350
|
+
idPrefix: 'txn', ...states["balance_transaction"],
|
|
721
351
|
filters: ['type', 'currency'],
|
|
722
352
|
},
|
|
723
353
|
// a coupon lapses at its redeem_by: "Date after which the coupon can no longer be redeemed", and `valid` is
|
|
724
354
|
// "Taking account of the above properties, whether this coupon can still be applied to a customer" (the served
|
|
725
355
|
// spec's coupon); the twin keeps no redemption count, so max_redemptions never lapses one
|
|
726
356
|
coupon: {
|
|
727
|
-
idPrefix: 'coupon', update: 'replace',
|
|
728
|
-
state: { valid: { initial: true, transitions: [by('time', ['true'], 'false', 'spec:/components/schemas/coupon/properties/redeem_by "Date after which the coupon can no longer be redeemed."')] } },
|
|
357
|
+
idPrefix: 'coupon', update: 'replace', ...states["coupon"],
|
|
729
358
|
},
|
|
730
359
|
// switched on and off by an update (Stripe also lapses one at expires_at or when fully redeemed; the
|
|
731
360
|
// twin keeps no redemption count or expiry)
|
|
732
361
|
promotion_code: {
|
|
733
362
|
idPrefix: 'promo',
|
|
734
363
|
update: 'replace',
|
|
735
|
-
notFound: "No such promotion code: '{id}'",
|
|
736
|
-
state: {
|
|
737
|
-
active: {
|
|
738
|
-
initial: true,
|
|
739
|
-
transitions: [
|
|
740
|
-
...flag('PostPromotionCodesPromotionCode', 'https://docs.stripe.com/api/promotion_codes/update'),
|
|
741
|
-
],
|
|
742
|
-
},
|
|
743
|
-
},
|
|
364
|
+
notFound: "No such promotion code: '{id}'", ...states["promotion_code"],
|
|
744
365
|
},
|
|
745
|
-
credit_note: { idPrefix: 'cn',
|
|
366
|
+
credit_note: { idPrefix: 'cn', ...states["credit_note"], embeds: { customer: 'customer', invoice: 'invoice' }, filters: ['invoice', 'customer'] },
|
|
746
367
|
subscription_schedule: {
|
|
747
368
|
idPrefix: 'sub_sched',
|
|
748
|
-
update: 'replace',
|
|
749
|
-
state: { status: scheduleStatus },
|
|
750
|
-
notState: ['end_behavior'],
|
|
369
|
+
update: 'replace', ...states["subscription_schedule"],
|
|
751
370
|
embeds: { customer: 'customer', subscription: 'subscription' },
|
|
752
371
|
filters: ['customer', 'subscription'],
|
|
753
372
|
},
|
|
754
373
|
'entitlements.feature': {
|
|
755
|
-
storedAs: 'entitlements_feature', idPrefix: 'feat', notFound: "No such feature: '{id}'",
|
|
756
|
-
state: { active: { initial: true, transitions: flag('PostEntitlementsFeaturesId', 'spec:PostEntitlementsFeaturesId "Update a feature’s metadata or permanently deactivate it."') } },
|
|
374
|
+
storedAs: 'entitlements_feature', idPrefix: 'feat', notFound: "No such feature: '{id}'", ...states["entitlements.feature"],
|
|
757
375
|
},
|
|
758
|
-
// an advance answers advancing and the clock is ready once it has reached the time (
|
|
376
|
+
// an advance answers advancing and the clock is ready once it has reached the time (./engine/test-clocks.ts)
|
|
759
377
|
'test_helpers.test_clock': {
|
|
760
378
|
storedAs: 'test_clock',
|
|
761
379
|
idPrefix: 'clock',
|
|
762
|
-
notFound: "No such test clock: '{id}'",
|
|
763
|
-
state: {
|
|
764
|
-
status: {
|
|
765
|
-
initial: 'ready',
|
|
766
|
-
transitions: [
|
|
767
|
-
// "advancing: The clock has started to advance but hasn't reached the specified time"; "ready: The clock has
|
|
768
|
-
// completed advancing to the specified time" (docs.stripe.com/billing/testing/test-clocks/api-advanced-usage)
|
|
769
|
-
{ operation: 'PostTestHelpersTestClocksTestClockAdvance', from: ['ready'], to: 'advancing', refusal: { status: 400, code: 'test_clock_not_ready', message: 'This test clock is still advancing.' }, source: 'https://docs.stripe.com/api/test_clocks/advance' },
|
|
770
|
-
by('vendor', ['advancing'], 'ready', 'https://docs.stripe.com/billing/testing/test-clocks/api-advanced-usage'),
|
|
771
|
-
// (Stripe may also end an advance in internal_failure; the twin's advances complete)
|
|
772
|
-
],
|
|
773
|
-
},
|
|
774
|
-
},
|
|
380
|
+
notFound: "No such test clock: '{id}'", ...states["test_helpers.test_clock"],
|
|
775
381
|
},
|
|
776
382
|
event: { idPrefix: 'evt', filters: ['type'] },
|
|
777
383
|
// disabled and re-enabled by an update's `disabled` (Stripe also disables one that keeps failing; the
|
|
778
384
|
// twin counts no failures)
|
|
779
385
|
webhook_endpoint: {
|
|
780
386
|
idPrefix: 'we',
|
|
781
|
-
notFound: "No such webhook endpoint: '{id}'",
|
|
782
|
-
state: {
|
|
783
|
-
status: {
|
|
784
|
-
initial: 'enabled',
|
|
785
|
-
transitions: [
|
|
786
|
-
...['enabled', 'disabled'].map((to) => ({ operation: 'PostWebhookEndpointsWebhookEndpoint', from: '*' as const, to, source: 'https://docs.stripe.com/api/webhook_endpoints/update#update_webhook_endpoint-disabled' })),
|
|
787
|
-
],
|
|
788
|
-
},
|
|
789
|
-
},
|
|
387
|
+
notFound: "No such webhook endpoint: '{id}'", ...states["webhook_endpoint"],
|
|
790
388
|
},
|
|
791
|
-
account: { idPrefix: 'acct',
|
|
792
|
-
person: { idPrefix: 'person',
|
|
389
|
+
account: { idPrefix: 'acct', ...states["account"], },
|
|
390
|
+
person: { idPrefix: 'person', ...states["person"], parent: { param: 'account', field: 'account', resource: 'account' } },
|
|
793
391
|
// a capability lives in its account's capability map; requesting one leaves it pending, withdrawing it inactive
|
|
794
392
|
capability: {
|
|
795
|
-
idPrefix: 'cap',
|
|
796
|
-
state: {
|
|
797
|
-
status: {
|
|
798
|
-
initial: 'unrequested',
|
|
799
|
-
transitions: [
|
|
800
|
-
...['pending', 'inactive'].map((to) => ({ operation: 'PostAccountsAccountCapabilitiesCapability', from: '*' as const, to, source: 'https://docs.stripe.com/api/capabilities/update' })),
|
|
801
|
-
// Stripe reviews the account's requirements
|
|
802
|
-
by('vendor', ['pending', 'inactive'], 'active', 'https://docs.stripe.com/connect/account-capabilities#capability-status'),
|
|
803
|
-
by('vendor', ['active', 'pending'], 'inactive', 'https://docs.stripe.com/connect/account-capabilities#capability-status'),
|
|
804
|
-
],
|
|
805
|
-
},
|
|
806
|
-
},
|
|
393
|
+
idPrefix: 'cap', ...states["capability"],
|
|
807
394
|
},
|
|
808
395
|
// allow_redisplay and regulated_status belong to a card destination: consent and the issuer's
|
|
809
396
|
// regulation, set when it is added, not a lifecycle
|
|
810
397
|
external_account: {
|
|
811
|
-
idPrefix: 'ba',
|
|
812
|
-
state: { status: bankAccountStatus('https://docs.stripe.com/api/external_account_bank_accounts/object#account_bank_account_object-status') },
|
|
813
|
-
notState: ['allow_redisplay', 'regulated_status'],
|
|
398
|
+
idPrefix: 'ba', ...states["external_account"],
|
|
814
399
|
},
|
|
815
400
|
account_link: { idPrefix: 'acctlink' },
|
|
816
401
|
account_session: { idPrefix: 'accts' },
|
|
@@ -818,285 +403,148 @@ export const manifest: DerivedManifest = {
|
|
|
818
403
|
transfer_reversal: { idPrefix: 'trr' },
|
|
819
404
|
// refunded once fee refunds take its whole amount
|
|
820
405
|
application_fee: {
|
|
821
|
-
idPrefix: 'fee', notFound: "No such application fee: '{id}'", filters: ['charge'],
|
|
822
|
-
state: { refunded: { initial: false, transitions: [
|
|
823
|
-
{ operation: 'PostApplicationFeesIdRefunds', from: ['false'], to: 'true', source: 'https://docs.stripe.com/api/fee_refunds/create' },
|
|
824
|
-
// a refund of its charge with refund_application_fee refunds it in proportion
|
|
825
|
-
...['PostRefunds', 'PostChargesChargeRefunds'].map((operation) => ({ operation, from: ['false'], to: 'true', source: 'https://docs.stripe.com/api/refunds/create#create_refund-refund_application_fee' })),
|
|
826
|
-
] } },
|
|
406
|
+
idPrefix: 'fee', notFound: "No such application fee: '{id}'", filters: ['charge'], ...states["application_fee"],
|
|
827
407
|
},
|
|
828
408
|
fee_refund: { idPrefix: 'fr' },
|
|
829
409
|
'apps.secret': { storedAs: 'apps_secret', idPrefix: 'apmc' },
|
|
830
410
|
token: { idPrefix: 'tok' },
|
|
831
|
-
file: { idPrefix: 'file',
|
|
411
|
+
file: { idPrefix: 'file', ...states["file"], filters: ['purpose'] },
|
|
832
412
|
file_link: { idPrefix: 'link' },
|
|
833
413
|
// the user submits on Stripe's hosted verification page and Stripe checks it (the twin's own helper
|
|
834
414
|
// outside Stripe's surface, POST …/verify, stands in for both at once)
|
|
835
415
|
'identity.verification_session': {
|
|
836
416
|
storedAs: 'verification_session',
|
|
837
417
|
idPrefix: 'vs',
|
|
838
|
-
notFound: "No such VerificationSession: '{id}'",
|
|
839
|
-
state: {
|
|
840
|
-
status: {
|
|
841
|
-
initial: 'requires_input',
|
|
842
|
-
transitions: [
|
|
843
|
-
by('external', ['requires_input'], 'processing', 'https://docs.stripe.com/identity/how-sessions-work'),
|
|
844
|
-
by('vendor', ['processing'], 'verified', 'https://docs.stripe.com/identity/how-sessions-work'),
|
|
845
|
-
by('vendor', ['processing'], 'requires_input', 'https://docs.stripe.com/identity/how-sessions-work'),
|
|
846
|
-
],
|
|
847
|
-
},
|
|
848
|
-
},
|
|
849
|
-
notState: ['type'],
|
|
418
|
+
notFound: "No such VerificationSession: '{id}'", ...states["identity.verification_session"],
|
|
850
419
|
},
|
|
851
|
-
'identity.verification_report': { storedAs: 'verification_report', idPrefix: 'vr', notFound: "No such verification report: '{id}'",
|
|
852
|
-
'billing_portal.session': { storedAs: 'billing_portal_session', idPrefix: 'bps',
|
|
420
|
+
'identity.verification_report': { storedAs: 'verification_report', idPrefix: 'vr', notFound: "No such verification report: '{id}'", ...states["identity.verification_report"], filters: ['verification_session', 'type'] },
|
|
421
|
+
'billing_portal.session': { storedAs: 'billing_portal_session', idPrefix: 'bps', ...states["billing_portal.session"], },
|
|
853
422
|
// is_default is Stripe's: the configuration the dashboard made first
|
|
854
423
|
'billing_portal.configuration': {
|
|
855
|
-
storedAs: 'billing_portal_configuration', idPrefix: 'bpc', notFound: "No such configuration: '{id}'",
|
|
856
|
-
state: { active: { initial: true, transitions: flag('PostBillingPortalConfigurationsConfiguration', 'https://docs.stripe.com/api/customer_portal/configurations/update') } },
|
|
857
|
-
notState: ['is_default'],
|
|
424
|
+
storedAs: 'billing_portal_configuration', idPrefix: 'bpc', notFound: "No such configuration: '{id}'", ...states["billing_portal.configuration"],
|
|
858
425
|
},
|
|
859
426
|
// `state` is a US state code, not a lifecycle
|
|
860
427
|
tax_rate: {
|
|
861
|
-
idPrefix: 'txr', notFound: "No such tax rate: '{id}'",
|
|
862
|
-
state: { active: { initial: true, transitions: flag('PostTaxRatesTaxRate', 'https://docs.stripe.com/api/tax_rates/update') } },
|
|
863
|
-
notState: ['jurisdiction_level', 'rate_type', 'state', 'tax_type'],
|
|
428
|
+
idPrefix: 'txr', notFound: "No such tax rate: '{id}'", ...states["tax_rate"],
|
|
864
429
|
},
|
|
865
430
|
// its status is derived on every read from whether a head office is set; nothing stores it
|
|
866
|
-
'tax.settings': { storedAs: 'tax_settings', idPrefix: 'taxset',
|
|
431
|
+
'tax.settings': { storedAs: 'tax_settings', idPrefix: 'taxset', ...states["tax.settings"], },
|
|
867
432
|
'tax.calculation': { storedAs: 'tax_calculation', idPrefix: 'taxcalc', notFound: "No such tax calculation: '{id}'" },
|
|
868
433
|
// a registration is active from creation here; its dates move it on the clock
|
|
869
434
|
'tax.registration': {
|
|
870
|
-
storedAs: 'tax_registration', idPrefix: 'taxreg', notFound: "No such tax registration: '{id}'", filters: ['status'],
|
|
871
|
-
state: {
|
|
872
|
-
// Stripe schedules a registration with a future active_from and expires one at expires_at; the twin's
|
|
873
|
-
// are active from the start and never expire
|
|
874
|
-
status: { initial: 'active', transitions: [] },
|
|
875
|
-
},
|
|
435
|
+
storedAs: 'tax_registration', idPrefix: 'taxreg', notFound: "No such tax registration: '{id}'", filters: ['status'], ...states["tax.registration"],
|
|
876
436
|
},
|
|
877
|
-
'tax.transaction': { storedAs: 'tax_transaction', idPrefix: 'tax', notFound: "No such tax transaction: '{id}'",
|
|
437
|
+
'tax.transaction': { storedAs: 'tax_transaction', idPrefix: 'tax', notFound: "No such tax transaction: '{id}'", ...states["tax.transaction"], },
|
|
878
438
|
payment_link: {
|
|
879
439
|
idPrefix: 'plink',
|
|
880
|
-
update: 'replace', notFound: "No such payment link: '{id}'",
|
|
881
|
-
state: { active: { initial: true, transitions: flag('PostPaymentLinksPaymentLink', 'https://docs.stripe.com/api/payment_links/payment_links/update') } },
|
|
882
|
-
notState: ['billing_address_collection', 'customer_creation', 'payment_method_collection', 'submit_type'],
|
|
440
|
+
update: 'replace', notFound: "No such payment link: '{id}'", ...states["payment_link"],
|
|
883
441
|
},
|
|
884
|
-
quote: { idPrefix: 'qt',
|
|
442
|
+
quote: { idPrefix: 'qt', ...states["quote"], filters: ['customer', 'status'] },
|
|
885
443
|
// a review is open until it is closed; approving closes it, once
|
|
886
444
|
review: {
|
|
887
445
|
storedAs: 'radar_review',
|
|
888
|
-
idPrefix: 'prv',
|
|
889
|
-
state: {
|
|
890
|
-
open: {
|
|
891
|
-
initial: true,
|
|
892
|
-
transitions: [
|
|
893
|
-
// (Stripe also closes one when the payment is refunded or disputed; the twin's close only on approval)
|
|
894
|
-
{ operation: 'PostReviewsReviewApprove', from: ['true'], to: 'false', refusal: { status: 400, code: 'review_already_closed', message: 'This review has already been closed.' }, source: 'https://docs.stripe.com/api/radar/reviews/approve' },
|
|
895
|
-
],
|
|
896
|
-
},
|
|
897
|
-
},
|
|
898
|
-
notState: ['closed_reason', 'opened_reason'],
|
|
446
|
+
idPrefix: 'prv', ...states["review"],
|
|
899
447
|
},
|
|
900
|
-
'radar.value_list': { storedAs: 'radar_value_list', idPrefix: 'rsl', notFound: "No such radar value list: '{id}'",
|
|
448
|
+
'radar.value_list': { storedAs: 'radar_value_list', idPrefix: 'rsl', notFound: "No such radar value list: '{id}'", ...states["radar.value_list"], filters: ['alias'] },
|
|
901
449
|
'radar.value_list_item': { storedAs: 'radar_value_list_item', idPrefix: 'rsli', notFound: "No such radar value list item: '{id}'" },
|
|
902
450
|
'issuing.cardholder': {
|
|
903
451
|
storedAs: 'issuing_cardholder',
|
|
904
452
|
idPrefix: 'ich',
|
|
905
|
-
notFound: "No such cardholder: '{id}'",
|
|
906
|
-
state: { status: { initial: 'active', transitions: setBy('PostIssuingCardholdersCardholder', ['active', 'inactive', 'blocked'], 'https://docs.stripe.com/api/issuing/cardholders/update') } },
|
|
907
|
-
notState: ['type'],
|
|
453
|
+
notFound: "No such cardholder: '{id}'", ...states["issuing.cardholder"],
|
|
908
454
|
filters: ['status', 'type', 'email'],
|
|
909
455
|
},
|
|
910
456
|
'issuing.card': {
|
|
911
457
|
storedAs: 'issuing_card',
|
|
912
458
|
idPrefix: 'ic',
|
|
913
|
-
notFound: "No such card: '{id}'",
|
|
914
|
-
state: { status: { initial: 'active', transitions: setBy('PostIssuingCardsCard', ['active', 'inactive', 'canceled'], 'https://docs.stripe.com/api/issuing/cards/update') } },
|
|
915
|
-
notState: ['cancellation_reason', 'replacement_reason', 'type'],
|
|
459
|
+
notFound: "No such card: '{id}'", ...states["issuing.card"],
|
|
916
460
|
filters: ['cardholder', 'status', 'type'],
|
|
917
461
|
},
|
|
918
|
-
'issuing.authorization': { storedAs: 'issuing_authorization', idPrefix: 'iauth',
|
|
919
|
-
'issuing.transaction': { storedAs: 'issuing_transaction', idPrefix: 'ipi', notFound: "No such transaction: '{id}'",
|
|
462
|
+
'issuing.authorization': { storedAs: 'issuing_authorization', idPrefix: 'iauth', ...states["issuing.authorization"], },
|
|
463
|
+
'issuing.transaction': { storedAs: 'issuing_transaction', idPrefix: 'ipi', notFound: "No such transaction: '{id}'", ...states["issuing.transaction"], filters: ['card', 'cardholder'] },
|
|
920
464
|
'issuing.dispute': {
|
|
921
465
|
storedAs: 'issuing_dispute',
|
|
922
466
|
idPrefix: 'idp',
|
|
923
|
-
notFound: "No such dispute: '{id}'",
|
|
924
|
-
state: {
|
|
925
|
-
status: {
|
|
926
|
-
initial: 'unsubmitted',
|
|
927
|
-
transitions: [
|
|
928
|
-
{ operation: 'PostIssuingDisputesDisputeSubmit', from: ['unsubmitted'], to: 'submitted', refusal: { status: 400, code: 'dispute_unsubmitted_required', message: 'This dispute has already been submitted (status {from}).' }, source: 'spec:PostIssuingDisputesDisputeSubmit "Submits an Issuing <code>Dispute</code> to the card network."' },
|
|
929
|
-
// (Stripe decides a submitted dispute won or lost and expires one never submitted; the twin decides none)
|
|
930
|
-
],
|
|
931
|
-
},
|
|
932
|
-
},
|
|
933
|
-
notState: ['loss_reason'],
|
|
467
|
+
notFound: "No such dispute: '{id}'", ...states["issuing.dispute"],
|
|
934
468
|
filters: ['status', 'transaction'],
|
|
935
469
|
},
|
|
936
470
|
'issuing.token': {
|
|
937
471
|
storedAs: 'issuing_token',
|
|
938
472
|
idPrefix: 'iss_tok',
|
|
939
|
-
notFound: "No such issuing token: '{id}'",
|
|
940
|
-
state: { status: { initial: 'active', transitions: [...setBy('PostIssuingTokensToken', ['active', 'deleted', 'suspended'], 'https://docs.stripe.com/api/issuing/tokens/update')] } },
|
|
941
|
-
notState: ['network', 'wallet_provider'],
|
|
473
|
+
notFound: "No such issuing token: '{id}'", ...states["issuing.token"],
|
|
942
474
|
filters: ['card', 'status'],
|
|
943
475
|
},
|
|
944
476
|
// a design waits in review (inactive) until the review test helpers decide it
|
|
945
477
|
'issuing.personalization_design': {
|
|
946
478
|
storedAs: 'personalization_design',
|
|
947
479
|
idPrefix: 'pd',
|
|
948
|
-
notFound: "No such personalization design: '{id}'",
|
|
949
|
-
state: {
|
|
950
|
-
status: {
|
|
951
|
-
// a new design waits on Stripe's review (docs.stripe.com/issuing/cards/physical/personalization-design)
|
|
952
|
-
initial: 'review',
|
|
953
|
-
transitions: [
|
|
954
|
-
...setBy('PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignActivate', ['active'], 'spec:PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignActivate "to <code>active</code>"'),
|
|
955
|
-
...setBy('PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignDeactivate', ['inactive'], 'spec:PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignDeactivate "to <code>inactive</code>"'),
|
|
956
|
-
...setBy('PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignReject', ['rejected'], 'spec:PostTestHelpersIssuingPersonalizationDesignsPersonalizationDesignReject "to <code>rejected</code>"'),
|
|
957
|
-
// (outside test mode Stripe's review decides it; the twin is test mode, where these helpers do)
|
|
958
|
-
],
|
|
959
|
-
},
|
|
960
|
-
},
|
|
480
|
+
notFound: "No such personalization design: '{id}'", ...states["issuing.personalization_design"],
|
|
961
481
|
},
|
|
962
482
|
'terminal.location': { storedAs: 'terminal_location', idPrefix: 'tml', notFound: "No such location: '{id}'" },
|
|
963
483
|
// a simulated reader is online from registration; a real one drops off and comes back
|
|
964
484
|
'terminal.reader': {
|
|
965
|
-
storedAs: 'terminal_reader', idPrefix: 'tmr', notFound: "No such reader: '{id}'",
|
|
966
|
-
// (a real reader goes offline and back; the twin's simulated readers stay online)
|
|
967
|
-
state: { status: { initial: 'online', transitions: [] } },
|
|
485
|
+
storedAs: 'terminal_reader', idPrefix: 'tmr', notFound: "No such reader: '{id}'", ...states["terminal.reader"], filters: ['location', 'status'],
|
|
968
486
|
},
|
|
969
|
-
'terminal.configuration': { storedAs: 'terminal_configuration', idPrefix: 'tmc', notFound: "No such configuration: '{id}'",
|
|
487
|
+
'terminal.configuration': { storedAs: 'terminal_configuration', idPrefix: 'tmc', notFound: "No such configuration: '{id}'", ...states["terminal.configuration"], },
|
|
970
488
|
topup: {
|
|
971
|
-
idPrefix: 'tu',
|
|
972
|
-
state: {
|
|
973
|
-
status: {
|
|
974
|
-
// a top-up starts pending (the create page's example answers "status": "pending") and its funds arrive days
|
|
975
|
-
// later: "USA (USD) ACH Debit Transfer 5 days" (docs.stripe.com/connect/top-ups; semantics/terminal.ts)
|
|
976
|
-
initial: 'pending',
|
|
977
|
-
transitions: [
|
|
978
|
-
{ operation: 'PostTopupsTopupCancel', from: ['pending'], to: 'canceled', refusal: { status: 400, code: 'topup_unexpected_state', message: 'This top-up cannot be canceled because it has a status of {from}.' }, source: 'https://docs.stripe.com/api/topups/cancel' },
|
|
979
|
-
// to the Issuing balance alike: "Your top-ups can take up to 5 business days to become available"
|
|
980
|
-
// (docs.stripe.com/issuing/funding/balance)
|
|
981
|
-
by('vendor', ['pending'], 'succeeded', 'https://docs.stripe.com/connect/top-ups'),
|
|
982
|
-
// (Stripe also fails a top-up or reverses a settled one; the twin's top-ups do neither)
|
|
983
|
-
],
|
|
984
|
-
},
|
|
985
|
-
},
|
|
986
|
-
notState: ['initiated_by'],
|
|
489
|
+
idPrefix: 'tu', ...states["topup"],
|
|
987
490
|
filters: ['status'],
|
|
988
491
|
},
|
|
989
492
|
// closing an account (POST …/close) is not modeled here; is_default is Stripe's
|
|
990
|
-
'treasury.financial_account': { storedAs: 'financial_account', idPrefix: 'fa', notFound: "No such financial account: '{id}'",
|
|
493
|
+
'treasury.financial_account': { storedAs: 'financial_account', idPrefix: 'fa', notFound: "No such financial account: '{id}'", ...states["treasury.financial_account"], filters: ['status'] },
|
|
991
494
|
'treasury.outbound_payment': {
|
|
992
495
|
storedAs: 'outbound_payment',
|
|
993
496
|
idPrefix: 'obp',
|
|
994
|
-
notFound: "No such outbound payment: '{id}'",
|
|
995
|
-
state: { status: flowCancel('PostTreasuryOutboundPaymentsIdCancel', 'outbound_payment_not_cancelable', 'OutboundPayment', outbound('https://docs.stripe.com/treasury/moving-money/financial-accounts/out-of/outbound-payments')) },
|
|
497
|
+
notFound: "No such outbound payment: '{id}'", ...states["treasury.outbound_payment"],
|
|
996
498
|
filters: ['financial_account', 'status'],
|
|
997
499
|
},
|
|
998
500
|
'treasury.outbound_transfer': {
|
|
999
501
|
storedAs: 'outbound_transfer',
|
|
1000
502
|
idPrefix: 'obt',
|
|
1001
|
-
notFound: "No such outbound transfer: '{id}'",
|
|
1002
|
-
state: { status: flowCancel('PostTreasuryOutboundTransfersOutboundTransferCancel', 'outbound_transfer_not_cancelable', 'OutboundTransfer', outbound('https://docs.stripe.com/treasury/moving-money/financial-accounts/out-of/outbound-transfers')) },
|
|
503
|
+
notFound: "No such outbound transfer: '{id}'", ...states["treasury.outbound_transfer"],
|
|
1003
504
|
filters: ['financial_account', 'status'],
|
|
1004
505
|
},
|
|
1005
506
|
'treasury.inbound_transfer': {
|
|
1006
507
|
storedAs: 'inbound_transfer',
|
|
1007
508
|
idPrefix: 'ibt',
|
|
1008
|
-
notFound: "No such inbound transfer: '{id}'",
|
|
1009
|
-
// "An InboundTransfer is processing if it is created and pending. The status changes to succeeded once the funds have
|
|
1010
|
-
// been "confirmed""; in test mode the succeed helper confirms them (docs.stripe.com/api/treasury/inbound_transfers)
|
|
1011
|
-
state: { status: flowCancel('PostTreasuryInboundTransfersInboundTransferCancel', 'inbound_transfer_not_cancelable', 'InboundTransfer', [
|
|
1012
|
-
{ operation: 'PostTestHelpersTreasuryInboundTransfersIdSucceed', from: ['processing'], to: 'succeeded', refusal: { status: 400, code: 'inbound_transfer_not_processing', message: 'This InboundTransfer cannot succeed because it is no longer processing.' }, source: 'https://docs.stripe.com/api/treasury/inbound_transfers' },
|
|
1013
|
-
]) },
|
|
509
|
+
notFound: "No such inbound transfer: '{id}'", ...states["treasury.inbound_transfer"],
|
|
1014
510
|
filters: ['financial_account', 'status'],
|
|
1015
511
|
},
|
|
1016
512
|
// received credits and debits are materialized by the network (test helpers the twin does not serve)
|
|
1017
|
-
'treasury.received_credit': { storedAs: 'received_credit', idPrefix: 'rc', notFound: "No such received credit: '{id}'",
|
|
1018
|
-
'treasury.received_debit': { storedAs: 'received_debit', idPrefix: 'rd', notFound: "No such received debit: '{id}'",
|
|
513
|
+
'treasury.received_credit': { storedAs: 'received_credit', idPrefix: 'rc', notFound: "No such received credit: '{id}'", ...states["treasury.received_credit"], filters: ['financial_account', 'status'] },
|
|
514
|
+
'treasury.received_debit': { storedAs: 'received_debit', idPrefix: 'rd', notFound: "No such received debit: '{id}'", ...states["treasury.received_debit"], filters: ['financial_account', 'status'] },
|
|
1019
515
|
// a ledger transaction is posted or left open by the flow that writes it; the network settles an open one
|
|
1020
516
|
'treasury.transaction': {
|
|
1021
|
-
storedAs: 'treasury_transaction', idPrefix: 'trxn', notFound: "No such treasury transaction: '{id}'",
|
|
1022
|
-
// void: "The Transaction never impacted the balance. For example, a Transaction would enter this state if an
|
|
1023
|
-
// OutboundPayment was initiated but then canceled" (docs.stripe.com/api/treasury/transactions/object); canceling an
|
|
1024
|
-
// outbound flow voids its open transaction (semantics/treasury.ts). (Stripe also posts an open transaction as its
|
|
1025
|
-
// flow settles; the twin's outbound flows stay processing)
|
|
1026
|
-
state: { status: { initial: 'open', transitions: [
|
|
1027
|
-
...['PostTreasuryOutboundPaymentsIdCancel', 'PostTreasuryOutboundTransfersOutboundTransferCancel', 'PostTreasuryInboundTransfersInboundTransferCancel'].map((operation) => ({ operation, from: ['open'], to: 'void', source: 'https://docs.stripe.com/api/treasury/transactions/object' })),
|
|
1028
|
-
// an inbound transfer's transaction posts when it succeeds ("a transaction is created and posted")
|
|
1029
|
-
{ operation: 'PostTestHelpersTreasuryInboundTransfersIdSucceed', from: ['open'], to: 'posted', source: 'https://docs.stripe.com/api/treasury/inbound_transfers' },
|
|
1030
|
-
] } },
|
|
517
|
+
storedAs: 'treasury_transaction', idPrefix: 'trxn', notFound: "No such treasury transaction: '{id}'", ...states["treasury.transaction"],
|
|
1031
518
|
},
|
|
1032
|
-
'treasury.transaction_entry': { storedAs: 'treasury_transaction_entry', idPrefix: 'trxne', notFound: "No such transaction entry: '{id}'",
|
|
519
|
+
'treasury.transaction_entry': { storedAs: 'treasury_transaction_entry', idPrefix: 'trxne', notFound: "No such transaction entry: '{id}'", ...states["treasury.transaction_entry"], },
|
|
1033
520
|
'climate.order': {
|
|
1034
521
|
storedAs: 'climate_order',
|
|
1035
522
|
idPrefix: 'climorder',
|
|
1036
|
-
notFound: "No such order: '{id}'",
|
|
1037
|
-
state: {
|
|
1038
|
-
status: {
|
|
1039
|
-
// an order is created confirmed: the create page's example answers "status": "confirmed" with confirmed_at set
|
|
1040
|
-
// (docs.stripe.com/api/climate/order/create)
|
|
1041
|
-
initial: 'confirmed',
|
|
1042
|
-
transitions: [
|
|
1043
|
-
{ operation: 'PostClimateOrdersOrderCancel', from: ['awaiting_funds', 'confirmed', 'open'], to: 'canceled', refusal: { status: 400, code: 'climate_order_not_cancelable', message: 'This order can no longer be canceled because it is {from}.' }, source: 'https://docs.stripe.com/api/climate/order/cancel' },
|
|
1044
|
-
// funded, confirmed by the supplier, then delivered
|
|
1045
|
-
// (Stripe funds, confirms and delivers an order over months; the twin's orders stay where they are made)
|
|
1046
|
-
],
|
|
1047
|
-
},
|
|
1048
|
-
},
|
|
1049
|
-
notState: ['cancellation_reason'],
|
|
523
|
+
notFound: "No such order: '{id}'", ...states["climate.order"],
|
|
1050
524
|
},
|
|
1051
525
|
'financial_connections.session': { storedAs: 'fc_session', idPrefix: 'fcsess' },
|
|
1052
526
|
'financial_connections.account': {
|
|
1053
527
|
storedAs: 'fc_account',
|
|
1054
528
|
idPrefix: 'fca',
|
|
1055
|
-
notFound: "No such account: '{id}'",
|
|
1056
|
-
state: {
|
|
1057
|
-
status: {
|
|
1058
|
-
initial: 'active',
|
|
1059
|
-
transitions: [
|
|
1060
|
-
{ operation: 'PostFinancialConnectionsAccountsAccountDisconnect', from: '*', to: 'disconnected', source: 'https://docs.stripe.com/api/financial_connections/accounts/disconnect' },
|
|
1061
|
-
// (Stripe marks an account inactive when the bank link breaks, and active again; the twin's links hold)
|
|
1062
|
-
],
|
|
1063
|
-
},
|
|
1064
|
-
},
|
|
1065
|
-
notState: ['category', 'subcategory'],
|
|
529
|
+
notFound: "No such account: '{id}'", ...states["financial_connections.account"],
|
|
1066
530
|
},
|
|
1067
531
|
// a linked account's transactions arrive posted here; the bank settles a pending one
|
|
1068
532
|
'financial_connections.transaction': {
|
|
1069
|
-
storedAs: 'fc_transaction', idPrefix: 'fctxn',
|
|
1070
|
-
// (a bank's pending transaction posts or is voided at Stripe; the twin's arrive posted)
|
|
1071
|
-
state: { status: { initial: 'posted', transitions: [] } },
|
|
533
|
+
storedAs: 'fc_transaction', idPrefix: 'fctxn', ...states["financial_connections.transaction"],
|
|
1072
534
|
},
|
|
1073
535
|
'forwarding.request': { storedAs: 'forwarding_request', idPrefix: 'fwdr', notFound: "No such forwarding request: '{id}'" },
|
|
1074
536
|
// the twin runs a report at once; Stripe runs it in the background
|
|
1075
537
|
'reporting.report_run': {
|
|
1076
|
-
storedAs: 'report_run', idPrefix: 'frr', notFound: "No such report run: '{id}'",
|
|
1077
|
-
// "When first created, the object appears with status="pending""; "When the run completes, Stripe updates the
|
|
1078
|
-
// object, and it has a status of succeeded" (docs.stripe.com/reports/api; semantics/platform.ts finishReportRuns).
|
|
1079
|
-
// (Stripe may also fail a run; the twin's runs succeed)
|
|
1080
|
-
state: { status: { initial: 'pending', transitions: [by('vendor', ['pending'], 'succeeded', 'https://docs.stripe.com/reports/api')] } },
|
|
538
|
+
storedAs: 'report_run', idPrefix: 'frr', notFound: "No such report run: '{id}'", ...states["reporting.report_run"],
|
|
1081
539
|
},
|
|
1082
540
|
// archived (active=false) and restored by an update
|
|
1083
|
-
product: { idPrefix: 'prod', update: 'replace',
|
|
541
|
+
product: { idPrefix: 'prod', update: 'replace', ...states["product"], },
|
|
1084
542
|
product_feature: { idPrefix: 'prodft' },
|
|
1085
543
|
price: {
|
|
1086
544
|
idPrefix: 'price',
|
|
1087
|
-
update: 'replace',
|
|
1088
|
-
// deleting a plan leaves its price for its subscribers, inactive: "Deleting plans means new subscribers can’t be added.
|
|
1089
|
-
// Existing subscribers aren’t affected." (docs.stripe.com/api/plans/delete; semantics/plans.ts)
|
|
1090
|
-
state: { active: { initial: true, transitions: [...flag('PostPricesPrice', 'https://docs.stripe.com/api/prices/update#update_price-active'), { operation: 'DeletePlansPlan', from: ['true'], to: 'false', source: 'https://docs.stripe.com/api/plans/delete' }] } },
|
|
545
|
+
update: 'replace', ...states["price"], embeds: { product: 'product' },
|
|
1091
546
|
},
|
|
1092
547
|
},
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
const version = request.headers.get('stripe-version') ?? undefined;
|
|
1096
|
-
// an Issuing authorization carries its full card in every egress, webhooks included; the write
|
|
1097
|
-
// hook is where the root is known, and the body it embeds into is the one the handler answers
|
|
1098
|
-
if (storedType === 'issuing_authorization') embedIssuingAuthorizationCard(body, root);
|
|
1099
|
-
await afterStripeWrite(storedType, operation, body, root, occurredAt, version && isValidApiVersion(version) ? version : undefined, request.headers.get('stripe-account') ?? undefined);
|
|
1100
|
-
},
|
|
548
|
+
// the webhooks Stripe's writes send (./semantics/shared.ts), each event's data and account rendered by ./semantics/events.ts
|
|
549
|
+
events: { ...STRIPE_EVENTS, render: data, values },
|
|
1101
550
|
};
|
|
1102
|
-
|