@payabli/component-contracts 0.1.2 → 0.2.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/LICENSE.md +7 -0
- package/README.md +522 -0
- package/dist/errors.d.ts +6 -0
- package/dist/index.js +67 -7
- package/dist/payin/definition.d.ts +9 -0
- package/dist/payin/schema.d.ts +35 -3
- package/dist/sdk.d.ts +1 -1
- package/package.json +5 -8
package/LICENSE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) 2026 Payabli Inc.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -24,6 +24,528 @@ pnpm add @payabli/component-contracts
|
|
|
24
24
|
Schemas are zod v4 mini and the runtime is bundled. Consumers on zod 3.25 or
|
|
25
25
|
later resolve the types through `zod/v4/mini`.
|
|
26
26
|
|
|
27
|
+
## PayIn contract summary
|
|
28
|
+
|
|
29
|
+
Create the session on your server. Pass only presentation settings to the browser.
|
|
30
|
+
PayIn does not accept `prefill` in SDK create/update options or React props.
|
|
31
|
+
Prefill remains a generic capability that other components may support through `PREFILL_SET` and `PREFILL_REQUEST`.
|
|
32
|
+
|
|
33
|
+
### Session/init config
|
|
34
|
+
|
|
35
|
+
The request is `POST /api/v2/{slug}/Session/init` with `platform: 'Web'`, `entryPoint`, `allowedParentOrigins`, and `components`.
|
|
36
|
+
`GET /api/v2/Session/bootstrap` returns each component's config unchanged.
|
|
37
|
+
Tenant identity, operation, payment amounts, customer data, and invoice data come only from the server session.
|
|
38
|
+
The browser submit payload contains payment credentials, capture results, and the selected method, not business configuration.
|
|
39
|
+
|
|
40
|
+
The API's generated SDK owns session types. Browser `payinOptionsSchema` contains only `showSubmitButton`, `initialMethod`, and `methodOrder`.
|
|
41
|
+
|
|
42
|
+
```js
|
|
43
|
+
components: [
|
|
44
|
+
{
|
|
45
|
+
type: 'payin',
|
|
46
|
+
config: {
|
|
47
|
+
operation: 'pay',
|
|
48
|
+
methods: ['card', 'ach', 'check', 'applepay', 'googlepay'],
|
|
49
|
+
acceptedCardBrands: ['Visa', 'Mastercard'],
|
|
50
|
+
defaults: { achAccountType: 'checking' },
|
|
51
|
+
ach: { allowedAccountTypes: ['checking', 'savings'] },
|
|
52
|
+
fields: {
|
|
53
|
+
card: {
|
|
54
|
+
holderName: 'required',
|
|
55
|
+
cvv: 'required',
|
|
56
|
+
postalCode: 'required',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
forceCustomerCreation: false,
|
|
60
|
+
paymentDetails: { totalAmount: 12.34, serviceFee: 0.34, currency: 'USD' },
|
|
61
|
+
customerData: { firstName: 'Jane', lastName: 'Doe' },
|
|
62
|
+
invoiceData: { invoiceNumber: 'INV-1001' },
|
|
63
|
+
saveIfSuccess: false,
|
|
64
|
+
idempotencyKey: 'partner-key-123', // Optional. Omit for a generated key.
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- `paymentDetails` is required for `pay` and `auth`. `totalAmount` must exceed zero and already includes `serviceFee`. Never add the fee again.
|
|
71
|
+
- `serviceFee` is optional. If present, it must be at least zero and less than `totalAmount`.
|
|
72
|
+
- `currency` is optional and accepts only `USD` or `CAD`. Omitted currency displays as USD and stays omitted in the API request.
|
|
73
|
+
- `customerData` is required and non-null for `pay` and `auth`. An explicit `{}` is allowed. `invoiceData` remains optional. Both pass through unchanged.
|
|
74
|
+
- `saveIfSuccess` defaults to `false`. A value of `true` sets `paymentMethod.saveIfSuccess` for card, ACH, or wallets. Check submissions reject it.
|
|
75
|
+
|
|
76
|
+
For `tokenize`, omit `paymentDetails` and `invoiceData`. Do not set `saveIfSuccess` to `true`.
|
|
77
|
+
The session API rejects unknown fields. It does not trim, change case, infer names, or merge addresses in customer or invoice data.
|
|
78
|
+
The session config rejects `amount`, `billingAddress`, and `requiredFields`. There are no compatibility aliases.
|
|
79
|
+
|
|
80
|
+
#### Payment, customer, and invoice data
|
|
81
|
+
|
|
82
|
+
`operation` is `pay`, `auth`, or `tokenize`. `methods` contains only methods supported by the paypoint and operation.
|
|
83
|
+
An empty methods list uses paypoint capabilities, filtered by the operation. Session creation fails when no supported method remains.
|
|
84
|
+
`acceptedCardBrands` stays server-owned. The exported `CARD_BRANDS` tuple lists the card brand vocabulary.
|
|
85
|
+
`defaults.achAccountType` supplies the ACH default. The ACH rules below constrain its value.
|
|
86
|
+
|
|
87
|
+
These are the supported nested fields. Except for `paymentDetails.totalAmount`, each nested field is optional.
|
|
88
|
+
Use the API's generated SDK for session types, not a second browser-side session schema.
|
|
89
|
+
|
|
90
|
+
```js
|
|
91
|
+
paymentDetails: {
|
|
92
|
+
totalAmount: 12.34, serviceFee: 0.34, currency: 'USD',
|
|
93
|
+
checkNumber: '1001', checkUniqueId: 'check-1001',
|
|
94
|
+
orderDescription: 'Order', orderId: '1001', orderIdAlternative: 'ALT-1001',
|
|
95
|
+
paymentDescription: 'Payment', settlementDescriptor: 'STORE', groupNumber: '1',
|
|
96
|
+
unbundled: false,
|
|
97
|
+
categories: [{ label: 'Item', description: 'Item details', amount: 1, qty: 1 }],
|
|
98
|
+
splitFunding: [{
|
|
99
|
+
recipientEntryPoint: 'recipient', accountId: 'account', description: 'Share', amount: 1,
|
|
100
|
+
}],
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`categories[].amount` and `splitFunding[].amount` must exceed zero when present.
|
|
105
|
+
The displayed total and wallet sheet amount are `totalAmount`. Wallet currency is `currency ?? 'USD'`.
|
|
106
|
+
RDC capture supplies `checkNumber`, `checkUniqueId`, and `checkImage`, overriding configured check identifiers.
|
|
107
|
+
All other configured payment details survive. The session rejects `checkImage`, `source`, and `payabliTransId` inside `paymentDetails`.
|
|
108
|
+
The app keeps its fixed top-level `source`. It gets `entryPoint` from the session.
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
customerData: {
|
|
112
|
+
customerId: 123, customerStatus: 1, firstName: 'Jane', lastName: 'Doe',
|
|
113
|
+
company: 'Example', customerNumber: 'C-1001',
|
|
114
|
+
billingAddress1: '123 Main St', billingAddress2: 'Unit 1', billingCity: 'Austin',
|
|
115
|
+
billingState: 'TX', billingZip: '78701', billingCountry: 'US',
|
|
116
|
+
billingPhone: '5125550100', billingEmail: 'jane@example.com',
|
|
117
|
+
shippingAddress1: '123 Main St', shippingAddress2: 'Unit 1', shippingCity: 'Austin',
|
|
118
|
+
shippingState: 'TX', shippingZip: '78701', shippingCountry: 'US',
|
|
119
|
+
additionalData: { key: 'value' }, identifierFields: ['email'],
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
An explicit customer or invoice `{}` stays `{}`. An absent optional object stays absent in the API request.
|
|
124
|
+
The app does not infer customer names from holder fields or merge card ZIP codes or wallet contacts into customer data.
|
|
125
|
+
Unknown properties in these objects and their nested arrays produce a clear HTTP 400 instead of silent removal.
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
invoiceData: {
|
|
129
|
+
invoiceNumber: 'INV-1001', invoiceDate: '2026-09-10', invoiceDueDate: '2026-10-10',
|
|
130
|
+
invoiceEndDate: '2026-10-10', invoiceStatus: 1, invoiceType: 0,
|
|
131
|
+
frequency: 'onetime', paymentTerms: 'Net 30', termsConditions: 'Terms', notes: 'Note',
|
|
132
|
+
tax: 0, discount: 0, invoiceAmount: 12.34, freightAmount: 0, dutyAmount: 0,
|
|
133
|
+
purchaseOrder: 'PO-1001', firstName: 'Jane', lastName: 'Doe', company: 'Example',
|
|
134
|
+
shippingAddress1: '123 Main St', shippingAddress2: 'Unit 1', shippingCity: 'Austin',
|
|
135
|
+
shippingState: 'TX', shippingZip: '78701', shippingCountry: 'US',
|
|
136
|
+
shippingEmail: 'jane@example.com', shippingPhone: '5125550100', shippingFromZip: '78701',
|
|
137
|
+
summaryCommodityCode: '1000',
|
|
138
|
+
items: [{
|
|
139
|
+
itemProductCode: 'SKU-1', itemProductName: 'Item', itemDescription: 'Item details',
|
|
140
|
+
itemCommodityCode: '1000', itemUnitOfMeasure: 'each', itemCost: 1, itemQty: 1,
|
|
141
|
+
itemMode: 0, itemCategories: ['Category'], itemTotalAmount: 1, itemTaxAmount: 0, itemTaxRate: 0,
|
|
142
|
+
}],
|
|
143
|
+
attachments: [{
|
|
144
|
+
ftype: 'pdf', filename: 'invoice.pdf', fileDescriptor: 'Invoice',
|
|
145
|
+
furl: 'https://example.com/invoice.pdf', fContent: 'base64',
|
|
146
|
+
}],
|
|
147
|
+
additionalData: { key: 'value' },
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Customer creation for pay and auth
|
|
152
|
+
|
|
153
|
+
Pay and auth sessions reject missing or null customer data with `customerData is required for pay and auth sessions`.
|
|
154
|
+
The payment API must match the customer through the paypoint identifiers.
|
|
155
|
+
If it cannot match the customer, it returns HTTP 400 unless `forceCustomerCreation: true` allows creation.
|
|
156
|
+
The optional top-level `forceCustomerCreation` flag defaults to `false` and applies only to `pay` and `auth`.
|
|
157
|
+
For `tokenize`, use `tokenization.forceCustomerCreation` instead. The API rejects the top-level flag for tokenize sessions.
|
|
158
|
+
|
|
159
|
+
#### ACH session settings
|
|
160
|
+
|
|
161
|
+
Set ACH restrictions and request flags in the server session:
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
config: {
|
|
165
|
+
operation: 'pay',
|
|
166
|
+
methods: ['ach'],
|
|
167
|
+
paymentDetails: { totalAmount: 50, currency: 'USD' },
|
|
168
|
+
customerData: { firstName: 'Jane', lastName: 'Doe' },
|
|
169
|
+
forceCustomerCreation: true,
|
|
170
|
+
defaults: { achAccountType: 'checking' },
|
|
171
|
+
ach: {
|
|
172
|
+
allowedAccountTypes: ['checking'],
|
|
173
|
+
confirmAccountNumber: true,
|
|
174
|
+
confirmRoutingNumber: true,
|
|
175
|
+
validation: true,
|
|
176
|
+
sameDay: true,
|
|
177
|
+
},
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
- `ach` is optional for `pay` and `tokenize`. Auth sessions reject it because ACH does not support authorization.
|
|
182
|
+
- A non-empty `methods` list must include `ach`. Otherwise, the API rejects the block with `ach settings require the ach method`.
|
|
183
|
+
- `allowedAccountTypes` defaults to `['checking', 'savings']`. Values must be lowercase. The list must contain at least one type without duplicates.
|
|
184
|
+
- `defaults.achAccountType` is optional and must be an allowed type. With one allowed type, the form uses it without a selector.
|
|
185
|
+
- The server rejects an account type outside the allowed list before any payment API call.
|
|
186
|
+
|
|
187
|
+
`confirmAccountNumber` and `confirmRoutingNumber` default to `false`.
|
|
188
|
+
When enabled, each UI-only confirmation field must match its original value. `change.isValid` includes these checks.
|
|
189
|
+
The session contains the confirmation flags. Confirmation values never enter browser submit payloads or payment API payloads.
|
|
190
|
+
The existing ACH consent text remains visible.
|
|
191
|
+
|
|
192
|
+
`ach.validation` defaults to `false` and applies only to pay sessions.
|
|
193
|
+
It enables the payment API's ACH validation add-on through the GetPaid query flag `achValidation`.
|
|
194
|
+
It does not enable local routing-number validation, microdeposits, or Plaid. The connector can also require this add-on.
|
|
195
|
+
Tokenize sessions reject `ach.validation`. Use `tokenization.achValidation` instead.
|
|
196
|
+
|
|
197
|
+
`ach.sameDay` defaults to `false` and applies only to pay sessions through the GetPaid query flag `sameDayACH`.
|
|
198
|
+
Tokenize sessions reject it. The payment form has no same-day control.
|
|
199
|
+
The server sends these query flags only when true and only for ACH pay submissions.
|
|
200
|
+
The server sends `forceCustomerCreation` only when true, for any pay method or an auth submission.
|
|
201
|
+
|
|
202
|
+
#### Field visibility and requiredness
|
|
203
|
+
|
|
204
|
+
Set `fields` in the server session config, not in browser options:
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
fields: {
|
|
208
|
+
card: {
|
|
209
|
+
holderName: 'required',
|
|
210
|
+
cvv: 'optional',
|
|
211
|
+
postalCode: 'hidden',
|
|
212
|
+
},
|
|
213
|
+
ach: { holderName: 'optional' },
|
|
214
|
+
check: { holderName: 'required' },
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The `fields` block, each method block, and every entry are optional.
|
|
219
|
+
Every entry defaults to `required`. Values must be lowercase `required`, `optional`, or `hidden`.
|
|
220
|
+
|
|
221
|
+
- `required` preserves the existing required input and validation rules.
|
|
222
|
+
- `optional` shows the input and allows an empty value. The API payload omits empty credentials instead of sending `""`.
|
|
223
|
+
- Non-empty optional values use the existing format rules, including three or four digits for CVV and the postal code format.
|
|
224
|
+
- `hidden` removes the input from the form, client validation, and `change.fields`. The API payload omits the credential key.
|
|
225
|
+
- The server rejects a non-empty browser submit value for a hidden field. Session rules also control server validation and `change.isValid`.
|
|
226
|
+
|
|
227
|
+
Card number, expiration, routing number, account number, and account type cannot be configured or hidden through `fields`.
|
|
228
|
+
The API rejects unknown members. The typed `fields` block replaces `requiredFields`, with no compatibility alias.
|
|
229
|
+
If a non-empty `methods` list excludes a method, the API rejects its field block with `fields.<method> requires the <method> method`.
|
|
230
|
+
Check is available only for pay. Tokenize sessions use the same field rules for card and ACH. Wallets are unaffected.
|
|
231
|
+
|
|
232
|
+
The playground shows a method's field controls only when that method is checked.
|
|
233
|
+
It sends only non-default entries and omits empty method blocks and an empty `fields` block.
|
|
234
|
+
|
|
235
|
+
#### Tokenization
|
|
236
|
+
|
|
237
|
+
Create tokenization configuration on your server with `Session/init`:
|
|
238
|
+
|
|
239
|
+
```js
|
|
240
|
+
components: [
|
|
241
|
+
{
|
|
242
|
+
type: 'payin',
|
|
243
|
+
config: {
|
|
244
|
+
operation: 'tokenize',
|
|
245
|
+
methods: ['card', 'ach'],
|
|
246
|
+
customerData: { customerId: 123 },
|
|
247
|
+
tokenization: {
|
|
248
|
+
lifetime: 'permanent', // Required: 'temporary' or 'permanent'.
|
|
249
|
+
customerMode: 'customer', // Required: 'anonymous' or 'customer'.
|
|
250
|
+
forceCustomerCreation: false, // Optional. Defaults to false.
|
|
251
|
+
achValidation: false, // Optional. Defaults to false.
|
|
252
|
+
methodDescription: 'Saved payment method', // Optional, 1 to 255 characters.
|
|
253
|
+
methodType: 0, // Optional: 0, 1, or 2. Omit for the connector default.
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
];
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
- `anonymous` mode forbids `customerData`. Omit `forceCustomerCreation` or set it to `false`.
|
|
261
|
+
- `customer` mode requires non-null `customerData`. The API must resolve the customer, or `forceCustomerCreation: true` must create it.
|
|
262
|
+
- `temporary` methods expire after 12 hours. Use `permanent` for storage without that expiration.
|
|
263
|
+
- `achValidation: true` requires ACH in `methods` and enables the API validation add-on. The connector can also require this add-on.
|
|
264
|
+
- `methodType` values are `0` for single use, `1` for a universal token, and `2` for a network token. Unsupported connector types return an error. The API stores `methodDescription` unchanged.
|
|
265
|
+
|
|
266
|
+
`methods` accepts only `card` and `ach`. An empty list uses the paypoint's methods, filtered to card and ACH.
|
|
267
|
+
Session creation fails if no supported method remains. Wallet and check tokenization are not available.
|
|
268
|
+
Fallback authorization is not offered because the API ignores `fallbackAuth` and `fallbackAuthAmount`.
|
|
269
|
+
|
|
270
|
+
`tokenization` is required for `tokenize` and rejected for `pay` or `auth`.
|
|
271
|
+
Omit `paymentDetails`, `invoiceData`, and `saveIfSuccess` for tokenize sessions.
|
|
272
|
+
The component shows no payment total. Its default submit label is `Save`, unless `appearance.labels.submit` overrides it.
|
|
273
|
+
|
|
274
|
+
#### Idempotency key
|
|
275
|
+
|
|
276
|
+
`idempotencyKey` is optional in `components[].config`. Supply it from your server, or omit it for a key generated by platform-api.
|
|
277
|
+
A supplied key must contain 1 to 64 characters from `[A-Za-z0-9._:-]`. The API stores it as `{sessionId}:{key}`.
|
|
278
|
+
|
|
279
|
+
### Browser options
|
|
280
|
+
|
|
281
|
+
`options` contains only the following browser presentation settings:
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
{
|
|
285
|
+
showSubmitButton?: boolean;
|
|
286
|
+
initialMethod?: 'card' | 'ach' | 'check';
|
|
287
|
+
methodOrder?: ('card' | 'ach' | 'check')[];
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
`showSubmitButton: true` shows the internal submit button. Set it to `false` when the host calls `submit()`.
|
|
292
|
+
|
|
293
|
+
`initialMethod` and `methodOrder` are optional browser `options`, alongside `showSubmitButton`.
|
|
294
|
+
Both accept only `card`, `ach`, and `check`. `methodOrder` must be an array.
|
|
295
|
+
The exported `FORM_METHODS` tuple defines the default order.
|
|
296
|
+
|
|
297
|
+
1. Use only session-allowed form methods. Options never enable a method.
|
|
298
|
+
2. Keep allowed `methodOrder` entries in the given order. The first occurrence wins. Ignore duplicates and disallowed entries.
|
|
299
|
+
3. Append unlisted allowed methods in the default order: card, ach, check.
|
|
300
|
+
4. Select `initialMethod` when session-allowed. Otherwise, select the first method in the effective order.
|
|
301
|
+
5. Keep wallets in their own section. These options do not affect wallets.
|
|
302
|
+
|
|
303
|
+
Without overrides, the default order and initial method stay unchanged.
|
|
304
|
+
The options schema rejects unknown method names and non-array orders. It accepts duplicates for the iframe to ignore.
|
|
305
|
+
The SDK forwards options unchanged through `CONFIG_SET.options`. React uses the existing `options` prop, with no new props.
|
|
306
|
+
`payin.update({ options: { initialMethod: 'card', methodOrder: ['card', 'ach'] } })` remounts the iframe.
|
|
307
|
+
No new session is required. Layout, density, label style, and color scheme are unchanged.
|
|
308
|
+
|
|
309
|
+
### Appearance
|
|
310
|
+
|
|
311
|
+
`appearance` is client-side. `update()` remounts the iframe without creating a new session.
|
|
312
|
+
|
|
313
|
+
| Setting | Values and behavior |
|
|
314
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
315
|
+
| `layout` | `tabs`, `accordion`, `stacked`, `minimal`. Default is `tabs`. A single-method session renders the bare form. |
|
|
316
|
+
| `layoutVariant` | Density: `compact`, `standard`, `wide`. |
|
|
317
|
+
| `labelStyle` | `above`, `floating`, `outlined`. Default is `above`. |
|
|
318
|
+
| `colorScheme` | `light`, `dark`, `system`. `system` follows the buyer's device. |
|
|
319
|
+
| `tokens` / `labels` | String records for supported CSS custom properties and text overrides. |
|
|
320
|
+
|
|
321
|
+
`above` places labels over inputs. `floating` lifts labels inside the box. `outlined` lifts labels onto a notch in the border.
|
|
322
|
+
Supported tokens include `--primary`, `--background`, `--pb-container-padding`, and `--pb-container-background`.
|
|
323
|
+
|
|
324
|
+
The SDK matches the iframe's `color-scheme` to its document. A mismatch makes the cross-origin frame opaque.
|
|
325
|
+
Use `--pb-container-background: transparent` to show the host page through the frame in both modes.
|
|
326
|
+
|
|
327
|
+
#### Text overrides
|
|
328
|
+
|
|
329
|
+
Set field text in `appearance.labels`. These browser settings do not change payloads, validation, or session-allowed methods.
|
|
330
|
+
|
|
331
|
+
| Label key | Placeholder key |
|
|
332
|
+
| -------------------------------- | ----------------------------------------- |
|
|
333
|
+
| `label.card.holderName` | `placeholder.card.holderName` |
|
|
334
|
+
| `label.card.number` | `placeholder.card.number` |
|
|
335
|
+
| `label.card.expiration` | `placeholder.card.expiration` |
|
|
336
|
+
| `label.card.cvv` | `placeholder.card.cvv` |
|
|
337
|
+
| `label.card.postalCode` | `placeholder.card.postalCode` |
|
|
338
|
+
| `label.ach.holderName` | `placeholder.ach.holderName` |
|
|
339
|
+
| `label.ach.accountType` | None |
|
|
340
|
+
| `label.ach.routingNumber` | `placeholder.ach.routingNumber` |
|
|
341
|
+
| `label.ach.accountNumber` | `placeholder.ach.accountNumber` |
|
|
342
|
+
| `label.ach.confirmRoutingNumber` | `placeholder.ach.confirmRoutingNumber` |
|
|
343
|
+
| `label.ach.confirmAccountNumber` | `placeholder.ach.confirmAccountNumber` |
|
|
344
|
+
| `label.check.holderName` | `placeholder.check.holderName` |
|
|
345
|
+
| `label.check.capture` | None, sets the RDC capture call to action |
|
|
346
|
+
|
|
347
|
+
`method-check` sets the check tab label. The existing keys remain available:
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
submit
|
|
351
|
+
method-card
|
|
352
|
+
method-ach
|
|
353
|
+
method-applepay
|
|
354
|
+
method-googlepay
|
|
355
|
+
wallet-divider
|
|
356
|
+
ach-consent
|
|
357
|
+
error-declined
|
|
358
|
+
error-generic
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The iframe drops keys outside this allowlist. It trims values and limits them to 120 characters.
|
|
362
|
+
It renders values as text with React escaping, never as HTML.
|
|
363
|
+
The shared wire schema remains `Record<string, string>` because other components use different keys.
|
|
364
|
+
Use the exported `PAYIN_LABEL_KEYS` tuple and `PayInLabelKey` type from `@payabli/component-contracts` for PayIn-specific typing:
|
|
365
|
+
|
|
366
|
+
```ts
|
|
367
|
+
import type { PayInLabelKey } from '@payabli/component-contracts';
|
|
368
|
+
|
|
369
|
+
const labels: Partial<Record<PayInLabelKey, string>> = {
|
|
370
|
+
'label.card.number': 'Card number',
|
|
371
|
+
'placeholder.card.number': 'Enter card number',
|
|
372
|
+
'method-check': 'Scan a check',
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
const payin = payabli.create('payin', {
|
|
376
|
+
appearance: { labels },
|
|
377
|
+
options: {
|
|
378
|
+
initialMethod: 'ach',
|
|
379
|
+
methodOrder: ['ach', 'card', 'check'],
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Events
|
|
385
|
+
|
|
386
|
+
#### Success and errors
|
|
387
|
+
|
|
388
|
+
`success` and React's `onSuccess` report confirmed success only. `submit()` resolves with the same result data.
|
|
389
|
+
`PayInSuccessPayload.transactionId` identifies a pay or auth transaction when present.
|
|
390
|
+
The wire success data remains an open record. The SDK preserves fields it does not interpret.
|
|
391
|
+
|
|
392
|
+
For tokenize sessions, `SUBMIT_RESULT.data`, the `success` event, and the `submit()` result contain:
|
|
393
|
+
|
|
394
|
+
```ts
|
|
395
|
+
{ referenceId: string, customerId?: number, methodReferenceId?: string }
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
`referenceId` is the saved payment method ID, not a transaction ID. `PayInSuccessPayload` declares it as an optional string.
|
|
399
|
+
|
|
400
|
+
A failed `SUBMIT_RESULT` rejects `submit()` and emits `error`, mapped to React's `onError`.
|
|
401
|
+
Errors have `{ code, message, recoverable, details? }`. The SDK forwards the code and message unchanged.
|
|
402
|
+
Wallet helpers report success only when the server classifies the result as successful.
|
|
403
|
+
The iframe emits failed `SUBMIT_RESULT` and `ERROR` with the same error once per wallet failure.
|
|
404
|
+
Recoverable failures release the lock. Non-recoverable failures keep it locked.
|
|
405
|
+
|
|
406
|
+
| Code | Meaning and action |
|
|
407
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
408
|
+
| `SUBMIT_FAILED` | Confirmed decline or validation failure. Keep entered values and allow correction when `recoverable: true`. |
|
|
409
|
+
| `OUTCOME_UNKNOWN` | The API did not confirm the result. A prior attempt may have processed. Do not retry this session. |
|
|
410
|
+
| `SESSION_COMPLETED` | The session already succeeded. Create a new session. |
|
|
411
|
+
| `UNSUPPORTED_OPERATION` | The session operation does not support this method. No payment API call occurs. |
|
|
412
|
+
| `UNSUPPORTED_SAVE_METHOD` | Check cannot use `saveIfSuccess: true`. No payment API call occurs. |
|
|
413
|
+
|
|
414
|
+
The server can report submit codes beyond the SDK's exported `ErrorCodes` constants, including `SUBMIT_FAILED` and `UNSUPPORTED_SAVE_METHOD`.
|
|
415
|
+
|
|
416
|
+
#### Lifecycle and wallet cancellation
|
|
417
|
+
|
|
418
|
+
`WALLET_CANCEL` maps to the SDK event `walletCancel` and the React callback `onWalletCancel`.
|
|
419
|
+
The payload is `{ wallet: 'applepay' | 'googlepay' }`.
|
|
420
|
+
The iframe emits it when the buyer closes the Apple Pay sheet or Google Pay returns `statusCode: "CANCELED"`.
|
|
421
|
+
Cancellation is not an error or a submit result. The iframe releases its lock, so the buyer can try another payment method.
|
|
422
|
+
The SDK does not emit `error` or `success`, or settle a pending `submit()` promise, for this event.
|
|
423
|
+
The `message` event also reports the inbound `WALLET_CANCEL` for the playground log.
|
|
424
|
+
|
|
425
|
+
```ts
|
|
426
|
+
payin.on('walletCancel', ({ wallet }) => {
|
|
427
|
+
// Update the checkout UI for the canceled wallet.
|
|
428
|
+
});
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
```tsx
|
|
432
|
+
<PayIn
|
|
433
|
+
onWalletCancel={({ wallet }) => {
|
|
434
|
+
// Update the checkout UI for the canceled wallet.
|
|
435
|
+
}}
|
|
436
|
+
/>
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
`ready` and `rendered` are lifecycle events. Validity is `change.isValid` (`STATE_CHANGE`).
|
|
440
|
+
In React, read `isValid` from `onChange`. Do not use `onReady` or `onRendered` as a validity signal.
|
|
441
|
+
|
|
442
|
+
#### SDK and session errors
|
|
443
|
+
|
|
444
|
+
| Code | Meaning and recovery |
|
|
445
|
+
| ------------------------ | --------------------------------------------------------------------------------------------------------- |
|
|
446
|
+
| `LOAD_TIMEOUT` | The iframe did not send READY within the timeout. The SDK retries loading once before reporting an error. |
|
|
447
|
+
| `PROTOCOL_ERROR` | postMessage validation failed. |
|
|
448
|
+
| `INVALID_STATE` | The operation targets a destroyed instance. |
|
|
449
|
+
| `SESSION_EXPIRED` | The session reached its ceiling or refresh failed without recovery. Supply a new session. |
|
|
450
|
+
| `SESSION_REFRESH_FAILED` | An individual auto-refresh attempt failed and is recoverable. |
|
|
451
|
+
| `TOKEN_EXPIRED` | An iframe API call used an expired JWT. The SDK refreshes immediately without a public event. |
|
|
452
|
+
| `RENDER_TOKEN_EXPIRED` | The frame URL no longer renders. The SDK rebuilds the frame and reports an error after the rebuild limit. |
|
|
453
|
+
| `RENDER_TOKEN_INVALID` | Render token signature, audience, or format checks failed. Global `sessionError` requires a new session. |
|
|
454
|
+
|
|
455
|
+
### Post-success lock and session replacement
|
|
456
|
+
|
|
457
|
+
The API namespaces a partner key as `{sessionId}:{key}` so two sessions can reuse the same partner key. A generated key uses the same form: `{sessionId}:{GUID}`, 65 characters in total. Attempt 1 sends the stored value returned by bootstrap, and later attempts append `-{n}` to that value.
|
|
458
|
+
The attempt counter advances only after a confirmed failure. Browser submissions do not supply the key or the attempt number.
|
|
459
|
+
|
|
460
|
+
`OUTCOME_UNKNOWN` means the payment API did not confirm the outcome. A previous attempt may have been processed.
|
|
461
|
+
This error is terminal for the session (`recoverable: false`). The component keeps entered values but stays locked.
|
|
462
|
+
The host must not retry with this session. A fresh session is required.
|
|
463
|
+
The SDK never retries a submit automatically. `SUBMIT_FAILED` remains the code for confirmed failures.
|
|
464
|
+
|
|
465
|
+
After success, the component clears sensitive payment fields and locks all fields and wallet buttons.
|
|
466
|
+
Repeated submissions return `SESSION_COMPLETED` with `recoverable: false`.
|
|
467
|
+
Both error codes pass unchanged to the `submit()` rejection and the `error` event, or React's `onError` callback.
|
|
468
|
+
|
|
469
|
+
Call `payabli.updateSession(newSession)` with a newly created session to unlock the component.
|
|
470
|
+
This sends `SESSION_UPDATE` with `replace: true`. A token refresh with `replace: false` does not unlock it.
|
|
471
|
+
|
|
472
|
+
Wallet sheets and form submission share one in-flight lock. Closing a wallet sheet releases it.
|
|
473
|
+
After success, the iframe clears card number, CVV, expiration, account number, routing number, and check capture.
|
|
474
|
+
The server records session completion and rejects later submissions before any payment API call.
|
|
475
|
+
A new bootstrap session ID also remounts the form with fresh state and the new session key.
|
|
476
|
+
Appearance updates and token refreshes do not clear the server completion lock.
|
|
477
|
+
|
|
478
|
+
The server stores attempt counters and completion records in Redis for the session lifetime. If Redis is unavailable, submission fails closed.
|
|
479
|
+
GetPaid and Authorize cache each idempotency key for two minutes before processing, regardless of the result.
|
|
480
|
+
Duplicate keys return HTTP 409 without replaying the original result. HTTP 409 maps to `OUTCOME_UNKNOWN`, not a decline.
|
|
481
|
+
Network failures, timeouts after dispatch, and unconfirmed server failures also map to `OUTCOME_UNKNOWN`.
|
|
482
|
+
TokenStorage does not deduplicate this header. The session attempt and completion locks still apply to tokenization.
|
|
483
|
+
|
|
484
|
+
### Method × operation matrix
|
|
485
|
+
|
|
486
|
+
| method | pay (GetPaid) | auth (Authorize) | tokenize (TokenStorage) |
|
|
487
|
+
| --------- | ------------- | ---------------- | ----------------------- |
|
|
488
|
+
| card | yes | yes | yes |
|
|
489
|
+
| ach | yes | NO | yes |
|
|
490
|
+
| check | yes | NO | NO |
|
|
491
|
+
| applepay | yes | yes | NO |
|
|
492
|
+
| googlepay | yes | yes | NO |
|
|
493
|
+
|
|
494
|
+
`Session/init` rejects method and operation pairs outside this table.
|
|
495
|
+
For `auth`, an empty `methods` list uses paypoint capabilities filtered to card, Apple Pay, and Google Pay.
|
|
496
|
+
Session creation fails if no supported method remains.
|
|
497
|
+
The iframe also rejects unsupported pairs before an API call. It never substitutes `pay` for `auth` or `tokenize`.
|
|
498
|
+
`UNSUPPORTED_OPERATION` means: "The session operation does not support this payment method."
|
|
499
|
+
|
|
500
|
+
### Migration from the legacy embedded component
|
|
501
|
+
|
|
502
|
+
This is a pre-production breaking change. Remove obsolete configuration instead of adding compatibility aliases.
|
|
503
|
+
|
|
504
|
+
| Legacy option or behavior | New location or action |
|
|
505
|
+
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
506
|
+
| Browser `operation`, `methods`, `acceptedCardBrands` | Server `components[].config` in `Session/init`. |
|
|
507
|
+
| `amount: { amount, currency }` | `config.paymentDetails: { totalAmount, currency }`. The total already includes the fee. |
|
|
508
|
+
| `billingAddress` | Removed. Supply customer billing fields in server-owned `config.customerData`. |
|
|
509
|
+
| `requiredFields` | Removed. Use typed `config.fields` entries. |
|
|
510
|
+
| PayIn `prefill` | Removed from SDK options and React props. Supply customer data in the server session. |
|
|
511
|
+
| Customer, invoice, and save-on-success data in browser config | `config.customerData`, `config.invoiceData`, `config.saveIfSuccess`. |
|
|
512
|
+
| Form selection and order | Browser `options.initialMethod` and `options.methodOrder`. Only session-allowed methods appear. |
|
|
513
|
+
| Field label and placeholder text | Browser `appearance.labels` using the keys above. |
|
|
514
|
+
| `appearance.mode` | `appearance.colorScheme`. |
|
|
515
|
+
| Ready-means-valid behavior | Use `change.isValid` or React `onChange`. `ready` and `rendered` are lifecycle events. |
|
|
516
|
+
| Repeated submit after success | Create a new session and call `payabli.updateSession(newSession)`. |
|
|
517
|
+
|
|
518
|
+
Pay and auth examples must supply non-null `customerData`. Use identifiers that match the paypoint's customer rules.
|
|
519
|
+
An empty object passes session validation but does not guarantee that the payment API can resolve a customer.
|
|
520
|
+
Do not send customer or invoice data from buyer-controlled browser configuration.
|
|
521
|
+
|
|
522
|
+
### Rollout order
|
|
523
|
+
|
|
524
|
+
1. Deploy platform-api so `Session/init` accepts and returns the new PayIn config. The bootstrap must carry that config.
|
|
525
|
+
2. Publish `@payabli/component-contracts`, the `@payabli/components-web` CDN script, and `@payabli/components-react`. The SDK must support `WALLET_CANCEL`, the new error codes, and the `initialMethod` and `methodOrder` options.
|
|
526
|
+
3. Deploy payabli/app with session-owned submission, field rules, tokenization, wallet classification, and locks. Remove its temporary local contract shims in a follow-up.
|
|
527
|
+
4. Update playground and example installations to use those releases.
|
|
528
|
+
|
|
529
|
+
Publish the SDK before deploying the iframe because an old SDK turns an unknown `WALLET_CANCEL` event into `PROTOCOL_ERROR`.
|
|
530
|
+
|
|
531
|
+
The follow-up removes these temporary local contract shims:
|
|
532
|
+
|
|
533
|
+
- Error literals in `app/modules/embed/payin-errors.ts`.
|
|
534
|
+
- The local `WALLET_CANCEL` schema and options extension in `meta.ts`.
|
|
535
|
+
- The `zod-v4` alias.
|
|
536
|
+
|
|
537
|
+
### Deferred items
|
|
538
|
+
|
|
539
|
+
| Area | Not included in this contract |
|
|
540
|
+
| ---------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
541
|
+
| Payment flows | Saved-method selection, recurring payments, cloud devices, and lightbox. |
|
|
542
|
+
| GetPaid metadata | Top-level `orderId`, `orderDescription`, and configurable `source`. Nested `paymentDetails` order fields remain supported. |
|
|
543
|
+
| Tokenization | Wallet and check tokenization. Wallet storage needs a product decision about the API's hidden $0.01 authorization and void. |
|
|
544
|
+
| Styling | External CSS and per-field layout. Use supported appearance tokens, layouts, and text keys. |
|
|
545
|
+
|
|
546
|
+
Fallback authorization is not offered. The API ignores `fallbackAuth` and `fallbackAuthAmount`.
|
|
547
|
+
Anonymous wallet storage also has an unresolved server failure. Do not bypass the wallet tokenization restriction.
|
|
548
|
+
|
|
27
549
|
## Versioning
|
|
28
550
|
|
|
29
551
|
Pre-1.0. A breaking wire change is a minor bump. `MESSAGE_VERSION` changes
|
package/dist/errors.d.ts
CHANGED
|
@@ -2,6 +2,12 @@ export declare const ErrorCodes: {
|
|
|
2
2
|
readonly LOAD_TIMEOUT: "LOAD_TIMEOUT";
|
|
3
3
|
readonly PROTOCOL_ERROR: "PROTOCOL_ERROR";
|
|
4
4
|
readonly INVALID_STATE: "INVALID_STATE";
|
|
5
|
+
/** The session operation does not support this payment method. */
|
|
6
|
+
readonly UNSUPPORTED_OPERATION: "UNSUPPORTED_OPERATION";
|
|
7
|
+
/** The payment API did not confirm the outcome. Do not retry with this session. */
|
|
8
|
+
readonly OUTCOME_UNKNOWN: "OUTCOME_UNKNOWN";
|
|
9
|
+
/** This session already completed an operation. Create a new session. */
|
|
10
|
+
readonly SESSION_COMPLETED: "SESSION_COMPLETED";
|
|
5
11
|
readonly SESSION_EXPIRED: "SESSION_EXPIRED";
|
|
6
12
|
readonly SESSION_REFRESH_FAILED: "SESSION_REFRESH_FAILED";
|
|
7
13
|
/** Reported by an iframe whose call was rejected for an expired JWT. Triggers a refresh. */
|
package/dist/index.js
CHANGED
|
@@ -1678,13 +1678,49 @@ function getComponentDescriptor(type) {
|
|
|
1678
1678
|
* PayIn-specific on purpose — a payout component defines its own methods in
|
|
1679
1679
|
* its own folder.
|
|
1680
1680
|
*/
|
|
1681
|
+
const FORM_METHODS = ['card', 'ach', 'check'];
|
|
1681
1682
|
const PAYMENT_METHODS = [
|
|
1682
|
-
|
|
1683
|
-
'ach',
|
|
1684
|
-
'check',
|
|
1683
|
+
...FORM_METHODS,
|
|
1685
1684
|
'applepay',
|
|
1686
1685
|
'googlepay',
|
|
1687
1686
|
];
|
|
1687
|
+
/** PayIn text keys. The iframe drops other keys, trims values, and limits text to 120 characters. */
|
|
1688
|
+
const PAYIN_LABEL_KEYS = [
|
|
1689
|
+
'submit',
|
|
1690
|
+
'method-card',
|
|
1691
|
+
'method-ach',
|
|
1692
|
+
'method-applepay',
|
|
1693
|
+
'method-googlepay',
|
|
1694
|
+
'wallet-divider',
|
|
1695
|
+
'ach-consent',
|
|
1696
|
+
'error-declined',
|
|
1697
|
+
'error-generic',
|
|
1698
|
+
'method-check',
|
|
1699
|
+
'label.card.holderName',
|
|
1700
|
+
'placeholder.card.holderName',
|
|
1701
|
+
'label.card.number',
|
|
1702
|
+
'placeholder.card.number',
|
|
1703
|
+
'label.card.expiration',
|
|
1704
|
+
'placeholder.card.expiration',
|
|
1705
|
+
'label.card.cvv',
|
|
1706
|
+
'placeholder.card.cvv',
|
|
1707
|
+
'label.card.postalCode',
|
|
1708
|
+
'placeholder.card.postalCode',
|
|
1709
|
+
'label.ach.holderName',
|
|
1710
|
+
'placeholder.ach.holderName',
|
|
1711
|
+
'label.ach.accountType',
|
|
1712
|
+
'label.ach.routingNumber',
|
|
1713
|
+
'placeholder.ach.routingNumber',
|
|
1714
|
+
'label.ach.accountNumber',
|
|
1715
|
+
'placeholder.ach.accountNumber',
|
|
1716
|
+
'label.ach.confirmRoutingNumber',
|
|
1717
|
+
'placeholder.ach.confirmRoutingNumber',
|
|
1718
|
+
'label.ach.confirmAccountNumber',
|
|
1719
|
+
'placeholder.ach.confirmAccountNumber',
|
|
1720
|
+
'label.check.holderName',
|
|
1721
|
+
'placeholder.check.holderName',
|
|
1722
|
+
'label.check.capture',
|
|
1723
|
+
];
|
|
1688
1724
|
/**
|
|
1689
1725
|
* A card network. Not a payment method. Accepted brands are session config
|
|
1690
1726
|
* (`Session/init` acceptedCardBrands), not a client option: the API owns them
|
|
@@ -1699,14 +1735,23 @@ const CARD_BRANDS = [
|
|
|
1699
1735
|
'Diners',
|
|
1700
1736
|
];
|
|
1701
1737
|
/**
|
|
1702
|
-
* Client-side UI behavior only.
|
|
1703
|
-
*
|
|
1704
|
-
*
|
|
1738
|
+
* Client-side UI behavior only. The partner server sets operation, methods,
|
|
1739
|
+
* required fields, paymentDetails, customerData, invoiceData, and saveIfSuccess
|
|
1740
|
+
* through `Session/init`. The API's generated SDK owns session types.
|
|
1741
|
+
*
|
|
1742
|
+
* totalAmount already includes serviceFee. Currency accepts USD or CAD.
|
|
1743
|
+
* Omitted currency displays as USD and stays omitted in the API request.
|
|
1744
|
+
* Customer and invoice data pass through unchanged and stay omitted when absent.
|
|
1745
|
+
* saveIfSuccess defaults to false and supports card, ACH, and wallets.
|
|
1705
1746
|
*
|
|
1706
1747
|
* The SDK sends this in CONFIG_SET.options and payhub parses with this same
|
|
1707
1748
|
* object (via the descriptor's `optionsSchema`).
|
|
1708
1749
|
*/
|
|
1709
1750
|
const payinOptionsSchema = object({
|
|
1751
|
+
initialMethod: optional(_enum(FORM_METHODS)
|
|
1752
|
+
.check(describe('Select this form method first when session-allowed. Otherwise, use the first method in the effective order. Wallets stay separate.'))),
|
|
1753
|
+
methodOrder: optional(array(_enum(FORM_METHODS))
|
|
1754
|
+
.check(describe('Order session-allowed form methods only. Ignore disallowed entries and duplicates after the first occurrence. Append unlisted allowed methods in card, ach, check order. Wallets stay separate.'))),
|
|
1710
1755
|
showSubmitButton: optional(boolean()
|
|
1711
1756
|
.check(describe('Render the submit button inside the component. Set false when the host page owns the button and calls submit().'))),
|
|
1712
1757
|
});
|
|
@@ -1717,6 +1762,11 @@ const payinEvents = {
|
|
|
1717
1762
|
applepay: boolean(),
|
|
1718
1763
|
googlepay: boolean(),
|
|
1719
1764
|
}),
|
|
1765
|
+
/**
|
|
1766
|
+
* Emitted when the buyer closes the wallet sheet. This is not an error.
|
|
1767
|
+
* The component is ready for another attempt.
|
|
1768
|
+
*/
|
|
1769
|
+
WALLET_CANCEL: object({ wallet: _enum(['applepay', 'googlepay']) }),
|
|
1720
1770
|
CARD_BRAND_CHANGE: object({
|
|
1721
1771
|
/** A known brand, or 'unknown' while the number is too short to classify. */
|
|
1722
1772
|
brand: _enum([...CARD_BRANDS, 'unknown']),
|
|
@@ -1738,6 +1788,10 @@ const payInEventSchemas = {
|
|
|
1738
1788
|
event: 'walletAvailable',
|
|
1739
1789
|
schema: payinEvents.WALLET_AVAILABLE,
|
|
1740
1790
|
},
|
|
1791
|
+
WALLET_CANCEL: {
|
|
1792
|
+
event: 'walletCancel',
|
|
1793
|
+
schema: payinEvents.WALLET_CANCEL,
|
|
1794
|
+
},
|
|
1741
1795
|
CARD_BRAND_CHANGE: {
|
|
1742
1796
|
event: 'cardBrandChange',
|
|
1743
1797
|
schema: payinEvents.CARD_BRAND_CHANGE,
|
|
@@ -1763,6 +1817,12 @@ const ErrorCodes = {
|
|
|
1763
1817
|
LOAD_TIMEOUT: 'LOAD_TIMEOUT',
|
|
1764
1818
|
PROTOCOL_ERROR: 'PROTOCOL_ERROR',
|
|
1765
1819
|
INVALID_STATE: 'INVALID_STATE',
|
|
1820
|
+
/** The session operation does not support this payment method. */
|
|
1821
|
+
UNSUPPORTED_OPERATION: 'UNSUPPORTED_OPERATION',
|
|
1822
|
+
/** The payment API did not confirm the outcome. Do not retry with this session. */
|
|
1823
|
+
OUTCOME_UNKNOWN: 'OUTCOME_UNKNOWN',
|
|
1824
|
+
/** This session already completed an operation. Create a new session. */
|
|
1825
|
+
SESSION_COMPLETED: 'SESSION_COMPLETED',
|
|
1766
1826
|
SESSION_EXPIRED: 'SESSION_EXPIRED',
|
|
1767
1827
|
SESSION_REFRESH_FAILED: 'SESSION_REFRESH_FAILED',
|
|
1768
1828
|
/** Reported by an iframe whose call was rejected for an expired JWT. Triggers a refresh. */
|
|
@@ -1797,4 +1857,4 @@ const BASE_COMPONENT_EVENT_NAMES = [
|
|
|
1797
1857
|
'resize',
|
|
1798
1858
|
];
|
|
1799
1859
|
|
|
1800
|
-
export { BASE_COMPONENT_EVENT_NAMES, CARD_BRANDS, ErrorCodes, MESSAGE_SOURCE, MESSAGE_VERSION, PAYMENT_METHODS, appearanceSchema, baseInboundEvents, componentDescriptors, componentErrorSchema, componentTypes, eventEnvelopeSchema, getComponentDescriptor, outboundMessages, parseEnvelope, parseMessage, parsePayload, payInDescriptor, payInEventSchemas, payinEvents, payinOptionsSchema, register };
|
|
1860
|
+
export { BASE_COMPONENT_EVENT_NAMES, CARD_BRANDS, ErrorCodes, FORM_METHODS, MESSAGE_SOURCE, MESSAGE_VERSION, PAYIN_LABEL_KEYS, PAYMENT_METHODS, appearanceSchema, baseInboundEvents, componentDescriptors, componentErrorSchema, componentTypes, eventEnvelopeSchema, getComponentDescriptor, outboundMessages, parseEnvelope, parseMessage, parsePayload, payInDescriptor, payInEventSchemas, payinEvents, payinOptionsSchema, register };
|
|
@@ -45,6 +45,15 @@ export declare const payInEventSchemas: {
|
|
|
45
45
|
googlepay: import("zod/v4/mini").ZodMiniBoolean<boolean>;
|
|
46
46
|
}, import("zod/v4/core").$strip>;
|
|
47
47
|
};
|
|
48
|
+
WALLET_CANCEL: {
|
|
49
|
+
event: "walletCancel";
|
|
50
|
+
schema: import("zod/v4/mini").ZodMiniObject<{
|
|
51
|
+
wallet: import("zod/v4/mini").ZodMiniEnum<{
|
|
52
|
+
applepay: "applepay";
|
|
53
|
+
googlepay: "googlepay";
|
|
54
|
+
}>;
|
|
55
|
+
}, import("zod/v4/core").$strip>;
|
|
56
|
+
};
|
|
48
57
|
CARD_BRAND_CHANGE: {
|
|
49
58
|
event: "cardBrandChange";
|
|
50
59
|
schema: import("zod/v4/mini").ZodMiniObject<{
|
package/dist/payin/schema.d.ts
CHANGED
|
@@ -4,8 +4,12 @@ import * as z from 'zod/v4/mini';
|
|
|
4
4
|
* PayIn-specific on purpose — a payout component defines its own methods in
|
|
5
5
|
* its own folder.
|
|
6
6
|
*/
|
|
7
|
+
export declare const FORM_METHODS: readonly ["card", "ach", "check"];
|
|
7
8
|
export declare const PAYMENT_METHODS: readonly ["card", "ach", "check", "applepay", "googlepay"];
|
|
8
9
|
export type PaymentMethodName = (typeof PAYMENT_METHODS)[number];
|
|
10
|
+
/** PayIn text keys. The iframe drops other keys, trims values, and limits text to 120 characters. */
|
|
11
|
+
export declare const PAYIN_LABEL_KEYS: readonly ["submit", "method-card", "method-ach", "method-applepay", "method-googlepay", "wallet-divider", "ach-consent", "error-declined", "error-generic", "method-check", "label.card.holderName", "placeholder.card.holderName", "label.card.number", "placeholder.card.number", "label.card.expiration", "placeholder.card.expiration", "label.card.cvv", "placeholder.card.cvv", "label.card.postalCode", "placeholder.card.postalCode", "label.ach.holderName", "placeholder.ach.holderName", "label.ach.accountType", "label.ach.routingNumber", "placeholder.ach.routingNumber", "label.ach.accountNumber", "placeholder.ach.accountNumber", "label.ach.confirmRoutingNumber", "placeholder.ach.confirmRoutingNumber", "label.ach.confirmAccountNumber", "placeholder.ach.confirmAccountNumber", "label.check.holderName", "placeholder.check.holderName", "label.check.capture"];
|
|
12
|
+
export type PayInLabelKey = (typeof PAYIN_LABEL_KEYS)[number];
|
|
9
13
|
/**
|
|
10
14
|
* A card network. Not a payment method. Accepted brands are session config
|
|
11
15
|
* (`Session/init` acceptedCardBrands), not a client option: the API owns them
|
|
@@ -14,14 +18,29 @@ export type PaymentMethodName = (typeof PAYMENT_METHODS)[number];
|
|
|
14
18
|
export declare const CARD_BRANDS: readonly ["Visa", "Mastercard", "Amex", "Discover", "Jcb", "Diners"];
|
|
15
19
|
export type CardBrand = (typeof CARD_BRANDS)[number];
|
|
16
20
|
/**
|
|
17
|
-
* Client-side UI behavior only.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
21
|
+
* Client-side UI behavior only. The partner server sets operation, methods,
|
|
22
|
+
* required fields, paymentDetails, customerData, invoiceData, and saveIfSuccess
|
|
23
|
+
* through `Session/init`. The API's generated SDK owns session types.
|
|
24
|
+
*
|
|
25
|
+
* totalAmount already includes serviceFee. Currency accepts USD or CAD.
|
|
26
|
+
* Omitted currency displays as USD and stays omitted in the API request.
|
|
27
|
+
* Customer and invoice data pass through unchanged and stay omitted when absent.
|
|
28
|
+
* saveIfSuccess defaults to false and supports card, ACH, and wallets.
|
|
20
29
|
*
|
|
21
30
|
* The SDK sends this in CONFIG_SET.options and payhub parses with this same
|
|
22
31
|
* object (via the descriptor's `optionsSchema`).
|
|
23
32
|
*/
|
|
24
33
|
export declare const payinOptionsSchema: z.ZodMiniObject<{
|
|
34
|
+
initialMethod: z.ZodMiniOptional<z.ZodMiniEnum<{
|
|
35
|
+
card: "card";
|
|
36
|
+
ach: "ach";
|
|
37
|
+
check: "check";
|
|
38
|
+
}>>;
|
|
39
|
+
methodOrder: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniEnum<{
|
|
40
|
+
card: "card";
|
|
41
|
+
ach: "ach";
|
|
42
|
+
check: "check";
|
|
43
|
+
}>>>;
|
|
25
44
|
showSubmitButton: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
|
|
26
45
|
}, z.core.$strip>;
|
|
27
46
|
/** PayIn's own inbound events, beyond the base set every component shares. */
|
|
@@ -39,6 +58,16 @@ export declare const payinEvents: {
|
|
|
39
58
|
applepay: z.ZodMiniBoolean<boolean>;
|
|
40
59
|
googlepay: z.ZodMiniBoolean<boolean>;
|
|
41
60
|
}, z.core.$strip>;
|
|
61
|
+
/**
|
|
62
|
+
* Emitted when the buyer closes the wallet sheet. This is not an error.
|
|
63
|
+
* The component is ready for another attempt.
|
|
64
|
+
*/
|
|
65
|
+
readonly WALLET_CANCEL: z.ZodMiniObject<{
|
|
66
|
+
wallet: z.ZodMiniEnum<{
|
|
67
|
+
applepay: "applepay";
|
|
68
|
+
googlepay: "googlepay";
|
|
69
|
+
}>;
|
|
70
|
+
}, z.core.$strip>;
|
|
42
71
|
readonly CARD_BRAND_CHANGE: z.ZodMiniObject<{
|
|
43
72
|
brand: z.ZodMiniEnum<{
|
|
44
73
|
unknown: "unknown";
|
|
@@ -68,5 +97,8 @@ export declare const payinEvents: {
|
|
|
68
97
|
* fields the SDK does not interpret, and it forwards all of them.
|
|
69
98
|
*/
|
|
70
99
|
export type PayInSuccessPayload = {
|
|
100
|
+
/** The transaction ID for pay or auth sessions. */
|
|
71
101
|
transactionId?: string;
|
|
102
|
+
/** The saved payment method ID for tokenize sessions. */
|
|
103
|
+
referenceId?: string;
|
|
72
104
|
} & Record<string, unknown>;
|
package/dist/sdk.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export interface PayabliConfig {
|
|
|
29
29
|
export interface CreateOptions<T extends ComponentType = ComponentType> {
|
|
30
30
|
appearance?: AppearanceOptions;
|
|
31
31
|
options?: ComponentOptions<T>;
|
|
32
|
-
prefill?: Record<string, string>;
|
|
32
|
+
prefill?: T extends 'payin' ? never : Record<string, string>;
|
|
33
33
|
locale?: string;
|
|
34
34
|
timeout?: number;
|
|
35
35
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payabli/component-contracts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Wire schemas, component registry, and partner-facing types shared by the Payabli embedded components SDK and payhub.",
|
|
5
5
|
"private": false,
|
|
6
|
-
"license": "
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/payabli/components-web.git",
|
|
10
|
-
"directory": "packages/component-contracts"
|
|
11
|
-
},
|
|
6
|
+
"license": "MIT",
|
|
12
7
|
"type": "module",
|
|
13
8
|
"sideEffects": false,
|
|
14
9
|
"main": "dist/index.js",
|
|
@@ -23,7 +18,8 @@
|
|
|
23
18
|
},
|
|
24
19
|
"files": [
|
|
25
20
|
"dist",
|
|
26
|
-
"!dist/__tests__"
|
|
21
|
+
"!dist/__tests__",
|
|
22
|
+
"LICENSE.md"
|
|
27
23
|
],
|
|
28
24
|
"publishConfig": {
|
|
29
25
|
"access": "public"
|
|
@@ -34,6 +30,7 @@
|
|
|
34
30
|
"devDependencies": {
|
|
35
31
|
"tslib": "^2.8.1"
|
|
36
32
|
},
|
|
33
|
+
"homepage": "https://docs.payabli.com/guides/pay-in-components-overview",
|
|
37
34
|
"scripts": {
|
|
38
35
|
"generate": "node scripts/generate-registry.mjs",
|
|
39
36
|
"build": "pnpm generate && rm -rf dist && rollup -c && tsc -p tsconfig.build.json --emitDeclarationOnly",
|