@peable.to/contracts 3.1.0 → 4.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 (43) hide show
  1. package/dist/cjs/resources/billingEngine/public.js +22 -3
  2. package/dist/cjs/resources/checkout/checkoutSessions.js +34 -9
  3. package/dist/cjs/resources/checkout/merchants.js +10 -23
  4. package/dist/cjs/resources/checkout/paymentMethodConfigurations.js +56 -10
  5. package/dist/cjs/resources/connect/balance.js +5 -0
  6. package/dist/cjs/resources/connect/connectedAccounts.js +11 -12
  7. package/dist/cjs/resources/connect/onboarding.js +13 -24
  8. package/dist/cjs/resources/payments/paymentIntents.js +39 -2
  9. package/dist/cjs/vocabulary/checkout.js +18 -1
  10. package/dist/cjs/vocabulary/errors.js +5 -3
  11. package/dist/cjs/vocabulary/paymentMethodConfigurations.js +24 -4
  12. package/dist/esm/resources/billingEngine/public.js +22 -3
  13. package/dist/esm/resources/checkout/checkoutSessions.js +35 -10
  14. package/dist/esm/resources/checkout/merchants.js +10 -23
  15. package/dist/esm/resources/checkout/paymentMethodConfigurations.js +57 -11
  16. package/dist/esm/resources/connect/balance.js +5 -0
  17. package/dist/esm/resources/connect/connectedAccounts.js +11 -12
  18. package/dist/esm/resources/connect/onboarding.js +12 -23
  19. package/dist/esm/resources/payments/paymentIntents.js +39 -2
  20. package/dist/esm/vocabulary/checkout.js +17 -0
  21. package/dist/esm/vocabulary/errors.js +5 -3
  22. package/dist/esm/vocabulary/paymentMethodConfigurations.js +25 -5
  23. package/dist/types/resources/billingEngine/index.d.ts +16 -2
  24. package/dist/types/resources/billingEngine/public.d.ts +32 -3
  25. package/dist/types/resources/checkout/checkoutSessions.d.ts +96 -31
  26. package/dist/types/resources/checkout/index.d.ts +406 -41
  27. package/dist/types/resources/checkout/merchants.d.ts +17 -28
  28. package/dist/types/resources/checkout/paymentMethodConfigurations.d.ts +440 -8
  29. package/dist/types/resources/connect/balance.d.ts +98 -5
  30. package/dist/types/resources/connect/connectedAccounts.d.ts +4 -4
  31. package/dist/types/resources/connect/index.d.ts +101 -10
  32. package/dist/types/resources/connect/onboarding.d.ts +15 -15
  33. package/dist/types/resources/connect/payouts.d.ts +64 -2
  34. package/dist/types/resources/payments/index.d.ts +310 -0
  35. package/dist/types/resources/payments/paymentIntents.d.ts +380 -0
  36. package/dist/types/resources/payments/testHelpers.d.ts +31 -0
  37. package/dist/types/resources/tax/deadlines.d.ts +3 -3
  38. package/dist/types/resources/tax/index.d.ts +2 -2
  39. package/dist/types/resources/tax/registrations.d.ts +2 -2
  40. package/dist/types/vocabulary/checkout.d.ts +13 -0
  41. package/dist/types/vocabulary/errors.d.ts +5 -3
  42. package/dist/types/vocabulary/paymentMethodConfigurations.d.ts +21 -7
  43. package/package.json +1 -1
@@ -1,10 +1,18 @@
1
1
  "use strict";
2
- // Payment method breadth on the card rail (`pmc_…`, `pmd_…`). Zod-free.
2
+ // Payment method breadth (`pmc_…`, `pmd_…`): the merchant's card-rail methods,
3
+ // and FairCoin, which is always offered (ADR 0021). Zod-free.
3
4
  Object.defineProperty(exports, "__esModule", { value: true });
4
5
  exports.PAYMENT_METHOD_CURRENCIES = exports.PAYMENT_METHOD_UNAVAILABLE_REASONS = exports.PAYMENT_METHOD_CONFIGURATION_TYPES = void 0;
5
6
  const money_1 = require("./money");
6
7
  /**
7
- * The methods a configuration can turn on.
8
+ * The methods a configuration lists.
9
+ *
10
+ * `faircoin` is listed and LOCKED (ADR 0021 D2): every payer can always pay
11
+ * with FairCoin, so its entry is always `display_preference.value: 'on'` with
12
+ * `locked: true`, and a create or update that sets it `off` is refused with
13
+ * `payment_method_locked`. It is the chain rail, never a card-provider method:
14
+ * it is never pushed to the provider and never appears in a card PaymentIntent's
15
+ * `payment_method_types`. Every other method is the merchant's to turn on and off.
8
16
  *
9
17
  * `apple_pay` and `google_pay` are WALLETS over a card: a payment made with one
10
18
  * is a `card` payment, so they appear here and never in a PaymentIntent's
@@ -16,6 +24,7 @@ const money_1 = require("./money");
16
24
  * scheme).
17
25
  */
18
26
  exports.PAYMENT_METHOD_CONFIGURATION_TYPES = [
27
+ 'faircoin',
19
28
  'card',
20
29
  'apple_pay',
21
30
  'google_pay',
@@ -29,18 +38,29 @@ exports.PAYMENT_METHOD_CONFIGURATION_TYPES = [
29
38
  * Why a method cannot be offered whatever the merchant chooses.
30
39
  *
31
40
  * - `provider_unsupported` — the processing provider does not offer it;
32
- * - `requires_card` — a wallet rides on card payments, and card is off.
41
+ * - `requires_card` — a wallet rides on card payments, and card is off;
42
+ * - `faircoin_wallet_missing` — the Peable wallet of the account that owns
43
+ * the merchant isn't set up yet (no identity key), so FairCoin cannot be
44
+ * received (ADR 0021 D5); the owner sets it up in Peable;
45
+ * - `faircoin_network_closed` — the deployment does not open the merchant's
46
+ * FairCoin network yet (ADR 0002's gate);
47
+ * - `temporarily_unavailable` — the wallet could not be checked just now.
33
48
  */
34
49
  exports.PAYMENT_METHOD_UNAVAILABLE_REASONS = [
35
50
  'provider_unsupported',
36
51
  'requires_card',
52
+ 'faircoin_wallet_missing',
53
+ 'faircoin_network_closed',
54
+ 'temporarily_unavailable',
37
55
  ];
38
56
  /**
39
57
  * The currencies each method can take a payment in. A method is offered on a
40
58
  * payment only when its currency is listed — so iDEAL never appears on a USD
41
- * payment, and a payer is never shown a method that would fail.
59
+ * payment, and a payer is never shown a method that would fail. FairCoin takes
60
+ * every currency: a `FAIR` order directly, a fiat one at a quoted price (ADR 0021).
42
61
  */
43
62
  exports.PAYMENT_METHOD_CURRENCIES = Object.freeze({
63
+ faircoin: money_1.CURRENCY_CODES,
44
64
  card: money_1.FIAT_CURRENCY_CODES,
45
65
  apple_pay: money_1.FIAT_CURRENCY_CODES,
46
66
  google_pay: money_1.FIAT_CURRENCY_CODES,
@@ -5,6 +5,7 @@ import { idParam } from '../../common/params.js';
5
5
  import { amount, currency, livemode, signedAmount, unixSeconds } from '../../common/primitives.js';
6
6
  import { defineRoute } from '../../route.js';
7
7
  import { PORTAL_PAYMENT_METHOD_UPDATE_STATUSES } from '../../vocabulary/billingPortal.js';
8
+ import { FAIRCOIN_UNAVAILABLE_REASONS } from '../../vocabulary/checkout.js';
8
9
  import { INVOICE_STATUSES, PUBLIC_INVOICE_PAYMENT_METHOD_TYPES } from '../../vocabulary/invoices.js';
9
10
  import { COLLECTION_METHODS, SUBSCRIPTION_STATUSES } from '../../vocabulary/subscriptions.js';
10
11
  import { billingPortalBusinessProfileSchema, billingPortalFeaturesSchema } from './billingPortal.js';
@@ -54,7 +55,17 @@ export const publicInvoiceSchema = defineObject('public_invoice', 'PublicInvoice
54
55
  paid_at: unixSeconds.nullable(),
55
56
  payment_method_types: z
56
57
  .array(z.enum(PUBLIC_INVOICE_PAYMENT_METHOD_TYPES))
57
- .describe("Which rail pays it: a card through the provider's fields, FairCoin from the payer's wallet."),
58
+ .describe("What the payer may choose: `['card', 'faircoin']` on a fiat invoice, `['faircoin']` on a FAIR one. FairCoin is always offered (ADR 0021); on a fiat invoice it is quoted when chosen."),
59
+ faircoin: z
60
+ .object({
61
+ available: z.boolean(),
62
+ unavailable_reason: z
63
+ .enum(FAIRCOIN_UNAVAILABLE_REASONS)
64
+ .nullable()
65
+ .describe('Why FairCoin cannot be paid with right now; it is still shown, never hidden.'),
66
+ })
67
+ .strict()
68
+ .describe('Whether the payer can choose FairCoin now (ADR 0021).'),
58
69
  invoice_pdf: z.string(),
59
70
  })
60
71
  .strict());
@@ -178,7 +189,15 @@ export const portalPaymentMethodUpdateResultSchema = defineComponent('PortalPaym
178
189
  })
179
190
  .strict());
180
191
  // ---- Requests ------------------------------------------------------------------------
181
- export const payPublicInvoiceParams = emptyBody;
192
+ /** How the payer pays the invoice (ADR 0021 D3). */
193
+ export const payPublicInvoiceParams = z
194
+ .object({
195
+ payment_method_type: z
196
+ .enum(PUBLIC_INVOICE_PAYMENT_METHOD_TYPES)
197
+ .optional()
198
+ .describe("One of the invoice's `payment_method_types`. Default: the rail of its currency (`card` on a fiat invoice). `faircoin` on a fiat invoice quotes the amount due in FAIR for 10 minutes; paying again with the other method replaces a payment that has not started moving money."),
199
+ })
200
+ .strict();
182
201
  /** A portal action on one of the customer's subscriptions. */
183
202
  export const portalSubscriptionParams = z.object({ subscription: idParam }).strict();
184
203
  /** Switch a (single-item) subscription to one of the configuration's plans, or change its quantity. */
@@ -221,7 +240,7 @@ export const publicBillingRoutes = [
221
240
  path: '/v1/invoices/public/{token}/pay',
222
241
  tag: 'Hosted invoices',
223
242
  summary: 'Pay a hosted invoice',
224
- description: 'The PaymentIntent the payer completes — a card through the provider’s own fields, FairCoin from the payer’s wallet. The same invoice answers the same intent while it can still be paid.',
243
+ description: 'The PaymentIntent the payer completes in the method they chose — a card through the provider’s own fields, or FairCoin from the payer’s wallet (quoted on a fiat invoice, ADR 0021). The same invoice answers the same intent while it can still be paid in that method.',
225
244
  auth: 'public',
226
245
  params: invoiceToken,
227
246
  body: payPublicInvoiceParams,
@@ -7,7 +7,7 @@ import { defineComponent, defineObject, expandable } from '../../common/objects.
7
7
  import { expandOnlyQuery, expandParam, listQuery, metadataCreateParam, metadataUpdateParam, } from '../../common/params.js';
8
8
  import { amount, currency, livemode, metadata, network, unixSeconds, } from '../../common/primitives.js';
9
9
  import { defineRoute } from '../../route.js';
10
- import { CHECKOUT_CUSTOMER_CREATIONS, CHECKOUT_LIMITS, CHECKOUT_LOCALES, CHECKOUT_PAYMENT_STATUSES, CHECKOUT_SESSION_MODES, CHECKOUT_SESSION_STATUSES, CHECKOUT_SUBMIT_TYPES, CHECKOUT_TAX_ID_TYPES, CHECKOUT_UI_MODES, } from '../../vocabulary/checkout.js';
10
+ import { CHECKOUT_CUSTOMER_CREATIONS, CHECKOUT_LIMITS, CHECKOUT_LOCALES, CHECKOUT_PAYMENT_STATUSES, CHECKOUT_SESSION_MODES, CHECKOUT_SESSION_STATUSES, CHECKOUT_SUBMIT_TYPES, CHECKOUT_TAX_ID_TYPES, CHECKOUT_UI_MODES, FAIRCOIN_UNAVAILABLE_REASONS, } from '../../vocabulary/checkout.js';
11
11
  import { adjustableIssues, adjustableQuantityParam, amountParam, checkoutAutomaticTaxSchema, checkoutBrandingSchema, checkoutConsentSchema, checkoutCustomerDetailsSchema, checkoutDiscountSchema, checkoutIdParam, checkoutLineItemSchema, checkoutShippingDetailsSchema, checkoutTotalDetailsSchema, collectionParams, collectionResponseFields, countryCodeParam, checkoutEmailParam, localeParam, merchantDisplaySchema, quantityParam, railSchema, redirectUrlParam, } from './shared.js';
12
12
  /**
13
13
  * Checkout Sessions (`cs_…`, Orbit Phase 3) — Stripe Checkout's session model:
@@ -30,8 +30,13 @@ const sessionFields = {
30
30
  .describe("The language checkout renders in; `null` follows the payer's browser."),
31
31
  submit_type: z.enum(CHECKOUT_SUBMIT_TYPES),
32
32
  currency,
33
- rail: railSchema,
34
- network: network.nullable().describe('FairCoin rail only; `null` on a card session.'),
33
+ rail: railSchema.describe("The rail that settles the order's currency: `faircoin` for a FAIR order, `card` for a fiat one. FairCoin is offered on every order beside it (`payment_method_types`, ADR 0021)."),
34
+ network: network
35
+ .nullable()
36
+ .describe('The FairCoin network a FairCoin payment of this order uses — the merchant’s (or the seller’s); `null` when the payee has no FairCoin key yet (test mode) and in `setup` mode.'),
37
+ payment_method_types: z
38
+ .array(railSchema)
39
+ .describe("What the payer may choose: `['card', 'faircoin']` on a fiat order, `['faircoin']` on a FAIR one. FairCoin is always offered (ADR 0021); `['card']` in `setup` mode."),
35
40
  amount_subtotal: amount,
36
41
  amount_total: amount,
37
42
  total_details: checkoutTotalDetailsSchema,
@@ -46,7 +51,6 @@ const sessionFields = {
46
51
  export const checkoutSessionSchema = defineObject('checkout_session', 'CheckoutSession', z
47
52
  .object({
48
53
  ...sessionFields,
49
- payment_method_types: z.array(railSchema),
50
54
  discounts: z.array(checkoutDiscountSchema),
51
55
  customer: expandable('customer', '`cus_…` (expandable) — given on create, or created at completion.').nullable(),
52
56
  customer_email: z.string().nullable(),
@@ -90,8 +94,8 @@ export const checkoutSessionSchema = defineObject('checkout_session', 'CheckoutS
90
94
  submit_type: 'auto',
91
95
  currency: 'EUR',
92
96
  rail: 'card',
93
- network: null,
94
- payment_method_types: ['card'],
97
+ network: 'mainnet',
98
+ payment_method_types: ['card', 'faircoin'],
95
99
  amount_subtotal: '1999',
96
100
  amount_total: '1999',
97
101
  total_details: { amount_discount: '0', amount_tax: '0', amount_shipping: '0' },
@@ -179,6 +183,17 @@ export const checkoutSessionPublicSchema = defineComponent('CheckoutSessionPubli
179
183
  .string()
180
184
  .nullable()
181
185
  .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
+ faircoin: z
187
+ .object({
188
+ available: z.boolean(),
189
+ unavailable_reason: z
190
+ .enum(FAIRCOIN_UNAVAILABLE_REASONS)
191
+ .nullable()
192
+ .describe('Why FairCoin cannot be paid with right now; it is still shown, never hidden.'),
193
+ })
194
+ .strict()
195
+ .nullable()
196
+ .describe('Whether the payer can choose FairCoin now (ADR 0021). On a fiat order the FAIR amount is quoted when the payer chooses it (`payment_intent.faircoin.quote`). `null` in `setup` mode.'),
182
197
  })
183
198
  .strict());
184
199
  // ---- Merchant create/update ---------------------------------------------------
@@ -279,9 +294,9 @@ export const createCheckoutSessionParams = z
279
294
  payment_method_types: z
280
295
  .array(z.enum(['card', 'faircoin']))
281
296
  .min(1)
282
- .max(1)
297
+ .max(2)
283
298
  .optional()
284
- .describe("`['card']` or `['faircoin']` — the rail the line items' currency allows."),
299
+ .describe("Must include `faircoin`, which is always offered (ADR 0021; leaving it out is 400 `payment_method_locked`): `['card', 'faircoin']` on a fiat order, `['faircoin']` on a FAIR one. Omit it for exactly that. The fiat methods are chosen in the payment method configuration."),
285
300
  locale: localeParam.optional(),
286
301
  ui_mode: z.enum(CHECKOUT_UI_MODES).optional(),
287
302
  success_url: redirectUrlParam
@@ -425,8 +440,18 @@ export const updateCheckoutSessionPublicParams = z
425
440
  .optional(),
426
441
  })
427
442
  .strict();
428
- /** `POST /v1/checkout_sessions/{id}/public/confirm` takes nothing: the order is the session's. */
429
- export const confirmCheckoutSessionPublicParams = z.object({}).strict();
443
+ /**
444
+ * `POST /v1/checkout_sessions/{id}/public/confirm` — the order is the
445
+ * session's; the payer only chooses how to pay it (ADR 0021 D3).
446
+ */
447
+ export const confirmCheckoutSessionPublicParams = z
448
+ .object({
449
+ payment_method_type: z
450
+ .enum(['card', 'faircoin'])
451
+ .optional()
452
+ .describe("How the payer pays: one of the session's `payment_method_types`. Default: the rail of the order's currency (`card` on a fiat order). `faircoin` on a fiat order quotes its total in FAIR for 10 minutes; confirming again with the other method replaces a payment that has not started moving money."),
453
+ })
454
+ .strict();
430
455
  /** `POST /v1/test_helpers/checkout_sessions/{id}/expire` takes nothing. */
431
456
  export const expireCheckoutSessionTestHelperParams = z.object({}).strict();
432
457
  const sessionId = { id: 'The Checkout Session (`cs_…`).' };
@@ -17,13 +17,11 @@ export const merchantSchema = defineObject('merchant', 'Merchant', z
17
17
  livemode: livemode.describe('`true` for a `production` merchant (ADR 0017).'),
18
18
  oxy_app_id: z.string().describe('The Oxy application this merchant belongs to.'),
19
19
  environment: z.enum(MERCHANT_ENVIRONMENTS),
20
- network: network
21
- .nullable()
22
- .describe('The FairCoin chain this merchant accepts on; `null` on a card-only merchant. Nullable together with `xpub`.'),
23
- xpub: z
20
+ network: network.describe("The FairCoin network this merchant's payments use — its environment's: `mainnet` live, `testnet` otherwise (ADR 0021 D5)."),
21
+ owner_account: z
24
22
  .string()
25
23
  .nullable()
26
- .describe('The watch-only account key receive addresses derive from; `null` on a card-only merchant.'),
24
+ .describe('The Oxy account (a person or an organization) that owns the application — its Peable wallet receives the merchant’s FairCoin (ADR 0021 D5). No key is ever registered. `null` until Peable has seen the owner.'),
27
25
  required_confirmations: z.number().int().positive(),
28
26
  display_name: z
29
27
  .string()
@@ -50,7 +48,7 @@ export const merchantSchema = defineObject('merchant', 'Merchant', z
50
48
  oxy_app_id: 'app_0193b8f2c1a87d3e9f4b',
51
49
  environment: 'development',
52
50
  network: 'testnet',
53
- xpub: 'tpubDC5FSnBiZDMmhiuCmWAYsLwgLYrrT9rAqvTySfuCCrgsWz8wxMXUS9Tb9iVMvcRbvFcAHGkMD5Kx8koh4GquNGNTfohfk7pgjhaPCdXpoba',
51
+ owner_account: '0193b8f2-c1a8-7d3e-9f4a-5b6c7d8e9f01',
54
52
  required_confirmations: 6,
55
53
  display_name: 'Jenny’s Plants',
56
54
  created: 1793750400,
@@ -66,32 +64,21 @@ const displayName = z.string().min(1).max(64);
66
64
  const avatarFileId = z.string().min(1).max(128);
67
65
  const merchantDescription = z.string().min(1).max(512);
68
66
  /**
69
- * `POST /v1/merchants`. The FairCoin half is OPTIONAL — both `network` and
70
- * `xpub`, or neither: a card-only merchant supplies no key for a chain it
71
- * never intends to use.
67
+ * `POST /v1/merchants`. No FairCoin key and no network: the network is the
68
+ * environment's, and FairCoin is received into the Peable wallet of the
69
+ * account that owns the application (ADR 0021 D5).
72
70
  */
73
71
  export const registerMerchantParams = z
74
72
  .object({
75
- network: network.optional(),
76
- xpub: z
77
- .string()
78
- .min(1)
79
- .optional()
80
- .describe('A watch-only account xpub. A private extended key is refused.'),
81
73
  required_confirmations: z.number().int().positive().optional(),
82
74
  display_name: displayName.optional(),
83
75
  avatar_file_id: avatarFileId.optional(),
84
76
  description: merchantDescription.optional(),
85
77
  })
86
- .strict()
87
- .refine((body) => (body.network === undefined) === (body.xpub === undefined), {
88
- message: 'accepting FairCoin needs both a network and a watch-only xpub, or neither — ' +
89
- 'omit both to register a card-only merchant',
90
- });
78
+ .strict();
91
79
  /**
92
- * `POST /v1/merchants/me`. `null` clears a field. The key, network and
93
- * environment never change: addresses already derived from the key, and the
94
- * test/live firewall, depend on them.
80
+ * `POST /v1/merchants/me`. `null` clears a field. The network and environment
81
+ * never change: the test/live firewall depends on them.
95
82
  */
96
83
  export const updateMerchantParams = z
97
84
  .object({
@@ -2,15 +2,17 @@ import { z } from 'zod';
2
2
  import { listOf } from '../../common/envelopes.js';
3
3
  import { defineComponent, defineObject } from '../../common/objects.js';
4
4
  import { expandOnlyQuery, listQuery, queryBoolean } from '../../common/params.js';
5
- import { fiatCurrency, livemode, unixSeconds } from '../../common/primitives.js';
5
+ import { currency, livemode, unixSeconds } from '../../common/primitives.js';
6
6
  import { defineRoute } from '../../route.js';
7
7
  import { PAYMENT_METHOD_CONFIGURATION_TYPES, PAYMENT_METHOD_UNAVAILABLE_REASONS, } from '../../vocabulary/paymentMethodConfigurations.js';
8
8
  /**
9
- * Payment method breadth on the card rail — which methods a merchant's payers
10
- * are offered (`pmc_…`), and the web domains wallets may run on (`pmd_…`).
11
- * Both are Orbit's objects; the provider's configuration and domain are
12
- * bindings behind them (ADR 0016). Card data and bank credentials are entered
13
- * in the provider's hosted fields and never reach Peable (PCI SAQ-A).
9
+ * Payment method breadth — which methods a merchant's payers are offered
10
+ * (`pmc_…`), and the web domains wallets may run on (`pmd_…`). FairCoin is an
11
+ * entry of every configuration and is locked on (ADR 0021 D2); the card-rail
12
+ * methods are the merchant's choice. Both are Orbit's objects; the provider's
13
+ * configuration and domain are bindings behind them (ADR 0016). Card data and
14
+ * bank credentials are entered in the provider's hosted fields and never reach
15
+ * Peable (PCI SAQ-A).
14
16
  */
15
17
  /** The merchant's choice (`none`: Orbit's default) and what is in effect. */
16
18
  export const paymentMethodDisplayPreferenceSchema = z
@@ -25,13 +27,28 @@ export const paymentMethodConfigurationEntrySchema = defineComponent('PaymentMet
25
27
  .boolean()
26
28
  .describe('Whether payers can be offered this method: it is on and nothing prevents it.'),
27
29
  display_preference: paymentMethodDisplayPreferenceSchema,
30
+ locked: z
31
+ .boolean()
32
+ .describe('Whether the merchant can change it. Only `faircoin` is locked: it is always on, because every payer can always pay with FairCoin (ADR 0021), and setting it `off` is refused with `payment_method_locked`.'),
28
33
  unavailable_reason: z
29
34
  .enum(PAYMENT_METHOD_UNAVAILABLE_REASONS)
30
35
  .nullable()
31
36
  .describe('Why it cannot be offered whatever the merchant chooses; `null` when it can.'),
32
- currencies: z.array(fiatCurrency).describe('The payment currencies it is offered on.'),
37
+ currencies: z.array(currency).describe('The payment currencies it is offered on.'),
33
38
  })
34
39
  .strict());
40
+ /** One entry of the configuration's documented example (abbreviated currency lists). */
41
+ function exampleEntry(preference, value, overrides = {}) {
42
+ const unavailable_reason = overrides.unavailable_reason ?? null;
43
+ return {
44
+ available: value === 'on' && unavailable_reason === null,
45
+ display_preference: { preference, value },
46
+ locked: false,
47
+ unavailable_reason,
48
+ currencies: ['EUR', 'USD', 'GBP'],
49
+ ...overrides,
50
+ };
51
+ }
35
52
  const entryFields = Object.fromEntries(PAYMENT_METHOD_CONFIGURATION_TYPES.map((type) => [type, paymentMethodConfigurationEntrySchema]));
36
53
  export const paymentMethodConfigurationSchema = defineObject('payment_method_configuration', 'PaymentMethodConfiguration', z
37
54
  .object({
@@ -49,7 +66,32 @@ export const paymentMethodConfigurationSchema = defineObject('payment_method_con
49
66
  updated_at: unixSeconds,
50
67
  ...entryFields,
51
68
  })
52
- .strict());
69
+ .strict(), {
70
+ examples: [
71
+ {
72
+ id: 'pmc_0193b8f2c1a87d3e9f4b',
73
+ object: 'payment_method_configuration',
74
+ livemode: false,
75
+ name: 'Default',
76
+ active: true,
77
+ is_default: true,
78
+ created: 1793750400,
79
+ updated_at: 1793750400,
80
+ faircoin: exampleEntry('on', 'on', { locked: true, currencies: ['FAIR', 'EUR', 'USD'] }),
81
+ card: exampleEntry('none', 'on'),
82
+ apple_pay: exampleEntry('none', 'on'),
83
+ google_pay: exampleEntry('none', 'on'),
84
+ sepa_debit: exampleEntry('on', 'on', { currencies: ['EUR'] }),
85
+ ideal: exampleEntry('none', 'off', { currencies: ['EUR'] }),
86
+ bancontact: exampleEntry('none', 'off', { currencies: ['EUR'] }),
87
+ eps: exampleEntry('none', 'off', { currencies: ['EUR'] }),
88
+ bizum: exampleEntry('none', 'off', {
89
+ currencies: ['EUR'],
90
+ unavailable_reason: 'provider_unsupported',
91
+ }),
92
+ },
93
+ ],
94
+ });
53
95
  /** A wallet's standing on one domain. */
54
96
  export const paymentMethodDomainWalletStatusSchema = defineComponent('PaymentMethodDomainWalletStatus', z
55
97
  .object({
@@ -92,7 +134,11 @@ export const paymentMethodDomainSchema = defineObject('payment_method_domain', '
92
134
  },
93
135
  ],
94
136
  });
95
- /** One method's setting in a create or update. `none` returns it to Orbit's default. */
137
+ /**
138
+ * One method's setting in a create or update. `none` returns it to Orbit's
139
+ * default. For `faircoin` only `on` and `none` are accepted, and neither stores
140
+ * anything: it is always on, and `off` is refused with `payment_method_locked`.
141
+ */
96
142
  export const paymentMethodConfigurationEntryParams = z
97
143
  .object({
98
144
  display_preference: z.object({ preference: z.enum(['on', 'off', 'none']) }).strict(),
@@ -150,7 +196,7 @@ export const paymentMethodConfigurationRoutes = [
150
196
  path: '/v1/payment_method_configurations',
151
197
  tag: 'Payment method configurations',
152
198
  summary: 'Create a payment method configuration',
153
- description: 'An additional, non-default configuration. Turning `on` a method the processing provider does not offer is refused.',
199
+ description: 'An additional, non-default configuration. Turning `on` a method the processing provider does not offer is refused, and so is turning `faircoin` `off` (`payment_method_locked`): FairCoin is always offered.',
154
200
  auth: 'service',
155
201
  scope: 'payments:write',
156
202
  idempotent: true,
@@ -178,7 +224,7 @@ export const paymentMethodConfigurationRoutes = [
178
224
  path: '/v1/payment_method_configurations/{id}',
179
225
  tag: 'Payment method configurations',
180
226
  summary: 'Update a payment method configuration',
181
- description: 'Method settings are merged; the default configuration is always active.',
227
+ description: 'Method settings are merged; the default configuration is always active. `faircoin` is locked on: setting it `off` is refused with `payment_method_locked`.',
182
228
  auth: 'service',
183
229
  scope: 'payments:write',
184
230
  idempotent: true,
@@ -4,6 +4,7 @@ import { defineComponent, defineObject } from '../../common/objects.js';
4
4
  import { expandOnlyQuery, idParam, listQuery } from '../../common/params.js';
5
5
  import { livemode, signedAmount, unixSeconds } from '../../common/primitives.js';
6
6
  import { defineRoute } from '../../route.js';
7
+ import { faircoinQuoteSchema } from '../payments/paymentIntents.js';
7
8
  import { BALANCE_TRANSACTION_FEE_TYPES, BALANCE_TRANSACTION_STATUSES, BALANCE_TRANSACTION_TYPES, RECONCILIATION_MISMATCH_KINDS, } from '../../vocabulary/connect.js';
8
9
  /**
9
10
  * Balance and balance transactions (ADR 0015 §3–§5).
@@ -87,6 +88,9 @@ export const balanceTransactionSchema = defineObject('balance_transaction', 'Bal
87
88
  created: unixSeconds.describe('When it happened at its source.'),
88
89
  description: z.string().nullable(),
89
90
  exchange_rate: z.number().nullable(),
91
+ faircoin_quote: faircoinQuoteSchema
92
+ .nullable()
93
+ .describe('A FairCoin payment of a fiat order: the quote it was priced at — its fiat equivalent (ADR 0021). Informational; no fiat moved.'),
90
94
  fee_details: z.array(balanceTransactionFeeDetailSchema),
91
95
  source: z
92
96
  .string()
@@ -118,6 +122,7 @@ export const balanceTransactionSchema = defineObject('balance_transaction', 'Bal
118
122
  created: 1793750400,
119
123
  description: 'Order 6735',
120
124
  exchange_rate: null,
125
+ faircoin_quote: null,
121
126
  fee_details: [{ amount: '88', currency: 'EUR', type: 'processing_fee' }],
122
127
  source: 'ch_0193b8f2f7c94b1d8e02',
123
128
  payout: null,
@@ -15,25 +15,24 @@ import { accountLinkSchema, accountRequirementsSchema } from './account.js';
15
15
  * ADR 0001 D3: a merchant integrates against Peable and never learns which
16
16
  * acquirer sat behind their seller, because the day that changes should be a
17
17
  * Peable deploy and not a merchant migration. No `acct_…`, no provider name —
18
- * and no seller xpub (ADR 0012 D6): an account xpub reveals every address of
19
- * that account, so a platform holding it would learn the seller's whole history
20
- * and balance. Nothing a platform does needs it; each payment carries its own
18
+ * and no key of any kind: a seller's FairCoin is paid into the Peable wallet
19
+ * of their own Oxy account (ADR 0021 D5), and each payment carries its own
21
20
  * address.
22
21
  */
23
22
  const capabilityStatus = z.enum(ACCOUNT_CAPABILITY_STATUSES);
24
- /** The FairCoin half of a seller's account. The seller's xpub is deliberately ABSENT (ADR 0012 D6). */
23
+ /** The FairCoin half of a seller's account: paid into the Peable wallet of the seller's own Oxy account (ADR 0021 D5). */
25
24
  export const connectedAccountFaircoinSchema = defineComponent('ConnectedAccountFaircoin', z
26
25
  .object({
27
26
  network: network.describe('The chain the seller is paid on. Fixed when the half was opened.'),
28
27
  status: z
29
28
  .enum(CONNECTED_ACCOUNT_FAIRCOIN_STATUSES)
30
- .describe('`pending`: the seller has not registered a key yet (an on-behalf payment is refused, `account_not_ready`). `active`: payments derive addresses from their key.'),
29
+ .describe('`pending`: the seller has not confirmed yet (an on-behalf payment is refused, `account_not_ready`). `active`: the seller confirmed, and payments go to the Peable wallet of their Oxy account.'),
31
30
  oxy_user_id: z
32
31
  .string()
33
- .describe('The Oxy user who may register the key — and, once `active`, who did.'),
32
+ .describe('The seller’s Oxy account — the only one that may confirm, and the one whose Peable wallet receives.'),
34
33
  registered_at: unixSeconds
35
34
  .nullable()
36
- .describe('When the seller registered their key. `null` while `pending`.'),
35
+ .describe('When the seller confirmed. `null` while `pending`.'),
37
36
  })
38
37
  .strict());
39
38
  export const connectedAccountSchema = defineObject('connected_account', 'ConnectedAccount', z
@@ -109,9 +108,9 @@ const OXY_USER_ID_MAX = 128;
109
108
  * `POST /v1/connected_accounts`: open (or return) the account for one seller.
110
109
  *
111
110
  * Two halves, at least one: the CARD half (`country` + `business_type`, both or
112
- * neither) and the FAIRCOIN half (`faircoin`). There is deliberately no `xpub`
113
- * here: the key comes from the SELLER's own session, never from the platform
114
- * (ADR 0012 D3).
111
+ * neither) and the FAIRCOIN half (`faircoin`). There is no key: the seller's
112
+ * FairCoin goes to their own account's Peable wallet, confirmed only from the
113
+ * SELLER's own session (ADR 0012 D3, ADR 0021 D5).
115
114
  */
116
115
  export const createConnectedAccountParams = z
117
116
  .object({
@@ -138,7 +137,7 @@ export const createConnectedAccountParams = z
138
137
  .string()
139
138
  .min(1)
140
139
  .max(OXY_USER_ID_MAX)
141
- .describe("The seller's Oxy user id — the only person who may register the key."),
140
+ .describe("The seller's Oxy account id — the only one that may confirm, and whose Peable wallet receives."),
142
141
  })
143
142
  .strict()
144
143
  .optional()
@@ -162,7 +161,7 @@ export const createConnectedAccountLinkParams = z
162
161
  rail: z
163
162
  .enum(CONNECTED_ACCOUNT_RAILS)
164
163
  .optional()
165
- .describe("Which half to onboard: `card` (the default) is the provider's hosted onboarding; `faircoin` is Peable's own page where the SELLER registers their watch-only key."),
164
+ .describe("Which half to onboard: `card` (the default) is the provider's hosted onboarding; `faircoin` is Peable's own page where the SELLER confirms, in their own Oxy session, that their FairCoin is paid into their Peable wallet."),
166
165
  })
167
166
  .strict();
168
167
  const accountIdParam = { accountId: 'The connected account (`ca_…`).' };
@@ -7,10 +7,10 @@ import { merchantDisplaySchema } from '../checkout/shared.js';
7
7
  * The SELLER-facing half of FairCoin connected accounts (ADR 0012 D3).
8
8
  *
9
9
  * A platform mints an onboarding link for a seller's account; the SELLER opens
10
- * it signed in with Oxy and registers the watch-only key their FairCoin will be
11
- * paid to. These routes are `auth: 'user'` — the seller's own session, never a
12
- * service token — because the key that decides who receives a seller's money is
13
- * accepted only from the seller. A platform cannot reach them at all, and the
10
+ * it signed in with Oxy and confirms that their FairCoin is paid into the
11
+ * Peable wallet of that account (ADR 0021 D5). These routes are `auth: 'user'`
12
+ * — the seller's own session, never a service token — because who receives a
13
+ * seller's money is the seller's consent. A platform cannot reach them at all, and the
14
14
  * link token alone is not enough without the session it names.
15
15
  */
16
16
  export const connectOnboardingSchema = defineObject('connect_onboarding', 'ConnectOnboarding', z
@@ -35,22 +35,11 @@ export const connectOnboardingCompleteSchema = defineComponent('ConnectOnboardin
35
35
  })
36
36
  .strict());
37
37
  /**
38
- * An extended public key is 111 characters in base58check; the bound is a
39
- * request-size guard with headroom, not a format check — the non-custody
40
- * firewall (`assertWatchOnly`) is.
38
+ * `POST /v1/connect/onboarding/{token}/faircoin` takes nothing: the seller
39
+ * confirms, in their own Oxy session, that their FairCoin is paid into the
40
+ * Peable wallet of that account (ADR 0021 D5). No key travels.
41
41
  */
42
- const XPUB_MAX_LENGTH = 200;
43
- /** `POST /v1/connect/onboarding/{token}/faircoin` — the seller's watch-only ACCOUNT xpub. */
44
- export const registerFaircoinKeyParams = z
45
- .object({
46
- xpub: z
47
- .string()
48
- .trim()
49
- .min(1)
50
- .max(XPUB_MAX_LENGTH)
51
- .describe('A watch-only extended PUBLIC key. A private extended key is refused (`watch_only_violation`) and never stored.'),
52
- })
53
- .strict();
42
+ export const confirmFaircoinOnboardingParams = z.object({}).strict();
54
43
  const tokenParam = { token: 'The onboarding link token (the last segment of its `url`).' };
55
44
  export const connectOnboardingRoutes = [
56
45
  defineRoute({
@@ -65,15 +54,15 @@ export const connectOnboardingRoutes = [
65
54
  response: connectOnboardingSchema,
66
55
  }),
67
56
  defineRoute({
68
- operationId: 'registerConnectOnboardingFaircoinKey',
57
+ operationId: 'confirmConnectOnboardingFaircoin',
69
58
  method: 'post',
70
59
  path: '/v1/connect/onboarding/{token}/faircoin',
71
60
  tag: 'Connect onboarding',
72
- summary: "Register the seller's FairCoin key",
73
- description: 'The ONLY way a key reaches a connected account: runs the non-custody firewall, consumes the link and tells the platform (`connected_account.updated`), in one transaction. The key is immutable once registered and never appears on any response.',
61
+ summary: 'Confirm FairCoin payments into the seller’s Peable wallet',
62
+ description: 'The seller, signed in as the account the link names, confirms that FairCoin paid to them goes to that account’s Peable wallet (ADR 0021 D5) — the only way a FairCoin half becomes payable. No key is sent: addresses derive from the account’s public identity key. 409 `faircoin_wallet_missing` while the account has no Peable wallet yet. Consumes the link and tells the platform (`connected_account.updated`) in one transaction.',
74
63
  auth: 'user',
75
64
  params: tokenParam,
76
- body: registerFaircoinKeyParams,
65
+ body: confirmFaircoinOnboardingParams,
77
66
  response: connectOnboardingCompleteSchema,
78
67
  }),
79
68
  ];
@@ -3,7 +3,7 @@ import { emailParam, shippingParams, shippingSchema } from '../../common/address
3
3
  import { listOf, searchResultOf } from '../../common/envelopes.js';
4
4
  import { defineComponent, defineObject, expandable } from '../../common/objects.js';
5
5
  import { clearable, expandParam, idParam, listQuery, metadataCreateParam, metadataUpdateParam, retrieveQuery, searchQuery, } from '../../common/params.js';
6
- import { amount, currency, livemode, metadata, network, nullableString, unixSeconds, } from '../../common/primitives.js';
6
+ import { amount, currency, fiatCurrency, livemode, metadata, network, nullableString, unixSeconds, } from '../../common/primitives.js';
7
7
  import { defineRoute } from '../../route.js';
8
8
  import { CURRENCY_CODES, isBaseUnitString, NETWORK_TYPES } from '../../vocabulary/money.js';
9
9
  import { CARD_RAIL_PAYMENT_METHOD_TYPES, CLIENT_ACTION_KINDS, MERCHANT_CANCELLATION_REASONS, PAYMENT_ERROR_TYPES, PAYMENT_INTENT_CANCELLATION_REASONS, PAYMENT_INTENT_CAPTURE_METHODS, PAYMENT_INTENT_RAILS, PAYMENT_INTENT_SETUP_FUTURE_USAGES, PAYMENT_INTENT_STATUSES, PAYMENT_METHOD_TYPES, } from '../../vocabulary/payments.js';
@@ -49,6 +49,39 @@ export const paymentIntentNextActionSchema = defineComponent('PaymentIntentNextA
49
49
  .strict(),
50
50
  z.object({ type: z.literal('use_peable_sdk') }).strict(),
51
51
  ]));
52
+ /**
53
+ * The FairCoin price of a FIAT order (ADR 0021 D4), carried by the FairCoin
54
+ * payment the payer chose for it. Pricing, never exchange: the payer pays
55
+ * `amount` FAIR (the intent's) to the payee's own address, and no fiat moves.
56
+ * `rate` is for display; the FAIR amount is exactly
57
+ * `ceil(amount ÷ rate)` computed from the sources' own figures.
58
+ */
59
+ export const faircoinQuoteSchema = defineComponent('FaircoinQuote', z
60
+ .object({
61
+ currency: fiatCurrency.describe("The order's currency."),
62
+ amount: amount.describe("The order's total in base units of `currency` (tax included)."),
63
+ rate: z.string().describe('`currency` per 1 FAIR, rounded to 10 significant digits.'),
64
+ price: z
65
+ .object({
66
+ source: z.literal('wfair-base'),
67
+ usd_per_fair: z.string().describe("The FairCoin Explorer's FAIR/USD price."),
68
+ observed_at: unixSeconds,
69
+ })
70
+ .strict(),
71
+ reference_rates: z
72
+ .object({
73
+ source: z.literal('ecb'),
74
+ usd_per_eur: z.string(),
75
+ currency_per_eur: z.string().describe('`1` for EUR.'),
76
+ observed_at: unixSeconds,
77
+ })
78
+ .strict()
79
+ .nullable()
80
+ .describe("The European Central Bank's reference rates; `null` for a USD order."),
81
+ quoted_at: unixSeconds,
82
+ expires_at: unixSeconds.describe('The payment expires with its quote unless already broadcast.'),
83
+ })
84
+ .strict());
52
85
  /**
53
86
  * The chain side of a FairCoin payment. `txid` and `confirmations` describe the
54
87
  * transaction the payer reported: `null`/`0` while `requires_action`, the
@@ -59,10 +92,13 @@ export const paymentIntentFaircoinSchema = defineComponent('PaymentIntentFaircoi
59
92
  network,
60
93
  address: z
61
94
  .string()
62
- .describe("Watch-only receive address derived per intent from the merchant's (or seller's) xpub."),
95
+ .describe("Receive address in the Peable wallet of the account this payment pays (the merchant's owner, or the seller), derived per payment from that account's public identity key (ADR 0021 D5)."),
63
96
  txid: nullableString,
64
97
  confirmations: z.number().int().nonnegative(),
65
98
  required_confirmations: z.number().int().nonnegative(),
99
+ quote: faircoinQuoteSchema
100
+ .nullable()
101
+ .describe('The fiat order this payment pays, as quoted (ADR 0021); `null` on a FAIR-priced payment.'),
66
102
  })
67
103
  .strict());
68
104
  /** Where a destination charge's funds go (`transfer_data`, ADR 0015 §2). */
@@ -193,6 +229,7 @@ export const paymentIntentSchema = defineObject('payment_intent', 'PaymentIntent
193
229
  txid: null,
194
230
  confirmations: 0,
195
231
  required_confirmations: 6,
232
+ quote: null,
196
233
  },
197
234
  merchant_id: 'merch_0193b8f2c1a87d3e9f4a',
198
235
  connected_account: null,