@fantastic.dev/better-stripe 0.20.0 → 0.21.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 (62) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +28 -1
  3. package/dist/client/connect/payoutReceipt.d.ts +53 -0
  4. package/dist/client/connect/payoutReceipt.d.ts.map +1 -0
  5. package/dist/client/connect/payoutReceipt.js +185 -0
  6. package/dist/client/connect/payoutReceipt.js.map +1 -0
  7. package/dist/client/connect/payoutReconciliation.d.ts +38 -0
  8. package/dist/client/connect/payoutReconciliation.d.ts.map +1 -0
  9. package/dist/client/connect/payoutReconciliation.js +110 -0
  10. package/dist/client/connect/payoutReconciliation.js.map +1 -0
  11. package/dist/client/payoutPolicy.d.ts +6 -0
  12. package/dist/client/payoutPolicy.d.ts.map +1 -1
  13. package/dist/client/payoutPolicy.js +8 -0
  14. package/dist/client/payoutPolicy.js.map +1 -1
  15. package/dist/component/_generated/component.d.ts +39 -0
  16. package/dist/component/_generated/component.d.ts.map +1 -1
  17. package/dist/component/earnings/triggers.d.ts +50 -2
  18. package/dist/component/earnings/triggers.d.ts.map +1 -1
  19. package/dist/component/payoutRelease/allocation.d.ts +1 -0
  20. package/dist/component/payoutRelease/allocation.d.ts.map +1 -1
  21. package/dist/component/payoutRelease/allocation.js +3 -0
  22. package/dist/component/payoutRelease/allocation.js.map +1 -1
  23. package/dist/component/payoutRelease/fees.d.ts +22 -0
  24. package/dist/component/payoutRelease/fees.d.ts.map +1 -0
  25. package/dist/component/payoutRelease/fees.js +73 -0
  26. package/dist/component/payoutRelease/fees.js.map +1 -0
  27. package/dist/component/payoutRelease/helpers.d.ts +4 -0
  28. package/dist/component/payoutRelease/helpers.d.ts.map +1 -1
  29. package/dist/component/payoutRelease/mutations.d.ts +23 -0
  30. package/dist/component/payoutRelease/mutations.d.ts.map +1 -1
  31. package/dist/component/payoutRelease/mutations.js +17 -0
  32. package/dist/component/payoutRelease/mutations.js.map +1 -1
  33. package/dist/component/payoutRelease/queries.d.ts +16 -0
  34. package/dist/component/payoutRelease/queries.d.ts.map +1 -1
  35. package/dist/component/payoutRelease/queries.js +10 -0
  36. package/dist/component/payoutRelease/queries.js.map +1 -1
  37. package/dist/component/payoutRelease/schema.d.ts +38 -2
  38. package/dist/component/payoutRelease/schema.d.ts.map +1 -1
  39. package/dist/component/payoutRelease/schema.js +11 -0
  40. package/dist/component/payoutRelease/schema.js.map +1 -1
  41. package/dist/component/schema.d.ts +25 -1
  42. package/dist/component/schema.js +2 -1
  43. package/dist/component/schema.js.map +1 -1
  44. package/docs/accounts-v2-preview.md +39 -1
  45. package/docs/react-workflows.md +31 -0
  46. package/docs/settlement.md +74 -3
  47. package/package.json +1 -1
  48. package/src/client/connect/payoutAllocation.test.ts +36 -3
  49. package/src/client/connect/payoutReceipt.test.ts +312 -0
  50. package/src/client/connect/payoutReceipt.ts +287 -0
  51. package/src/client/connect/payoutReconciliation.test.ts +385 -0
  52. package/src/client/connect/payoutReconciliation.ts +174 -0
  53. package/src/client/payoutPolicy.ts +16 -0
  54. package/src/component/_generated/api.ts +2 -0
  55. package/src/component/_generated/component.ts +38 -0
  56. package/src/component/payout-fees.test.ts +224 -0
  57. package/src/component/payoutRelease/allocation.ts +6 -0
  58. package/src/component/payoutRelease/fees.ts +93 -0
  59. package/src/component/payoutRelease/mutations.ts +17 -0
  60. package/src/component/payoutRelease/queries.ts +11 -0
  61. package/src/component/payoutRelease/schema.ts +12 -0
  62. package/src/component/schema.ts +2 -0
@@ -73,6 +73,10 @@ export declare const claimFields: {
73
73
  attemptedAt: import("convex/values").VFloat64<number | undefined, "optional">;
74
74
  stripePayoutId: import("convex/values").VString<string | undefined, "optional">;
75
75
  returnTransactionId: import("convex/values").VString<string | undefined, "optional">;
76
+ feeRevision: import("convex/values").VFloat64<number | undefined, "optional">;
77
+ debitTransactionId: import("convex/values").VString<string | undefined, "optional">;
78
+ debitFee: import("convex/values").VFloat64<number | undefined, "optional">;
79
+ providerFee: import("convex/values").VFloat64<number | undefined, "optional">;
76
80
  rejection: import("convex/values").VObject<{
77
81
  code: "amount_too_small" | "balance_insufficient";
78
82
  requestId: string;
@@ -93,7 +97,10 @@ export declare const claimDoc: import("convex/values").VObject<{
93
97
  amount: number;
94
98
  attemptedAt?: number | undefined;
95
99
  currency: string;
100
+ debitFee?: number | undefined;
101
+ debitTransactionId?: string | undefined;
96
102
  expectedRevision: number;
103
+ feeRevision?: number | undefined;
97
104
  observations: {
98
105
  currency: string;
99
106
  ledgerFingerprint: string;
@@ -105,6 +112,7 @@ export declare const claimDoc: import("convex/values").VObject<{
105
112
  }[];
106
113
  operationKey: string;
107
114
  ownerKey: string;
115
+ providerFee?: number | undefined;
108
116
  rejection?: {
109
117
  code: "amount_too_small" | "balance_insufficient";
110
118
  requestId: string;
@@ -161,6 +169,10 @@ export declare const claimDoc: import("convex/values").VObject<{
161
169
  attemptedAt: import("convex/values").VFloat64<number | undefined, "optional">;
162
170
  stripePayoutId: import("convex/values").VString<string | undefined, "optional">;
163
171
  returnTransactionId: import("convex/values").VString<string | undefined, "optional">;
172
+ feeRevision: import("convex/values").VFloat64<number | undefined, "optional">;
173
+ debitTransactionId: import("convex/values").VString<string | undefined, "optional">;
174
+ debitFee: import("convex/values").VFloat64<number | undefined, "optional">;
175
+ providerFee: import("convex/values").VFloat64<number | undefined, "optional">;
164
176
  rejection: import("convex/values").VObject<{
165
177
  code: "amount_too_small" | "balance_insufficient";
166
178
  requestId: string;
@@ -170,7 +182,7 @@ export declare const claimDoc: import("convex/values").VObject<{
170
182
  }, "optional", "code" | "requestId">;
171
183
  _id: import("convex/values").VId<import("convex/values").GenericId<"payoutReleaseClaims">, "required">;
172
184
  _creationTime: import("convex/values").VFloat64<number, "required">;
173
- }, "required", "_creationTime" | "_id" | "accountId" | "allocations" | "amount" | "attemptedAt" | "currency" | "expectedRevision" | "observations" | "operationKey" | "ownerKey" | "rejection" | "rejection.code" | "rejection.requestId" | "returnTransactionId" | "status" | "stripePayoutId">;
185
+ }, "required", "_creationTime" | "_id" | "accountId" | "allocations" | "amount" | "attemptedAt" | "currency" | "debitFee" | "debitTransactionId" | "expectedRevision" | "feeRevision" | "observations" | "operationKey" | "ownerKey" | "providerFee" | "rejection" | "rejection.code" | "rejection.requestId" | "returnTransactionId" | "status" | "stripePayoutId">;
174
186
  export declare const claimsTable: import("convex/server").TableDefinition<import("convex/values").VObject<{
175
187
  accountId: string;
176
188
  allocations: {
@@ -181,7 +193,10 @@ export declare const claimsTable: import("convex/server").TableDefinition<import
181
193
  amount: number;
182
194
  attemptedAt?: number | undefined;
183
195
  currency: string;
196
+ debitFee?: number | undefined;
197
+ debitTransactionId?: string | undefined;
184
198
  expectedRevision: number;
199
+ feeRevision?: number | undefined;
185
200
  observations: {
186
201
  currency: string;
187
202
  ledgerFingerprint: string;
@@ -193,6 +208,7 @@ export declare const claimsTable: import("convex/server").TableDefinition<import
193
208
  }[];
194
209
  operationKey: string;
195
210
  ownerKey: string;
211
+ providerFee?: number | undefined;
196
212
  rejection?: {
197
213
  code: "amount_too_small" | "balance_insufficient";
198
214
  requestId: string;
@@ -249,6 +265,10 @@ export declare const claimsTable: import("convex/server").TableDefinition<import
249
265
  attemptedAt: import("convex/values").VFloat64<number | undefined, "optional">;
250
266
  stripePayoutId: import("convex/values").VString<string | undefined, "optional">;
251
267
  returnTransactionId: import("convex/values").VString<string | undefined, "optional">;
268
+ feeRevision: import("convex/values").VFloat64<number | undefined, "optional">;
269
+ debitTransactionId: import("convex/values").VString<string | undefined, "optional">;
270
+ debitFee: import("convex/values").VFloat64<number | undefined, "optional">;
271
+ providerFee: import("convex/values").VFloat64<number | undefined, "optional">;
252
272
  rejection: import("convex/values").VObject<{
253
273
  code: "amount_too_small" | "balance_insufficient";
254
274
  requestId: string;
@@ -256,8 +276,9 @@ export declare const claimsTable: import("convex/server").TableDefinition<import
256
276
  requestId: import("convex/values").VString<string, "required">;
257
277
  code: import("convex/values").VUnion<"amount_too_small" | "balance_insufficient", [import("convex/values").VLiteral<"balance_insufficient", "required">, import("convex/values").VLiteral<"amount_too_small", "required">], "required", never>;
258
278
  }, "optional", "code" | "requestId">;
259
- }, "required", "accountId" | "allocations" | "amount" | "attemptedAt" | "currency" | "expectedRevision" | "observations" | "operationKey" | "ownerKey" | "rejection" | "rejection.code" | "rejection.requestId" | "returnTransactionId" | "status" | "stripePayoutId">, {
279
+ }, "required", "accountId" | "allocations" | "amount" | "attemptedAt" | "currency" | "debitFee" | "debitTransactionId" | "expectedRevision" | "feeRevision" | "observations" | "operationKey" | "ownerKey" | "providerFee" | "rejection" | "rejection.code" | "rejection.requestId" | "returnTransactionId" | "status" | "stripePayoutId">, {
260
280
  by_account_status: ["accountId", "status", "_creationTime"];
281
+ by_debit_receipt: ["debitTransactionId", "_creationTime"];
261
282
  by_operation: ["operationKey", "_creationTime"];
262
283
  by_provider_payout: ["stripePayoutId", "_creationTime"];
263
284
  by_rejection_request: ["rejection.requestId", "_creationTime"];
@@ -286,4 +307,19 @@ export declare const identity: {
286
307
  ownerKey: import("convex/values").VString<string, "required">;
287
308
  operationKey: import("convex/values").VString<string, "required">;
288
309
  };
310
+ export declare const feeBalancesTable: import("convex/server").TableDefinition<import("convex/values").VObject<{
311
+ accountId: string;
312
+ amount: number;
313
+ currency: string;
314
+ ownerKey: string;
315
+ revision: number;
316
+ }, {
317
+ accountId: import("convex/values").VString<string, "required">;
318
+ ownerKey: import("convex/values").VString<string, "required">;
319
+ currency: import("convex/values").VString<string, "required">;
320
+ amount: import("convex/values").VFloat64<number, "required">;
321
+ revision: import("convex/values").VFloat64<number, "required">;
322
+ }, "required", "accountId" | "amount" | "currency" | "ownerKey" | "revision">, {
323
+ by_account_currency: ["accountId", "currency", "_creationTime"];
324
+ }, {}, {}>;
289
325
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/component/payoutRelease/schema.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;wIAQtB,CAAC;AACH,eAAO,MAAM,UAAU;;;;;;;;sDAMrB,CAAC;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4BvB,CAAC;AACF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gSAInB,CAAC;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAKiC,CAAC;AAC1D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;UAQY,CAAC;AACtC,eAAO,MAAM,QAAQ;;;;CAA+C,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/component/payoutRelease/schema.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;wIAQtB,CAAC;AACH,eAAO,MAAM,UAAU;;;;;;;;sDAMrB,CAAC;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCvB,CAAC;AACF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oWAInB,CAAC;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAMiC,CAAC;AAC1D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;UAQY,CAAC;AACtC,eAAO,MAAM,QAAQ;;;;CAA+C,CAAC;AAErE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;UAK6B,CAAC"}
@@ -27,6 +27,10 @@ export const claimFields = {
27
27
  attemptedAt: v.optional(v.number()),
28
28
  stripePayoutId: v.optional(v.string()),
29
29
  returnTransactionId: v.optional(v.string()),
30
+ feeRevision: v.optional(v.number()),
31
+ debitTransactionId: v.optional(v.string()),
32
+ debitFee: v.optional(v.number()),
33
+ providerFee: v.optional(v.number()),
30
34
  rejection: v.optional(v.object({
31
35
  requestId: v.string(),
32
36
  code: v.union(v.literal("balance_insufficient"), v.literal("amount_too_small")),
@@ -41,6 +45,7 @@ export const claimsTable = defineTable(claimFields)
41
45
  .index("by_operation", ["operationKey"])
42
46
  .index("by_account_status", ["accountId", "status"])
43
47
  .index("by_provider_payout", ["stripePayoutId"])
48
+ .index("by_debit_receipt", ["debitTransactionId"])
44
49
  .index("by_return_receipt", ["returnTransactionId"])
45
50
  .index("by_rejection_request", ["rejection.requestId"]);
46
51
  export const sourcesTable = defineTable({
@@ -53,4 +58,10 @@ export const sourcesTable = defineTable({
53
58
  .index("by_transfer", ["stripeTransferId"])
54
59
  .index("by_account", ["accountId"]);
55
60
  export const identity = { ...scopeFields, operationKey: v.string() };
61
+ export const feeBalancesTable = defineTable({
62
+ ...scopeFields,
63
+ currency: v.string(),
64
+ amount: v.number(),
65
+ revision: v.number(),
66
+ }).index("by_account_currency", ["accountId", "currency"]);
56
67
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/component/payoutRelease/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/component/payoutRelease/schema.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,19 @@
1
1
  declare const _default: import("convex/server").SchemaDefinition<{
2
+ payoutFeeBalances: import("convex/server").TableDefinition<import("convex/values").VObject<{
3
+ accountId: string;
4
+ amount: number;
5
+ currency: string;
6
+ ownerKey: string;
7
+ revision: number;
8
+ }, {
9
+ accountId: import("convex/values").VString<string, "required">;
10
+ ownerKey: import("convex/values").VString<string, "required">;
11
+ currency: import("convex/values").VString<string, "required">;
12
+ amount: import("convex/values").VFloat64<number, "required">;
13
+ revision: import("convex/values").VFloat64<number, "required">;
14
+ }, "required", "accountId" | "amount" | "currency" | "ownerKey" | "revision">, {
15
+ by_account_currency: ["accountId", "currency", "_creationTime"];
16
+ }, {}, {}>;
2
17
  payoutReleaseClaims: import("convex/server").TableDefinition<import("convex/values").VObject<{
3
18
  accountId: string;
4
19
  allocations: {
@@ -9,7 +24,10 @@ declare const _default: import("convex/server").SchemaDefinition<{
9
24
  amount: number;
10
25
  attemptedAt?: number | undefined;
11
26
  currency: string;
27
+ debitFee?: number | undefined;
28
+ debitTransactionId?: string | undefined;
12
29
  expectedRevision: number;
30
+ feeRevision?: number | undefined;
13
31
  observations: {
14
32
  currency: string;
15
33
  ledgerFingerprint: string;
@@ -21,6 +39,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
21
39
  }[];
22
40
  operationKey: string;
23
41
  ownerKey: string;
42
+ providerFee?: number | undefined;
24
43
  rejection?: {
25
44
  code: "amount_too_small" | "balance_insufficient";
26
45
  requestId: string;
@@ -77,6 +96,10 @@ declare const _default: import("convex/server").SchemaDefinition<{
77
96
  attemptedAt: import("convex/values").VFloat64<number | undefined, "optional">;
78
97
  stripePayoutId: import("convex/values").VString<string | undefined, "optional">;
79
98
  returnTransactionId: import("convex/values").VString<string | undefined, "optional">;
99
+ feeRevision: import("convex/values").VFloat64<number | undefined, "optional">;
100
+ debitTransactionId: import("convex/values").VString<string | undefined, "optional">;
101
+ debitFee: import("convex/values").VFloat64<number | undefined, "optional">;
102
+ providerFee: import("convex/values").VFloat64<number | undefined, "optional">;
80
103
  rejection: import("convex/values").VObject<{
81
104
  code: "amount_too_small" | "balance_insufficient";
82
105
  requestId: string;
@@ -84,8 +107,9 @@ declare const _default: import("convex/server").SchemaDefinition<{
84
107
  requestId: import("convex/values").VString<string, "required">;
85
108
  code: import("convex/values").VUnion<"amount_too_small" | "balance_insufficient", [import("convex/values").VLiteral<"balance_insufficient", "required">, import("convex/values").VLiteral<"amount_too_small", "required">], "required", never>;
86
109
  }, "optional", "code" | "requestId">;
87
- }, "required", "accountId" | "allocations" | "amount" | "attemptedAt" | "currency" | "expectedRevision" | "observations" | "operationKey" | "ownerKey" | "rejection" | "rejection.code" | "rejection.requestId" | "returnTransactionId" | "status" | "stripePayoutId">, {
110
+ }, "required", "accountId" | "allocations" | "amount" | "attemptedAt" | "currency" | "debitFee" | "debitTransactionId" | "expectedRevision" | "feeRevision" | "observations" | "operationKey" | "ownerKey" | "providerFee" | "rejection" | "rejection.code" | "rejection.requestId" | "returnTransactionId" | "status" | "stripePayoutId">, {
88
111
  by_account_status: ["accountId", "status", "_creationTime"];
112
+ by_debit_receipt: ["debitTransactionId", "_creationTime"];
89
113
  by_operation: ["operationKey", "_creationTime"];
90
114
  by_provider_payout: ["stripePayoutId", "_creationTime"];
91
115
  by_rejection_request: ["rejection.requestId", "_creationTime"];
@@ -1,4 +1,4 @@
1
- import { claimsTable as payoutReleaseClaimsTable, sourcesTable as payoutSourceAllocationsTable, } from "./payoutRelease/schema.js";
1
+ import { feeBalancesTable as payoutFeeBalancesTable, claimsTable as payoutReleaseClaimsTable, sourcesTable as payoutSourceAllocationsTable, } from "./payoutRelease/schema.js";
2
2
  import { policiesTable, operationsTable } from "./payoutPolicy/schema.js";
3
3
  import { currencyTotalsTable } from "./earnings/schema.js";
4
4
  import { claimsTable, balancesTable, groupsTable, reservationsTable, } from "./costRecovery/schema";
@@ -10,6 +10,7 @@ import { accountsTable } from "./core/schema";
10
10
  import { pricesTable, productsTable } from "./products/schema";
11
11
  import { webhookEventsTable } from "./webhooks/schema";
12
12
  export default defineSchema({
13
+ payoutFeeBalances: payoutFeeBalancesTable,
13
14
  payoutReleaseClaims: payoutReleaseClaimsTable,
14
15
  payoutSourceAllocations: payoutSourceAllocationsTable,
15
16
  payoutPolicies: policiesTable,
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,IAAI,wBAAwB,EACvC,YAAY,IAAI,4BAA4B,GAC7C,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,aAAa,EACb,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,YAAY,EACZ,wBAAwB,EACxB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,eAAe,YAAY,CAAC;IAC1B,mBAAmB,EAAE,wBAAwB;IAC7C,uBAAuB,EAAE,4BAA4B;IACrD,cAAc,EAAE,aAAa;IAC7B,sBAAsB,EAAE,eAAe;IACvC,cAAc,EAAE,mBAAmB;IACnC,cAAc,EAAE,WAAW;IAC3B,gBAAgB,EAAE,aAAa;IAC/B,cAAc,EAAE,WAAW;IAC3B,oBAAoB,EAAE,iBAAiB;IACvC,qBAAqB,EAAE,gBAAgB;IACvC,eAAe,EAAE,oBAAoB;IACrC,mBAAmB,EAAE,wBAAwB;IAC7C,OAAO;IACP,QAAQ,EAAE,aAAa;IAEvB,WAAW;IACX,QAAQ,EAAE,aAAa;IACvB,MAAM,EAAE,WAAW;IAEnB,UAAU;IACV,aAAa,EAAE,kBAAkB;IACjC,gBAAgB,EAAE,qBAAqB;IACvC,QAAQ,EAAE,aAAa;IAEvB,UAAU;IACV,QAAQ,EAAE,aAAa;IACvB,OAAO,EAAE,YAAY;IACrB,iBAAiB,EAAE,sBAAsB;IACzC,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE,aAAa;IACvB,SAAS,EAAE,cAAc;IACzB,mBAAmB,EAAE,wBAAwB;IAE7C,WAAW;IACX,aAAa,EAAE,kBAAkB;CAClC,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,IAAI,sBAAsB,EAC1C,WAAW,IAAI,wBAAwB,EACvC,YAAY,IAAI,4BAA4B,GAC7C,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,iBAAiB,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,EACL,qBAAqB,EACrB,aAAa,EACb,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,aAAa,EACb,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,YAAY,EACZ,wBAAwB,EACxB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,eAAe,YAAY,CAAC;IAC1B,iBAAiB,EAAE,sBAAsB;IACzC,mBAAmB,EAAE,wBAAwB;IAC7C,uBAAuB,EAAE,4BAA4B;IACrD,cAAc,EAAE,aAAa;IAC7B,sBAAsB,EAAE,eAAe;IACvC,cAAc,EAAE,mBAAmB;IACnC,cAAc,EAAE,WAAW;IAC3B,gBAAgB,EAAE,aAAa;IAC/B,cAAc,EAAE,WAAW;IAC3B,oBAAoB,EAAE,iBAAiB;IACvC,qBAAqB,EAAE,gBAAgB;IACvC,eAAe,EAAE,oBAAoB;IACrC,mBAAmB,EAAE,wBAAwB;IAC7C,OAAO;IACP,QAAQ,EAAE,aAAa;IAEvB,WAAW;IACX,QAAQ,EAAE,aAAa;IACvB,MAAM,EAAE,WAAW;IAEnB,UAAU;IACV,aAAa,EAAE,kBAAkB;IACjC,gBAAgB,EAAE,qBAAqB;IACvC,QAAQ,EAAE,aAAa;IAEvB,UAAU;IACV,QAAQ,EAAE,aAAa;IACvB,OAAO,EAAE,YAAY;IACrB,iBAAiB,EAAE,sBAAsB;IACzC,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE,aAAa;IACvB,SAAS,EAAE,cAAc;IACzB,mBAAmB,EAAE,wBAAwB;IAE7C,WAAW;IACX,aAAa,EAAE,kBAAkB;CAClC,CAAC,CAAC"}
@@ -16,7 +16,7 @@ enable the account feature or extend BetterStripe's supported-version list.
16
16
 
17
17
  ## Enable the sandbox feature first
18
18
 
19
- In the intended sandbox, the account owner must enable **Reusable payment
19
+ For a non-Connect merchant, the account owner must enable **Reusable payment
20
20
  methods for Global Payouts** under **Account previews and features**. If the toggle
21
21
  is unavailable or disabled, check account-owner permissions and request access
22
22
  using Stripe's form. A disabled toggle alone does not identify the cause. This also enables Stripe's
@@ -28,6 +28,44 @@ Accounts and changes how Stripe-hosted integrations create customers. Review
28
28
  Stripe's limitations and migration behavior before changing any live account.
29
29
  See [Stripe's customer Account guide](https://docs.stripe.com/accounts-v2/use-accounts-as-customers).
30
30
 
31
+ ## Connect sandbox setup findings, 2026-10-15
32
+
33
+ Saved-card setup verification initially encountered
34
+ `non_connect_platform_accounts_v2_access_blocked` while creating a
35
+ customer-configured Account. Changing between the supported GA and preview
36
+ request versions did not resolve the account eligibility block.
37
+
38
+ For the Connect integration under test, enabling Connect in the existing
39
+ standalone test sandbox resolved the block. We used Stripe CLI `1.53.1` and its
40
+ `tools` plugin `0.15.0`. With an authenticated CLI profile for the intended
41
+ sandbox, replace `YOUR_SANDBOX_PROFILE` with its profile name:
42
+
43
+ ```sh
44
+ stripe --project-name YOUR_SANDBOX_PROFILE tools enable_connect --json
45
+ ```
46
+
47
+ Confirm the profile points to the intended standalone sandbox before running it.
48
+ The tool enables Connect in that sandbox and is idempotent. Its help states that
49
+ live accounts and sandboxes controlled by another platform are not eligible.
50
+ Inspect `stripe tools enable_connect --help` for the installed version's behavior.
51
+ See Stripe's [sandbox guide](https://docs.stripe.com/sandboxes) and
52
+ [Connect guide](https://docs.stripe.com/connect).
53
+
54
+ After enablement, customer-account provisioning, SetupIntent authentication and
55
+ later saved-card payments passed with test credentials. The browser flow used
56
+ `2026-09-30.endive`; separate API checks passed on `2026-09-30.preview` in the
57
+ same Connect-enabled sandbox. These results do not prove non-Connect preview
58
+ eligibility. A merchant using customer-only Accounts must follow the preview
59
+ setup above rather than enabling Connect merely to bypass the block. Neither
60
+ BetterStripe nor a different request version enables Stripe account features.
61
+
62
+ The [live verification evidence](https://github.com/FantasticDevHQ/better-stripe/pull/166#issuecomment-6185124292)
63
+ contains screenshots and sanitized provider records. The
64
+ [React guide](react-workflows.md#live-authentication-and-reuse-results-2026-10-15)
65
+ records authentication and reuse outcomes. Successful test payments were refunded,
66
+ unfinished intents canceled, saved test cards detached and fixture products/prices
67
+ archived. No live account configuration or live payment was part of these checks.
68
+
31
69
  ## Configure one client and its webhook route
32
70
 
33
71
  ```ts
@@ -609,6 +609,37 @@ Existing `AddCardForm` and `PaymentMethods` tokenization/attach integrations rem
609
609
  available. Tokenization plus attachment does not complete SetupIntent or SCA
610
610
  verification.
611
611
 
612
+ ### Live authentication and reuse results, 2026-10-15
613
+
614
+ The public `SaveCard` workflow and `BetterStripe.createSetupIntent` /
615
+ `BetterStripe.createPaymentIntent` methods were exercised against real Stripe.js
616
+ and Stripe test APIs at commit `332d49c`, merged in
617
+ [PR #166](https://github.com/FantasticDevHQ/better-stripe/pull/166).
618
+ The Connect-enabled sandbox used `2026-09-30.endive` for browser confirmation.
619
+ Separate API checks also passed on `2026-09-30.preview`.
620
+
621
+ | Check | Observed result |
622
+ | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
623
+ | Explicit consent and repeated provisioning with the same request key | Off-session setup accepted; retries returned the same intent. |
624
+ | Card `4000000000003220`, failed 3DS challenge then retry | A retryable authentication error appeared. Retrying the same SetupIntent and completing 3DS succeeded. Stripe SetupAttempts recorded both outcomes. |
625
+ | Card `4000002500003155`, setup then later off-session payment | 3DS setup succeeded with `usage: "off_session"` and `allow_redisplay: "always"`. The saved method belonged to the expected V2 customer; the later payment succeeded and was refunded. |
626
+ | Later off-session reuse of card ending `3220` | Stripe returned `authentication_required`. Successful setup does not guarantee every later payment can avoid authentication. |
627
+ | API decline and payment retry checks | Decline returned `card_declined` / `requires_payment_method`; same-key payment provisioning returned the same intent. |
628
+
629
+ Use these public test card numbers only in a Stripe test payment form, with a
630
+ future expiration and test CVC. Use Stripe's test PaymentMethod IDs for API tests.
631
+ See [Stripe's testing guide](https://docs.stripe.com/testing#regulatory-cards).
632
+
633
+ [Uploaded screenshots and provider records](https://github.com/FantasticDevHQ/better-stripe/pull/166#issuecomment-6185124292)
634
+ show the challenge, retryable failure and successful reuse. No continuous video
635
+ was recorded. Test payments were refunded and disposable fixtures cleaned up.
636
+ The test used a local ownership fixture for the host callback. It verifies package
637
+ orchestration and actual provider authentication, not production application
638
+ authentication, redirect-return recovery, webhook delivery or Dojo's saved-card UI.
639
+ Consumer applications still need to verify their own authenticated adapters and saved-card UI.
640
+ See [sandbox setup findings](accounts-v2-preview.md#connect-sandbox-setup-findings-2026-10-15)
641
+ for the account eligibility requirement.
642
+
612
643
  ## Component history and currency summaries
613
644
 
614
645
  See the [read contract guide](read-contracts.md) for reactive product, price and payout
@@ -222,8 +222,8 @@ Sources: [payout schedules](https://docs.stripe.com/connect/manage-payout-schedu
222
222
  ### Transactional claim ledger implementation status
223
223
 
224
224
  The component contains `payoutRelease` claim and source-allocation tables. These
225
- are server-side building blocks for the release boundary, with no public client
226
- executor or scheduled bank-payout integration yet. Do not call the claim
225
+ are server-side building blocks for the release boundary, with no automatic
226
+ payout-creation or scheduled bank-payout integration yet. Do not call the claim
227
227
  mutation with UI totals or a transfer receipt alone. Its trusted upstream caller
228
228
  must establish complete provider history, still-unpaid ownership, adoption of
229
229
  prior payouts, independent liabilities, and live payout controls first.
@@ -245,7 +245,7 @@ held. This window stays below Stripe's [24-hour v1 idempotency retention minimum
245
245
  The current claim snapshot is deliberately bounded to 100 account transfer rows
246
246
  and 1,000 receipt IDs per source. Larger or incomplete histories reject the whole
247
247
  claim, without using partial totals. A resumable reconciliation/adoption process,
248
- provider payout creation and receipt verification, payout-fee accounting, and
248
+ provider payout creation and receipt verification, historical fee adoption, other account debit allocation, and
249
249
  recurring release/expiry integration remain required before custom payout
250
250
  minimums can be presented as an operational feature. In-memory claim tests are
251
251
  not evidence of a completed Stripe bank payout.
@@ -299,3 +299,74 @@ remains intact for retries.
299
299
  Sources: [transfer provenance](https://docs.stripe.com/api/transfers/object),
300
300
  [receipt maturity](https://docs.stripe.com/api/balance_transactions/object), and
301
301
  [history pagination and payout-filter limits](https://docs.stripe.com/api/balance_transactions/list).
302
+
303
+ ## Verified payout receipts and reconciliation
304
+
305
+ In an authorized server action, read a Connect Stripe-balance payout with:
306
+
307
+ ```ts
308
+ const receipt = await stripe.payoutPolicy.payoutReceipt({
309
+ accountId,
310
+ stripePayoutId,
311
+ });
312
+ ```
313
+
314
+ The reader retrieves the payout and its actual account-scoped balance
315
+ transactions, including a failed/canceled payout's return transaction. It checks
316
+ transaction identity, currency, exact principal, signed fees, net amounts and
317
+ maturity, then re-reads the payout to detect changes. Expanded transaction
318
+ objects are not trusted in place of scoped retrieval. Automatic and manual
319
+ history can both be inspected; a manual payout receipt does not identify the
320
+ transfers that funded it. Changed snapshots, missing debit/return receipts,
321
+ pending debits or returns, unsupported currency allocation and bank-payout reversals return
322
+ `not_ready` without partial financial totals.
323
+
324
+ A ready receipt preserves `providerStatus`, original `debit`, optional returned
325
+ `credit`, `returnedPrincipal` and `returnedNet`. A returned principal can differ
326
+ from net cash because payout fees are retained or credited separately. This data
327
+ alone does not authorize releasing a reservation, identify still-unpaid earnings,
328
+ or prove that a pending payout reached the bank. Global Payouts requires a
329
+ separate receipt and capability implementation.
330
+
331
+ To reconcile an already attempted durable claim:
332
+
333
+ ```ts
334
+ const outcome = await stripe.payoutPolicy.reconcilePayout(ctx, {
335
+ accountId,
336
+ ownerKey,
337
+ operationKey,
338
+ // stripePayoutId, // optional when the provider ID is already known
339
+ maxPages: 10,
340
+ });
341
+ ```
342
+
343
+ The host authenticates the account/owner/operation before this call. Reconciliation
344
+ requires `ctx.runMutation`. It never creates or retries a bank payout. A stored
345
+ provider ID must agree with any supplied ID. Otherwise, bounded provider history
346
+ is scanned for the exact reserved `bsPayoutClaim` marker. Discovery must finish;
347
+ partial history, duplicate matches and a changed history head stay held. The
348
+ page budget is 1 to 100, default 10. No match, including after idempotency expiry,
349
+ never proves that money did not move.
350
+
351
+ Adoption verifies the claim marker, amount, currency, creation window and
352
+ standard manual bank-payout type. Current claims use the card source balance;
353
+ other source rails return an explicit allocation limitation. A missing or
354
+ immature return keeps allocations reserved. Verified paid and returned outcomes
355
+ update source allocations and payout fees in one component transaction. Unknown
356
+ provider and persistence errors propagate so the host can retry reconciliation.
357
+ Canceled/rejected claim states are returned as terminal states, not as bank
358
+ payment confirmation.
359
+
360
+ Net non-refundable payout fees are retained per recipient/currency and deducted
361
+ from later mature unpaid entitlement. They are not deducted again from fresh
362
+ provider availability, which already reflects the debit. A newly observed fee
363
+ invalidates an unattempted claim prepared against an older fee revision. Fee
364
+ credits after a return reduce only the verified original fee; excess credits
365
+ require explicit allocation. Original debit receipts and their fees remain
366
+ immutable. Older returned claims can receive verified fee evidence without
367
+ releasing their principal again.
368
+
369
+ These APIs reconcile existing claims; full automatic qualification/creation,
370
+ historical source adoption, large-history collection, other account debit
371
+ allocation and recurring/UI integration remain separate work. Do not expose a
372
+ custom minimum as fully enforced solely because reconciliation is available.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fantastic.dev/better-stripe",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "description": "A Convex component for Stripe V2 Accounts API integration.",
5
5
  "keywords": [
6
6
  "stripe",
@@ -139,7 +139,7 @@ describe("combined recipient payout allocation", () => {
139
139
  expect(result).toMatchObject({
140
140
  status: "qualified",
141
141
  amount: 1300,
142
- matureUnpaid: 2000,
142
+ matureUnpaid: 1800,
143
143
  });
144
144
  expect(
145
145
  planRecipientPayout({
@@ -149,8 +149,8 @@ describe("combined recipient payout allocation", () => {
149
149
  }),
150
150
  ).toMatchObject({
151
151
  status: "held",
152
- reason: "insufficient_available",
153
- matureUnpaid: 1000,
152
+ reason: "below_threshold",
153
+ matureUnpaid: 999,
154
154
  });
155
155
  });
156
156
  it("does not subtract reservations again from an already debited provider balance", () => {
@@ -290,3 +290,36 @@ describe("combined recipient payout allocation", () => {
290
290
  function awaitInvalid(action: () => unknown) {
291
291
  expect(action).toThrow(/Invalid|Unsafe|Duplicate/);
292
292
  }
293
+ it("deducts confirmed payout fees from entitlement without deducting them twice from provider availability", () => {
294
+ expect(
295
+ planRecipientPayout({
296
+ ...options([source("tr_one", 1500)]),
297
+ providerAvailable: 1470,
298
+ confirmedFees: 30,
299
+ }),
300
+ ).toMatchObject({ status: "qualified", amount: 1470, matureUnpaid: 1470 });
301
+ expect(
302
+ planRecipientPayout({
303
+ ...options([source("tr_one", 1000)]),
304
+ providerAvailable: 5000,
305
+ confirmedFees: 30,
306
+ }),
307
+ ).toMatchObject({
308
+ status: "held",
309
+ reason: "below_threshold",
310
+ matureUnpaid: 970,
311
+ });
312
+ });
313
+ it("does not qualify the gross threshold while known independent liabilities remain", () => {
314
+ expect(
315
+ planRecipientPayout({
316
+ ...options(),
317
+ providerAvailable: 5000,
318
+ independentLiabilities: 1,
319
+ }),
320
+ ).toMatchObject({
321
+ status: "held",
322
+ reason: "below_threshold",
323
+ matureUnpaid: 999,
324
+ });
325
+ });