@peable.to/contracts 3.0.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 (58) 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/events/webhookDeliveries.js +1 -1
  9. package/dist/cjs/resources/events/webhookEndpoints.js +1 -1
  10. package/dist/cjs/resources/payments/disputes.js +16 -0
  11. package/dist/cjs/resources/payments/paymentIntents.js +39 -2
  12. package/dist/cjs/resources/payments/refunds.js +46 -11
  13. package/dist/cjs/vocabulary/checkout.js +18 -1
  14. package/dist/cjs/vocabulary/errors.js +5 -3
  15. package/dist/cjs/vocabulary/events.js +5 -0
  16. package/dist/cjs/vocabulary/paymentMethodConfigurations.js +24 -4
  17. package/dist/esm/resources/billingEngine/public.js +22 -3
  18. package/dist/esm/resources/checkout/checkoutSessions.js +35 -10
  19. package/dist/esm/resources/checkout/merchants.js +10 -23
  20. package/dist/esm/resources/checkout/paymentMethodConfigurations.js +57 -11
  21. package/dist/esm/resources/connect/balance.js +5 -0
  22. package/dist/esm/resources/connect/connectedAccounts.js +11 -12
  23. package/dist/esm/resources/connect/onboarding.js +12 -23
  24. package/dist/esm/resources/events/webhookDeliveries.js +1 -1
  25. package/dist/esm/resources/events/webhookEndpoints.js +1 -1
  26. package/dist/esm/resources/payments/disputes.js +16 -0
  27. package/dist/esm/resources/payments/paymentIntents.js +39 -2
  28. package/dist/esm/resources/payments/refunds.js +46 -11
  29. package/dist/esm/vocabulary/checkout.js +17 -0
  30. package/dist/esm/vocabulary/errors.js +5 -3
  31. package/dist/esm/vocabulary/events.js +5 -0
  32. package/dist/esm/vocabulary/paymentMethodConfigurations.js +25 -5
  33. package/dist/types/resources/billingEngine/index.d.ts +16 -2
  34. package/dist/types/resources/billingEngine/public.d.ts +32 -3
  35. package/dist/types/resources/checkout/checkoutSessions.d.ts +96 -31
  36. package/dist/types/resources/checkout/index.d.ts +406 -41
  37. package/dist/types/resources/checkout/merchants.d.ts +17 -28
  38. package/dist/types/resources/checkout/paymentMethodConfigurations.d.ts +440 -8
  39. package/dist/types/resources/connect/balance.d.ts +103 -10
  40. package/dist/types/resources/connect/connectedAccounts.d.ts +4 -4
  41. package/dist/types/resources/connect/index.d.ts +105 -14
  42. package/dist/types/resources/connect/onboarding.d.ts +15 -15
  43. package/dist/types/resources/connect/payouts.d.ts +66 -4
  44. package/dist/types/resources/events/index.d.ts +5 -0
  45. package/dist/types/resources/events/webhookEndpoints.d.ts +7 -0
  46. package/dist/types/resources/payments/disputes.d.ts +35 -0
  47. package/dist/types/resources/payments/index.d.ts +382 -0
  48. package/dist/types/resources/payments/paymentIntents.d.ts +380 -0
  49. package/dist/types/resources/payments/refunds.d.ts +56 -5
  50. package/dist/types/resources/payments/testHelpers.d.ts +31 -0
  51. package/dist/types/resources/tax/deadlines.d.ts +3 -3
  52. package/dist/types/resources/tax/index.d.ts +2 -2
  53. package/dist/types/resources/tax/registrations.d.ts +2 -2
  54. package/dist/types/vocabulary/checkout.d.ts +13 -0
  55. package/dist/types/vocabulary/errors.d.ts +5 -3
  56. package/dist/types/vocabulary/events.d.ts +5 -1
  57. package/dist/types/vocabulary/paymentMethodConfigurations.d.ts +21 -7
  58. package/package.json +1 -1
@@ -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
  ];
@@ -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) or was disabled first — never retried. `dead`: every attempt failed transiently for three days; it can be redelivered.'),
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
  ];
@@ -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,
@@ -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's settlement figures. The provider's own
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
- * What a payment actually came to, as the PROVIDER reports it. Every figure is
57
- * nullable and that is the contract: "the fee was zero" and "the fee is not
58
- * known yet" are different facts, and `status` says which produced the nulls.
59
- * It reports what the provider took; it attributes that cost to nobody.
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.nullable().describe('Base units of `currency`.'),
70
- fee: amount.nullable(),
71
- net: signedAmount.nullable(),
72
- currency: nullableString.describe("The SETTLEMENT currency (uppercase ISO 4217), which may differ from the payment's."),
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',
@@ -2,6 +2,23 @@
2
2
  // Checkout Sessions and Payment Links. Zod-free, so the hosted checkout and
3
3
  // the wallet import them without the schemas (`@peable.to/contracts/vocabulary`,
4
4
  // re-exported by `@peable.to/shared-types`).
5
+ /**
6
+ * Why FairCoin cannot be paid with on an order right now (ADR 0021). It is
7
+ * still offered — never hidden — and says why:
8
+ *
9
+ * - `faircoin_wallet_missing` — the Peable wallet of the account that receives
10
+ * (the merchant's owner, or the seller) isn't set up yet: no identity key;
11
+ * - `faircoin_network_closed` — this deployment does not open payments on the
12
+ * order's FairCoin network yet (ADR 0002's gate);
13
+ * - `price_unavailable` — no fresh FairCoin price exists to quote a fiat order;
14
+ * - `temporarily_unavailable` — whether the wallet exists could not be checked.
15
+ */
16
+ export const FAIRCOIN_UNAVAILABLE_REASONS = [
17
+ 'faircoin_wallet_missing',
18
+ 'faircoin_network_closed',
19
+ 'price_unavailable',
20
+ 'temporarily_unavailable',
21
+ ];
5
22
  export const CHECKOUT_SESSION_MODES = ['payment', 'setup', 'subscription'];
6
23
  export const CHECKOUT_SESSION_STATUSES = ['open', 'complete', 'expired'];
7
24
  export const CHECKOUT_PAYMENT_STATUSES = ['paid', 'unpaid', 'no_payment_required'];
@@ -55,6 +55,7 @@ export const ERROR_CODE_DESCRIPTIONS = {
55
55
  parameter_missing: 'A required parameter is missing; `param` names it.',
56
56
  parameter_unknown: 'The request carries a parameter this route does not accept; `param` names it.',
57
57
  payment_intent_unexpected_state: 'The PaymentIntent is in a status that does not allow this operation.',
58
+ payment_method_locked: 'The payment method cannot be turned off or removed: FairCoin is always offered to every payer; `param` names the field.',
58
59
  payout_not_allowed: 'Payouts cannot be created for this account.',
59
60
  rate_limited: 'Too many requests; back off and retry.',
60
61
  refund_not_cancelable: 'The refund has already left a cancelable state.',
@@ -65,7 +66,6 @@ export const ERROR_CODE_DESCRIPTIONS = {
65
66
  test_mode_only: 'This operation exists in test mode only.',
66
67
  too_many_streams: 'Too many live streams are open for this merchant.',
67
68
  url_invalid: 'The URL is not an allowed https URL.',
68
- watch_only_violation: 'The extended key carries a private key. Peable only ever accepts watch-only (public) keys.',
69
69
  webhook_endpoint_disabled: 'The webhook endpoint is disabled.',
70
70
  webhook_endpoint_limit_reached: 'The merchant already has the maximum number of webhook endpoints.',
71
71
  account_not_ready: 'The connected account cannot take this payment yet: its onboarding or a capability is incomplete.',
@@ -126,6 +126,9 @@ export const ERROR_CODE_DESCRIPTIONS = {
126
126
  promotion_code_minimum_amount: 'The purchase is below the promotion code minimum amount.',
127
127
  payment_method_missing: 'No payment method is available to charge.',
128
128
  faircoin_cannot_debit: 'A FairCoin invoice cannot be charged automatically: the payer signs every payment.',
129
+ faircoin_price_unavailable: 'No fresh FairCoin price exists right now, so this order cannot be quoted in FAIR. The other payment methods still work; try FairCoin again shortly.',
130
+ faircoin_wallet_missing: "The Peable wallet that receives this payment (the merchant owner's, or the seller's) isn't set up yet, so it cannot be paid in FairCoin. The other payment methods still work.",
131
+ faircoin_network_closed: 'FairCoin payments on this network are not open on this deployment yet. The other payment methods still work.',
129
132
  credit_note_exceeds_invoice: "The credit note's amount exceeds what the invoice can still credit.",
130
133
  test_clock_unexpected_state: 'The test clock is advancing; wait until it is ready.',
131
134
  meter_event_customer_missing: 'The meter event names no customer of this merchant.',
@@ -138,8 +141,7 @@ export const ERROR_CODE_DESCRIPTIONS = {
138
141
  // Connect onboarding (ADR 0012 D3): the seller-facing refusals.
139
142
  link_expired: 'The onboarding link has expired or was already used; `refresh_url` is where the seller gets a fresh one.',
140
143
  wrong_seller: 'The onboarding link names a different Oxy account; sign in as the seller it was minted for.',
141
- already_registered: 'The seller already registered a FairCoin key, and it cannot be changed.',
142
- key_in_use: 'The key already receives payments for another account.',
144
+ already_registered: 'The seller already confirmed FairCoin payments into their Peable wallet.',
143
145
  no_faircoin_half: 'The connected account has no FairCoin half to register a key for.',
144
146
  // The dashboard routes (`/v1/dashboard/*`, Orbit): the signed-in person, not a credential.
145
147
  merchant_missing: 'The application has no merchant in this environment yet; register one (Orbit shows "Set up payments").',
@@ -147,10 +147,15 @@ export const WEBHOOK_ENDPOINT_STATUSES = ['enabled', 'disabled'];
147
147
  * - `delivery_failures` — every delivery to it failed for three days
148
148
  * straight, so Peable stopped sending. Re-enabling it (`disabled: false`)
149
149
  * starts the clock again.
150
+ * - `url_refused` — its stored `url` breaks the rules a URL is
151
+ * registered under (https in live mode, ports 80/443, no private, loopback
152
+ * or reserved address), judged again before every delivery, so Peable never
153
+ * sent to it. It is re-enabled only together with a `url` that passes.
150
154
  */
151
155
  export const WEBHOOK_ENDPOINT_DISABLED_REASONS = [
152
156
  'disabled_by_merchant',
153
157
  'delivery_failures',
158
+ 'url_refused',
154
159
  ];
155
160
  /** At most this many endpoints per merchant (per mode). */
156
161
  export const WEBHOOK_ENDPOINTS_MAX_PER_MERCHANT = 16;
@@ -1,7 +1,15 @@
1
- // Payment method breadth on the card rail (`pmc_…`, `pmd_…`). Zod-free.
2
- import { FIAT_CURRENCY_CODES } from './money.js';
1
+ // Payment method breadth (`pmc_…`, `pmd_…`): the merchant's card-rail methods,
2
+ // and FairCoin, which is always offered (ADR 0021). Zod-free.
3
+ import { CURRENCY_CODES, FIAT_CURRENCY_CODES } from './money.js';
3
4
  /**
4
- * The methods a configuration can turn on.
5
+ * The methods a configuration lists.
6
+ *
7
+ * `faircoin` is listed and LOCKED (ADR 0021 D2): every payer can always pay
8
+ * with FairCoin, so its entry is always `display_preference.value: 'on'` with
9
+ * `locked: true`, and a create or update that sets it `off` is refused with
10
+ * `payment_method_locked`. It is the chain rail, never a card-provider method:
11
+ * it is never pushed to the provider and never appears in a card PaymentIntent's
12
+ * `payment_method_types`. Every other method is the merchant's to turn on and off.
5
13
  *
6
14
  * `apple_pay` and `google_pay` are WALLETS over a card: a payment made with one
7
15
  * is a `card` payment, so they appear here and never in a PaymentIntent's
@@ -13,6 +21,7 @@ import { FIAT_CURRENCY_CODES } from './money.js';
13
21
  * scheme).
14
22
  */
15
23
  export const PAYMENT_METHOD_CONFIGURATION_TYPES = [
24
+ 'faircoin',
16
25
  'card',
17
26
  'apple_pay',
18
27
  'google_pay',
@@ -26,18 +35,29 @@ export const PAYMENT_METHOD_CONFIGURATION_TYPES = [
26
35
  * Why a method cannot be offered whatever the merchant chooses.
27
36
  *
28
37
  * - `provider_unsupported` — the processing provider does not offer it;
29
- * - `requires_card` — a wallet rides on card payments, and card is off.
38
+ * - `requires_card` — a wallet rides on card payments, and card is off;
39
+ * - `faircoin_wallet_missing` — the Peable wallet of the account that owns
40
+ * the merchant isn't set up yet (no identity key), so FairCoin cannot be
41
+ * received (ADR 0021 D5); the owner sets it up in Peable;
42
+ * - `faircoin_network_closed` — the deployment does not open the merchant's
43
+ * FairCoin network yet (ADR 0002's gate);
44
+ * - `temporarily_unavailable` — the wallet could not be checked just now.
30
45
  */
31
46
  export const PAYMENT_METHOD_UNAVAILABLE_REASONS = [
32
47
  'provider_unsupported',
33
48
  'requires_card',
49
+ 'faircoin_wallet_missing',
50
+ 'faircoin_network_closed',
51
+ 'temporarily_unavailable',
34
52
  ];
35
53
  /**
36
54
  * The currencies each method can take a payment in. A method is offered on a
37
55
  * payment only when its currency is listed — so iDEAL never appears on a USD
38
- * payment, and a payer is never shown a method that would fail.
56
+ * payment, and a payer is never shown a method that would fail. FairCoin takes
57
+ * every currency: a `FAIR` order directly, a fiat one at a quoted price (ADR 0021).
39
58
  */
40
59
  export const PAYMENT_METHOD_CURRENCIES = Object.freeze({
60
+ faircoin: CURRENCY_CODES,
41
61
  card: FIAT_CURRENCY_CODES,
42
62
  apple_pay: FIAT_CURRENCY_CODES,
43
63
  google_pay: FIAT_CURRENCY_CODES,
@@ -4822,6 +4822,15 @@ export declare const billingEngineRoutes: readonly [{
4822
4822
  card: "card";
4823
4823
  faircoin: "faircoin";
4824
4824
  }>>;
4825
+ faircoin: import("zod").ZodObject<{
4826
+ available: import("zod").ZodBoolean;
4827
+ unavailable_reason: import("zod").ZodNullable<import("zod").ZodEnum<{
4828
+ faircoin_wallet_missing: "faircoin_wallet_missing";
4829
+ faircoin_network_closed: "faircoin_network_closed";
4830
+ price_unavailable: "price_unavailable";
4831
+ temporarily_unavailable: "temporarily_unavailable";
4832
+ }>>;
4833
+ }, import("zod/v4/core").$strict>;
4825
4834
  invoice_pdf: import("zod").ZodString;
4826
4835
  }, import("zod/v4/core").$strict>;
4827
4836
  }, {
@@ -4830,12 +4839,17 @@ export declare const billingEngineRoutes: readonly [{
4830
4839
  readonly path: "/v1/invoices/public/{token}/pay";
4831
4840
  readonly tag: "Hosted invoices";
4832
4841
  readonly summary: "Pay a hosted invoice";
4833
- readonly 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.";
4842
+ readonly 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.";
4834
4843
  readonly auth: "public";
4835
4844
  readonly params: {
4836
4845
  readonly token: "The hosted invoice token (from `hosted_invoice_url`).";
4837
4846
  };
4838
- readonly body: import("zod").ZodObject<{}, import("zod/v4/core").$strict>;
4847
+ readonly body: import("zod").ZodObject<{
4848
+ payment_method_type: import("zod").ZodOptional<import("zod").ZodEnum<{
4849
+ card: "card";
4850
+ faircoin: "faircoin";
4851
+ }>>;
4852
+ }, import("zod/v4/core").$strict>;
4839
4853
  readonly response: import("zod").ZodObject<{
4840
4854
  object: import("zod").ZodLiteral<"public_invoice_payment">;
4841
4855
  payment_intent: import("zod").ZodString;
@@ -59,6 +59,15 @@ export declare const publicInvoiceSchema: z.ZodObject<{
59
59
  card: "card";
60
60
  faircoin: "faircoin";
61
61
  }>>;
62
+ faircoin: z.ZodObject<{
63
+ available: z.ZodBoolean;
64
+ unavailable_reason: z.ZodNullable<z.ZodEnum<{
65
+ faircoin_wallet_missing: "faircoin_wallet_missing";
66
+ faircoin_network_closed: "faircoin_network_closed";
67
+ price_unavailable: "price_unavailable";
68
+ temporarily_unavailable: "temporarily_unavailable";
69
+ }>>;
70
+ }, z.core.$strict>;
62
71
  invoice_pdf: z.ZodString;
63
72
  }, z.core.$strict>;
64
73
  export type PublicInvoice = Expand<z.output<typeof publicInvoiceSchema>>;
@@ -509,7 +518,13 @@ declare module '../../common/objects' {
509
518
  'billing_portal.public_session': PublicPortalSession;
510
519
  }
511
520
  }
512
- export declare const payPublicInvoiceParams: z.ZodObject<{}, z.core.$strict>;
521
+ /** How the payer pays the invoice (ADR 0021 D3). */
522
+ export declare const payPublicInvoiceParams: z.ZodObject<{
523
+ payment_method_type: z.ZodOptional<z.ZodEnum<{
524
+ card: "card";
525
+ faircoin: "faircoin";
526
+ }>>;
527
+ }, z.core.$strict>;
513
528
  /** A portal action on one of the customer's subscriptions. */
514
529
  export declare const portalSubscriptionParams: z.ZodObject<{
515
530
  subscription: z.ZodString;
@@ -611,6 +626,15 @@ export declare const publicBillingRoutes: readonly [{
611
626
  card: "card";
612
627
  faircoin: "faircoin";
613
628
  }>>;
629
+ faircoin: z.ZodObject<{
630
+ available: z.ZodBoolean;
631
+ unavailable_reason: z.ZodNullable<z.ZodEnum<{
632
+ faircoin_wallet_missing: "faircoin_wallet_missing";
633
+ faircoin_network_closed: "faircoin_network_closed";
634
+ price_unavailable: "price_unavailable";
635
+ temporarily_unavailable: "temporarily_unavailable";
636
+ }>>;
637
+ }, z.core.$strict>;
614
638
  invoice_pdf: z.ZodString;
615
639
  }, z.core.$strict>;
616
640
  }, {
@@ -619,12 +643,17 @@ export declare const publicBillingRoutes: readonly [{
619
643
  readonly path: "/v1/invoices/public/{token}/pay";
620
644
  readonly tag: "Hosted invoices";
621
645
  readonly summary: "Pay a hosted invoice";
622
- readonly 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.";
646
+ readonly 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.";
623
647
  readonly auth: "public";
624
648
  readonly params: {
625
649
  readonly token: "The hosted invoice token (from `hosted_invoice_url`).";
626
650
  };
627
- readonly body: z.ZodObject<{}, z.core.$strict>;
651
+ readonly body: z.ZodObject<{
652
+ payment_method_type: z.ZodOptional<z.ZodEnum<{
653
+ card: "card";
654
+ faircoin: "faircoin";
655
+ }>>;
656
+ }, z.core.$strict>;
628
657
  readonly response: z.ZodObject<{
629
658
  object: z.ZodLiteral<"public_invoice_payment">;
630
659
  payment_intent: z.ZodString;