@volter/twin-stripe 0.1.2 → 2.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.
Files changed (219) hide show
  1. package/README.md +64 -27
  2. package/client/dashboard-api.ts +286 -0
  3. package/client/stripe-mirror.css +272 -159
  4. package/client/stripe-mirror.tsx +1384 -541
  5. package/dist/client/dashboard-api.d.ts +107 -0
  6. package/dist/client/dashboard-api.js +238 -0
  7. package/dist/client/dashboard-api.ts +286 -0
  8. package/dist/client/stripe-mirror.bundle.js +236 -0
  9. package/dist/client/stripe-mirror.css +275 -0
  10. package/dist/client/stripe-mirror.d.ts +134 -0
  11. package/dist/client/stripe-mirror.js +823 -0
  12. package/dist/client/stripe-mirror.tsx +1534 -0
  13. package/dist/src/cli.d.ts +2 -0
  14. package/dist/src/cli.js +39 -0
  15. package/dist/src/generated/events.gen.json +1 -0
  16. package/dist/src/generated/surface.gen.json +1 -0
  17. package/dist/src/generated/ui.gen.json +1 -0
  18. package/dist/src/index.d.ts +14 -0
  19. package/dist/src/index.js +73 -0
  20. package/dist/src/manifest.d.ts +2 -0
  21. package/dist/src/manifest.js +1065 -0
  22. package/dist/src/screens/checkout.d.ts +31 -0
  23. package/dist/src/screens/checkout.js +241 -0
  24. package/dist/src/screens/consent-skin.d.ts +4 -0
  25. package/dist/src/screens/consent-skin.js +18 -0
  26. package/dist/src/screens/financial-connections.d.ts +5 -0
  27. package/dist/src/screens/financial-connections.js +90 -0
  28. package/dist/src/screens/identity.d.ts +5 -0
  29. package/dist/src/screens/identity.js +86 -0
  30. package/dist/src/screens/industries.d.ts +1 -0
  31. package/dist/src/screens/industries.js +267 -0
  32. package/dist/src/screens/onboarding.d.ts +13 -0
  33. package/dist/src/screens/onboarding.js +225 -0
  34. package/dist/src/screens/portal.d.ts +5 -0
  35. package/dist/src/screens/portal.js +214 -0
  36. package/dist/src/screens/public-details.d.ts +5 -0
  37. package/dist/src/screens/public-details.js +90 -0
  38. package/dist/src/semantics/after-payment.d.ts +22 -0
  39. package/dist/src/semantics/after-payment.js +93 -0
  40. package/dist/src/semantics/apps-secrets.d.ts +2 -0
  41. package/dist/src/semantics/apps-secrets.js +54 -0
  42. package/dist/src/semantics/balance.d.ts +11 -0
  43. package/dist/src/semantics/balance.js +195 -0
  44. package/dist/src/semantics/billing.d.ts +2 -0
  45. package/dist/src/semantics/billing.js +220 -0
  46. package/dist/src/semantics/charges.d.ts +28 -0
  47. package/dist/src/semantics/charges.js +201 -0
  48. package/dist/src/semantics/checkout.d.ts +15 -0
  49. package/dist/src/semantics/checkout.js +303 -0
  50. package/dist/src/semantics/connect.d.ts +5 -0
  51. package/dist/src/semantics/connect.js +476 -0
  52. package/dist/src/semantics/coupons.d.ts +6 -0
  53. package/dist/src/semantics/coupons.js +92 -0
  54. package/dist/src/semantics/credit-notes.d.ts +2 -0
  55. package/dist/src/semantics/credit-notes.js +172 -0
  56. package/dist/src/semantics/customers.d.ts +6 -0
  57. package/dist/src/semantics/customers.js +429 -0
  58. package/dist/src/semantics/disputes.d.ts +2 -0
  59. package/dist/src/semantics/disputes.js +51 -0
  60. package/dist/src/semantics/entitlements.d.ts +2 -0
  61. package/dist/src/semantics/entitlements.js +95 -0
  62. package/dist/src/semantics/ephemeral-keys.d.ts +2 -0
  63. package/dist/src/semantics/ephemeral-keys.js +34 -0
  64. package/dist/src/semantics/files.d.ts +2 -0
  65. package/dist/src/semantics/files.js +125 -0
  66. package/dist/src/semantics/invoices.d.ts +18 -0
  67. package/dist/src/semantics/invoices.js +541 -0
  68. package/dist/src/semantics/issuing.d.ts +13 -0
  69. package/dist/src/semantics/issuing.js +570 -0
  70. package/dist/src/semantics/ledger.d.ts +54 -0
  71. package/dist/src/semantics/ledger.js +181 -0
  72. package/dist/src/semantics/payment-intents.d.ts +18 -0
  73. package/dist/src/semantics/payment-intents.js +404 -0
  74. package/dist/src/semantics/payment-links.d.ts +2 -0
  75. package/dist/src/semantics/payment-links.js +133 -0
  76. package/dist/src/semantics/payment-methods.d.ts +20 -0
  77. package/dist/src/semantics/payment-methods.js +138 -0
  78. package/dist/src/semantics/plans.d.ts +5 -0
  79. package/dist/src/semantics/plans.js +121 -0
  80. package/dist/src/semantics/platform.d.ts +9 -0
  81. package/dist/src/semantics/platform.js +206 -0
  82. package/dist/src/semantics/products.d.ts +2 -0
  83. package/dist/src/semantics/products.js +140 -0
  84. package/dist/src/semantics/radar.d.ts +2 -0
  85. package/dist/src/semantics/radar.js +83 -0
  86. package/dist/src/semantics/refunds.d.ts +9 -0
  87. package/dist/src/semantics/refunds.js +195 -0
  88. package/dist/src/semantics/renewals.d.ts +47 -0
  89. package/dist/src/semantics/renewals.js +251 -0
  90. package/dist/src/semantics/setup-intents.d.ts +2 -0
  91. package/dist/src/semantics/setup-intents.js +84 -0
  92. package/dist/src/semantics/shared.d.ts +78 -0
  93. package/dist/src/semantics/shared.js +192 -0
  94. package/dist/src/semantics/subscription-schedules.d.ts +2 -0
  95. package/dist/src/semantics/subscription-schedules.js +119 -0
  96. package/dist/src/semantics/subscriptions.d.ts +11 -0
  97. package/dist/src/semantics/subscriptions.js +605 -0
  98. package/dist/src/semantics/tax.d.ts +2 -0
  99. package/dist/src/semantics/tax.js +197 -0
  100. package/dist/src/semantics/terminal.d.ts +5 -0
  101. package/dist/src/semantics/terminal.js +182 -0
  102. package/dist/src/semantics/test-clocks.d.ts +6 -0
  103. package/dist/src/semantics/test-clocks.js +73 -0
  104. package/dist/src/semantics/tokens.d.ts +4 -0
  105. package/dist/src/semantics/tokens.js +44 -0
  106. package/dist/src/semantics/transfers.d.ts +2 -0
  107. package/dist/src/semantics/transfers.js +154 -0
  108. package/dist/src/semantics/treasury.d.ts +2 -0
  109. package/dist/src/semantics/treasury.js +377 -0
  110. package/dist/src/semantics/webhook-endpoints.d.ts +3 -0
  111. package/dist/src/semantics/webhook-endpoints.js +85 -0
  112. package/dist/src/stripe-budget.d.ts +55 -0
  113. package/dist/src/stripe-budget.js +155 -0
  114. package/dist/src/stripe-capabilities.d.ts +3 -0
  115. package/dist/src/stripe-capabilities.js +5052 -0
  116. package/dist/src/stripe-conformance.d.ts +41 -0
  117. package/dist/src/stripe-conformance.js +96 -0
  118. package/dist/src/stripe-connector.d.ts +161 -0
  119. package/dist/src/stripe-connector.js +414 -0
  120. package/dist/src/stripe-emit.d.ts +2 -0
  121. package/dist/src/stripe-emit.js +145 -0
  122. package/dist/src/stripe-events.d.ts +93 -0
  123. package/dist/src/stripe-events.js +388 -0
  124. package/dist/src/stripe-js.d.ts +4 -0
  125. package/dist/src/stripe-js.js +70 -0
  126. package/dist/src/stripe-mirror-ui.d.ts +15 -0
  127. package/dist/src/stripe-mirror-ui.js +87 -0
  128. package/dist/src/stripe-params.d.ts +3 -0
  129. package/dist/src/stripe-params.js +43 -0
  130. package/dist/src/stripe-perform-harness.d.ts +9 -0
  131. package/dist/src/stripe-perform-harness.js +26 -0
  132. package/dist/src/stripe-server.d.ts +33 -0
  133. package/dist/src/stripe-server.js +326 -0
  134. package/dist/src/stripe-shared.d.ts +106 -0
  135. package/dist/src/stripe-shared.js +273 -0
  136. package/dist/src/stripe-twin.d.ts +155 -0
  137. package/dist/src/stripe-twin.js +1226 -0
  138. package/dist/src/stripe-ui-conformance.d.ts +5 -0
  139. package/dist/src/stripe-ui-conformance.js +79 -0
  140. package/dist/src/stripe-ui-structure.d.ts +3 -0
  141. package/dist/src/stripe-ui-structure.js +168 -0
  142. package/dist/src/stripe-version.d.ts +10 -0
  143. package/dist/src/stripe-version.js +285 -0
  144. package/dist/test-fixtures/stripe-known-deviations.json +105 -0
  145. package/dist/test-fixtures/stripe-openapi-operations.SOURCE.md +14 -0
  146. package/dist/test-fixtures/stripe-openapi-operations.json +4717 -0
  147. package/dist/test-fixtures/stripe-schemas.SOURCE.md +35 -0
  148. package/dist/test-fixtures/stripe-schemas.json +3740 -0
  149. package/package.json +18 -10
  150. package/src/cli.ts +7 -7
  151. package/src/generated/events.gen.json +1 -0
  152. package/src/generated/surface.gen.json +1 -0
  153. package/src/generated/ui.gen.json +1 -0
  154. package/src/index.ts +31 -9
  155. package/src/manifest.ts +1097 -0
  156. package/src/screens/checkout.tsx +252 -0
  157. package/src/screens/consent-skin.ts +20 -0
  158. package/src/screens/financial-connections.tsx +101 -0
  159. package/src/screens/identity.tsx +96 -0
  160. package/src/screens/industries.ts +267 -0
  161. package/src/screens/onboarding.tsx +243 -0
  162. package/src/screens/portal.tsx +218 -0
  163. package/src/screens/public-details.tsx +105 -0
  164. package/src/semantics/after-payment.ts +113 -0
  165. package/src/semantics/apps-secrets.ts +58 -0
  166. package/src/semantics/balance.ts +209 -0
  167. package/src/semantics/billing.ts +216 -0
  168. package/src/semantics/charges.ts +211 -0
  169. package/src/semantics/checkout.ts +297 -0
  170. package/src/semantics/connect.ts +471 -0
  171. package/src/semantics/coupons.ts +97 -0
  172. package/src/semantics/credit-notes.ts +168 -0
  173. package/src/semantics/customers.ts +432 -0
  174. package/src/semantics/disputes.ts +62 -0
  175. package/src/semantics/entitlements.ts +94 -0
  176. package/src/semantics/ephemeral-keys.ts +34 -0
  177. package/src/semantics/files.ts +143 -0
  178. package/src/semantics/invoices.ts +541 -0
  179. package/src/semantics/issuing.ts +585 -0
  180. package/src/semantics/ledger.ts +216 -0
  181. package/src/semantics/payment-intents.ts +420 -0
  182. package/src/semantics/payment-links.ts +148 -0
  183. package/src/semantics/payment-methods.ts +143 -0
  184. package/src/semantics/plans.ts +131 -0
  185. package/src/semantics/platform.ts +220 -0
  186. package/src/semantics/products.ts +154 -0
  187. package/src/semantics/radar.ts +85 -0
  188. package/src/semantics/refunds.ts +218 -0
  189. package/src/semantics/renewals.ts +274 -0
  190. package/src/semantics/setup-intents.ts +87 -0
  191. package/src/semantics/shared.ts +215 -0
  192. package/src/semantics/subscription-schedules.ts +129 -0
  193. package/src/semantics/subscriptions.ts +610 -0
  194. package/src/semantics/tax.ts +220 -0
  195. package/src/semantics/terminal.ts +195 -0
  196. package/src/semantics/test-clocks.ts +77 -0
  197. package/src/semantics/tokens.ts +52 -0
  198. package/src/semantics/transfers.ts +174 -0
  199. package/src/semantics/treasury.ts +383 -0
  200. package/src/semantics/webhook-endpoints.ts +87 -0
  201. package/src/stripe-budget.ts +4 -4
  202. package/src/stripe-capabilities.ts +1456 -222
  203. package/src/stripe-conformance.ts +6 -5
  204. package/src/stripe-connector.ts +68 -40
  205. package/src/stripe-emit.ts +14 -7
  206. package/src/stripe-events.ts +94 -36
  207. package/src/stripe-js.ts +70 -0
  208. package/src/stripe-mirror-ui.ts +28 -298
  209. package/src/stripe-params.ts +44 -0
  210. package/src/stripe-perform-harness.ts +29 -0
  211. package/src/stripe-server.ts +263 -38
  212. package/src/stripe-shared.ts +294 -0
  213. package/src/stripe-twin.ts +429 -5325
  214. package/src/stripe-ui-conformance.ts +70 -107
  215. package/src/stripe-ui-structure.ts +124 -348
  216. package/src/stripe-version.ts +278 -0
  217. package/test-fixtures/stripe-known-deviations.json +2 -7
  218. package/test-fixtures/stripe-openapi-operations.json +1188 -2855
  219. package/src/stripe-form.ts +0 -35
@@ -0,0 +1,105 @@
1
+ {
2
+ "_doc": "Declared scope for the Stripe twin: published fields it does NOT emit, each with a reason. The spec-conformance gate (stripe-conformance.ts) treats a missing-required field as a BUG unless it is declared here. Applies across the Stripe objects the twin serves. Stripe is the twin we cannot dual-run live, so the published OpenAPI is the authority \u2014 keeping this list short and reasoned is how we stay honest about the gaps.",
3
+ "deviations": [
4
+ {
5
+ "path": "type",
6
+ "kind": "missing-required",
7
+ "reason": "Stripe's price.type (one_time|recurring) collides with the kernel's resource-type discriminator (every twin resource carries an internal `type`, which view() strips before emit). So a vendor `type` field cannot currently be emitted. Known limitation \u2014 a candidate for moving the kernel discriminator to a reserved key. Only `price` declares a required `type`; other served objects do not."
8
+ },
9
+ {
10
+ "path": "_price.type-list-filter",
11
+ "kind": "list-filter-approximated",
12
+ "reason": "GET /v1/prices?type=one_time|recurring cannot filter on the (stripped) price.type field for the same reason price.type is a declared missing-required deviation above. It is approximated by the presence of the vendor `recurring` object \u2014 recurring prices carry it, one-time prices do not \u2014 which is faithful for prices the twin itself created. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
13
+ },
14
+ {
15
+ "path": "_invoice.subscription-list-filter",
16
+ "kind": "list-filter-unmodeled",
17
+ "reason": "GET /v1/invoices accepts a `subscription` filter param (Stripe documents it) but the twin does not auto-link invoices to subscriptions: invoices are created as standalone drafts, and modern Stripe nests the link under parent.subscription_details.subscription rather than a top-level field (the vendor schema has no top-level invoice.subscription). The filter therefore only matches when a caller has explicitly stored a `subscription` field on the invoice; otherwise it yields no matches. The param is accepted, not rejected \u2014 consistent with Stripe ignoring filters that match nothing. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
18
+ },
19
+ {
20
+ "path": "_dispute.not-auto-created",
21
+ "kind": "resource-modeled-statefully",
22
+ "reason": "Disputes are modeled statefully via the action log (create/list/retrieve/update/close), NOT auto-raised from charges: the twin does not simulate an acquirer/cardholder raising a chargeback, so no dispute appears merely because a charge exists. A caller (or seeding) creates one referencing a charge via POST /v1/disputes. All 15 vendor-required dispute fields ARE emitted (amount, balance_transactions, charge, created, currency, enhanced_eligibility_types, evidence, evidence_details, is_charge_refundable, livemode, metadata, reason, status, plus id/object); `amount`/`charge` come from the caller (Stripe disputes always reference a charge). Closing is terminal (status -> lost), matching Stripe. evidence/evidence_details emit Stripe's canonical empty shapes (all-null evidence bag), not fabricated content. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
23
+ },
24
+ {
25
+ "path": "_payout.created-not-settled",
26
+ "kind": "resource-modeled-statefully",
27
+ "reason": "Payouts are modeled statefully via the action log (create/list/retrieve/cancel). The twin does not simulate the bank-settlement timeline: a created payout starts `status=pending` and only transitions on an explicit POST /v1/payouts/:id/cancel (-> canceled); it does not auto-advance to in_transit/paid. arrival_date is stamped at creation time rather than a real future settlement date. All vendor-required payout fields are emitted; `amount`/`currency` come from the caller and are validated (positive integer + currency) like charges. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
28
+ },
29
+ {
30
+ "path": "_balance.synthesized-from-ledger",
31
+ "kind": "resource-synthesized",
32
+ "reason": "GET /v1/balance is synthesized from the balance_transaction ledger, not stored: settled transactions (status=available) fold into the `available` array and unsettled ones (status=pending) into `pending`, summed by currency over each transaction's `net` (amount minus fee). This mirrors Stripe's available/pending arrays per currency. The per-currency source_types breakdown is approximated as all-`card`. With no ledger the balance is a valid zero (one usd entry). Leading underscore marks this as a twin-internal note (not a vendor schema path)."
33
+ },
34
+ {
35
+ "path": "_balance_transaction.writable-for-seeding",
36
+ "kind": "resource-modeled-statefully",
37
+ "reason": "In real Stripe, balance_transactions are created only as side-effects of money movement (charges, refunds, payouts) and have no create endpoint. The twin exposes POST /v1/balance_transactions so the ledger can be seeded statefully, since the twin does not auto-generate a balance_transaction for every charge/refund/payout. `net` defaults to amount - fee. All vendor-required fields are emitted with faithful enum values (type/status/balance_type/reporting_category). Leading underscore marks this as a twin-internal note (not a vendor schema path)."
38
+ },
39
+ {
40
+ "path": "_card.declines-test-set-only",
41
+ "kind": "behavior-modeled-subset",
42
+ "reason": "Charge/PaymentIntent-confirm card declines are modeled for Stripe's DOCUMENTED TEST CARDS only (PAN 4242\u20264242 + pm_card_visa/tok_visa succeed; 4000\u20260002 generic_decline, 4000\u20269995 insufficient_funds, 4000\u20260069 expired_card, 4000\u20260127 incorrect_cvc, 4000\u20260119 processing_error, plus the matching pm_card_*/tok_* tokens). A known declining card returns the real Stripe card-error envelope (HTTP 402, error.type=card_error, code, decline_code for card_declined, message, param=card, and the charge/payment_intent id) records the attempt as a failed charge (failure_code, failure_message, outcome) that the error names and a confirmed PaymentIntent's latest_charge points at, leaving the intent at status=requires_payment_method with last_payment_error (carrying the declined card) set and no payment_method. ANY card the twin does not recognize (real PANs, unknown test tokens, or no card at all) succeeds, deterministically \u2014 the twin is not a risk/fraud engine and does not simulate issuer behavior beyond Stripe's published test set. Resolution reads card[number]/source[number] (raw PAN) or payment_method/source/card (token id). Leading underscore marks this as a twin-internal note (not a vendor schema path)."
43
+ },
44
+ {
45
+ "path": "_idempotency.stored-per-root",
46
+ "kind": "behavior-modeled-statefully",
47
+ "reason": "The Idempotency-Key request header is honored on POST: the first request with a key executes and its (status + body) response is persisted in the action log as an internal `_idempotency` resource; a replay with the SAME key returns the byte-identical stored response without re-applying the write (verified: two POSTs \u2192 one resource). Simplifications vs real Stripe: the stored response is keyed per twin-root (a fork has its own keyspace) rather than per Stripe account+key; there is no 24h expiry; and the twin does not detect a request-payload mismatch for a reused key (real Stripe 400s when the same key is reused with different params). Every executed POST is stored, including card-decline 402s (Stripe also persists those). `_idempotency` is twin-internal and never served as a Stripe object, so it is exempt from spec conformance. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
48
+ },
49
+ {
50
+ "path": "_event.modeled-shape",
51
+ "kind": "resource-modeled-statefully",
52
+ "reason": "The Events API (GET /v1/events, GET /v1/events/:id) is modeled statefully via the action log. The twin separately emits live webhook events on writes (stripe-events.ts); the Events API here serves explicitly-recorded event objects with the faithful vendor shape (type, api_version, created, data.object, livemode, pending_webhooks). pending_webhooks defaults to 0 because the twin delivers webhooks synchronously. data.object defaults to an empty object when the caller does not supply a snapshot. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
53
+ },
54
+ {
55
+ "path": "_checkout.completion-modeled",
56
+ "kind": "behavior-modeled-statefully",
57
+ "reason": "Real Stripe completes a Checkout Session when the customer pays on the hosted page (there is no public REST verb to complete a session). The twin serves that page at the session's url (/c/pay/:id, src/screens/checkout.tsx): paying there (only while `open`) completes the session and creates+links a real twin object: a succeeded payment_intent (mode=payment, amount = amount_total) with payment_status\u2192paid, an active subscription (mode=subscription, when a customer is present) with payment_status\u2192paid, or a succeeded setup_intent (mode=setup). POST :id/expire transitions open\u2192expired (terminal). amount_subtotal/amount_total are computed by summing resolved line_items (an existing Price's unit_amount, or inline price_data.unit_amount, \u00d7 quantity). Leading underscore marks this as a twin-internal note (not a vendor schema path)."
58
+ },
59
+ {
60
+ "path": "_tax.calculation-list-endpoint",
61
+ "kind": "endpoint-added-for-mirror",
62
+ "reason": "Real Stripe has NO list endpoint for tax calculations (POST creates a calculation, GET :id retrieves it, GET :id/line_items lists its items). The twin adds GET /v1/tax/calculations as a faithful-shaped list envelope (object:'list', data[]) purely so the dashboard mirror's Tax > Calculations section can render the calculations stored in twin state. Create/retrieve/line_items match Stripe exactly; the list is a twin convenience. The twin also models a DEFAULT 10% exclusive tax rate for calculations (real Stripe derives the rate from the customer's jurisdiction + registrations) so the returned amount_total/tax_amount_exclusive are deterministic and assertable. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
63
+ },
64
+ {
65
+ "path": "_tax_id.flat-list-endpoint",
66
+ "kind": "list-endpoint-added",
67
+ "reason": "Real Stripe scopes tax IDs UNDER a customer (POST/GET /v1/customers/:id/tax_ids). The twin also exposes a flat GET /v1/tax_ids list (filterable by customer) so the dashboard mirror can render a Customer Tax IDs section; the canonical per-customer create/retrieve/list/delete are the faithful surface and all enforce 404 on a missing customer/tax_id. Deleted tax IDs (DELETE returns the deleted-object stub) are excluded from both lists. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
68
+ },
69
+ {
70
+ "path": "_customer_balance_transaction.flat-list-endpoint",
71
+ "kind": "list-endpoint-added",
72
+ "reason": "Real Stripe scopes customer balance transactions UNDER a customer (POST/GET /v1/customers/:id/balance_transactions). The twin also exposes a flat GET /v1/customer_balance_transactions list so the mirror can render a Customer Balance section. ending_balance is the running balance after each txn (a negative amount is a credit), computed from the prior ledger, and the owning customer.balance is kept in sync. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
73
+ },
74
+ {
75
+ "path": "_credit_note.single-amount-type",
76
+ "kind": "field-simplified",
77
+ "reason": "CreditNotes are modeled in the amount form (the credited cents) referencing a finalized invoice (POST /v1/credit_notes requires invoice (must exist) plus a positive amount); preview (GET /v1/credit_notes/preview), retrieve, /lines, void (terminal: status void) and list all round-trip. Stripe additionally supports per-invoice-line credits and a mixed type; the twin emits a single custom_line_item and picks pre_payment (unpaid invoice) or post_payment (paid invoice) for the vendor type. All 22 vendor-required credit_note fields are emitted. The vendor type field collides with the kernel discriminator and is stashed under the reserved _stripe_type key (restored by view()), like payout/account. Leading underscore marks this as a twin-internal note (not a vendor schema path)."
78
+ },
79
+ {
80
+ "path": "current_period_start",
81
+ "kind": "extra",
82
+ "reason": "Real Stripe moved current_period_start off the top-level Subscription object onto subscription ITEMS in the 2025-03-31.basil API version. The vendored stripe-schemas.json fixture is fetched from stripe/openapi@master (always the LATEST published shape), so its subscription schema reflects the post-migration object and has no current_period_start property — hence this shows as a fabricated 'extra' field under the harness's single-snapshot schema. But this twin's own DEFAULT served version when a caller sends no Stripe-Version header is TWIN_API_VERSION ('2024-06-20', see its definition in stripe-twin.ts), which pre-dates that migration; on that version real Stripe DOES emit current_period_start top-level, so emitting it here is faithful to what this twin actually serves by default. Prior to this fix the twin never set this field at all (a real fidelity gap: real Stripe on ANY version always populates a billing period on a subscription). It is now computed (== the create-time billing_cycle_anchor, or trial_start during a trial — see the POST /v1/subscriptions handler and POST /v1/checkout/sessions/:id completion handler). A future improvement would branch by req.apiVersion and additionally/only emit it at the item level for callers explicitly on 2025-03-31.basil+, but the twin does not currently branch response SHAPE by apiVersion anywhere (only the recorded api_version metadata on events does), so that is left as a known follow-up rather than implemented speculatively here."
83
+ },
84
+ {
85
+ "path": "current_period_end",
86
+ "kind": "extra",
87
+ "reason": "Same deviation and reasoning as current_period_start immediately above — also computed by the same two create paths as current_period_start + one billing interval (day/week/month/year × interval_count) taken from the subscription's first item's Price.recurring, defaulting to month/1 when no recurring price is resolvable (e.g. an inline price_data item, or — real Stripe would itself reject this — no item at all)."
88
+ },
89
+ {
90
+ "path": "payment_intent",
91
+ "kind": "extra",
92
+ "reason": "Real Stripe removed the top-level payment_intent field from Invoice (replaced by the `payments` list + `confirmation_secret`) as part of the multiple-payment-attempts migration on newer API versions. The vendored stripe-schemas.json fixture is fetched from stripe/openapi@master (always the LATEST published shape), so its invoice schema reflects the post-migration object and has no payment_intent property — hence this shows as a fabricated 'extra' field under the harness's single-snapshot schema, same mechanism as current_period_start/_end above. But this twin's own DEFAULT served version when a caller sends no Stripe-Version header is TWIN_API_VERSION ('2024-06-20', see its definition in stripe-twin.ts), which pre-dates that migration; on that version real Stripe DOES emit invoice.payment_intent top-level, so emitting it here is faithful to what this twin actually serves by default. Prior to this fix the field existed in the EXPANDABLE map (expand[]=payment_intent was already wired) but the invoice action handler (POST /v1/invoices/:id/{finalize,pay,send}) never created a PaymentIntent or set it — every expand came back with nothing (PEAK-3102). It is now minted the moment a charge_automatically invoice with a positive balance is finalized (or auto-finalized via send), null for send_invoice / $0 invoices, and set to null explicitly at draft creation so the field round-trips before finalize too."
93
+ },
94
+ {
95
+ "path": "invoice",
96
+ "kind": "extra",
97
+ "reason": "Same pre-2025 API-version story as the payment_intent deviation immediately above, on the OTHER two objects of that same reverse link: real Stripe also removed the top-level invoice field from BOTH PaymentIntent and Charge in the same multiple-payment-attempts migration (a payment's invoice is reached via Invoice.payments now, not a back-reference on the payment side), so stripe-schemas.json (LATEST published shape) has no invoice property on payment_intent or charge — 'extra' under the harness's single-snapshot schema. On this twin's default-served TWIN_API_VERSION ('2024-06-20', pre-migration) real Stripe DOES emit both. The twin's own EXPANDABLE map already declared payment_intent.invoice and charge.invoice as expandable before this fix (used by the subscription default_incomplete first-invoice PaymentIntent); this fix (PEAK-3102) is the first path that also sets charge.invoice, when POST /v1/invoices/:id/pay settles the invoice's PaymentIntent and mints a Charge referencing it."
98
+ },
99
+ {
100
+ "path": "price",
101
+ "kind": "extra",
102
+ "reason": "PEAK-3102 round 2: POST /v1/invoiceitems now stores the caller-supplied `price` id on the invoiceitem (needed to resolve amount = unit_amount * quantity for PeakHealth's catalog-product order path). Real Stripe replaced the top-level InvoiceItem.price field with a `pricing.price_details` object in a later API-version migration — stripe-schemas.json (LATEST published shape) reflects the post-migration object and has no price property, hence 'extra' under the harness's single-snapshot schema, same mechanism as current_period_start/_end and payment_intent above. This twin's default-served TWIN_API_VERSION ('2024-06-20') pre-dates that migration, where real Stripe DOES emit invoiceitem.price top-level, so emitting it here is faithful to what this twin actually serves by default."
103
+ }
104
+ ]
105
+ }
@@ -0,0 +1,14 @@
1
+ # stripe-openapi-operations.json — provenance
2
+
3
+ The operation-inventory denominator for `../stripe-spec-census.json`: a scope-filtered subset of
4
+ the vendor's published spec, enumerated by `deriveFromOpenAPI` (`packages/world-tooling/src/derive.ts`).
5
+
6
+ - **Upstream:** https://github.com/stripe/openapi — `openapi/spec3.json`.
7
+ - **How it was built:** `bun scripts/spec-census-bootstrap.ts --vendor stripe --from-file <openapi/spec3.json> --scope-paths /v1/account,/v1/account_links,/v1/account_sessions,/v1/accounts,/v1/application_fees,/v1/balance,/v1/balance_transactions,/v1/billing,/v1/billing_portal,/v1/charges,/v1/checkout,/v1/climate,/v1/coupons,/v1/credit_notes,/v1/crypto,/v1/customer_balance_transactions,/v1/customers,/v1/disputes,/v1/entitlements,/v1/ephemeral_keys,/v1/events,/v1/file_links,/v1/files,/v1/financial_connections,/v1/forwarding,/v1/identity,/v1/invoiceitems,/v1/invoices,/v1/mandates,/v1/payment_intents,/v1/payment_links,/v1/payment_methods,/v1/payouts,/v1/prices,/v1/products,/v1/promotion_codes,/v1/quotes,/v1/radar,/v1/refunds,/v1/reporting,/v1/reviews,/v1/setup_intents,/v1/sources,/v1/subscription_items,/v1/subscription_schedules,/v1/subscriptions,/v1/tax,/v1/tax_ids,/v1/tax_rates,/v1/test_helpers,/v1/tokens,/v1/topups,/v1/transfers,/v1/treasury,/v1/webhook_endpoints --apply`
8
+ over a copy of the upstream file fetched 2026-09-01; operation metadata only (operationId, summary, tags), schemas and response codes dropped. The gate never fetches — refreshing the fixture is
9
+ `bun scripts/spec-refresh.ts --vendor stripe --from-file <newer spec> --apply` over a newly fetched copy.
10
+ - **Scope (475 of 594 upstream operations):** every operation whose path starts with one of
11
+ `/v1/account`, `/v1/account_links`, `/v1/account_sessions`, `/v1/accounts`, `/v1/application_fees`, `/v1/balance`, `/v1/balance_transactions`, `/v1/billing`, `/v1/billing_portal`, `/v1/charges`, `/v1/checkout`, `/v1/climate`, `/v1/coupons`, `/v1/credit_notes`, `/v1/crypto`, `/v1/customer_balance_transactions`, `/v1/customers`, `/v1/disputes`, `/v1/entitlements`, `/v1/ephemeral_keys`, `/v1/events`, `/v1/file_links`, `/v1/files`, `/v1/financial_connections`, `/v1/forwarding`, `/v1/identity`, `/v1/invoiceitems`, `/v1/invoices`, `/v1/mandates`, `/v1/payment_intents`, `/v1/payment_links`, `/v1/payment_methods`, `/v1/payouts`, `/v1/prices`, `/v1/products`, `/v1/promotion_codes`, `/v1/quotes`, `/v1/radar`, `/v1/refunds`, `/v1/reporting`, `/v1/reviews`, `/v1/setup_intents`, `/v1/sources`, `/v1/subscription_items`, `/v1/subscription_schedules`, `/v1/subscriptions`, `/v1/tax`, `/v1/tax_ids`, `/v1/tax_rates`, `/v1/test_helpers`, `/v1/tokens`, `/v1/topups`, `/v1/transfers`, `/v1/treasury`, `/v1/webhook_endpoints`.
12
+ - **Mapping:** 418 operations mapped to capability ids by segment match at birth and reviewed by
13
+ hand; 57 left `unmapped` (the ratchet baseline). Every later ruling (a `$ruled` marker, a
14
+ remap) is an edit to the census, never to this fixture.