@peable.to/contracts 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/resources/catalog/index.js +1 -5
- package/dist/cjs/resources/checkout/checkoutSessions.js +0 -4
- package/dist/cjs/resources/events/events.js +1 -32
- package/dist/cjs/resources/events/webhookDeliveries.js +1 -1
- package/dist/cjs/resources/events/webhookEndpoints.js +1 -1
- package/dist/cjs/resources/payments/disputes.js +16 -0
- package/dist/cjs/resources/payments/refunds.js +46 -11
- package/dist/cjs/vocabulary/catalog.js +1 -17
- package/dist/cjs/vocabulary/errors.js +0 -13
- package/dist/cjs/vocabulary/events.js +5 -1
- package/dist/esm/resources/catalog/index.js +1 -5
- package/dist/esm/resources/checkout/checkoutSessions.js +0 -4
- package/dist/esm/resources/events/events.js +0 -31
- package/dist/esm/resources/events/webhookDeliveries.js +1 -1
- package/dist/esm/resources/events/webhookEndpoints.js +1 -1
- package/dist/esm/resources/payments/disputes.js +16 -0
- package/dist/esm/resources/payments/refunds.js +46 -11
- package/dist/esm/vocabulary/catalog.js +0 -16
- package/dist/esm/vocabulary/errors.js +0 -13
- package/dist/esm/vocabulary/events.js +5 -1
- package/dist/types/resources/catalog/index.d.ts +1 -851
- package/dist/types/resources/checkout/checkoutSessions.d.ts +13 -61
- package/dist/types/resources/checkout/index.d.ts +10 -46
- package/dist/types/resources/connect/balance.d.ts +5 -5
- package/dist/types/resources/connect/index.d.ts +4 -4
- package/dist/types/resources/connect/payouts.d.ts +2 -2
- package/dist/types/resources/events/events.d.ts +0 -22
- package/dist/types/resources/events/index.d.ts +7 -15
- package/dist/types/resources/events/webhookDeliveries.d.ts +0 -3
- package/dist/types/resources/events/webhookEndpoints.d.ts +11 -16
- package/dist/types/resources/payments/disputes.d.ts +35 -0
- package/dist/types/resources/payments/index.d.ts +82 -10
- package/dist/types/resources/payments/paymentIntents.d.ts +10 -10
- package/dist/types/resources/payments/refunds.d.ts +56 -5
- package/dist/types/resources/payments/testHelpers.d.ts +1 -1
- package/dist/types/resources/tax/index.d.ts +1 -1
- package/dist/types/resources/tax/registrations.d.ts +2 -2
- package/dist/types/vocabulary/catalog.d.ts +0 -9
- package/dist/types/vocabulary/errors.d.ts +0 -13
- package/dist/types/vocabulary/events.d.ts +5 -2
- package/package.json +1 -1
- package/dist/cjs/resources/catalog/billing.js +0 -753
- package/dist/esm/resources/catalog/billing.js +0 -750
- package/dist/types/resources/catalog/billing.d.ts +0 -1723
|
@@ -17,7 +17,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.catalogRoutes = exports.queryIdList = exports.queryFlag = exports.baseUnitAmountParam = void 0;
|
|
18
18
|
// Contracts of this group: one module per resource, re-exported here, and
|
|
19
19
|
// their routes concatenated into `catalogRoutes`.
|
|
20
|
-
const billing_1 = require("./billing");
|
|
21
20
|
const billingSettings_1 = require("./billingSettings");
|
|
22
21
|
const coupons_1 = require("./coupons");
|
|
23
22
|
const entitlements_1 = require("./entitlements");
|
|
@@ -26,7 +25,6 @@ const prices_1 = require("./prices");
|
|
|
26
25
|
const products_1 = require("./products");
|
|
27
26
|
const promotionCodes_1 = require("./promotionCodes");
|
|
28
27
|
const testClocks_1 = require("./testClocks");
|
|
29
|
-
__exportStar(require("./billing"), exports);
|
|
30
28
|
__exportStar(require("./billingSettings"), exports);
|
|
31
29
|
__exportStar(require("./coupons"), exports);
|
|
32
30
|
__exportStar(require("./entitlements"), exports);
|
|
@@ -42,8 +40,7 @@ Object.defineProperty(exports, "queryFlag", { enumerable: true, get: function ()
|
|
|
42
40
|
Object.defineProperty(exports, "queryIdList", { enumerable: true, get: function () { return shared_1.queryIdList; } });
|
|
43
41
|
/**
|
|
44
42
|
* The catalog (products, prices, coupons, promotion codes), entitlements, the
|
|
45
|
-
* billing engine's platform objects (test clocks, billing settings, meters)
|
|
46
|
-
* and the recurring billing transport (`/v1/billing/*`).
|
|
43
|
+
* billing engine's platform objects (test clocks, billing settings, meters).
|
|
47
44
|
*/
|
|
48
45
|
exports.catalogRoutes = [
|
|
49
46
|
...products_1.productRoutes,
|
|
@@ -54,5 +51,4 @@ exports.catalogRoutes = [
|
|
|
54
51
|
...testClocks_1.testClockRoutes,
|
|
55
52
|
...billingSettings_1.billingSettingsRoutes,
|
|
56
53
|
...meters_1.meterRoutes,
|
|
57
|
-
...billing_1.billingRoutes,
|
|
58
54
|
];
|
|
@@ -4,7 +4,6 @@ exports.checkoutSessionRoutes = exports.expireCheckoutSessionTestHelperParams =
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const catalog_1 = require("../../vocabulary/catalog");
|
|
6
6
|
const payments_1 = require("../../vocabulary/payments");
|
|
7
|
-
const billing_1 = require("../catalog/billing");
|
|
8
7
|
const objects_1 = require("../../common/objects");
|
|
9
8
|
const envelopes_1 = require("../../common/envelopes");
|
|
10
9
|
const objects_2 = require("../../common/objects");
|
|
@@ -183,9 +182,6 @@ exports.checkoutSessionPublicSchema = (0, objects_2.defineComponent)('CheckoutSe
|
|
|
183
182
|
.string()
|
|
184
183
|
.nullable()
|
|
185
184
|
.describe("The card provider's PUBLIC key for this session's mode, so the payment fields can mount before the payment exists. `null` on FairCoin."),
|
|
186
|
-
billing_quote: billing_1.billingFaircoinFxQuoteSchema
|
|
187
|
-
.optional()
|
|
188
|
-
.describe('FairCoin billing invoices: the frozen USD price and FAIR settlement quote.'),
|
|
189
185
|
})
|
|
190
186
|
.strict());
|
|
191
187
|
// ---- Merchant create/update ---------------------------------------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.eventRoutes = exports.WEBHOOK_EVENT_DESCRIPTIONS = exports.streamEventsQuery = exports.retrieveEventQuery = exports.listEventsQuery = exports.listEventsFilters = exports.eventSchema = exports.eventRequestSchema =
|
|
3
|
+
exports.eventRoutes = exports.WEBHOOK_EVENT_DESCRIPTIONS = exports.streamEventsQuery = exports.retrieveEventQuery = exports.listEventsQuery = exports.listEventsFilters = exports.eventSchema = exports.eventRequestSchema = void 0;
|
|
4
4
|
exports.eventSchemaOf = eventSchemaOf;
|
|
5
5
|
const zod_1 = require("zod");
|
|
6
6
|
const envelopes_1 = require("../../common/envelopes");
|
|
@@ -16,36 +16,6 @@ const events_1 = require("../../vocabulary/events");
|
|
|
16
16
|
* every matching webhook endpoint: a delivery's body and `GET /v1/events/:id`
|
|
17
17
|
* are byte for byte the same object.
|
|
18
18
|
*/
|
|
19
|
-
/**
|
|
20
|
-
* The payload of `billing.observation.updated`: a wake-up, never paid or grant
|
|
21
|
-
* authority. Re-read the owner-bound resource it names.
|
|
22
|
-
*/
|
|
23
|
-
exports.billingObservationSchema = (0, objects_1.defineObject)('billing_observation', 'BillingObservation', zod_1.z
|
|
24
|
-
.object({
|
|
25
|
-
object: zod_1.z.literal('billing_observation'),
|
|
26
|
-
livemode: primitives_1.livemode.describe('The mode of the billing cohort observed (ADR 0017).'),
|
|
27
|
-
resource_kind: zod_1.z.enum(['subscription', 'invoice']),
|
|
28
|
-
resource_id: zod_1.z.string().describe('The provider subscription or invoice observed.'),
|
|
29
|
-
subscription_id: zod_1.z
|
|
30
|
-
.string()
|
|
31
|
-
.optional()
|
|
32
|
-
.describe('Owner-scoped wake-up hint only; re-read the subscription before resolving a payer.'),
|
|
33
|
-
revision: zod_1.z.number().int().describe('The observation revision; later revisions are newer.'),
|
|
34
|
-
observed_at: primitives_1.unixSeconds,
|
|
35
|
-
})
|
|
36
|
-
.strict(), {
|
|
37
|
-
examples: [
|
|
38
|
-
{
|
|
39
|
-
object: 'billing_observation',
|
|
40
|
-
livemode: false,
|
|
41
|
-
resource_kind: 'subscription',
|
|
42
|
-
resource_id: 'sub_1Q2w3E4r5T6y7U8i',
|
|
43
|
-
subscription_id: 'sub_1Q2w3E4r5T6y7U8i',
|
|
44
|
-
revision: 3,
|
|
45
|
-
observed_at: 1793750400,
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
});
|
|
49
19
|
/**
|
|
50
20
|
* What caused an event, when an API request did (Stripe's `event.request`).
|
|
51
21
|
* Both `null` for an event caused by something else — the chain watcher, the
|
|
@@ -242,7 +212,6 @@ exports.WEBHOOK_EVENT_DESCRIPTIONS = {
|
|
|
242
212
|
'setup_intent.succeeded': 'A SetupIntent succeeded: its PaymentMethod is saved.',
|
|
243
213
|
'setup_intent.setup_failed': 'A SetupIntent attempt failed.',
|
|
244
214
|
'setup_intent.canceled': 'A SetupIntent was canceled.',
|
|
245
|
-
'billing.observation.updated': 'A recurring billing resource was observed to change. A wake-up only: re-read the resource.',
|
|
246
215
|
'connected_account.updated': "A seller's connected account changed — its readiness, in practice.",
|
|
247
216
|
'product.created': 'A Product was created.',
|
|
248
217
|
'product.updated': 'A Product was updated; `previous_attributes` names what moved.',
|
|
@@ -26,7 +26,7 @@ exports.webhookDeliverySchema = (0, objects_1.defineObject)('webhook_delivery',
|
|
|
26
26
|
delivered: zod_1.z.boolean(),
|
|
27
27
|
last_status: zod_1.z
|
|
28
28
|
.enum(events_1.WEBHOOK_DELIVERY_STATUSES)
|
|
29
|
-
.describe('`pending`: will be attempted (`next_attempt_at`). `delivered`: terminal success. `failed`: the endpoint refused it (a 4xx, a blocked address)
|
|
29
|
+
.describe('`pending`: will be attempted (`next_attempt_at`). `delivered`: terminal success. `failed`: the endpoint refused it (a 4xx, a blocked address), was disabled first, or its stored url breaks the registration rules — never retried. `dead`: every attempt failed transiently for three days; it can be redelivered.'),
|
|
30
30
|
last_error: zod_1.z
|
|
31
31
|
.string()
|
|
32
32
|
.optional()
|
|
@@ -29,7 +29,7 @@ const endpointShape = {
|
|
|
29
29
|
disabled_reason: zod_1.z
|
|
30
30
|
.enum(events_1.WEBHOOK_ENDPOINT_DISABLED_REASONS)
|
|
31
31
|
.nullable()
|
|
32
|
-
.describe('`null` exactly when `status` is `enabled`. `delivery_failures`: every delivery failed for three days straight.'),
|
|
32
|
+
.describe('`null` exactly when `status` is `enabled`. `delivery_failures`: every delivery failed for three days straight. `url_refused`: the stored `url` breaks the registration rules, judged before every delivery; re-enable it with a `url` that passes.'),
|
|
33
33
|
api_version: zod_1.z.string().describe('The wire version events are rendered with for this endpoint.'),
|
|
34
34
|
metadata: primitives_1.metadata,
|
|
35
35
|
created: primitives_1.unixSeconds,
|
|
@@ -7,6 +7,7 @@ const objects_1 = require("../../common/objects");
|
|
|
7
7
|
const params_1 = require("../../common/params");
|
|
8
8
|
const primitives_1 = require("../../common/primitives");
|
|
9
9
|
const route_1 = require("../../route");
|
|
10
|
+
const refunds_1 = require("./refunds");
|
|
10
11
|
const payments_1 = require("../../vocabulary/payments");
|
|
11
12
|
/**
|
|
12
13
|
* Disputes (`dp_…`) — the card network holding a payment's money while a
|
|
@@ -201,4 +202,19 @@ exports.disputeRoutes = [
|
|
|
201
202
|
response: exports.disputeSchema,
|
|
202
203
|
sdk: 'disputes.close',
|
|
203
204
|
}),
|
|
205
|
+
(0, route_1.defineRoute)({
|
|
206
|
+
operationId: 'retrieveDisputeSettlement',
|
|
207
|
+
method: 'get',
|
|
208
|
+
path: '/v1/disputes/{disputeId}/settlement',
|
|
209
|
+
tag: 'Disputes',
|
|
210
|
+
summary: "Retrieve a dispute's settlement",
|
|
211
|
+
description: 'What the dispute WITHDREW from the settlement balance — `gross` the principal, `fee` the dispute fee, a negative `net` — in the settlement currency, read live from the provider. An inquiry moves no money: `unknown`, every figure `null`, never `0`. A reinstatement after a won dispute is not this figure.',
|
|
212
|
+
auth: 'service',
|
|
213
|
+
scope: 'payments:read',
|
|
214
|
+
params: disputeId,
|
|
215
|
+
query: params_1.expandOnlyQuery,
|
|
216
|
+
response: refunds_1.settlementSchema,
|
|
217
|
+
sdk: 'disputes.settlement',
|
|
218
|
+
expandable: 'settlement',
|
|
219
|
+
}),
|
|
204
220
|
];
|
|
@@ -10,7 +10,8 @@ const route_1 = require("../../route");
|
|
|
10
10
|
const money_1 = require("../../vocabulary/money");
|
|
11
11
|
const payments_1 = require("../../vocabulary/payments");
|
|
12
12
|
/**
|
|
13
|
-
* Refunds (`re_…`) and a payment
|
|
13
|
+
* Refunds (`re_…`) and the settlement figures of a payment, a refund or a
|
|
14
|
+
* dispute. The provider's own
|
|
14
15
|
* refund id never appears: a merchant integrates against Peable and never
|
|
15
16
|
* learns which acquirer sat behind it (ADR 0001 D3).
|
|
16
17
|
*/
|
|
@@ -56,23 +57,42 @@ exports.refundSchema = (0, objects_1.defineObject)('refund', 'Refund', zod_1.z
|
|
|
56
57
|
],
|
|
57
58
|
});
|
|
58
59
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
60
|
+
* One movement of the settlement balance, as the PROVIDER reports it: what a
|
|
61
|
+
* payment brought in (`GET /v1/payment_intents/{intentId}/settlement`), what a
|
|
62
|
+
* refund took out (`GET /v1/refunds/{id}/settlement`) or what a dispute
|
|
63
|
+
* withdrew (`GET /v1/disputes/{disputeId}/settlement`). `refund` and `dispute`
|
|
64
|
+
* say which: both `null` for a payment's.
|
|
65
|
+
*
|
|
66
|
+
* Every figure is nullable and that is the contract: "the fee was zero" and
|
|
67
|
+
* "the fee is not known yet" are different facts, and `status` says which
|
|
68
|
+
* produced the nulls. It reports what the provider took; it attributes that
|
|
69
|
+
* cost to nobody.
|
|
70
|
+
*
|
|
71
|
+
* The signs: `gross` is the MAGNITUDE of the movement, `fee` the provider's fee
|
|
72
|
+
* on it (positive when charged, negative when returned), `net` its SIGNED
|
|
73
|
+
* effect on the balance — so `net = gross − fee` for a payment and
|
|
74
|
+
* `net = −gross − fee` for a refund or a dispute.
|
|
63
75
|
*/
|
|
64
76
|
exports.settlementSchema = (0, objects_1.defineObject)('settlement', 'Settlement', zod_1.z
|
|
65
77
|
.object({
|
|
66
78
|
object: zod_1.z.literal('settlement'),
|
|
67
79
|
livemode: primitives_1.livemode,
|
|
68
|
-
payment_intent: (0, objects_1.expandable)('payment_intent', 'The `pi_…` this describes, or the PaymentIntent with `expand[]=payment_intent`.'),
|
|
80
|
+
payment_intent: (0, objects_1.expandable)('payment_intent', 'The `pi_…` this describes (the refunded or disputed payment, for a refund or a dispute), or the PaymentIntent with `expand[]=payment_intent`.'),
|
|
81
|
+
refund: (0, objects_1.expandable)('refund', 'The `re_…` whose movement this is, or the Refund with `expand[]=refund`; `null` unless this is the settlement of a refund.').nullable(),
|
|
82
|
+
dispute: (0, objects_1.expandable)('dispute', 'The `dp_…` whose withdrawal this is, or the Dispute with `expand[]=dispute`; `null` unless this is the settlement of a dispute.').nullable(),
|
|
69
83
|
status: zod_1.z
|
|
70
84
|
.enum(payments_1.SETTLEMENT_STATUSES)
|
|
71
|
-
.describe('`available`: settled, the figures are final; `pending`: not final yet; `unknown`: there is none to read — **not zero**.'),
|
|
72
|
-
gross: primitives_1.amount
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
85
|
+
.describe('`available`: settled, the figures are final; `pending`: not final yet; `unknown`: there is none to read — **not zero**. A dispute inquiry, which moves no money, and a refund that failed or was canceled are `unknown`.'),
|
|
86
|
+
gross: primitives_1.amount
|
|
87
|
+
.nullable()
|
|
88
|
+
.describe('The MAGNITUDE of the movement, never negative, in base units of `currency`: what the payment brought in, the refund took out or the dispute withdrew.'),
|
|
89
|
+
fee: primitives_1.signedAmount
|
|
90
|
+
.nullable()
|
|
91
|
+
.describe("The provider's fee on THIS movement, as the provider signs it: positive when charged to the balance (a payment's processing fee, a dispute fee), negative when returned to it (part of the original fee on some refunds). A refund's is usually `0`."),
|
|
92
|
+
net: primitives_1.signedAmount
|
|
93
|
+
.nullable()
|
|
94
|
+
.describe('The SIGNED effect on the balance: positive for a payment, negative for a refund or a dispute. Always `gross − fee` for a payment and `−gross − fee` for a refund or a dispute.'),
|
|
95
|
+
currency: primitives_1.nullableString.describe("The SETTLEMENT currency (uppercase ISO 4217) every figure is in, which may differ from the payment's, refund's or dispute's."),
|
|
76
96
|
available_on: primitives_1.unixSeconds.nullable().describe('When the funds become available.'),
|
|
77
97
|
exchange_rate: zod_1.z
|
|
78
98
|
.number()
|
|
@@ -228,6 +248,21 @@ exports.refundRoutes = [
|
|
|
228
248
|
sdk: 'refunds.settlement',
|
|
229
249
|
expandable: 'settlement',
|
|
230
250
|
}),
|
|
251
|
+
(0, route_1.defineRoute)({
|
|
252
|
+
operationId: 'retrieveRefundSettlement',
|
|
253
|
+
method: 'get',
|
|
254
|
+
path: '/v1/refunds/{id}/settlement',
|
|
255
|
+
tag: 'Refunds',
|
|
256
|
+
summary: "Retrieve a refund's settlement",
|
|
257
|
+
description: 'What the refund took off the settlement balance — `gross`, `fee`, a negative `net` — in the settlement currency, read live from the provider. A missing figure is `null` with a `status`, never `0`; a refund that failed or was canceled is `unknown`.',
|
|
258
|
+
auth: 'service',
|
|
259
|
+
scope: 'payments:read',
|
|
260
|
+
params: refundId,
|
|
261
|
+
query: params_1.expandOnlyQuery,
|
|
262
|
+
response: exports.settlementSchema,
|
|
263
|
+
sdk: 'refunds.refundSettlement',
|
|
264
|
+
expandable: 'settlement',
|
|
265
|
+
}),
|
|
231
266
|
(0, route_1.defineRoute)({
|
|
232
267
|
operationId: 'searchRefunds',
|
|
233
268
|
method: 'get',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.METER_STATUSES = exports.METER_AGGREGATIONS = exports.BILLING_SETTINGS_LIMITS = exports.DUNNING_INVOICE_ACTIONS = exports.DUNNING_FINAL_ACTIONS = exports.TEST_CLOCK_STATUSES = exports.RECURRING_INTERVAL_COUNT_MAX = exports.CATALOG_MAX_WHOLE_UNITS = exports.CATALOG_LIMITS = exports.COUPON_DURATIONS = exports.TRANSFORM_QUANTITY_ROUNDS = exports.PRICE_TAX_BEHAVIORS = exports.RECURRING_USAGE_TYPES = exports.RECURRING_INTERVALS = exports.PRICE_TYPES = exports.PRICE_TIERS_MODES = exports.PRICE_BILLING_SCHEMES = void 0;
|
|
4
4
|
exports.maxBaseUnits = maxBaseUnits;
|
|
5
5
|
// The catalog's and the billing engine platform's closed value sets (ADR 0016,
|
|
6
6
|
// ADR 0018): what a price, a coupon, a test clock, a meter and the billing
|
|
@@ -91,20 +91,4 @@ exports.BILLING_SETTINGS_LIMITS = Object.freeze({
|
|
|
91
91
|
/** How a meter combines a period's events into the quantity billed. */
|
|
92
92
|
exports.METER_AGGREGATIONS = ['sum', 'count', 'last'];
|
|
93
93
|
exports.METER_STATUSES = ['active', 'inactive'];
|
|
94
|
-
// ---- Recurring billing transport (`/v1/billing/*`) ---------------------------
|
|
95
|
-
/** A provider subscription's status, as the recurring transport observes it. */
|
|
96
|
-
exports.BILLING_SUBSCRIPTION_STATUSES = [
|
|
97
|
-
'incomplete',
|
|
98
|
-
'incomplete_expired',
|
|
99
|
-
'trialing',
|
|
100
|
-
'active',
|
|
101
|
-
'past_due',
|
|
102
|
-
'canceled',
|
|
103
|
-
'unpaid',
|
|
104
|
-
'paused',
|
|
105
|
-
];
|
|
106
|
-
/** `fiat` (Stripe and any further provider) or `faircoin` (native, to the merchant's watch-only wallet). */
|
|
107
|
-
exports.BILLING_RAIL_SETTLEMENTS = ['fiat', 'faircoin'];
|
|
108
|
-
/** `automatic`: the provider charges each period. `payer_initiated`: each period is an explicit payment. */
|
|
109
|
-
exports.BILLING_RAIL_RENEWALS = ['automatic', 'payer_initiated'];
|
|
110
94
|
// Product tax codes are Peable Tax's vocabulary: `vocabulary/tax.ts` (`TAX_CODES`).
|
|
@@ -47,19 +47,15 @@ exports.ERROR_CODE_DESCRIPTIONS = {
|
|
|
47
47
|
account_invalid: 'The `Peable-Account` header names no connected account of this platform.',
|
|
48
48
|
account_missing: 'The merchant has no account object yet.',
|
|
49
49
|
amount_not_representable: 'The amount does not fit the currency or the rail.',
|
|
50
|
-
billing_not_enabled: 'Billing is not enabled for this merchant.',
|
|
51
|
-
billing_provider_unavailable: 'The billing provider could not be reached; retry.',
|
|
52
50
|
domain_taken: 'The domain is already registered by another merchant.',
|
|
53
51
|
file_too_large: 'The uploaded file is larger than its purpose allows.',
|
|
54
52
|
file_unavailable: 'The file exists but its contents cannot be served right now.',
|
|
55
53
|
idempotency_error: 'The `Idempotency-Key` was used with a different request, or its first request is still running.',
|
|
56
54
|
idempotency_key_invalid: 'The `Idempotency-Key` header is not a valid key.',
|
|
57
55
|
insufficient_scope: 'The credential is valid but was not granted the Oxy scope this route requires (`payments:read`, `payments:write`, …); `message` names it.',
|
|
58
|
-
invalid_billing_request: 'The billing request is not valid for this subscription or offer.',
|
|
59
56
|
keyless_recipient: 'The recipient has no receive key, so no address can be derived for them.',
|
|
60
57
|
link_not_found: 'The link does not exist or is no longer active.',
|
|
61
58
|
live_payments_gated: 'Live payments are not enabled for this application yet.',
|
|
62
|
-
local_test_request_required: 'This test helper only answers a local test request.',
|
|
63
59
|
parameter_invalid: 'A parameter is invalid; `param` names it.',
|
|
64
60
|
parameter_missing: 'A required parameter is missing; `param` names it.',
|
|
65
61
|
parameter_unknown: 'The request carries a parameter this route does not accept; `param` names it.',
|
|
@@ -88,10 +84,7 @@ exports.ERROR_CODE_DESCRIPTIONS = {
|
|
|
88
84
|
customer_location_invalid: "The tax provider could not use the customer's location.",
|
|
89
85
|
dispute_already_submitted: 'Evidence for this dispute has already been submitted; it is one shot.',
|
|
90
86
|
dispute_not_answerable: 'The dispute is in a status that no longer accepts evidence.',
|
|
91
|
-
idempotency_conflict: 'The same operation key was used for a different billing request.',
|
|
92
|
-
identity_conflict: 'The billing identity already belongs to another customer or subscription.',
|
|
93
87
|
in_progress: 'The same operation is still running; retry with the same key.',
|
|
94
|
-
invalid_provider_response: 'The provider answered with something Peable cannot trust; the operation was not applied.',
|
|
95
88
|
invalid_registration: 'The tax registration is not valid.',
|
|
96
89
|
invalid_registration_declaration: 'The tax registration declaration is not valid.',
|
|
97
90
|
invalid_tax_code: 'The tax code does not exist.',
|
|
@@ -106,12 +99,9 @@ exports.ERROR_CODE_DESCRIPTIONS = {
|
|
|
106
99
|
product_in_use: 'The product is referenced by a subscription or a link.',
|
|
107
100
|
promotion_code_invalid: 'The promotion code does not exist, is inactive or does not apply.',
|
|
108
101
|
promotion_code_taken: 'Another active promotion code already uses this `code`.',
|
|
109
|
-
provider_unavailable: 'The payment provider could not be reached; retry.',
|
|
110
102
|
rail_unavailable: 'The payment rail this request needs is not available.',
|
|
111
|
-
reconciliation_required: 'The billing operation has an unknown outcome at the provider and is being reconciled.',
|
|
112
103
|
registration_immutable: 'An approved or ended tax registration cannot be deleted or changed this way; end it instead.',
|
|
113
104
|
resource_already_exists: 'An object with this identity already exists.',
|
|
114
|
-
result_expired: 'The stored result of this operation has expired.',
|
|
115
105
|
review_item_not_open: 'The review item is already resolved or dismissed.',
|
|
116
106
|
rule_set_version_unavailable: 'The tax rule set version is not available.',
|
|
117
107
|
subscription_line_invalid: 'A subscription line item is not valid for Checkout.',
|
|
@@ -119,9 +109,6 @@ exports.ERROR_CODE_DESCRIPTIONS = {
|
|
|
119
109
|
tax_calculation_unavailable: 'Tax could not be calculated; a covered sale fails closed.',
|
|
120
110
|
tax_provider_registration_mismatch: "The provider's registrations disagree with the ones Peable has approved.",
|
|
121
111
|
tax_settings_not_active: 'Tax settings are not active for this merchant.',
|
|
122
|
-
local_test_unavailable: 'The local test checkout is not available.',
|
|
123
|
-
local_test_configuration_unavailable: 'The local test checkout has no provider configuration.',
|
|
124
|
-
local_test_subscription_unavailable: 'The local test subscription cannot be read.',
|
|
125
112
|
rail_mismatch: 'The operation does not apply to the rail this payment uses.',
|
|
126
113
|
checkout_session_changed: 'The Checkout Session changed while this request ran (a price, a discount, its tax); read it again and retry.',
|
|
127
114
|
checkout_session_locked: 'The Checkout Session is being confirmed and cannot change.',
|
|
@@ -61,7 +61,6 @@ exports.WEBHOOK_EVENT_OBJECTS = {
|
|
|
61
61
|
'setup_intent.succeeded': 'setup_intent',
|
|
62
62
|
'setup_intent.setup_failed': 'setup_intent',
|
|
63
63
|
'setup_intent.canceled': 'setup_intent',
|
|
64
|
-
'billing.observation.updated': 'billing_observation',
|
|
65
64
|
'connected_account.updated': 'connected_account',
|
|
66
65
|
'product.created': 'product',
|
|
67
66
|
'product.updated': 'product',
|
|
@@ -151,10 +150,15 @@ exports.WEBHOOK_ENDPOINT_STATUSES = ['enabled', 'disabled'];
|
|
|
151
150
|
* - `delivery_failures` — every delivery to it failed for three days
|
|
152
151
|
* straight, so Peable stopped sending. Re-enabling it (`disabled: false`)
|
|
153
152
|
* starts the clock again.
|
|
153
|
+
* - `url_refused` — its stored `url` breaks the rules a URL is
|
|
154
|
+
* registered under (https in live mode, ports 80/443, no private, loopback
|
|
155
|
+
* or reserved address), judged again before every delivery, so Peable never
|
|
156
|
+
* sent to it. It is re-enabled only together with a `url` that passes.
|
|
154
157
|
*/
|
|
155
158
|
exports.WEBHOOK_ENDPOINT_DISABLED_REASONS = [
|
|
156
159
|
'disabled_by_merchant',
|
|
157
160
|
'delivery_failures',
|
|
161
|
+
'url_refused',
|
|
158
162
|
];
|
|
159
163
|
/** At most this many endpoints per merchant (per mode). */
|
|
160
164
|
exports.WEBHOOK_ENDPOINTS_MAX_PER_MERCHANT = 16;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Contracts of this group: one module per resource, re-exported here, and
|
|
2
2
|
// their routes concatenated into `catalogRoutes`.
|
|
3
|
-
import { billingRoutes } from './billing.js';
|
|
4
3
|
import { billingSettingsRoutes } from './billingSettings.js';
|
|
5
4
|
import { couponRoutes } from './coupons.js';
|
|
6
5
|
import { entitlementRoutes } from './entitlements.js';
|
|
@@ -9,7 +8,6 @@ import { priceRoutes } from './prices.js';
|
|
|
9
8
|
import { productRoutes } from './products.js';
|
|
10
9
|
import { promotionCodeRoutes } from './promotionCodes.js';
|
|
11
10
|
import { testClockRoutes } from './testClocks.js';
|
|
12
|
-
export * from './billing.js';
|
|
13
11
|
export * from './billingSettings.js';
|
|
14
12
|
export * from './coupons.js';
|
|
15
13
|
export * from './entitlements.js';
|
|
@@ -22,8 +20,7 @@ export * from './testClocks.js';
|
|
|
22
20
|
export { baseUnitAmountParam, queryFlag, queryIdList } from './shared.js';
|
|
23
21
|
/**
|
|
24
22
|
* The catalog (products, prices, coupons, promotion codes), entitlements, the
|
|
25
|
-
* billing engine's platform objects (test clocks, billing settings, meters)
|
|
26
|
-
* and the recurring billing transport (`/v1/billing/*`).
|
|
23
|
+
* billing engine's platform objects (test clocks, billing settings, meters).
|
|
27
24
|
*/
|
|
28
25
|
export const catalogRoutes = [
|
|
29
26
|
...productRoutes,
|
|
@@ -34,5 +31,4 @@ export const catalogRoutes = [
|
|
|
34
31
|
...testClockRoutes,
|
|
35
32
|
...billingSettingsRoutes,
|
|
36
33
|
...meterRoutes,
|
|
37
|
-
...billingRoutes,
|
|
38
34
|
];
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { CATALOG_LIMITS, PRICE_TAX_BEHAVIORS, RECURRING_INTERVALS } from '../../vocabulary/catalog.js';
|
|
3
3
|
import { SETUP_INTENT_STATUSES } from '../../vocabulary/payments.js';
|
|
4
|
-
import { billingFaircoinFxQuoteSchema } from '../catalog/billing.js';
|
|
5
4
|
import { embedded } from '../../common/objects.js';
|
|
6
5
|
import { listOf } from '../../common/envelopes.js';
|
|
7
6
|
import { defineComponent, defineObject, expandable } from '../../common/objects.js';
|
|
@@ -180,9 +179,6 @@ export const checkoutSessionPublicSchema = defineComponent('CheckoutSessionPubli
|
|
|
180
179
|
.string()
|
|
181
180
|
.nullable()
|
|
182
181
|
.describe("The card provider's PUBLIC key for this session's mode, so the payment fields can mount before the payment exists. `null` on FairCoin."),
|
|
183
|
-
billing_quote: billingFaircoinFxQuoteSchema
|
|
184
|
-
.optional()
|
|
185
|
-
.describe('FairCoin billing invoices: the frozen USD price and FAIR settlement quote.'),
|
|
186
182
|
})
|
|
187
183
|
.strict());
|
|
188
184
|
// ---- Merchant create/update ---------------------------------------------------
|
|
@@ -12,36 +12,6 @@ import { WEBHOOK_EVENT_OBJECTS, WEBHOOK_EVENT_TYPES, } from '../../vocabulary/ev
|
|
|
12
12
|
* every matching webhook endpoint: a delivery's body and `GET /v1/events/:id`
|
|
13
13
|
* are byte for byte the same object.
|
|
14
14
|
*/
|
|
15
|
-
/**
|
|
16
|
-
* The payload of `billing.observation.updated`: a wake-up, never paid or grant
|
|
17
|
-
* authority. Re-read the owner-bound resource it names.
|
|
18
|
-
*/
|
|
19
|
-
export const billingObservationSchema = defineObject('billing_observation', 'BillingObservation', z
|
|
20
|
-
.object({
|
|
21
|
-
object: z.literal('billing_observation'),
|
|
22
|
-
livemode: livemode.describe('The mode of the billing cohort observed (ADR 0017).'),
|
|
23
|
-
resource_kind: z.enum(['subscription', 'invoice']),
|
|
24
|
-
resource_id: z.string().describe('The provider subscription or invoice observed.'),
|
|
25
|
-
subscription_id: z
|
|
26
|
-
.string()
|
|
27
|
-
.optional()
|
|
28
|
-
.describe('Owner-scoped wake-up hint only; re-read the subscription before resolving a payer.'),
|
|
29
|
-
revision: z.number().int().describe('The observation revision; later revisions are newer.'),
|
|
30
|
-
observed_at: unixSeconds,
|
|
31
|
-
})
|
|
32
|
-
.strict(), {
|
|
33
|
-
examples: [
|
|
34
|
-
{
|
|
35
|
-
object: 'billing_observation',
|
|
36
|
-
livemode: false,
|
|
37
|
-
resource_kind: 'subscription',
|
|
38
|
-
resource_id: 'sub_1Q2w3E4r5T6y7U8i',
|
|
39
|
-
subscription_id: 'sub_1Q2w3E4r5T6y7U8i',
|
|
40
|
-
revision: 3,
|
|
41
|
-
observed_at: 1793750400,
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
});
|
|
45
15
|
/**
|
|
46
16
|
* What caused an event, when an API request did (Stripe's `event.request`).
|
|
47
17
|
* Both `null` for an event caused by something else — the chain watcher, the
|
|
@@ -238,7 +208,6 @@ export const WEBHOOK_EVENT_DESCRIPTIONS = {
|
|
|
238
208
|
'setup_intent.succeeded': 'A SetupIntent succeeded: its PaymentMethod is saved.',
|
|
239
209
|
'setup_intent.setup_failed': 'A SetupIntent attempt failed.',
|
|
240
210
|
'setup_intent.canceled': 'A SetupIntent was canceled.',
|
|
241
|
-
'billing.observation.updated': 'A recurring billing resource was observed to change. A wake-up only: re-read the resource.',
|
|
242
211
|
'connected_account.updated': "A seller's connected account changed — its readiness, in practice.",
|
|
243
212
|
'product.created': 'A Product was created.',
|
|
244
213
|
'product.updated': 'A Product was updated; `previous_attributes` names what moved.',
|
|
@@ -23,7 +23,7 @@ export const webhookDeliverySchema = defineObject('webhook_delivery', 'WebhookDe
|
|
|
23
23
|
delivered: z.boolean(),
|
|
24
24
|
last_status: z
|
|
25
25
|
.enum(WEBHOOK_DELIVERY_STATUSES)
|
|
26
|
-
.describe('`pending`: will be attempted (`next_attempt_at`). `delivered`: terminal success. `failed`: the endpoint refused it (a 4xx, a blocked address)
|
|
26
|
+
.describe('`pending`: will be attempted (`next_attempt_at`). `delivered`: terminal success. `failed`: the endpoint refused it (a 4xx, a blocked address), was disabled first, or its stored url breaks the registration rules — never retried. `dead`: every attempt failed transiently for three days; it can be redelivered.'),
|
|
27
27
|
last_error: z
|
|
28
28
|
.string()
|
|
29
29
|
.optional()
|
|
@@ -26,7 +26,7 @@ const endpointShape = {
|
|
|
26
26
|
disabled_reason: z
|
|
27
27
|
.enum(WEBHOOK_ENDPOINT_DISABLED_REASONS)
|
|
28
28
|
.nullable()
|
|
29
|
-
.describe('`null` exactly when `status` is `enabled`. `delivery_failures`: every delivery failed for three days straight.'),
|
|
29
|
+
.describe('`null` exactly when `status` is `enabled`. `delivery_failures`: every delivery failed for three days straight. `url_refused`: the stored `url` breaks the registration rules, judged before every delivery; re-enable it with a `url` that passes.'),
|
|
30
30
|
api_version: z.string().describe('The wire version events are rendered with for this endpoint.'),
|
|
31
31
|
metadata,
|
|
32
32
|
created: unixSeconds,
|
|
@@ -4,6 +4,7 @@ import { defineComponent, defineObject, expandable } from '../../common/objects.
|
|
|
4
4
|
import { expandOnlyQuery, idParam, listQuery, metadataUpdateParam } from '../../common/params.js';
|
|
5
5
|
import { amount, currency, livemode, metadata, unixSeconds } from '../../common/primitives.js';
|
|
6
6
|
import { defineRoute } from '../../route.js';
|
|
7
|
+
import { settlementSchema } from './refunds.js';
|
|
7
8
|
import { DISPUTE_EVIDENCE_TEXT_MAX, DISPUTE_FILE_EVIDENCE_FIELDS, DISPUTE_REASONS, DISPUTE_STATUSES, DISPUTE_TEXT_EVIDENCE_FIELDS, } from '../../vocabulary/payments.js';
|
|
8
9
|
/**
|
|
9
10
|
* Disputes (`dp_…`) — the card network holding a payment's money while a
|
|
@@ -198,4 +199,19 @@ export const disputeRoutes = [
|
|
|
198
199
|
response: disputeSchema,
|
|
199
200
|
sdk: 'disputes.close',
|
|
200
201
|
}),
|
|
202
|
+
defineRoute({
|
|
203
|
+
operationId: 'retrieveDisputeSettlement',
|
|
204
|
+
method: 'get',
|
|
205
|
+
path: '/v1/disputes/{disputeId}/settlement',
|
|
206
|
+
tag: 'Disputes',
|
|
207
|
+
summary: "Retrieve a dispute's settlement",
|
|
208
|
+
description: 'What the dispute WITHDREW from the settlement balance — `gross` the principal, `fee` the dispute fee, a negative `net` — in the settlement currency, read live from the provider. An inquiry moves no money: `unknown`, every figure `null`, never `0`. A reinstatement after a won dispute is not this figure.',
|
|
209
|
+
auth: 'service',
|
|
210
|
+
scope: 'payments:read',
|
|
211
|
+
params: disputeId,
|
|
212
|
+
query: expandOnlyQuery,
|
|
213
|
+
response: settlementSchema,
|
|
214
|
+
sdk: 'disputes.settlement',
|
|
215
|
+
expandable: 'settlement',
|
|
216
|
+
}),
|
|
201
217
|
];
|
|
@@ -7,7 +7,8 @@ import { defineRoute } from '../../route.js';
|
|
|
7
7
|
import { isBaseUnitString } from '../../vocabulary/money.js';
|
|
8
8
|
import { REFUND_ORIGINS, REFUND_REASONS, REFUND_STATUSES, SETTLEMENT_STATUSES, } from '../../vocabulary/payments.js';
|
|
9
9
|
/**
|
|
10
|
-
* Refunds (`re_…`) and a payment
|
|
10
|
+
* Refunds (`re_…`) and the settlement figures of a payment, a refund or a
|
|
11
|
+
* dispute. The provider's own
|
|
11
12
|
* refund id never appears: a merchant integrates against Peable and never
|
|
12
13
|
* learns which acquirer sat behind it (ADR 0001 D3).
|
|
13
14
|
*/
|
|
@@ -53,23 +54,42 @@ export const refundSchema = defineObject('refund', 'Refund', z
|
|
|
53
54
|
],
|
|
54
55
|
});
|
|
55
56
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
57
|
+
* One movement of the settlement balance, as the PROVIDER reports it: what a
|
|
58
|
+
* payment brought in (`GET /v1/payment_intents/{intentId}/settlement`), what a
|
|
59
|
+
* refund took out (`GET /v1/refunds/{id}/settlement`) or what a dispute
|
|
60
|
+
* withdrew (`GET /v1/disputes/{disputeId}/settlement`). `refund` and `dispute`
|
|
61
|
+
* say which: both `null` for a payment's.
|
|
62
|
+
*
|
|
63
|
+
* Every figure is nullable and that is the contract: "the fee was zero" and
|
|
64
|
+
* "the fee is not known yet" are different facts, and `status` says which
|
|
65
|
+
* produced the nulls. It reports what the provider took; it attributes that
|
|
66
|
+
* cost to nobody.
|
|
67
|
+
*
|
|
68
|
+
* The signs: `gross` is the MAGNITUDE of the movement, `fee` the provider's fee
|
|
69
|
+
* on it (positive when charged, negative when returned), `net` its SIGNED
|
|
70
|
+
* effect on the balance — so `net = gross − fee` for a payment and
|
|
71
|
+
* `net = −gross − fee` for a refund or a dispute.
|
|
60
72
|
*/
|
|
61
73
|
export const settlementSchema = defineObject('settlement', 'Settlement', z
|
|
62
74
|
.object({
|
|
63
75
|
object: z.literal('settlement'),
|
|
64
76
|
livemode,
|
|
65
|
-
payment_intent: expandable('payment_intent', 'The `pi_…` this describes, or the PaymentIntent with `expand[]=payment_intent`.'),
|
|
77
|
+
payment_intent: expandable('payment_intent', 'The `pi_…` this describes (the refunded or disputed payment, for a refund or a dispute), or the PaymentIntent with `expand[]=payment_intent`.'),
|
|
78
|
+
refund: expandable('refund', 'The `re_…` whose movement this is, or the Refund with `expand[]=refund`; `null` unless this is the settlement of a refund.').nullable(),
|
|
79
|
+
dispute: expandable('dispute', 'The `dp_…` whose withdrawal this is, or the Dispute with `expand[]=dispute`; `null` unless this is the settlement of a dispute.').nullable(),
|
|
66
80
|
status: z
|
|
67
81
|
.enum(SETTLEMENT_STATUSES)
|
|
68
|
-
.describe('`available`: settled, the figures are final; `pending`: not final yet; `unknown`: there is none to read — **not zero**.'),
|
|
69
|
-
gross: amount
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
82
|
+
.describe('`available`: settled, the figures are final; `pending`: not final yet; `unknown`: there is none to read — **not zero**. A dispute inquiry, which moves no money, and a refund that failed or was canceled are `unknown`.'),
|
|
83
|
+
gross: amount
|
|
84
|
+
.nullable()
|
|
85
|
+
.describe('The MAGNITUDE of the movement, never negative, in base units of `currency`: what the payment brought in, the refund took out or the dispute withdrew.'),
|
|
86
|
+
fee: signedAmount
|
|
87
|
+
.nullable()
|
|
88
|
+
.describe("The provider's fee on THIS movement, as the provider signs it: positive when charged to the balance (a payment's processing fee, a dispute fee), negative when returned to it (part of the original fee on some refunds). A refund's is usually `0`."),
|
|
89
|
+
net: signedAmount
|
|
90
|
+
.nullable()
|
|
91
|
+
.describe('The SIGNED effect on the balance: positive for a payment, negative for a refund or a dispute. Always `gross − fee` for a payment and `−gross − fee` for a refund or a dispute.'),
|
|
92
|
+
currency: nullableString.describe("The SETTLEMENT currency (uppercase ISO 4217) every figure is in, which may differ from the payment's, refund's or dispute's."),
|
|
73
93
|
available_on: unixSeconds.nullable().describe('When the funds become available.'),
|
|
74
94
|
exchange_rate: z
|
|
75
95
|
.number()
|
|
@@ -225,6 +245,21 @@ export const refundRoutes = [
|
|
|
225
245
|
sdk: 'refunds.settlement',
|
|
226
246
|
expandable: 'settlement',
|
|
227
247
|
}),
|
|
248
|
+
defineRoute({
|
|
249
|
+
operationId: 'retrieveRefundSettlement',
|
|
250
|
+
method: 'get',
|
|
251
|
+
path: '/v1/refunds/{id}/settlement',
|
|
252
|
+
tag: 'Refunds',
|
|
253
|
+
summary: "Retrieve a refund's settlement",
|
|
254
|
+
description: 'What the refund took off the settlement balance — `gross`, `fee`, a negative `net` — in the settlement currency, read live from the provider. A missing figure is `null` with a `status`, never `0`; a refund that failed or was canceled is `unknown`.',
|
|
255
|
+
auth: 'service',
|
|
256
|
+
scope: 'payments:read',
|
|
257
|
+
params: refundId,
|
|
258
|
+
query: expandOnlyQuery,
|
|
259
|
+
response: settlementSchema,
|
|
260
|
+
sdk: 'refunds.refundSettlement',
|
|
261
|
+
expandable: 'settlement',
|
|
262
|
+
}),
|
|
228
263
|
defineRoute({
|
|
229
264
|
operationId: 'searchRefunds',
|
|
230
265
|
method: 'get',
|
|
@@ -87,20 +87,4 @@ export const BILLING_SETTINGS_LIMITS = Object.freeze({
|
|
|
87
87
|
/** How a meter combines a period's events into the quantity billed. */
|
|
88
88
|
export const METER_AGGREGATIONS = ['sum', 'count', 'last'];
|
|
89
89
|
export const METER_STATUSES = ['active', 'inactive'];
|
|
90
|
-
// ---- Recurring billing transport (`/v1/billing/*`) ---------------------------
|
|
91
|
-
/** A provider subscription's status, as the recurring transport observes it. */
|
|
92
|
-
export const BILLING_SUBSCRIPTION_STATUSES = [
|
|
93
|
-
'incomplete',
|
|
94
|
-
'incomplete_expired',
|
|
95
|
-
'trialing',
|
|
96
|
-
'active',
|
|
97
|
-
'past_due',
|
|
98
|
-
'canceled',
|
|
99
|
-
'unpaid',
|
|
100
|
-
'paused',
|
|
101
|
-
];
|
|
102
|
-
/** `fiat` (Stripe and any further provider) or `faircoin` (native, to the merchant's watch-only wallet). */
|
|
103
|
-
export const BILLING_RAIL_SETTLEMENTS = ['fiat', 'faircoin'];
|
|
104
|
-
/** `automatic`: the provider charges each period. `payer_initiated`: each period is an explicit payment. */
|
|
105
|
-
export const BILLING_RAIL_RENEWALS = ['automatic', 'payer_initiated'];
|
|
106
90
|
// Product tax codes are Peable Tax's vocabulary: `vocabulary/tax.ts` (`TAX_CODES`).
|