@capxul/sdk 0.0.0-rc-2cdddbb91
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/README.md +417 -0
- package/dist/access-CNha7G9T.mjs +25089 -0
- package/dist/index-Czjrh-Fo.d.mts +39793 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +348 -0
- package/dist/node/index.d.mts +50 -0
- package/dist/node/index.mjs +147 -0
- package/dist/organizations-BMEWnFEC.mjs +12702 -0
- package/dist/permission-approvals-Bk-zuWEQ.mjs +138 -0
- package/dist/production-Bcjowmxk.mjs +5021 -0
- package/dist/testing/index.d.mts +151 -0
- package/dist/testing/index.mjs +1159 -0
- package/package.json +103 -0
package/README.md
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
# `@capxul/sdk`
|
|
2
|
+
|
|
3
|
+
The imperative TypeScript client for Capxul. It owns the public
|
|
4
|
+
`createCapxulClient` factory, domain method bundles, production adapter assembly,
|
|
5
|
+
and the internal Effect-based ports and flows that those methods bridge.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { createCapxulClient } from "@capxul/sdk";
|
|
9
|
+
|
|
10
|
+
const created = await createCapxulClient({
|
|
11
|
+
publishableKey: process.env.CAPXUL_PUBLISHABLE_KEY!,
|
|
12
|
+
requirement: "counterfactual",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (!created.ok) throw created.error;
|
|
16
|
+
const client = created.value;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Every public operation resolves a `Promise<CapxulResult<T>>`. Domain failures
|
|
20
|
+
are values, not thrown exceptions.
|
|
21
|
+
|
|
22
|
+
After the Person and personal Account are ready, begin Organization setup and
|
|
23
|
+
store its exact ID before signer interaction:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
const begun = await client.onboarding.beginOrganization({
|
|
27
|
+
name: "Analytical Engines",
|
|
28
|
+
handle: "analytical-engines",
|
|
29
|
+
country: "GH",
|
|
30
|
+
});
|
|
31
|
+
if (!begun.ok) throw begun.error;
|
|
32
|
+
|
|
33
|
+
const { orgId } = begun.value;
|
|
34
|
+
if (begun.value.setup.status === "awaitingAuthorization") {
|
|
35
|
+
const authorized = await client.org(orgId).setup.authorize();
|
|
36
|
+
if (!authorized.ok) throw authorized.error;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const observed = await client.org(orgId).setup.subscribe((snapshot) => {
|
|
40
|
+
if (snapshot.status === "value") console.log(snapshot.value.status);
|
|
41
|
+
});
|
|
42
|
+
if (!observed.ok) throw observed.error;
|
|
43
|
+
// Call observed.value() when the screen no longer needs updates.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`setup.resume()` requests a backend check for the same Organization. It does
|
|
47
|
+
not ask the signer to submit again. `onboarding.completeOrganization()` runs
|
|
48
|
+
begin, authorization when needed, and observation through `ready`.
|
|
49
|
+
|
|
50
|
+
An authenticated client can find unfinished founder setups without a local
|
|
51
|
+
recovery file. Read pages until `isDone` is true; omit `cursor` on the first
|
|
52
|
+
request:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
let cursor: string | undefined;
|
|
56
|
+
do {
|
|
57
|
+
const listed = await client.onboarding.listOrganizationSetups(
|
|
58
|
+
cursor === undefined ? {} : { cursor },
|
|
59
|
+
);
|
|
60
|
+
if (!listed.ok) throw listed.error;
|
|
61
|
+
for (const setup of listed.value.page) console.log(setup.orgId, setup.status);
|
|
62
|
+
if (listed.value.isDone) break;
|
|
63
|
+
if (listed.value.cursor === null) throw new Error("Missing setup cursor");
|
|
64
|
+
cursor = listed.value.cursor;
|
|
65
|
+
} while (true);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`listOrganizationSetups` is a read. It does not authorize, resume, or sign.
|
|
69
|
+
|
|
70
|
+
## Local Effect DevTools
|
|
71
|
+
|
|
72
|
+
Start the repository collector with `vp run devtools:serve`, then create a
|
|
73
|
+
development client:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const created = await createCapxulClient({
|
|
77
|
+
publishableKey,
|
|
78
|
+
devToolsUrl: "ws://127.0.0.1:34439",
|
|
79
|
+
});
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Run an operation and read its spans and metrics with `vp run devtools:snapshot`.
|
|
83
|
+
For the editor view, start its Effect DevTools server and run the collector with
|
|
84
|
+
`vp run devtools:serve --vscode`. Browser and
|
|
85
|
+
Node hosts use the same option. Omit it to disable the connection. Call
|
|
86
|
+
`client.close()` when the host no longer needs the client; close also releases
|
|
87
|
+
DevTools. The URL must use `ws` or `wss` on `localhost`, `127.0.0.1`, `[::1]`, or
|
|
88
|
+
`host.docker.internal`, without credentials, a query, or a fragment.
|
|
89
|
+
This local connection carries native debug detail. It does not change remote
|
|
90
|
+
telemetry configuration. See the [development workflow](../../docs/canon/development-and-verification.md)
|
|
91
|
+
for agent access and the shared local collector.
|
|
92
|
+
|
|
93
|
+
## Invitation updates
|
|
94
|
+
|
|
95
|
+
Use `client.org(orgId).invitations.subscribe({ invitationId }, listener, { signal })`
|
|
96
|
+
to observe one offer. The listener receives `loading`, then validated `value`
|
|
97
|
+
snapshots or a terminal typed `error`. The successful result holds an idempotent
|
|
98
|
+
unsubscribe function. Abort, sign-out, account replacement, and client close
|
|
99
|
+
stop delivery. A late registration handle is released when it arrives.
|
|
100
|
+
This read never accepts an offer or retries a write. Bound a wait through the
|
|
101
|
+
caller’s AbortSignal; per-call timeout options do not define stream lifetime.
|
|
102
|
+
|
|
103
|
+
## Asset amount input and display
|
|
104
|
+
|
|
105
|
+
Use the asset helpers at Payment form and display boundaries. They keep the
|
|
106
|
+
exact AssetId and do not convert a value to a JavaScript number.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { formatAssetAmount, parseAssetAmount, requireAsset, TOKENS } from "@capxul/sdk";
|
|
110
|
+
|
|
111
|
+
const amount = parseAssetAmount("1,000.25", requireAsset(TOKENS.BASE_SEPOLIA.CAPXUL_TEST_USDC));
|
|
112
|
+
|
|
113
|
+
if ("kind" in amount) {
|
|
114
|
+
console.error(amount.reason); // closed code — the app owns the sentence (ADR-0023)
|
|
115
|
+
} else {
|
|
116
|
+
console.log(formatAssetAmount(amount)); // 1,000.25 USDC
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`parseAssetAmount` returns validation errors as values. Payment, request,
|
|
121
|
+
Budget, Payroll, and activity amounts require AssetAmount. Fiat Money remains
|
|
122
|
+
separate valuation data.
|
|
123
|
+
|
|
124
|
+
## Value all asset positions
|
|
125
|
+
|
|
126
|
+
Use `holdings.current` for raw positions. Use `valueIn` to value exact asset
|
|
127
|
+
quantities in a display currency. A token symbol does not identify an asset.
|
|
128
|
+
Quantities from different assets cannot be compared as a headline balance.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { formatMoney, valueIn } from "@capxul/sdk";
|
|
132
|
+
|
|
133
|
+
const valuation = valueIn(amounts, displayCurrency, rates);
|
|
134
|
+
if (valuation.total !== null) {
|
|
135
|
+
console.log(formatMoney(valuation.total));
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Keep `valuation.unrated` visible beside the known subtotal. A missing rate
|
|
140
|
+
does not mean a zero balance.
|
|
141
|
+
|
|
142
|
+
## Approvals
|
|
143
|
+
|
|
144
|
+
Every signature a person makes goes through one approval. A caller with no
|
|
145
|
+
key, such as the CLI or an agent, prepares the Payment and hands the person
|
|
146
|
+
the link. Nothing is signed or sent until the person approves it there.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
const prepared = await client.approvals.prepare({
|
|
150
|
+
to: { kind: "email", email: "ada@example.com" },
|
|
151
|
+
amount: { asset: usdc.assetId, value: "25" },
|
|
152
|
+
});
|
|
153
|
+
if (!prepared.ok) throw prepared.error;
|
|
154
|
+
console.log(prepared.value.url, prepared.value.summary);
|
|
155
|
+
|
|
156
|
+
// Sends the approved operation once, then waits until its Payment settles.
|
|
157
|
+
const outcome = await client.approvals.wait(prepared.value.approvalId, { signal });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The approval page runs as the same person, with their own signer:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
await client.approvals.review(approvalId); // the first open is recorded
|
|
164
|
+
const approved = await client.approvals.approve(approvalId); // or reject(approvalId)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
`approve` signs only the digest the approval's operation describes, and only
|
|
168
|
+
with the approval's signer. The backend checks the signature and never signs.
|
|
169
|
+
A rejected or expired approval ends `wait` with that state.
|
|
170
|
+
|
|
171
|
+
## Observability
|
|
172
|
+
|
|
173
|
+
Hosts can attach the PostHog client they already initialized through one
|
|
174
|
+
product-and-failure module:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import { postHogObservability } from "@capxul/sdk";
|
|
178
|
+
|
|
179
|
+
const created = await createCapxulClient({
|
|
180
|
+
publishableKey: "cap_pk_…",
|
|
181
|
+
observability: postHogObservability(posthog, {
|
|
182
|
+
capxulEnv: "production",
|
|
183
|
+
context: () => ({ correlationId, journeyId, organizationId }),
|
|
184
|
+
}),
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The SDK initializes no analytics client and preserves host consent. Product
|
|
189
|
+
events and sanitized failures share one enable/context/delivery policy.
|
|
190
|
+
Engineering logs and traces are separate internally, but applications do not
|
|
191
|
+
configure them: the versioned bootstrap response optionally supplies the
|
|
192
|
+
governed PostHog ingest origin, public project token, and environment. The SDK
|
|
193
|
+
derives endpoints, service, producer, and version. Missing or invalid policy
|
|
194
|
+
disables engineering export without failing client creation.
|
|
195
|
+
|
|
196
|
+
Person onboarding is one Core SDK journey. It requires a normalized, globally
|
|
197
|
+
unique handle before it writes the Profile or starts Account setup:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
const onboarded = await client.onboarding.completePerson({
|
|
201
|
+
displayName: "Ada Lovelace",
|
|
202
|
+
country: "GH",
|
|
203
|
+
handle: "ada_lovelace",
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The backend remains the authority for reserved names and global uniqueness.
|
|
208
|
+
The method returns only after the client requirement reaches a ready Account.
|
|
209
|
+
The React frontend does not use this journey yet.
|
|
210
|
+
|
|
211
|
+
A Node host that keeps login outside the browser can pass `openfortSignerFactory`.
|
|
212
|
+
The factory receives only the validated Openfort and auth bootstrap fields. Its
|
|
213
|
+
browser page can use `createOpenfortBrowserSigner` with host-owned access-token
|
|
214
|
+
and encryption-session callbacks. It does not need a second login or private SDK import.
|
|
215
|
+
|
|
216
|
+
## Published entry points
|
|
217
|
+
|
|
218
|
+
The packed npm package exposes only:
|
|
219
|
+
|
|
220
|
+
- `@capxul/sdk` — the client factory, public method and value types, signers,
|
|
221
|
+
host observability helper, and immutable Base Sepolia Payment contract
|
|
222
|
+
identity. It also re-exports the canonical Capxul operation vocabulary.
|
|
223
|
+
- `@capxul/sdk/node` — Node-only signer and runtime helpers.
|
|
224
|
+
- `@capxul/sdk/testing` — the real identity runtime assembled over
|
|
225
|
+
deterministic in-memory ports, with OTP, advance-only clock, transition,
|
|
226
|
+
observation, seed, and close controls for tests.
|
|
227
|
+
|
|
228
|
+
The many extra subpaths in `package.json#exports` are workspace development
|
|
229
|
+
surfaces. Do not show them in consumer examples unless `publishConfig.exports`
|
|
230
|
+
also contains them.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { createCapxulTestClient } from "@capxul/sdk/testing";
|
|
234
|
+
|
|
235
|
+
const testing = createCapxulTestClient();
|
|
236
|
+
await testing.seedIdentity({
|
|
237
|
+
authUserId: "auth_seeded_test",
|
|
238
|
+
email: "test@example.test",
|
|
239
|
+
});
|
|
240
|
+
await testing.clock.advance(1_000);
|
|
241
|
+
await testing.client.auth.signIn({ email: "test@example.test" });
|
|
242
|
+
const otp = testing.peekOtp("test@example.test");
|
|
243
|
+
if (!otp) throw new Error("expected a test OTP");
|
|
244
|
+
await testing.client.auth.verifyOtp({ email: "test@example.test", code: otp });
|
|
245
|
+
// Drive the real public client, then inspect testing.transitions.
|
|
246
|
+
await testing.close();
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The seeded email is bound to the requested auth user ID, so verifying its OTP
|
|
250
|
+
loads that exact seeded Profile. The public clock exposes only `advance(ms)`;
|
|
251
|
+
the internal clock adapter and its Effect/conformance methods remain private.
|
|
252
|
+
The testing entry is identity-scoped and hermetic. Fine-grained
|
|
253
|
+
`@capxul/sdk/testing/*` adapter paths remain workspace-only.
|
|
254
|
+
|
|
255
|
+
## Documentation
|
|
256
|
+
|
|
257
|
+
- [Maintainer context](./CONTEXT.md) — ownership, boundaries, invariants,
|
|
258
|
+
evidence, and update triggers.
|
|
259
|
+
- [Architecture](./docs/architecture.md) — client assembly, flows, ports,
|
|
260
|
+
adapters, and proof map.
|
|
261
|
+
- [Observation](./docs/observation.md) — unified host observability,
|
|
262
|
+
bootstrap-owned engineering policy, and bounded backend linkage.
|
|
263
|
+
- [Public SDK documentation](../../apps/docs/content/docs/sdk/index.mdx) —
|
|
264
|
+
tutorials, guides, reference, and explanation for npm consumers.
|
|
265
|
+
|
|
266
|
+
React integration is a separate projection owned by `@capxul/sdk-react`.
|
|
267
|
+
|
|
268
|
+
## Development
|
|
269
|
+
|
|
270
|
+
Run package commands through Vite+:
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
vp run --filter @capxul/sdk check-types
|
|
274
|
+
vp run --filter @capxul/sdk test
|
|
275
|
+
vp run --filter @capxul/sdk build
|
|
276
|
+
vp run --filter @capxul/sdk proofs:live
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
`proofs:live` runs the Organization Core SDK journey against the configured
|
|
280
|
+
Convex deployment and Base Sepolia. Run it with the synchronized candidate.
|
|
281
|
+
The package tests prove local SDK behavior.
|
|
282
|
+
See [maintainer context](./CONTEXT.md#capability-and-proof-boundaries).
|
|
283
|
+
|
|
284
|
+
The browser production path owns its Openfort signer when no signer is supplied.
|
|
285
|
+
Integration recovery evidence and its published-package boundary were recorded
|
|
286
|
+
in the #870 receipt (since deleted; see git history).
|
|
287
|
+
|
|
288
|
+
### Node session storage
|
|
289
|
+
|
|
290
|
+
A Node host can pass `nodeSessionStorage: { load, save }` to
|
|
291
|
+
`createCapxulClient`. Both methods return promises. `load` returns an opaque
|
|
292
|
+
BetterAuth credential or `null`; `save` receives the credential or `null` on
|
|
293
|
+
logout. Store it with owner-only access and isolate it by application and
|
|
294
|
+
environment. Do not print it or use a cached `AuthSession` as backend authority.
|
|
295
|
+
The SDK validates the credential and expiry with BetterAuth on process restart.
|
|
296
|
+
With durable storage, each adapter serializes session reads, OTP verification,
|
|
297
|
+
sign-out, and Convex token reads. A delayed response cannot clear or rotate a
|
|
298
|
+
credential from a later operation on that adapter. Cancellation while queued
|
|
299
|
+
returns immediately and prevents that operation from reaching the provider.
|
|
300
|
+
Hosts that share storage across clients or processes must fence writes, for
|
|
301
|
+
example with an atomic compare-and-set; the adapter cannot order other clients.
|
|
302
|
+
|
|
303
|
+
For separate OTP request and verification processes, retain the email and
|
|
304
|
+
original request timestamp. After `auth.getSession()` confirms signed-out state,
|
|
305
|
+
call `auth.resumeOtp({ email, requestedAt })`, then `auth.verifyOtp({ email,
|
|
306
|
+
code })`. Resume restores pending input only. It does not send another OTP or
|
|
307
|
+
authenticate the caller. Keep OTP values out of arguments, logs, and stored data.
|
|
308
|
+
|
|
309
|
+
### Existing financial documents
|
|
310
|
+
|
|
311
|
+
Use `paymentDocuments.verify({ documentHash, contentHash })` to verify stored
|
|
312
|
+
content. Use `paymentDocuments.render` with the same pair for safe semantic HTML.
|
|
313
|
+
Call `paymentDocuments.get` only for a deliberate download. Its `bytesBase64`
|
|
314
|
+
contains the exact stored bytes. Do not log document results or error payloads.
|
|
315
|
+
Get references from Payment or Movement activity detail. References include
|
|
316
|
+
kind, format, and role. A hash is not permission to read a document.
|
|
317
|
+
Reads check current Payment participants or current Movement actor access.
|
|
318
|
+
Missing and unauthorized pairs return the same refusal. These methods do not
|
|
319
|
+
create documents or add Payment links.
|
|
320
|
+
|
|
321
|
+
## Inbox documents
|
|
322
|
+
|
|
323
|
+
Personal Account and Organization Inbox reads include `documents` on each
|
|
324
|
+
item. An unpaid issued Invoice can have document references before a Payment
|
|
325
|
+
exists. Requests without an attached document return an empty array. The
|
|
326
|
+
references preserve the document and content hashes needed by
|
|
327
|
+
`paymentDocuments.get`, `verify`, and `render`. Inbox listing does not render
|
|
328
|
+
or download documents. Existing issuer and payer access checks still apply.
|
|
329
|
+
|
|
330
|
+
Issued requests and Inbox items retain a linked `paymentId` when preparation
|
|
331
|
+
has started. Invoice Inbox items also retain the stored `issuerSafe`. These
|
|
332
|
+
fields do not mean that the Payment has settled.
|
|
333
|
+
|
|
334
|
+
`inbox.paymentTerms(requestId)` reads exact private terms without a signer or
|
|
335
|
+
write. It returns the issued Invoice instruction or a deterministic Memo
|
|
336
|
+
instruction for a generic request. Prepared requests retain their stored
|
|
337
|
+
instruction. Only the addressed payer can read these terms.
|
|
338
|
+
|
|
339
|
+
`inbox.fulfill(confirmation, { onPrepared })` executes the confirmed request
|
|
340
|
+
through the existing signer. `onPrepared({ paymentIds })` receives verified
|
|
341
|
+
durable IDs before signing. If the callback fails, signing stops. Do not await
|
|
342
|
+
the fulfillment call inside this callback. Organization confirmation requires
|
|
343
|
+
an admitted Permission; personal confirmation does not accept one. The backend
|
|
344
|
+
checks the payer, exact amount, issuer Safe, release, and frozen instruction.
|
|
345
|
+
|
|
346
|
+
## Fixed offers and checkout
|
|
347
|
+
|
|
348
|
+
`account.offers` and `org(id).offers` manage reusable fixed-price offers with
|
|
349
|
+
explicit quantity limits. Creation uses a caller request key. Revisions append
|
|
350
|
+
immutable prices and require the expected revision.
|
|
351
|
+
|
|
352
|
+
`checkouts.offer(id)` is a public read and creates no purchase. `checkouts.create`
|
|
353
|
+
uses a UUID v4 purchase key, selected revision, quantity, and funding wallet to
|
|
354
|
+
freeze one purchase. `checkouts.get` restores its exact snapshot. `checkouts.prepare`
|
|
355
|
+
returns unsigned approval and Payments-contract transactions for that wallet.
|
|
356
|
+
The consumer checks chain, balance, allowance, and gas. Preparation does not sign,
|
|
357
|
+
submit, or prove settlement. No checkout URL is returned before the page exists.
|
|
358
|
+
|
|
359
|
+
## Fixed offer checkout candidate
|
|
360
|
+
|
|
361
|
+
The checkout APIs below are source candidate APIs. The published beta17 baseline
|
|
362
|
+
does not include them. Consume a matching packed candidate for local integration.
|
|
363
|
+
|
|
364
|
+
`account.offers` and `org(id).offers` provide create, list, get, revise, and
|
|
365
|
+
deactivate. Create uses a caller replay key. Revision and deactivation require the
|
|
366
|
+
current revision. Each offer has one asset, an exact unit amount, and bounded whole
|
|
367
|
+
unit quantities. An offer revision does not change an existing purchase.
|
|
368
|
+
|
|
369
|
+
Public `checkouts.offer(id)` reads approved offer fields. `checkouts.create(input)`
|
|
370
|
+
explicitly freezes the offer revision, quantity, funding wallet, recipient, amount,
|
|
371
|
+
network, contract, instruction, and settlement identity. Reuse the same UUID v4
|
|
372
|
+
purchase key after a lost reply. Different terms with the same key refuse.
|
|
373
|
+
`checkouts.get(id)` recovers the frozen snapshot. These methods do not sign.
|
|
374
|
+
|
|
375
|
+
`checkouts.prepare({ checkoutId, sourceWallet })` returns exact unsigned approval
|
|
376
|
+
and payment transactions. The consumer checks network, balance, gas, and allowance
|
|
377
|
+
before requesting wallet action. A connection or submission is not settlement.
|
|
378
|
+
|
|
379
|
+
`checkouts.state(id)` performs a checked read. It returns historical receipt data
|
|
380
|
+
separately from current verification: `unpaid`, `verified`, `orphaned`, or
|
|
381
|
+
`unavailable`. Provider failure cannot prove that a receipt was removed.
|
|
382
|
+
`checkouts.reconcile({ checkoutId, transactionHash })` returns the candidate result
|
|
383
|
+
and independently checked stored state. An unrelated candidate cannot change a
|
|
384
|
+
valid stored payment. Canonical occurrence correction retains logical identity.
|
|
385
|
+
|
|
386
|
+
These offer methods do not implement recurring billing.
|
|
387
|
+
`checkouts.payRegistered({ checkoutId, payer, permissionId? })` prepares, verifies,
|
|
388
|
+
and submits through the existing registered signer. Account and Organization
|
|
389
|
+
authority remain mandatory. Submission does not establish settlement. Public
|
|
390
|
+
Invoice funding and frontend registered-payer adoption remain separate work.
|
|
391
|
+
|
|
392
|
+
`isCheckoutSettlementConsumed(error, settlementId)` decodes the contract's refusal
|
|
393
|
+
for the exact frozen ID. Use it for structured or raw RPC errors. Error message
|
|
394
|
+
text alone does not establish that an ID was consumed.
|
|
395
|
+
|
|
396
|
+
## Invoice checkout candidate
|
|
397
|
+
|
|
398
|
+
`checkouts.invoice(linkToken)` exposes only the approved payment summary.
|
|
399
|
+
Itemization, notes, billing identity and document bytes remain restricted to the
|
|
400
|
+
issuer and named debtor. Funding does not change that debtor or grant document
|
|
401
|
+
access. Existing link tokens resolve the original obligation.
|
|
402
|
+
|
|
403
|
+
`prepareInvoice({ linkToken, sourceWallet })` returns unsigned transactions.
|
|
404
|
+
`invoiceState(linkToken)` checks current receipt evidence. `reconcileInvoice`
|
|
405
|
+
verifies an explicitly supplied transaction against the fixed terms. Late exact
|
|
406
|
+
payments remain visible after expiry or cancellation. Conflicting consumption is
|
|
407
|
+
unavailable, never paid, and does not create another settlement identity.
|
|
408
|
+
|
|
409
|
+
`payInvoiceRegistered({ linkToken, payer, sourceWallet, permissionId? })` uses the
|
|
410
|
+
existing registered signer. The selected Safe must match the backend's current
|
|
411
|
+
spending authority. The response omits private source commands and document
|
|
412
|
+
bundles. Existing private preparations retain their original settlement ID.
|
|
413
|
+
|
|
414
|
+
`checkoutUrl(frontendOrigin, reference)` constructs an offer or Invoice route.
|
|
415
|
+
The caller supplies the selected environment's frontend origin. The consumer
|
|
416
|
+
still validates the reference and reads authoritative backend terms. Constructing
|
|
417
|
+
a URL does not prove that its consumer is deployed.
|