@ledewire/browser 0.6.1 → 0.8.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/README.md +55 -13
- package/dist/index.d.ts +1546 -46
- package/dist/index.js +465 -600
- package/dist/index.js.map +1 -1
- package/dist/ledewire.min.js +2 -2
- package/dist/ledewire.min.js.map +1 -1
- package/llms.txt +140 -28
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* const lw = Ledewire.init({ apiKey: 'your_api_key' })
|
|
13
13
|
* const state = await lw.checkout.state('content-id')
|
|
14
14
|
* // state.checkout_state.next_required_action:
|
|
15
|
-
* // 'authenticate' | 'fund_wallet' | 'purchase'
|
|
15
|
+
* // 'authenticate' | 'fund_wallet' | 'purchase'
|
|
16
16
|
* </script>
|
|
17
17
|
* ```
|
|
18
18
|
*
|
|
@@ -44,12 +44,16 @@ export declare type AuthenticationResponse = components['schemas']['Authenticati
|
|
|
44
44
|
* or when a token refresh fails and re-authentication is required.
|
|
45
45
|
*/
|
|
46
46
|
export declare class AuthError extends LedewireError {
|
|
47
|
-
|
|
47
|
+
static readonly brand: string;
|
|
48
|
+
constructor(message: string, code?: number, type?: ErrorTypeValue, details?: Record<string, unknown>);
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
/** Request body for API key authentication (seller). */
|
|
51
52
|
declare type AuthLoginApiKeyRequest = components['schemas']['AuthLoginApiKeyRequest'];
|
|
52
53
|
|
|
54
|
+
/** Request body for authenticating as a buyer using a named API key + secret. */
|
|
55
|
+
declare type AuthLoginBuyerApiKeyRequest = components['schemas']['AuthLoginBuyerApiKeyRequest'];
|
|
56
|
+
|
|
53
57
|
/** Request body for buyer email/password login. */
|
|
54
58
|
declare type AuthLoginEmailRequest = components['schemas']['AuthLoginEmailRequest'];
|
|
55
59
|
|
|
@@ -130,6 +134,26 @@ declare class BrowserAuthNamespace {
|
|
|
130
134
|
* @returns The authentication token response.
|
|
131
135
|
*/
|
|
132
136
|
loginWithGoogle(body: AuthLoginOAuthRequest): Promise<AuthenticationResponse>;
|
|
137
|
+
/**
|
|
138
|
+
* Log in using a buyer API key and secret.
|
|
139
|
+
* Returns a buyer-scoped JWT, stored automatically after successful authentication.
|
|
140
|
+
*
|
|
141
|
+
* Primarily useful when building buyer-facing dashboards where the user
|
|
142
|
+
* has created a named API key and wishes to authenticate with it programmatically,
|
|
143
|
+
* or for agent workflows running inside a browser context.
|
|
144
|
+
*
|
|
145
|
+
* @param body - The buyer API key and secret.
|
|
146
|
+
* @returns The authentication token response.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* await lw.auth.loginWithBuyerApiKey({
|
|
151
|
+
* key: 'bktst_abc123',
|
|
152
|
+
* secret: 'deadbeef...',
|
|
153
|
+
* })
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
loginWithBuyerApiKey(body: AuthLoginBuyerApiKeyRequest): Promise<AuthenticationResponse>;
|
|
133
157
|
/**
|
|
134
158
|
* Request a password reset code to be sent to the buyer's email address.
|
|
135
159
|
*
|
|
@@ -192,6 +216,8 @@ declare class BrowserClient {
|
|
|
192
216
|
readonly content: BrowserContentNamespace;
|
|
193
217
|
/** Seller operations: API key login, content list/search/get */
|
|
194
218
|
readonly seller: BrowserSellerNamespace;
|
|
219
|
+
/** Authenticated buyer account: API key management */
|
|
220
|
+
readonly user: UserNamespace;
|
|
195
221
|
/* Excluded from this release type: __constructor */
|
|
196
222
|
}
|
|
197
223
|
|
|
@@ -266,8 +292,10 @@ declare class BrowserConfigNamespace {
|
|
|
266
292
|
* @example
|
|
267
293
|
* ```ts
|
|
268
294
|
* const result = await lw.content.getWithAccess('content-id')
|
|
269
|
-
* if (result.access_info.
|
|
270
|
-
*
|
|
295
|
+
* if (result.access_info.has_purchased) {
|
|
296
|
+
* // Note: single-use — a past purchase does not imply access. Buy again
|
|
297
|
+
* // via lw.purchases.create() to receive the content; the delivery comes
|
|
298
|
+
* // back directly in that response, not from this endpoint.
|
|
271
299
|
* }
|
|
272
300
|
* ```
|
|
273
301
|
*/
|
|
@@ -286,8 +314,10 @@ declare class BrowserContentNamespace {
|
|
|
286
314
|
* @example
|
|
287
315
|
* ```ts
|
|
288
316
|
* const result = await lw.content.getWithAccess('article-123')
|
|
289
|
-
* if (result.access_info.next_required_action === '
|
|
290
|
-
*
|
|
317
|
+
* if (result.access_info.next_required_action === 'purchase') {
|
|
318
|
+
* // Buy (or re-buy) via lw.purchases.create() — the response carries
|
|
319
|
+
* // content_body / content_uri directly. has_purchased means only
|
|
320
|
+
* // "has ever bought" and does not by itself grant access.
|
|
291
321
|
* }
|
|
292
322
|
* ```
|
|
293
323
|
*/
|
|
@@ -297,6 +327,11 @@ declare class BrowserContentNamespace {
|
|
|
297
327
|
/**
|
|
298
328
|
* Buyer purchases namespace — create and retrieve content purchases.
|
|
299
329
|
*
|
|
330
|
+
* **Single-use purchase model:** a completed purchase does not imply
|
|
331
|
+
* standing access. `has_purchased` on other endpoints means only "has ever
|
|
332
|
+
* bought" — it is not a re-access grant. Buying again is how the buyer
|
|
333
|
+
* receives the content a second time; see {@link BrowserPurchasesNamespace.create}.
|
|
334
|
+
*
|
|
300
335
|
* Obtain via `lw.purchases` — do not construct directly.
|
|
301
336
|
*
|
|
302
337
|
* @example
|
|
@@ -309,10 +344,50 @@ declare class BrowserPurchasesNamespace {
|
|
|
309
344
|
protected readonly http: HttpClient;
|
|
310
345
|
constructor(http: HttpClient);
|
|
311
346
|
/**
|
|
312
|
-
* Completes a content purchase using the buyer's wallet balance
|
|
347
|
+
* Completes a content purchase using the buyer's wallet balance and
|
|
348
|
+
* delivers the content in the same response.
|
|
349
|
+
*
|
|
350
|
+
* **This response is the only place the delivered content ever arrives.**
|
|
351
|
+
* For a deliverable LedeWire holds, `content_body` carries the full body as
|
|
352
|
+
* plain UTF-8 text — it is never base64-encoded on the wire, so no
|
|
353
|
+
* `atob()` or decoding step is needed. For a deliverable hosted elsewhere,
|
|
354
|
+
* `content_uri` carries its URL instead. Neither field is present on
|
|
355
|
+
* {@link BrowserPurchasesNamespace.get} or {@link BrowserPurchasesNamespace.list}
|
|
356
|
+
* — there is no route that serves the same content a second time — so
|
|
357
|
+
* persist `content_body` / `content_uri` immediately if you need it later.
|
|
358
|
+
* A past purchase does not grant re-access: buying the same content again
|
|
359
|
+
* is a new charge that delivers it again.
|
|
313
360
|
*
|
|
314
361
|
* @param body - The content ID and expected price in cents.
|
|
315
|
-
* @returns The completed purchase record.
|
|
362
|
+
* @returns The completed purchase record, including the delivered content.
|
|
363
|
+
* @throws {SpendCapReachedError} `402` — the buyer's daily spend cap has
|
|
364
|
+
* been reached. There is no funding URL for this refusal: adding money
|
|
365
|
+
* to the wallet does not clear it. It clears only when the spend window
|
|
366
|
+
* rolls over at `resetsAt`, or when the cap is raised via
|
|
367
|
+
* `lw.user.spendCap.update()`.
|
|
368
|
+
* @throws {NotFoundError} `404` — the content does not exist, or its
|
|
369
|
+
* visibility is `unlisted` (non-public) and this buyer has no standing
|
|
370
|
+
* grant to see it. Non-public content is not purchasable through this
|
|
371
|
+
* endpoint.
|
|
372
|
+
*
|
|
373
|
+
* @example
|
|
374
|
+
* ```ts
|
|
375
|
+
* const purchase = await lw.purchases.create({ content_id: 'content-id' })
|
|
376
|
+
* await saveDeliveredContent(purchase) // persist now — one-time delivery
|
|
377
|
+
*
|
|
378
|
+
* if (purchase.content_body && purchase.content.content_type === 'markdown') {
|
|
379
|
+
* renderMarkdown(purchase.content_body)
|
|
380
|
+
* } else if (purchase.content_body && purchase.content.content_type === 'html') {
|
|
381
|
+
* // Inline HTML is seller-supplied — sanitise before inserting it.
|
|
382
|
+
* container.innerHTML = DOMPurify.sanitize(purchase.content_body)
|
|
383
|
+
* } else if (purchase.content_uri) {
|
|
384
|
+
* // Seller-supplied URI — check the scheme before navigating to it.
|
|
385
|
+
* const uri = new URL(purchase.content_uri)
|
|
386
|
+
* if (['https:', 'http:'].includes(uri.protocol)) {
|
|
387
|
+
* window.location.href = purchase.content_uri
|
|
388
|
+
* }
|
|
389
|
+
* }
|
|
390
|
+
* ```
|
|
316
391
|
*/
|
|
317
392
|
create(body: PurchaseCreateRequest): Promise<PurchaseResponse>;
|
|
318
393
|
/**
|
|
@@ -457,12 +532,33 @@ declare class BrowserWalletNamespace {
|
|
|
457
532
|
/**
|
|
458
533
|
* Returns the authenticated buyer's current wallet balance.
|
|
459
534
|
*
|
|
460
|
-
*
|
|
535
|
+
* `balance_cents` and `spendable_cents` are always the same number —
|
|
536
|
+
* `balance_cents` has always meant "what you can spend," and money committed to
|
|
537
|
+
* a bulk acquisition is a hold, which moves it out of the wallet rather than
|
|
538
|
+
* annotating it. `held_cents` is the total currently committed to active bulk
|
|
539
|
+
* acquisitions and not yet spent or released, and `holds` lists one entry per
|
|
540
|
+
* such acquisition (`acquisition_id`, `held_cents`, `authorized_at`) so a buyer
|
|
541
|
+
* mid-acquisition can see why their balance is lower than their purchase
|
|
542
|
+
* history explains.
|
|
543
|
+
*
|
|
544
|
+
* @returns The current wallet balance in cents, including held funds detail.
|
|
461
545
|
*/
|
|
462
546
|
balance(): Promise<WalletBalanceResponse>;
|
|
463
547
|
/**
|
|
464
548
|
* Returns the authenticated buyer's wallet transaction history, newest first.
|
|
465
549
|
*
|
|
550
|
+
* `bulk_acquisition` and `bulk_hold` are each a single entry for a whole bulk
|
|
551
|
+
* acquisition — its per-work purchases are deliberately not listed here,
|
|
552
|
+
* because one acquisition can hold tens of thousands of them and they describe
|
|
553
|
+
* one decision. A `bulk_hold` entry is an acquisition still holding funds (money
|
|
554
|
+
* left the wallet but has not been spent); it becomes a `bulk_acquisition` entry
|
|
555
|
+
* for the amount actually captured once the acquisition ends, and an
|
|
556
|
+
* acquisition never produces both. Note that a bulk acquisition's per-work
|
|
557
|
+
* purchases each carry a display `price_cents` that is **not summable** — bulk
|
|
558
|
+
* prices at micro precision and rounds to cents once, on the acquisition total,
|
|
559
|
+
* so `amount_cents` on the `bulk_acquisition` / `bulk_hold` entry is the figure
|
|
560
|
+
* to read.
|
|
561
|
+
*
|
|
466
562
|
* @returns A list of completed wallet transaction entries.
|
|
467
563
|
*/
|
|
468
564
|
transactions(): Promise<WalletTransactionItem[]>;
|
|
@@ -491,7 +587,12 @@ declare class BrowserWalletNamespace {
|
|
|
491
587
|
* ```ts
|
|
492
588
|
* const state = await lw.checkout.state('content-id')
|
|
493
589
|
* // state.checkout_state.next_required_action:
|
|
494
|
-
* // 'authenticate' | 'fund_wallet' | 'purchase'
|
|
590
|
+
* // 'authenticate' | 'fund_wallet' | 'purchase'
|
|
591
|
+
* //
|
|
592
|
+
* // Single-use model: a completed purchase does not imply access, so
|
|
593
|
+
* // 'purchase' can still be the next action even when has_purchased is
|
|
594
|
+
* // true. Buying delivers the content directly in the POST /v1/purchases
|
|
595
|
+
* // response — there is no separate "view content" step.
|
|
495
596
|
* ```
|
|
496
597
|
*/
|
|
497
598
|
declare class CheckoutNamespace {
|
|
@@ -512,11 +613,18 @@ declare class CheckoutNamespace {
|
|
|
512
613
|
}
|
|
513
614
|
|
|
514
615
|
/**
|
|
515
|
-
* Next step in a content checkout flow.
|
|
516
|
-
*
|
|
517
|
-
*
|
|
616
|
+
* Next step in a content checkout flow. Consumer-facing alias for
|
|
617
|
+
* `CheckoutStateResponse['checkout_state']['next_required_action']`.
|
|
618
|
+
*
|
|
619
|
+
* **Single-use purchase model:** there is no terminal "you have access" state.
|
|
620
|
+
* A completed purchase does not imply access — `has_purchased` means only "has ever
|
|
621
|
+
* bought" — so `next_required_action` can still read `'purchase'` for content the
|
|
622
|
+
* buyer already bought once. Buying again is how the buyer receives the content:
|
|
623
|
+
* the delivery (`content_body` / `content_uri`) is returned directly in the
|
|
624
|
+
* response to `POST /v1/purchases`, and nowhere else — not on `GET`/list, and not
|
|
625
|
+
* via a since-withdrawn `'view_content'` state.
|
|
518
626
|
*/
|
|
519
|
-
export declare type CheckoutNextAction = 'authenticate' | 'fund_wallet' | 'purchase'
|
|
627
|
+
export declare type CheckoutNextAction = 'authenticate' | 'fund_wallet' | 'purchase';
|
|
520
628
|
|
|
521
629
|
/**
|
|
522
630
|
* Checkout state machine result for a specific content item, as returned by
|
|
@@ -548,7 +656,7 @@ declare interface components {
|
|
|
548
656
|
has_sufficient_funds: boolean;
|
|
549
657
|
wallet_balance_cents: number;
|
|
550
658
|
/** @enum {string} */
|
|
551
|
-
next_required_action: 'authenticate' | 'fund_wallet' | 'purchase'
|
|
659
|
+
next_required_action: 'authenticate' | 'fund_wallet' | 'purchase';
|
|
552
660
|
};
|
|
553
661
|
AuthenticationResponse: {
|
|
554
662
|
/** @enum {string} */
|
|
@@ -621,6 +729,11 @@ declare interface components {
|
|
|
621
729
|
error: {
|
|
622
730
|
code: number;
|
|
623
731
|
message: string;
|
|
732
|
+
/**
|
|
733
|
+
* @description Machine-readable reason, present on refusals that carry one. Branch on this rather than on `message`, which is prose and may be reworded. `retrieval_failed` is transient and worth retrying; `not_licensable` means report it undelivered; `price_drifted` means re-quote; `client_error` is ours to fix and must never be retried unchanged; `insufficient_funds` is cleared by funding the wallet and `daily_spend_cap_reached` deliberately is not.
|
|
734
|
+
* @enum {string}
|
|
735
|
+
*/
|
|
736
|
+
type?: 'retrieval_failed' | 'not_licensable' | 'price_drifted' | 'client_error' | 'insufficient_funds' | 'daily_spend_cap_reached';
|
|
624
737
|
};
|
|
625
738
|
};
|
|
626
739
|
AuthSignupRequest: {
|
|
@@ -646,6 +759,430 @@ declare interface components {
|
|
|
646
759
|
key: string;
|
|
647
760
|
secret?: string;
|
|
648
761
|
};
|
|
762
|
+
AuthLoginBuyerApiKeyRequest: {
|
|
763
|
+
/** @description Structured buyer API key (e.g. bktst_abc123) */
|
|
764
|
+
key: string;
|
|
765
|
+
/** @description 64-char hex secret, shown once at creation */
|
|
766
|
+
secret: string;
|
|
767
|
+
};
|
|
768
|
+
UserApiKey: {
|
|
769
|
+
/** Format: uuid */
|
|
770
|
+
id: string;
|
|
771
|
+
name: string;
|
|
772
|
+
/** @description Structured public identifier (e.g. bktst_abc123) */
|
|
773
|
+
key: string;
|
|
774
|
+
/** Format: date-time */
|
|
775
|
+
last_used_at?: string | null;
|
|
776
|
+
/** @description Maximum cumulative spend in cents. null = no limit. */
|
|
777
|
+
spending_limit_cents?: number | null;
|
|
778
|
+
/** Format: date-time */
|
|
779
|
+
created_at: string;
|
|
780
|
+
};
|
|
781
|
+
UserApiKeyCreateRequest: {
|
|
782
|
+
/** @description Human-readable label for the key */
|
|
783
|
+
name: string;
|
|
784
|
+
/** @description Optional spend ceiling in cents */
|
|
785
|
+
spending_limit_cents?: number | null;
|
|
786
|
+
};
|
|
787
|
+
/** @description Returned once only at creation. The secret is not stored and cannot be retrieved again. */
|
|
788
|
+
UserApiKeyCreateResponse: {
|
|
789
|
+
/** Format: uuid */
|
|
790
|
+
id: string;
|
|
791
|
+
/** @description Structured public identifier (e.g. bktst_abc123) */
|
|
792
|
+
key: string;
|
|
793
|
+
/** @description 64-char hex authentication secret. Store immediately — shown once only. */
|
|
794
|
+
secret: string;
|
|
795
|
+
};
|
|
796
|
+
/** @description The authenticated buyer's daily spend cap, read against the current spend window. The cap governs every wallet debit the buyer makes — MCP, REST, or the web payment gate — and spend is derived from completed purchases, so a refund returns allowance. cap_cents, spent_cents, remaining_cents and resets_at are spelled exactly as they are in DailySpendCapReachedError, so a refusal and this resource describe the same numbers. */
|
|
797
|
+
UserSpendCap: {
|
|
798
|
+
/** @description The daily spend cap in cents. null means uncapped. */
|
|
799
|
+
cap_cents: number | null;
|
|
800
|
+
/** @description IANA timezone whose calendar day bounds the spend window. Defaults to UTC. Reports the zone actually used, so an unrecognised stored value reads back as UTC. */
|
|
801
|
+
spend_window_timezone: string;
|
|
802
|
+
/** @description Total spent so far in the current spend window, summed over completed purchases by any path. */
|
|
803
|
+
spent_cents: number;
|
|
804
|
+
/** @description Cap minus spend so far, floored at zero. null when the buyer is uncapped — there is no ceiling to subtract from. Zero after the cap is lowered below spend already made. */
|
|
805
|
+
remaining_cents: number | null;
|
|
806
|
+
/**
|
|
807
|
+
* Format: date-time
|
|
808
|
+
* @description The instant the current spend window rolls, in UTC.
|
|
809
|
+
*/
|
|
810
|
+
resets_at: string;
|
|
811
|
+
/** @description Whether this buyer's bulk acquisitions are exempt from the cap. When true, spent_cents and remaining_cents describe ordinary spend only — an authorized bulk acquisition does not consume them — so a client presenting remaining_cents must say which number it is. */
|
|
812
|
+
bulk_exempt: boolean;
|
|
813
|
+
};
|
|
814
|
+
/** @description Sets the buyer's cap. The field is required and nullable: null is how a buyer becomes uncapped, and an omitted field is treated as a client error rather than as a request to be uncapped. A cap below spend already made in the current window is accepted — it simply leaves remaining_cents at zero until the window rolls. Zero is a valid cap and refuses every priced purchase. */
|
|
815
|
+
UserSpendCapUpdateRequest: {
|
|
816
|
+
/** @description New cap in whole cents, or null to remove the cap. Negative and fractional values are rejected with 422. */
|
|
817
|
+
daily_spend_limit_cents: number | null;
|
|
818
|
+
};
|
|
819
|
+
McpApiKeyCreateRequest: {
|
|
820
|
+
/** @description Human-readable name for the key */
|
|
821
|
+
label: string;
|
|
822
|
+
/** @description Grants access to search and read-only MCP tools. Defaults to true. */
|
|
823
|
+
can_search?: boolean;
|
|
824
|
+
/** @description Grants access to payment submission via MCP. Defaults to false. */
|
|
825
|
+
can_purchase?: boolean;
|
|
826
|
+
/**
|
|
827
|
+
* Format: uuid
|
|
828
|
+
* @description Scopes the key to a specific store. User must be an owner or author of that store.
|
|
829
|
+
*/
|
|
830
|
+
store_id?: string | null;
|
|
831
|
+
/** @description Grants access to seller content management tools. Defaults to false. */
|
|
832
|
+
can_manage_content?: boolean;
|
|
833
|
+
/** @description Grants access to seller analytics tools. Defaults to false. */
|
|
834
|
+
can_read_analytics?: boolean;
|
|
835
|
+
};
|
|
836
|
+
/** @description Returned once only at creation. The secret cannot be retrieved again. */
|
|
837
|
+
McpApiKeyCreateResponse: {
|
|
838
|
+
/** Format: uuid */
|
|
839
|
+
id: string;
|
|
840
|
+
/** @description Public identifier used to look up the key */
|
|
841
|
+
key: string;
|
|
842
|
+
/** @description Authentication secret. Store immediately — shown once only. */
|
|
843
|
+
secret: string;
|
|
844
|
+
label: string;
|
|
845
|
+
can_search: boolean;
|
|
846
|
+
can_purchase: boolean;
|
|
847
|
+
/** Format: uuid */
|
|
848
|
+
store_id?: string | null;
|
|
849
|
+
can_manage_content: boolean;
|
|
850
|
+
can_read_analytics: boolean;
|
|
851
|
+
};
|
|
852
|
+
McpApiKey: {
|
|
853
|
+
/** Format: uuid */
|
|
854
|
+
id: string;
|
|
855
|
+
label: string;
|
|
856
|
+
key: string;
|
|
857
|
+
can_search: boolean;
|
|
858
|
+
can_purchase: boolean;
|
|
859
|
+
/** Format: uuid */
|
|
860
|
+
store_id?: string | null;
|
|
861
|
+
can_manage_content: boolean;
|
|
862
|
+
can_read_analytics: boolean;
|
|
863
|
+
/** Format: date-time */
|
|
864
|
+
last_used_at?: string | null;
|
|
865
|
+
/** Format: date-time */
|
|
866
|
+
created_at: string;
|
|
867
|
+
};
|
|
868
|
+
McpContentSearchResult: {
|
|
869
|
+
/** Format: uuid */
|
|
870
|
+
id: string;
|
|
871
|
+
title: string;
|
|
872
|
+
/** @description Plain UTF-8 text preview. Never base64. */
|
|
873
|
+
teaser: string;
|
|
874
|
+
price_cents: number;
|
|
875
|
+
/** @enum {string} */
|
|
876
|
+
content_type: 'markdown' | 'html' | 'pdf' | 'image' | 'video' | 'external_ref' | 'brokered';
|
|
877
|
+
/** Format: uuid */
|
|
878
|
+
store_id: string;
|
|
879
|
+
store_name: string;
|
|
880
|
+
tags: string[];
|
|
881
|
+
/** @description Canonical article URL. Populated for Tollbit results; null for Ledewire items unless resource_url is set. */
|
|
882
|
+
url?: string | null;
|
|
883
|
+
/** @description Academic author display names. Null for non-academic content or unknown values. */
|
|
884
|
+
authors: string[] | null;
|
|
885
|
+
/** @description Academic abstract text. Null for non-academic content or when unavailable. */
|
|
886
|
+
abstract: string | null;
|
|
887
|
+
/** @description DOI URL for academic works. Null for non-academic content or unknown values. */
|
|
888
|
+
doi: string | null;
|
|
889
|
+
/** @description Academic publication date. Null for non-academic content or unknown values. */
|
|
890
|
+
publication_date: string | null;
|
|
891
|
+
/** @description Academic citation count from source metadata. Null for non-academic content or unknown values. */
|
|
892
|
+
citation_count: number | null;
|
|
893
|
+
};
|
|
894
|
+
/** @description Content returned to a store team member (owner or author) accessing their own content without a purchase. */
|
|
895
|
+
McpSellerContent: components['schemas']['McpContentSearchResult'] & {
|
|
896
|
+
/** @description Article body. Present when content_type is `markdown` or inline `html`. */
|
|
897
|
+
content_body?: string | null;
|
|
898
|
+
/** @description External content URI. Present when content_type is `external_ref`, `pdf`, `image`, `video`, or remote `html`. */
|
|
899
|
+
content_uri?: string | null;
|
|
900
|
+
};
|
|
901
|
+
McpFullContent: components['schemas']['McpContentSearchResult'] & {
|
|
902
|
+
/** @description Article body. Present when content_type is `markdown` or inline `html`. */
|
|
903
|
+
content_body?: string | null;
|
|
904
|
+
/** @description External content URI. Present when content_type is `external_ref`, `pdf`, `image`, `video`, or remote `html`. */
|
|
905
|
+
content_uri?: string | null;
|
|
906
|
+
/** Format: date-time */
|
|
907
|
+
purchased_at: string;
|
|
908
|
+
/** @description The licence the broker granted for this work, as returned on the retrieval — not the one we requested. Null when no grant was recorded: every non-brokered purchase, and brokered purchases made before the grant was captured. Null means "not recorded", never "no rights granted". */
|
|
909
|
+
license?: {
|
|
910
|
+
/**
|
|
911
|
+
* @description The broker's licence type, e.g. `ON_DEMAND_LICENSE` or `ON_DEMAND_FULL_USE_LICENSE`. Which one is minted depends on the rates the property publishes, so it varies per work.
|
|
912
|
+
* @example ON_DEMAND_LICENSE
|
|
913
|
+
*/
|
|
914
|
+
type: string;
|
|
915
|
+
/**
|
|
916
|
+
* @description The rights granted. `ON_DEMAND_LICENSE` carries `PARTIAL_USE` alone; `ON_DEMAND_FULL_USE_LICENSE` carries `FULL_USE` and `PARTIAL_USE`.
|
|
917
|
+
* @example [
|
|
918
|
+
* "PARTIAL_USE"
|
|
919
|
+
* ]
|
|
920
|
+
*/
|
|
921
|
+
permissions: string[];
|
|
922
|
+
/** @description The broker-hosted licence document for this grant. */
|
|
923
|
+
document_url: string | null;
|
|
924
|
+
} | null;
|
|
925
|
+
_meta: {
|
|
926
|
+
'x402/payment-response': {
|
|
927
|
+
success: boolean;
|
|
928
|
+
transaction: string;
|
|
929
|
+
network: string;
|
|
930
|
+
payer: string;
|
|
931
|
+
accessToken: string;
|
|
932
|
+
};
|
|
933
|
+
};
|
|
934
|
+
};
|
|
935
|
+
/** @description A record that a purchase happened: what was bought, when, at what price, and under which licence. Deliberately **not** a content schema. `list_purchases` used to return `McpFullContent`, which carries the article body, so a Buyer could re-read the full text of every work they had ever bought, free, 20 per call. Under single use (#939) a purchase is one licensed delivery, so purchase history is a receipt and the body is not part of it. Use `get_content` to buy a work — including one bought before. */
|
|
936
|
+
McpPurchaseReceipt: {
|
|
937
|
+
/** @description The purchase this receipt records. Distinct per purchase, so repeat buys of one work are distinguishable. */
|
|
938
|
+
purchase_id: string;
|
|
939
|
+
content_id: string;
|
|
940
|
+
title: string;
|
|
941
|
+
/** @description Where the work lives. Not a way to read it — a brokered URL serves a paywall to an unlicensed caller. */
|
|
942
|
+
url?: string | null;
|
|
943
|
+
store_id: string;
|
|
944
|
+
store_name: string;
|
|
945
|
+
/** @description What this purchase was charged, at the price in force when it was made. */
|
|
946
|
+
price_cents: number;
|
|
947
|
+
/** Format: date-time */
|
|
948
|
+
purchased_at: string;
|
|
949
|
+
/** @description The licence the broker granted for this purchase, as returned on the retrieval. Null when no grant was recorded: every non-brokered purchase, and brokered purchases made before the grant was captured. Null means "not recorded", never "no rights granted". */
|
|
950
|
+
license?: {
|
|
951
|
+
/** @example ON_DEMAND_LICENSE */
|
|
952
|
+
type: string;
|
|
953
|
+
/**
|
|
954
|
+
* @example [
|
|
955
|
+
* "PARTIAL_USE"
|
|
956
|
+
* ]
|
|
957
|
+
*/
|
|
958
|
+
permissions: string[];
|
|
959
|
+
document_url: string | null;
|
|
960
|
+
} | null;
|
|
961
|
+
};
|
|
962
|
+
McpGetWalletBalanceResult: {
|
|
963
|
+
/** @description Current wallet balance in cents for the authenticated MCP key owner. */
|
|
964
|
+
wallet_balance_cents: number;
|
|
965
|
+
};
|
|
966
|
+
McpRegisterResult: {
|
|
967
|
+
/** @description The API key identifier (not secret). */
|
|
968
|
+
key: string;
|
|
969
|
+
/** @description The API key secret — returned once, never retrievable again. */
|
|
970
|
+
secret: string;
|
|
971
|
+
label: string;
|
|
972
|
+
can_search: boolean;
|
|
973
|
+
can_purchase: boolean;
|
|
974
|
+
};
|
|
975
|
+
McpGetContentDetailsResult: {
|
|
976
|
+
content: components['schemas']['McpContentSearchResult'];
|
|
977
|
+
/** @description Whether the authenticated user has a completed purchase for this content. */
|
|
978
|
+
has_purchased: boolean;
|
|
979
|
+
/** @description Current wallet balance in cents for the authenticated MCP key owner. */
|
|
980
|
+
wallet_balance_cents: number;
|
|
981
|
+
};
|
|
982
|
+
McpListPurchasesResult: {
|
|
983
|
+
/** @description Receipts, newest first, one per purchase and never collapsed — a Buyer may hold several purchases of one work, each at the price in force when it was made. These were `McpFullContent` until #939, which meant this endpoint returned the body of every article the Buyer had ever bought. */
|
|
984
|
+
purchases: components['schemas']['McpPurchaseReceipt'][];
|
|
985
|
+
/** @description Total number of completed purchases. */
|
|
986
|
+
total_count: number;
|
|
987
|
+
offset: number;
|
|
988
|
+
limit: number;
|
|
989
|
+
};
|
|
990
|
+
/** @description Returned as structuredContent when a get_content payment attempt fails due to insufficient wallet balance. Always accompanied by isError: true. */
|
|
991
|
+
McpInsufficientFundsError: {
|
|
992
|
+
/** @enum {string} */
|
|
993
|
+
error: 'insufficient_funds';
|
|
994
|
+
/** @description Current wallet balance in cents. */
|
|
995
|
+
wallet_balance_cents: number;
|
|
996
|
+
/** @description Price of the content in cents. */
|
|
997
|
+
required_cents: number;
|
|
998
|
+
/** @description Amount needed to top up the wallet to cover this purchase (required_cents - wallet_balance_cents). */
|
|
999
|
+
shortfall_cents: number;
|
|
1000
|
+
/**
|
|
1001
|
+
* Format: uri
|
|
1002
|
+
* @description Direct link to the Ledewire wallet funding page, pre-filled with the shortfall amount.
|
|
1003
|
+
*/
|
|
1004
|
+
funding_url: string;
|
|
1005
|
+
};
|
|
1006
|
+
/** @description Returned as structuredContent when a get_content call is refused because the buyer's daily spend cap would be exceeded. Always accompanied by isError: true. Deliberately carries no funding_url — adding money to the wallet cannot raise a cap, and a payload resembling McpInsufficientFundsError would send agents to the wrong remedy. The cap resets at resets_at; until then the only remedies are raising the cap or waiting. */
|
|
1007
|
+
McpDailySpendCapReachedError: {
|
|
1008
|
+
/** @enum {string} */
|
|
1009
|
+
error: 'daily_spend_cap_reached';
|
|
1010
|
+
/** @description The buyer's daily spend cap in cents. */
|
|
1011
|
+
cap_cents: number;
|
|
1012
|
+
/** @description Total spent so far in the current spend window. Ordinary completed purchases are summed per row; a bulk acquisition contributes its total, never its per-work purchases. */
|
|
1013
|
+
spent_cents: number;
|
|
1014
|
+
/** @description Cap minus spend so far, floored at zero — what the buyer may still spend in this window. */
|
|
1015
|
+
remaining_cents: number;
|
|
1016
|
+
/**
|
|
1017
|
+
* Format: date-time
|
|
1018
|
+
* @description The instant the current spend window rolls, in UTC. One calendar day boundary in the buyer's own timezone.
|
|
1019
|
+
*/
|
|
1020
|
+
resets_at: string;
|
|
1021
|
+
/** @description Whether this buyer's bulk acquisitions are exempt from the cap. When true, spent_cents and remaining_cents describe ordinary spend only — an authorized bulk acquisition does not consume them — so a client presenting remaining_cents must say which number it is. */
|
|
1022
|
+
bulk_exempt: boolean;
|
|
1023
|
+
};
|
|
1024
|
+
/** @description The REST and x402 web-gate form of the same refusal, returned with HTTP 402 Payment Required by POST /v1/purchases and GET /v1/x402/contents/{id}. Carries the same fields as McpDailySpendCapReachedError alongside the standard error envelope, and the same absence of a funding URL. `error.type` is the machine-readable discriminator. */
|
|
1025
|
+
DailySpendCapReachedError: {
|
|
1026
|
+
error: {
|
|
1027
|
+
/** @enum {integer} */
|
|
1028
|
+
code: 402;
|
|
1029
|
+
message: string;
|
|
1030
|
+
/** @enum {string} */
|
|
1031
|
+
type: 'daily_spend_cap_reached';
|
|
1032
|
+
};
|
|
1033
|
+
/** @description The buyer's daily spend cap in cents. */
|
|
1034
|
+
cap_cents: number;
|
|
1035
|
+
/** @description Total spent so far in the current spend window, summed over completed purchases by any path. */
|
|
1036
|
+
spent_cents: number;
|
|
1037
|
+
/** @description Cap minus spend so far, floored at zero — what the buyer may still spend in this window. */
|
|
1038
|
+
remaining_cents: number;
|
|
1039
|
+
/**
|
|
1040
|
+
* Format: date-time
|
|
1041
|
+
* @description The instant the current spend window rolls, in UTC.
|
|
1042
|
+
*/
|
|
1043
|
+
resets_at: string;
|
|
1044
|
+
/** @description Whether this buyer's bulk acquisitions are exempt from the cap. When true, spent_cents and remaining_cents describe ordinary spend only. */
|
|
1045
|
+
bulk_exempt: boolean;
|
|
1046
|
+
};
|
|
1047
|
+
/** @description Returned by the fund_wallet tool. Contains the buyer portal wallet URL. Open this link in a browser to add funds using the Ledewire wallet funding page. */
|
|
1048
|
+
McpFundWalletResult: {
|
|
1049
|
+
/**
|
|
1050
|
+
* Format: uri
|
|
1051
|
+
* @description Buyer portal wallet URL. Includes an `amount` query param when amount_cents was provided.
|
|
1052
|
+
*/
|
|
1053
|
+
url: string;
|
|
1054
|
+
};
|
|
1055
|
+
/** @description One JSON-RPC 2.0 request envelope. `id` is omitted for notifications (`notifications/initialized`), which are acknowledged with HTTP 202 and no body. */
|
|
1056
|
+
McpJsonRpcRequest: {
|
|
1057
|
+
/** @enum {string} */
|
|
1058
|
+
jsonrpc: '2.0';
|
|
1059
|
+
/** @enum {string} */
|
|
1060
|
+
method: 'initialize' | 'notifications/initialized' | 'ping' | 'tools/list' | 'tools/call' | 'resources/list' | 'resources/read' | 'prompts/list' | 'prompts/get';
|
|
1061
|
+
/** @description Client-supplied request identifier. Echoed back in the response. Omitted for notifications. */
|
|
1062
|
+
id?: number | string;
|
|
1063
|
+
/** @description Shape depends on `method`. `initialize`: `{ protocolVersion, capabilities, clientInfo }` — all three required. `tools/call`: `{ name: "<tool_name>", arguments: { ... } }`; call `tools/list` for each tool's full `inputSchema`. `resources/read`: `{ uri: "ledewire://..." }`. `prompts/get`: `{ name: "<prompt_name>", arguments: { ... } }`. `tools/list`, `resources/list`, `prompts/list` and `ping` take no parameters. */
|
|
1064
|
+
params?: {
|
|
1065
|
+
/**
|
|
1066
|
+
* @description Tool name for `tools/call`, prompt name for `prompts/get`.
|
|
1067
|
+
* @enum {string}
|
|
1068
|
+
*/
|
|
1069
|
+
name?: 'search_content' | 'list_publications' | 'list_publication_works' | 'register' | 'get_wallet_balance' | 'get_content_details' | 'get_content' | 'list_purchases' | 'list_my_stores' | 'fund_wallet' | 'list_my_content' | 'search_my_content' | 'register_content' | 'update_content' | 'check_content_status' | 'get_sales_summary' | 'get_content_sales' | 'get_buyer_insights' | 'onboarding_checklist' | 'troubleshoot_integration' | 'optimize_pricing';
|
|
1070
|
+
arguments?: {
|
|
1071
|
+
[key: string]: unknown;
|
|
1072
|
+
};
|
|
1073
|
+
/**
|
|
1074
|
+
* @description Resource URI for `resources/read`.
|
|
1075
|
+
* @enum {string}
|
|
1076
|
+
*/
|
|
1077
|
+
uri?: 'ledewire://docs/overview' | 'ledewire://docs/pricing-guidelines' | 'ledewire://seller/context';
|
|
1078
|
+
/** @description Requested revision for `initialize`. See the negotiation note on the endpoint. */
|
|
1079
|
+
protocolVersion?: string;
|
|
1080
|
+
capabilities?: Record<string, never>;
|
|
1081
|
+
clientInfo?: Record<string, never>;
|
|
1082
|
+
};
|
|
1083
|
+
};
|
|
1084
|
+
/** @description Returned by the list_my_stores tool. Every store the authenticated key's owner holds owner or author access to, with that store's non-archived content count. */
|
|
1085
|
+
McpListMyStoresResult: {
|
|
1086
|
+
stores: {
|
|
1087
|
+
/** Format: uuid */
|
|
1088
|
+
store_id: string;
|
|
1089
|
+
store_name: string;
|
|
1090
|
+
/**
|
|
1091
|
+
* @description Highest access the key owner holds on this store.
|
|
1092
|
+
* @enum {string}
|
|
1093
|
+
*/
|
|
1094
|
+
role: 'owner' | 'author';
|
|
1095
|
+
/** @description Non-archived content items in the store. */
|
|
1096
|
+
content_count: number;
|
|
1097
|
+
}[];
|
|
1098
|
+
};
|
|
1099
|
+
/** @description Returned by the list_my_content tool. A page of the connected store's catalog, including items no buyer can see. Pagination follows the standard `offset`/`limit` contract shared with search_content and list_purchases; the `total`, `page` and `per_page` fields are retained for clients written against the tool's original contract and describe the same window. */
|
|
1100
|
+
McpListMyContentResult: {
|
|
1101
|
+
contents: {
|
|
1102
|
+
/** Format: uuid */
|
|
1103
|
+
id: string;
|
|
1104
|
+
title: string;
|
|
1105
|
+
teaser?: string | null;
|
|
1106
|
+
price_cents: number;
|
|
1107
|
+
/** @description `public`, `unlisted`, or `archived`. */
|
|
1108
|
+
visibility: string;
|
|
1109
|
+
/** @enum {string} */
|
|
1110
|
+
content_type: 'markdown' | 'html' | 'pdf' | 'image' | 'video' | 'external_ref' | 'brokered';
|
|
1111
|
+
tags: string[];
|
|
1112
|
+
/** Format: date-time */
|
|
1113
|
+
created_at: string;
|
|
1114
|
+
}[];
|
|
1115
|
+
/** @description Total matching items across all pages, before pagination. */
|
|
1116
|
+
total_count: number;
|
|
1117
|
+
/** @description Number of records skipped to produce this page. */
|
|
1118
|
+
offset: number;
|
|
1119
|
+
/** @description Maximum records this page could contain. */
|
|
1120
|
+
limit: number;
|
|
1121
|
+
/** @description Legacy, superseded by `total_count`. Identical value, retained for existing clients. */
|
|
1122
|
+
total: number;
|
|
1123
|
+
/** @description Legacy, superseded by `offset`. One-based page number of the page *containing* the first record returned, derived from the window actually applied. When `offset` is not a multiple of `limit` there is no exact page number and this page's own span only overlaps the records returned — `offset: 25, limit: 10` returns records 25-34 and reports page 3, which spans 20-29. Paginate by `offset`, not by incrementing this field. */
|
|
1124
|
+
page: number;
|
|
1125
|
+
/** @description Legacy, superseded by `limit`. Identical value, retained for existing clients. */
|
|
1126
|
+
per_page: number;
|
|
1127
|
+
};
|
|
1128
|
+
/** @description Returned by the search_my_content tool. Deliberately narrower than McpListMyContentResult — it is a lookup aid for finding a content_id, not a catalog view. */
|
|
1129
|
+
McpSearchMyContentResult: {
|
|
1130
|
+
contents: {
|
|
1131
|
+
/** Format: uuid */
|
|
1132
|
+
id: string;
|
|
1133
|
+
title: string;
|
|
1134
|
+
teaser?: string | null;
|
|
1135
|
+
/** @enum {string} */
|
|
1136
|
+
content_type: 'markdown' | 'html' | 'pdf' | 'image' | 'video' | 'external_ref' | 'brokered';
|
|
1137
|
+
tags: string[];
|
|
1138
|
+
}[];
|
|
1139
|
+
};
|
|
1140
|
+
/** @description Returned by both register_content and update_content on success. The two tools share one shape: the identifying fields of the content item as it now stands. Neither returns the body — read it back with get_content if you need it. */
|
|
1141
|
+
McpContentMutationResult: {
|
|
1142
|
+
/** Format: uuid */
|
|
1143
|
+
id?: string;
|
|
1144
|
+
title?: string;
|
|
1145
|
+
/** @enum {string} */
|
|
1146
|
+
content_type?: 'markdown' | 'html' | 'pdf' | 'image' | 'video' | 'external_ref' | 'brokered';
|
|
1147
|
+
/** @description `public`, `unlisted`, or `archived`. */
|
|
1148
|
+
visibility?: string;
|
|
1149
|
+
price_cents?: number;
|
|
1150
|
+
};
|
|
1151
|
+
/** @description Returned by the check_content_status tool. Read-only diagnosis of one content item — `issues` is empty exactly when `is_healthy` is true. */
|
|
1152
|
+
McpCheckContentStatusResult: {
|
|
1153
|
+
/** Format: uuid */
|
|
1154
|
+
content_id: string;
|
|
1155
|
+
title: string;
|
|
1156
|
+
/** @description Problems found, in plain English. Empty when the item is healthy. */
|
|
1157
|
+
issues: string[];
|
|
1158
|
+
/** @description Suggested next steps, one per issue where a fix is known. */
|
|
1159
|
+
recommendations: string[];
|
|
1160
|
+
is_healthy: boolean;
|
|
1161
|
+
};
|
|
1162
|
+
/** @description One row of the get_content_sales tool's result — a single content item's sales performance. */
|
|
1163
|
+
McpContentSalesRow: {
|
|
1164
|
+
/** Format: uuid */
|
|
1165
|
+
content_id: string;
|
|
1166
|
+
title: string;
|
|
1167
|
+
purchase_count: number;
|
|
1168
|
+
revenue_cents: number;
|
|
1169
|
+
};
|
|
1170
|
+
/** @description Result of the get_content_sales tool — one page of the store's per-content sales ranking. Carried identically in structuredContent and in the double-encoded text block. */
|
|
1171
|
+
McpGetContentSalesResult: {
|
|
1172
|
+
content_sales: components['schemas']['McpContentSalesRow'][];
|
|
1173
|
+
/** @description Number of content items in the whole ranking, not in the returned page. Scoped the same way the rows are — an author key counts only their attributed content. */
|
|
1174
|
+
total_count: number;
|
|
1175
|
+
offset: number;
|
|
1176
|
+
limit: number;
|
|
1177
|
+
};
|
|
1178
|
+
/** @description Result of the get_buyer_insights tool — one page of the store's buyers, ranked by total spend descending. Carried identically in structuredContent and in the text block. */
|
|
1179
|
+
McpGetBuyerInsightsResult: {
|
|
1180
|
+
buyer_insights: components['schemas']['BuyerStatisticsItem'][];
|
|
1181
|
+
/** @description Number of buyers in the whole ranking, not in the returned page. Scoped the same way the rows are — an author key counts only buyers of their attributed content. */
|
|
1182
|
+
total_count: number;
|
|
1183
|
+
offset: number;
|
|
1184
|
+
limit: number;
|
|
1185
|
+
};
|
|
649
1186
|
AuthTokenRefreshRequest: {
|
|
650
1187
|
refresh_token?: string;
|
|
651
1188
|
};
|
|
@@ -735,8 +1272,26 @@ declare interface components {
|
|
|
735
1272
|
[key: string]: unknown;
|
|
736
1273
|
};
|
|
737
1274
|
};
|
|
1275
|
+
/** @description The buyer's wallet. balance_cents and spendable_cents are the same number and always will be — balance_cents has always meant "what you can spend", and money committed to a bulk acquisition is a hold, which moves it out of the wallet rather than annotating it. held_cents and holds exist so a buyer mid-acquisition can see why their balance is lower than their purchase history explains. */
|
|
738
1276
|
WalletBalanceResponse: {
|
|
1277
|
+
/** @description Spendable balance in cents. Excludes funds held against a bulk acquisition. */
|
|
739
1278
|
balance_cents: number;
|
|
1279
|
+
/** @description The same figure as balance_cents, named in the vocabulary holds require. */
|
|
1280
|
+
spendable_cents: number;
|
|
1281
|
+
/** @description Total committed to active bulk acquisitions and not yet spent or released. */
|
|
1282
|
+
held_cents: number;
|
|
1283
|
+
/** @description One entry per bulk acquisition currently holding funds. Empty when none is. */
|
|
1284
|
+
holds: {
|
|
1285
|
+
/** Format: uuid */
|
|
1286
|
+
acquisition_id: string;
|
|
1287
|
+
/** @description What this acquisition is currently holding. */
|
|
1288
|
+
held_cents: number;
|
|
1289
|
+
/**
|
|
1290
|
+
* Format: date-time
|
|
1291
|
+
* @description When the hold was placed.
|
|
1292
|
+
*/
|
|
1293
|
+
authorized_at: string;
|
|
1294
|
+
}[];
|
|
740
1295
|
};
|
|
741
1296
|
WalletTransactionItem: {
|
|
742
1297
|
/** @description ID of the transaction entry (matches the source record) */
|
|
@@ -747,17 +1302,20 @@ declare interface components {
|
|
|
747
1302
|
*/
|
|
748
1303
|
type: 'credit' | 'debit';
|
|
749
1304
|
/**
|
|
750
|
-
* @description What caused this wallet movement
|
|
1305
|
+
* @description What caused this wallet movement. bulk_acquisition and bulk_hold are each one entry for a whole bulk acquisition — its per-work purchases are deliberately not listed here, because one acquisition can hold tens of thousands of them and they describe one decision. bulk_hold is an acquisition still holding funds: the money has left the wallet but has not been spent, and it becomes a bulk_acquisition entry for the amount actually captured once the acquisition ends. An acquisition never produces both.
|
|
751
1306
|
* @enum {string}
|
|
752
1307
|
*/
|
|
753
|
-
reason: 'wallet_funding' | 'purchase' | 'refund';
|
|
754
|
-
/** @description Always positive; direction expressed by `type
|
|
1308
|
+
reason: 'wallet_funding' | 'purchase' | 'refund' | 'bulk_acquisition' | 'bulk_hold';
|
|
1309
|
+
/** @description Always positive; direction expressed by `type`. For a bulk_hold entry this is what is currently held; for a bulk_acquisition entry it is what was captured, not what was held — the uncaptured remainder was released, never charged. Note that a bulk acquisition's per-work purchases each carry a price_cents that is a rounded display value and is NOT summable: bulk prices at micro precision and rounds to cents once, on the acquisition total, so this aggregate is the figure to read. */
|
|
755
1310
|
amount_cents: number;
|
|
756
1311
|
/** @description Running wallet balance immediately after this event */
|
|
757
1312
|
balance_after_cents: number;
|
|
758
|
-
/**
|
|
759
|
-
|
|
760
|
-
|
|
1313
|
+
/**
|
|
1314
|
+
* @description Status of the source record. authorized/acquiring/settled/cancelled/failed are bulk acquisition states; the rest are purchase and funding transfer states.
|
|
1315
|
+
* @enum {string}
|
|
1316
|
+
*/
|
|
1317
|
+
status: 'completed' | 'pending' | 'failed' | 'cancelled' | 'settled' | 'reverted' | 'refunded' | 'authorized' | 'acquiring';
|
|
1318
|
+
/** @description ID of the source record (Purchase, FundingTransfer or Acquisition) */
|
|
761
1319
|
reference_id: string;
|
|
762
1320
|
/** @description Human-readable label suitable for display */
|
|
763
1321
|
description: string;
|
|
@@ -783,17 +1341,17 @@ declare interface components {
|
|
|
783
1341
|
has_sufficient_funds?: boolean;
|
|
784
1342
|
};
|
|
785
1343
|
};
|
|
786
|
-
/** @description Update request for content. `content_body` applies to `markdown` content; `content_uri`
|
|
1344
|
+
/** @description Update request for content. `content_body` applies to `markdown` and inline `html` content; `content_uri` applies to `external_ref` and remote `html` content. For `html`, submitting both `content_body` and `content_uri` in the same request is rejected with `400`. */
|
|
787
1345
|
ContentUpdateRequest: {
|
|
788
1346
|
/** @description Content title */
|
|
789
1347
|
title?: string;
|
|
790
1348
|
/**
|
|
791
1349
|
* Format: byte
|
|
792
|
-
* @description Full article body
|
|
1350
|
+
* @description Full article body, base64 encoded. For `markdown` and inline `html` content. Must be base64-encoded before sending (e.g. `btoa(bodyText)`).
|
|
793
1351
|
*/
|
|
794
1352
|
content_body?: string;
|
|
795
1353
|
/**
|
|
796
|
-
* @description URI of the resource.
|
|
1354
|
+
* @description URI of the resource. For `external_ref` and remote `html` content.
|
|
797
1355
|
* @example https://vimeo.com/123456789
|
|
798
1356
|
*/
|
|
799
1357
|
content_uri?: string;
|
|
@@ -804,7 +1362,7 @@ declare interface components {
|
|
|
804
1362
|
external_identifier?: string | null;
|
|
805
1363
|
/**
|
|
806
1364
|
* Format: byte
|
|
807
|
-
* @description Content teaser, base64 encoded
|
|
1365
|
+
* @description Content teaser, base64 encoded. Must be base64-encoded before sending (e.g. `btoa(teaserText)`)
|
|
808
1366
|
*/
|
|
809
1367
|
teaser?: string;
|
|
810
1368
|
/** @description Price in cents (must be greater than 0) */
|
|
@@ -1025,22 +1583,22 @@ declare interface components {
|
|
|
1025
1583
|
*/
|
|
1026
1584
|
started_at?: string;
|
|
1027
1585
|
};
|
|
1028
|
-
/** @description Create request body for content. Required fields vary by `content_type`: `markdown` requires `content_body`; `
|
|
1586
|
+
/** @description Create request body for content. Required fields vary by `content_type`: `markdown` requires `content_body`; `html` requires exactly one of `content_body` (inline) or `content_uri` (remote); `external_ref`, `pdf`, `image`, and `video` require `content_uri` (`content_body` is not accepted). */
|
|
1029
1587
|
Content: {
|
|
1030
1588
|
/**
|
|
1031
|
-
* @description The type of content being created.
|
|
1589
|
+
* @description The type of content being created. `pdf`, `image`, and `video` require `content_uri`; `content_body` is not accepted for these types.
|
|
1032
1590
|
* @enum {string}
|
|
1033
1591
|
*/
|
|
1034
|
-
content_type: 'markdown' | 'external_ref';
|
|
1592
|
+
content_type: 'markdown' | 'html' | 'pdf' | 'image' | 'video' | 'external_ref';
|
|
1035
1593
|
/** @description Content title */
|
|
1036
1594
|
title: string;
|
|
1037
1595
|
/**
|
|
1038
1596
|
* Format: byte
|
|
1039
|
-
* @description Full article body
|
|
1597
|
+
* @description Full article body, base64 encoded. Required when `content_type` is `markdown`. For `html` content, provide either `content_body` (inline) or `content_uri` (remote) — not both. Must be base64-encoded before sending (e.g. `btoa(htmlText)`). Note: HTML special characters (`<`, `>`, `&`) should be unicode-escaped when embedding the JSON response in a `<script>` tag.
|
|
1040
1598
|
*/
|
|
1041
1599
|
content_body?: string;
|
|
1042
1600
|
/**
|
|
1043
|
-
* @description URI of the resource. Required when `content_type` is `external_ref
|
|
1601
|
+
* @description URI of the resource. Required when `content_type` is `external_ref`, `pdf`, `image`, `video`, or remote `html`.
|
|
1044
1602
|
* @example https://vimeo.com/123456789
|
|
1045
1603
|
*/
|
|
1046
1604
|
content_uri?: string;
|
|
@@ -1051,7 +1609,7 @@ declare interface components {
|
|
|
1051
1609
|
external_identifier?: string;
|
|
1052
1610
|
/**
|
|
1053
1611
|
* Format: byte
|
|
1054
|
-
* @description (Optional) Article teaser, written in markdown and base64 encoded.
|
|
1612
|
+
* @description (Optional) Article teaser, written in markdown and base64 encoded. Must be base64-encoded before sending (e.g. `btoa(teaserText)`).
|
|
1055
1613
|
*/
|
|
1056
1614
|
teaser?: string;
|
|
1057
1615
|
/** @description Price for the content in cents. */
|
|
@@ -1071,23 +1629,23 @@ declare interface components {
|
|
|
1071
1629
|
[key: string]: unknown;
|
|
1072
1630
|
};
|
|
1073
1631
|
};
|
|
1074
|
-
/** @description Response shape for a single content item. The presence of `content_body` vs `content_uri` depends on `content_type
|
|
1632
|
+
/** @description Response shape for a single content item. The presence of `content_body` vs `content_uri` depends on `content_type` and storage mode: `markdown`, `brokered`, and inline `html` include `content_body`; `external_ref`, `pdf`, `image`, `video`, and remote `html` include `content_uri`. */
|
|
1075
1633
|
ContentResponse: {
|
|
1076
1634
|
id: string;
|
|
1077
1635
|
/**
|
|
1078
|
-
* @description The type of content.
|
|
1636
|
+
* @description The type of content. `pdf`, `image`, and `video` are remote-only types; `content_uri` is withheld until purchase. `brokered` is system-managed (e.g. Tollbit-sourced) and cannot be created directly via this API.
|
|
1079
1637
|
* @enum {string}
|
|
1080
1638
|
*/
|
|
1081
|
-
content_type: 'markdown' | 'external_ref';
|
|
1639
|
+
content_type: 'markdown' | 'html' | 'pdf' | 'image' | 'video' | 'external_ref' | 'brokered';
|
|
1082
1640
|
/** @description Content title */
|
|
1083
1641
|
title: string;
|
|
1084
1642
|
/**
|
|
1085
1643
|
* Format: byte
|
|
1086
|
-
* @description Full article body
|
|
1644
|
+
* @description Full article body, base64 encoded. Present when `content_type` is `markdown` or inline `html`. Must be base64-decoded before rendering (e.g. `atob(content.content_body ?? '')`). Note: HTML special characters (`<`, `>`, `&`) must be unicode-escaped when embedding the JSON in a `<script>` tag.
|
|
1087
1645
|
*/
|
|
1088
1646
|
content_body?: string | null;
|
|
1089
1647
|
/**
|
|
1090
|
-
* @description URI of the external resource. Present when `content_type` is `external_ref`.
|
|
1648
|
+
* @description URI of the external resource. Present when `content_type` is `external_ref`, `pdf`, `image`, `video`, or remote `html`.
|
|
1091
1649
|
* @example https://vimeo.com/123456789
|
|
1092
1650
|
*/
|
|
1093
1651
|
content_uri?: string | null;
|
|
@@ -1096,9 +1654,11 @@ declare interface components {
|
|
|
1096
1654
|
* @example vimeo:123456789
|
|
1097
1655
|
*/
|
|
1098
1656
|
external_identifier?: string | null;
|
|
1657
|
+
/** @description Canonical URL of this content on its origin site. Used by the x402 verify-origin endpoint to bind a third-party page to a Ledewire content record. */
|
|
1658
|
+
resource_url?: string | null;
|
|
1099
1659
|
/**
|
|
1100
1660
|
* Format: byte
|
|
1101
|
-
* @description Article teaser, base64 encoded.
|
|
1661
|
+
* @description Article teaser, base64 encoded. Must be base64-decoded before rendering (e.g. `atob(content.teaser ?? '')`).
|
|
1102
1662
|
*/
|
|
1103
1663
|
teaser: string;
|
|
1104
1664
|
/** @description Price for the content in cents. */
|
|
@@ -1189,12 +1749,12 @@ declare interface components {
|
|
|
1189
1749
|
ContentListItem: {
|
|
1190
1750
|
id: string;
|
|
1191
1751
|
/** @enum {string} */
|
|
1192
|
-
content_type: 'markdown' | 'external_ref';
|
|
1752
|
+
content_type: 'markdown' | 'html' | 'pdf' | 'image' | 'video' | 'external_ref' | 'brokered';
|
|
1193
1753
|
title: string;
|
|
1194
1754
|
price_cents: number;
|
|
1195
1755
|
/**
|
|
1196
1756
|
* Format: byte
|
|
1197
|
-
* @description Article teaser, base64 encoded. Null when not set.
|
|
1757
|
+
* @description Article teaser, base64 encoded. Null when not set. Must be base64-decoded before rendering (e.g. `atob(item.teaser ?? '')`).
|
|
1198
1758
|
*/
|
|
1199
1759
|
teaser: string | null;
|
|
1200
1760
|
/** @enum {string} */
|
|
@@ -1205,11 +1765,13 @@ declare interface components {
|
|
|
1205
1765
|
content_uri: string | null;
|
|
1206
1766
|
/** @description Namespaced platform ID for `external_ref` content. Null for other types. */
|
|
1207
1767
|
external_identifier?: string | null;
|
|
1768
|
+
/** @description Canonical URL of this content on its origin site. Used by the x402 verify-origin endpoint. */
|
|
1769
|
+
resource_url?: string | null;
|
|
1208
1770
|
};
|
|
1209
1771
|
/**
|
|
1210
1772
|
* @description Full content detail plus real-time access and wallet context for a specific user. Returned by the buyer-facing `GET /v1/content/:id/with-access` endpoint.
|
|
1211
1773
|
*
|
|
1212
|
-
* **URI gating for
|
|
1774
|
+
* **URI gating for remote content:** `content_uri` is only present in the response when `access_info.has_purchased` is `true`. This applies to `external_ref` content and remote-mode `html` content (where the payload is a URI rather than an inline body). For all other states (unauthenticated, insufficient funds, not yet purchased) it is omitted, ensuring buyers cannot access the Vimeo link, PDF URI, or other external resource without completing a purchase.
|
|
1213
1775
|
*/
|
|
1214
1776
|
ContentWithAccessResponse: components['schemas']['ContentResponse'] & {
|
|
1215
1777
|
access_info: components['schemas']['ContentAccessInfo'];
|
|
@@ -1245,6 +1807,17 @@ declare interface components {
|
|
|
1245
1807
|
/** Format: date-time */
|
|
1246
1808
|
timestamp: string;
|
|
1247
1809
|
status: components['schemas']['PurchaseStatus'];
|
|
1810
|
+
/**
|
|
1811
|
+
* @description The delivered work, present **only** on the response to `POST /v1/purchases` and only when the deliverable is something we hold. It is the delivery, not a field of the purchase record: the same purchase read back from `GET /v1/purchases/{id}` or listed from `GET /v1/purchases` does not carry it, and there is no route that serves it again.
|
|
1812
|
+
*
|
|
1813
|
+
* That asymmetry is the rule rather than an omission. A Buyer keeps what they were given — single use is non-transferable, not read-once — but LedeWire does not hand the same bytes over a second time without a second grant, and every read from LedeWire is a purchase.
|
|
1814
|
+
*/
|
|
1815
|
+
content_body?: string;
|
|
1816
|
+
/**
|
|
1817
|
+
* Format: uri
|
|
1818
|
+
* @description Where the work lives, in place of `content_body`, for a deliverable hosted elsewhere. Same rule: present only on the response to the purchase that paid for it.
|
|
1819
|
+
*/
|
|
1820
|
+
content_uri?: string;
|
|
1248
1821
|
};
|
|
1249
1822
|
MerchantSaleResponse: {
|
|
1250
1823
|
id: string;
|
|
@@ -1301,7 +1874,7 @@ declare interface components {
|
|
|
1301
1874
|
has_sufficient_funds?: boolean | null;
|
|
1302
1875
|
has_purchased: boolean;
|
|
1303
1876
|
/** @enum {string} */
|
|
1304
|
-
next_required_action: 'authenticate' | 'fund_wallet' | 'purchase'
|
|
1877
|
+
next_required_action: 'authenticate' | 'fund_wallet' | 'purchase';
|
|
1305
1878
|
};
|
|
1306
1879
|
};
|
|
1307
1880
|
WalletPaymentStatusResponse: {
|
|
@@ -1329,6 +1902,491 @@ declare interface components {
|
|
|
1329
1902
|
};
|
|
1330
1903
|
};
|
|
1331
1904
|
};
|
|
1905
|
+
/** @description A single x402 v2 resource entry returned by the Bazaar discovery endpoint. */
|
|
1906
|
+
X402BazaarResource: {
|
|
1907
|
+
/** @description Canonical URL for this content. Equal to `resource_url` when the content has one; otherwise constructed as `{base_url}/v1/x402/contents/{id}`. */
|
|
1908
|
+
resource: string;
|
|
1909
|
+
/** @enum {string} */
|
|
1910
|
+
type: 'http';
|
|
1911
|
+
/** @enum {integer} */
|
|
1912
|
+
x402Version: 2;
|
|
1913
|
+
accepts: {
|
|
1914
|
+
/** @example ledewire-wallet */
|
|
1915
|
+
scheme: string;
|
|
1916
|
+
/** @example ledewire:v1 */
|
|
1917
|
+
network: string;
|
|
1918
|
+
}[];
|
|
1919
|
+
/** @description Unix timestamp (seconds) of the content's last update. */
|
|
1920
|
+
lastUpdated: number;
|
|
1921
|
+
metadata: {
|
|
1922
|
+
title: string;
|
|
1923
|
+
/** @description Plain UTF-8 preview text. Never base64. */
|
|
1924
|
+
teaser: string;
|
|
1925
|
+
store_name: string;
|
|
1926
|
+
/** @description `metadata["category"]` when present; otherwise falls back to `content_type`. Never null. */
|
|
1927
|
+
category: string;
|
|
1928
|
+
};
|
|
1929
|
+
};
|
|
1930
|
+
/** @description Response from the x402 Bazaar discovery endpoint. */
|
|
1931
|
+
X402BazaarDiscoveryResponse: {
|
|
1932
|
+
/** @description Total number of public resources (ignores pagination). */
|
|
1933
|
+
total: number;
|
|
1934
|
+
resources: components['schemas']['X402BazaarResource'][];
|
|
1935
|
+
};
|
|
1936
|
+
/** @description Response body returned by the x402 content endpoint on a successful `200`. Delivers the purchased content directly in the settlement response. `content_body` is present when `content_type` is `markdown`, `brokered`, or inline `html`; `content_uri` is present when `content_type` is `external_ref`, `pdf`, `image`, `video`, or remote `html`. `purchase_id` is the UUID of the settled Purchase record (null for free content). */
|
|
1937
|
+
X402ContentResponse: {
|
|
1938
|
+
id: string;
|
|
1939
|
+
/** @enum {string} */
|
|
1940
|
+
content_type: 'markdown' | 'html' | 'pdf' | 'image' | 'video' | 'external_ref' | 'brokered';
|
|
1941
|
+
title: string;
|
|
1942
|
+
price_cents: number;
|
|
1943
|
+
/** @description Plain UTF-8 text preview. */
|
|
1944
|
+
teaser: string;
|
|
1945
|
+
/** @enum {string} */
|
|
1946
|
+
visibility: 'public' | 'unlisted' | 'private';
|
|
1947
|
+
metadata?: {
|
|
1948
|
+
[key: string]: unknown;
|
|
1949
|
+
};
|
|
1950
|
+
external_identifier?: string | null;
|
|
1951
|
+
/** @description UUID of the settled Purchase record. Null for free content. */
|
|
1952
|
+
purchase_id?: string | null;
|
|
1953
|
+
/** @description Canonical URL of this content on its origin site. Set when content was registered via a pricing rule or manual resource_url assignment. */
|
|
1954
|
+
resource_url?: string | null;
|
|
1955
|
+
/** @description Full article body in plain UTF-8 markdown. Present when content_type is markdown. */
|
|
1956
|
+
content_body?: string | null;
|
|
1957
|
+
/** @description URI of the external resource. Present when content_type is `external_ref`, `pdf`, `image`, or `video`. */
|
|
1958
|
+
content_uri?: string | null;
|
|
1959
|
+
};
|
|
1960
|
+
/** @description Returned when the URL matches a registered Ledewire content item. */
|
|
1961
|
+
VerifyOriginVerified: {
|
|
1962
|
+
/** @enum {boolean} */
|
|
1963
|
+
verified: true;
|
|
1964
|
+
/** @description UUID of the matching Content record. */
|
|
1965
|
+
content_id: string;
|
|
1966
|
+
/** @description UUID of the store that owns this content. */
|
|
1967
|
+
store_id: string;
|
|
1968
|
+
/** @description Price in cents as a string (e.g. "10" = $0.10). */
|
|
1969
|
+
amount: string;
|
|
1970
|
+
/** @description Content title. */
|
|
1971
|
+
title: string;
|
|
1972
|
+
};
|
|
1973
|
+
/** @description Returned when the URL is not registered or the URL is invalid. */
|
|
1974
|
+
VerifyOriginUnverified: {
|
|
1975
|
+
/** @enum {boolean} */
|
|
1976
|
+
verified: false;
|
|
1977
|
+
};
|
|
1978
|
+
/** @description JSON Web Key Set (RFC 7517) containing the RS256 public key for x402 accessToken verification. */
|
|
1979
|
+
JwksResponse: {
|
|
1980
|
+
keys: {
|
|
1981
|
+
/** @enum {string} */
|
|
1982
|
+
kty: 'RSA';
|
|
1983
|
+
/** @enum {string} */
|
|
1984
|
+
use: 'sig';
|
|
1985
|
+
/** @enum {string} */
|
|
1986
|
+
alg: 'RS256';
|
|
1987
|
+
/** @description Key ID. Matches the `kid` header claim in minted access tokens. */
|
|
1988
|
+
kid: string;
|
|
1989
|
+
/** @description RSA modulus (Base64url-encoded). */
|
|
1990
|
+
n: string;
|
|
1991
|
+
/** @description RSA public exponent (Base64url-encoded). */
|
|
1992
|
+
e: string;
|
|
1993
|
+
}[];
|
|
1994
|
+
};
|
|
1995
|
+
/**
|
|
1996
|
+
* @description One work in a Selection, and what happened to it. Every submitted row appears, including the ones we refused — a malformed line and a duplicate spelling are dispositions rather than omissions, and a row that vanished silently between upload and quote is the failure the acknowledgement step exists to prevent.
|
|
1997
|
+
*
|
|
1998
|
+
* `line_state`, `purchased` and `delivery_state` answer three different questions and none implies another. A work can be quoted and never reached, purchased and not delivered, or excluded and therefore never attempted.
|
|
1999
|
+
*/
|
|
2000
|
+
AcquisitionWork: {
|
|
2001
|
+
/** @description 1-based place in the submitted file, so a Buyer can find the row they wrote. */
|
|
2002
|
+
position: number;
|
|
2003
|
+
/** @description The address exactly as submitted. */
|
|
2004
|
+
submitted_url: string;
|
|
2005
|
+
/** @description The address after canonicalization — the identity function for a brokered work. Two rows that differ only in `www.`, a query string or a fragment name one work, and the second is excluded as a duplicate rather than bought twice. */
|
|
2006
|
+
canonical_url?: string | null;
|
|
2007
|
+
/**
|
|
2008
|
+
* @description What the quote said. `firm` was priced from a rate the broker answered with; `estimated` from a rate we already held because the broker could not be asked; `excluded` will not be bought.
|
|
2009
|
+
* @enum {string}
|
|
2010
|
+
*/
|
|
2011
|
+
line_state: 'pending' | 'firm' | 'estimated' | 'excluded';
|
|
2012
|
+
/**
|
|
2013
|
+
* @description Present only on an excluded line. `excluded_rate_unavailable` is the one transient reason.
|
|
2014
|
+
* @enum {string|null}
|
|
2015
|
+
*/
|
|
2016
|
+
exclusion_reason?: 'excluded_malformed' | 'excluded_duplicate' | 'excluded_no_rate' | 'excluded_free_not_supported' | 'excluded_not_deliverable' | 'excluded_insufficient_rights' | 'excluded_above_price_ceiling' | 'excluded_rate_unavailable' | null;
|
|
2017
|
+
/** @description What this work was quoted at, in micros. **Never published in cents.** Per-work cents are display-only and non-summable for a Bulk acquisition — the authoritative figure is micros and the acquisition total is what reconciles, so a client is given nothing here that invites adding up to the charge. */
|
|
2018
|
+
price_micros?: number | null;
|
|
2019
|
+
/**
|
|
2020
|
+
* @description Whether a Purchase was made for this work.
|
|
2021
|
+
*
|
|
2022
|
+
* **History, not access.** Under single use a completed Purchase is a receipt for a delivery that has already happened; it grants nothing further, and is never a reason to serve a body again. Reported so a Buyer can tell "we bought this and the bytes did not arrive" — a delivery we owe — from "we never bought it".
|
|
2023
|
+
*/
|
|
2024
|
+
purchased: boolean;
|
|
2025
|
+
/**
|
|
2026
|
+
* @description What the run did. `pending` means not yet attempted — which is also what an excluded work reads, because it was never attempted and `undelivered` would claim we tried and failed. Those are different answers to a Buyer and only the second is worth a retry.
|
|
2027
|
+
* @enum {string}
|
|
2028
|
+
*/
|
|
2029
|
+
delivery_state: 'pending' | 'delivered' | 'undelivered';
|
|
2030
|
+
/**
|
|
2031
|
+
* @description Why an attempted work did not arrive, as a type rather than prose. Only `retrieval_failed` is transient; the rest fail identically on every attempt, so retrying one spends a run's budget on works that need re-pricing, a fix, or money.
|
|
2032
|
+
* @enum {string|null}
|
|
2033
|
+
*/
|
|
2034
|
+
failure_reason?: 'retrieval_failed' | 'not_licensable' | 'price_drifted' | 'client_error' | 'insufficient_funds' | 'cap_refused' | null;
|
|
2035
|
+
/** @description How many times retrieval was tried, the successful attempt included. */
|
|
2036
|
+
attempts?: number | null;
|
|
2037
|
+
};
|
|
2038
|
+
/**
|
|
2039
|
+
* @description A Publication a Buyer can license from — the title a Bulk acquisition is organised around. Listed from our own registry, which is reconciled daily against the Broker's directory, rather than from a live call.
|
|
2040
|
+
*
|
|
2041
|
+
* Licensability is a rights answer, not a quality one. A publication that publishes no `FULL_USE` rate is still listed, with `bulk_licensable: false`: its works can be bought one at a time but are excluded from a corpus as `excluded_insufficient_rights`.
|
|
2042
|
+
*/
|
|
2043
|
+
Publication: {
|
|
2044
|
+
/** Format: uuid */
|
|
2045
|
+
id: string;
|
|
2046
|
+
/** @description The Broker's display name for the publication. */
|
|
2047
|
+
name: string;
|
|
2048
|
+
/** @description The domains the publication is listed under, spelled as the Broker spells them — including a `www.` prefix where it has one. */
|
|
2049
|
+
domains: string[];
|
|
2050
|
+
/** @description Whether works from this publication can come back in a Bulk acquisition's corpus — true when it publishes a `FULL_USE` rate. */
|
|
2051
|
+
bulk_licensable: boolean;
|
|
2052
|
+
};
|
|
2053
|
+
/** @description Every Publication the Broker reports as ready to license, paginated. */
|
|
2054
|
+
PublicationListResponse: {
|
|
2055
|
+
data: components['schemas']['Publication'][];
|
|
2056
|
+
pagination: components['schemas']['PaginationMeta'];
|
|
2057
|
+
};
|
|
2058
|
+
/** @description The MCP `list_publications` result: one page of the Publications a Buyer can license from, paged by offset and limit as `search_content` is. */
|
|
2059
|
+
McpListPublicationsResult: {
|
|
2060
|
+
publications: components['schemas']['Publication'][];
|
|
2061
|
+
total_count: number;
|
|
2062
|
+
offset: number;
|
|
2063
|
+
limit: number;
|
|
2064
|
+
};
|
|
2065
|
+
/** @description A work a Publication has available to license, as the Broker's catalog lists it. `url` is exactly what a Selection takes. */
|
|
2066
|
+
PublicationWork: {
|
|
2067
|
+
/** Format: uri */
|
|
2068
|
+
url: string;
|
|
2069
|
+
/**
|
|
2070
|
+
* Format: date-time
|
|
2071
|
+
* @description When the Broker says the work was last modified. Null where it supplies none, which on some publications is every work.
|
|
2072
|
+
*/
|
|
2073
|
+
last_mod: string | null;
|
|
2074
|
+
};
|
|
2075
|
+
/** @description One page of a Publication's works, read live from the Broker's catalog. Unpriced: pricing happens when a Selection of these URLs is quoted. */
|
|
2076
|
+
PublicationWorkListResponse: {
|
|
2077
|
+
/** Format: uuid */
|
|
2078
|
+
publication_id: string;
|
|
2079
|
+
/** @description The Publication domain this page was read from, in the Broker's spelling. A publication with several domains is walked one domain after another. Null only when the publication has no live domain to read. */
|
|
2080
|
+
domain: string | null;
|
|
2081
|
+
/**
|
|
2082
|
+
* @description How `from`/`to` applied to this page's domain. `applied` means the Broker filtered and every work is in range. `unsupported` means the filtered query returned nothing while the same domain unfiltered does not: the domain's catalog carries no modification dates, so the range cannot be answered. That is not the same as having no works in the range. The unfiltered works are deliberately not returned in their place, because they are not known to fall inside the range.
|
|
2083
|
+
* @enum {string}
|
|
2084
|
+
*/
|
|
2085
|
+
date_filter: 'not_requested' | 'applied' | 'unsupported';
|
|
2086
|
+
works: components['schemas']['PublicationWork'][];
|
|
2087
|
+
/** @description Opaque. Pass it back as `cursor` with the same `from`/`to` for the next page. Null means the walk is over; an empty page with a cursor is not the end. */
|
|
2088
|
+
next_cursor: string | null;
|
|
2089
|
+
};
|
|
2090
|
+
/** @description The MCP `list_publication_works` result. It is the same page as `GET /v1/publications/{id}/works` returns, by reference, so the two cannot drift. */
|
|
2091
|
+
McpListPublicationWorksResult: components['schemas']['PublicationWorkListResponse'];
|
|
2092
|
+
/** @description Per-work dispositions for a Bulk acquisition, paginated. Its own endpoint rather than a field on the acquisition because a Selection may name 10,000 works and the acquisition resource has to stay cheap enough to poll for hours. */
|
|
2093
|
+
PaginatedAcquisitionWorkList: {
|
|
2094
|
+
data: components['schemas']['AcquisitionWork'][];
|
|
2095
|
+
pagination: components['schemas']['PaginationMeta'];
|
|
2096
|
+
};
|
|
2097
|
+
/**
|
|
2098
|
+
* @description A Bulk acquisition — the one resource the whole flow hangs off. The Buyer holds this id from the moment they submit a Selection, and every later step reads or advances it: the quote arrives on it, the acknowledgement is a timestamp on it, the hold is sized from its total, and the run writes its outcome back to it.
|
|
2099
|
+
*
|
|
2100
|
+
* `status` and `quote_state` are two independent state machines and are not collapsible. `status` is the money — `quoted` holds nothing, `authorized` and `acquiring` hold funds, and every terminal state releases what is left. `quote_state` is whether the prices are in. A `quoted` acquisition whose quote is still `pending` has a snapshot and no prices, and a client that read one field would mis-read exactly that case.
|
|
2101
|
+
*/
|
|
2102
|
+
AcquisitionResponse: {
|
|
2103
|
+
/** Format: uuid */
|
|
2104
|
+
id: string;
|
|
2105
|
+
/**
|
|
2106
|
+
* @description Where the money is. `quoted` reserves nothing; `authorized` and `acquiring` hold the stated maximum chargeable total; `settled`, `cancelled` and `failed` are terminal and have released whatever was not captured.
|
|
2107
|
+
* @enum {string}
|
|
2108
|
+
*/
|
|
2109
|
+
status: 'quoted' | 'authorized' | 'acquiring' | 'settled' | 'cancelled' | 'failed';
|
|
2110
|
+
/**
|
|
2111
|
+
* @description Whether the Selection has been priced. Pricing is asynchronous — resolving rates for 10,000 works is ~200 upstream batch calls under undocumented limits — so a submitted Selection comes back `pending` and the client polls this.
|
|
2112
|
+
* @enum {string}
|
|
2113
|
+
*/
|
|
2114
|
+
quote_state: 'pending' | 'ready' | 'failed';
|
|
2115
|
+
/** @description How many distinct publications the Selection spans. Nothing in a Bulk acquisition is keyed on a single publication. */
|
|
2116
|
+
publication_count: number;
|
|
2117
|
+
/** @description How many rows the upload named and we accepted. Published alongside `work_count` because until pricing finishes the two differ and only this one is known: nothing carries a price while `quote_state` is `pending`, so a freshly submitted 10,000-row Selection reports `work_count: 0` and would otherwise read exactly like an empty one. */
|
|
2118
|
+
submitted_work_count: number;
|
|
2119
|
+
/** @description Works that carry a price — firm or estimated. Excluded rows are not counted here, and neither is anything still waiting to be priced. */
|
|
2120
|
+
work_count: number;
|
|
2121
|
+
quote: components['schemas']['AcquisitionQuote'];
|
|
2122
|
+
/** @description What we cannot sell, grouped by reason and counted. Grouped rather than enumerated because a 10,000-work Selection can exclude thousands of rows and the acknowledgement step asks the Buyer to register what kinds of thing are not coming; the per-work detail is `GET /v1/acquisitions/{id}/works`, which paginates. */
|
|
2123
|
+
exclusions: {
|
|
2124
|
+
/**
|
|
2125
|
+
* @description Six of these are the Buyer's to act on and one is ours. `excluded_rate_unavailable` is the only transient one — it says we could not reach the broker to ask, and is the only reason here worth asking us to retry. `excluded_not_deliverable` is a broker failure we observed; `excluded_insufficient_rights` is a rights decision we made; `excluded_above_price_ceiling` is a price we declined. Those three are the ones most easily collapsed and must not be.
|
|
2126
|
+
* @enum {string}
|
|
2127
|
+
*/
|
|
2128
|
+
reason: 'excluded_malformed' | 'excluded_duplicate' | 'excluded_no_rate' | 'excluded_free_not_supported' | 'excluded_not_deliverable' | 'excluded_insufficient_rights' | 'excluded_above_price_ceiling' | 'excluded_rate_unavailable';
|
|
2129
|
+
count: number;
|
|
2130
|
+
}[];
|
|
2131
|
+
/** @description What the run has done. `purchased` and `delivered` are separate facts and both are reported, because a Purchase can complete and its body fail to arrive — a delivery LedeWire owes, and not a reason to charge again. An acquisition with 10,000 purchases and 9,700 deliveries has 300 outstanding, which no single number says. */
|
|
2132
|
+
delivery: {
|
|
2133
|
+
/** @description Works a Purchase was made for. History, not an entitlement to re-read. */
|
|
2134
|
+
purchased: number;
|
|
2135
|
+
delivered: number;
|
|
2136
|
+
/** @description Attempted and not delivered. An excluded work is not counted here — it was never attempted, and "not in your corpus because we refused to quote it" is a different answer from "not in your corpus because retrieval failed". */
|
|
2137
|
+
undelivered: number;
|
|
2138
|
+
/** @description Quoted and not yet reached. What a resumed run will attempt. */
|
|
2139
|
+
outstanding: number;
|
|
2140
|
+
};
|
|
2141
|
+
/** Format: date-time */
|
|
2142
|
+
created_at: string;
|
|
2143
|
+
};
|
|
2144
|
+
/** @description The priced Selection, and the promise made about it. */
|
|
2145
|
+
AcquisitionQuote: {
|
|
2146
|
+
/** @enum {string} */
|
|
2147
|
+
state: 'pending' | 'ready' | 'failed';
|
|
2148
|
+
/** @description Subtotal of works priced from a rate the broker answered with, in micros (millionths of a dollar). */
|
|
2149
|
+
firm_micros: number;
|
|
2150
|
+
/** @description Subtotal of works priced from a rate we already held, because the broker could not be asked. Estimated, never firm — the price may have moved, and observed broker prices move materially in both directions. What protects the Buyer is `maximum_chargeable_total_cents`. */
|
|
2151
|
+
estimated_micros: number;
|
|
2152
|
+
/**
|
|
2153
|
+
* @description The most this acquisition can charge. Settlement clamps captures to it and absorbs any drift above it from margin, so it is a ceiling rather than an estimate — an acquisition that cannot deliver every work charges less.
|
|
2154
|
+
*
|
|
2155
|
+
* Subtotals are published in micros and the ceiling in cents deliberately: rounding happens **once**, on the total. Two rounded cent subtotals would not reliably sum to the rounded total, and publishing them that way would invite a client to add them up and disagree with the figure we charge. Per-work prices never sum to this either.
|
|
2156
|
+
*/
|
|
2157
|
+
maximum_chargeable_total_cents: number;
|
|
2158
|
+
/** Format: date-time */
|
|
2159
|
+
quoted_at?: string | null;
|
|
2160
|
+
/**
|
|
2161
|
+
* Format: date-time
|
|
2162
|
+
* @description When the stated maximum chargeable total stops standing — 24 hours after pricing. Published rather than left to the client to compute, so the window is not hard-coded against a constant of ours. Re-pricing is cheap: it re-prices the snapshot without re-resolving it, so the Buyer gets the same works at today's prices without uploading anything again.
|
|
2163
|
+
*/
|
|
2164
|
+
expires_at?: string | null;
|
|
2165
|
+
/**
|
|
2166
|
+
* Format: date-time
|
|
2167
|
+
* @description When the Buyer registered what we cannot sell them. Withdrawn on every re-quote, so it always refers to the current set of exclusions and never to a previous one — an acknowledgement carried forward would be a Buyer authorizing a list they never saw.
|
|
2168
|
+
*/
|
|
2169
|
+
exclusions_acknowledged_at?: string | null;
|
|
2170
|
+
};
|
|
2171
|
+
/**
|
|
2172
|
+
* @description Where a Bulk acquisition's Corpus is — a **state**, never an error.
|
|
2173
|
+
*
|
|
2174
|
+
* A corpus is a rendering of Purchases the Buyer already holds, not an entitlement of its own, which is what makes everything about it cheap: it can be discarded and rebuilt, and rebuilding grants nothing that was not already granted. So a blob past its 30-day retention answers `rebuild_required` at 200 rather than 404 or 410 — those would tell the Buyer something was lost, and nothing was.
|
|
2175
|
+
*
|
|
2176
|
+
* `rebuild_required` covers "never assembled" as well as "expired", on purpose: from the Buyer's side they are one situation — there is no file, ask for one — and splitting them would put our bookkeeping into their contract.
|
|
2177
|
+
*/
|
|
2178
|
+
CorpusResponse: {
|
|
2179
|
+
/**
|
|
2180
|
+
* @description `ready` is downloadable now. `assembling` means a run is in flight and `pending` that one is queued — poll either. `rebuild_required` means ask for it again, with `POST /v1/acquisitions/{id}/corpus`. `failed` carries a reason.
|
|
2181
|
+
* @enum {string}
|
|
2182
|
+
*/
|
|
2183
|
+
state: 'pending' | 'assembling' | 'ready' | 'rebuild_required' | 'failed';
|
|
2184
|
+
/**
|
|
2185
|
+
* @description The archive rendering. There is no size-conditional switching — a client never branches on how big its corpus is.
|
|
2186
|
+
* @enum {string|null}
|
|
2187
|
+
*/
|
|
2188
|
+
format?: 'tar_gz' | 'jsonl_gz' | null;
|
|
2189
|
+
/** @description Size of the assembled archive. Null unless `ready`. */
|
|
2190
|
+
byte_size?: number | null;
|
|
2191
|
+
/**
|
|
2192
|
+
* Format: date-time
|
|
2193
|
+
* @description When the blob is retired, 30 days after assembly. The signed Manifest has no expiry and is served separately from `/v1/acquisitions/{id}/manifest`, because an auditor years later must be able to obtain the record without the corpus.
|
|
2194
|
+
*/
|
|
2195
|
+
expires_at?: string | null;
|
|
2196
|
+
/** @description Why assembly broke. Present only when `state` is `failed`. */
|
|
2197
|
+
failure_reason?: string | null;
|
|
2198
|
+
/**
|
|
2199
|
+
* @description Where to fetch the archive, relative to this API, and null in every state but `ready`.
|
|
2200
|
+
*
|
|
2201
|
+
* An authenticated route of ours rather than a presigned store URL. Fetch it with the same bearer token as this request and the response is the archive itself — there is no redirect to follow and no second URL to capture. A link to the object store handed out here would stand whether or not its reader could authenticate, and a client may log, cache or forward a poll response. The corpus is the most sensitive thing this API serves, so the authorization decision belongs on every request for it.
|
|
2202
|
+
*/
|
|
2203
|
+
download_url?: string | null;
|
|
2204
|
+
};
|
|
2205
|
+
/**
|
|
2206
|
+
* @description The signed Manifest of a Bulk acquisition — the audit record itself, not a summary of one. There is no separate receipt: two representations of the same facts eventually disagree, and a manifest that disagrees with the signed record is worse than no manifest.
|
|
2207
|
+
*
|
|
2208
|
+
* Served verbatim from the bytes stored at first assembly. It is **not** re-derived from the rows it was generated from, because the signature covers bytes rather than meaning — a re-derived document would read the same, hash differently, and fail its own signature. A row edited in 2029 therefore cannot change a document written in 2026.
|
|
2209
|
+
*
|
|
2210
|
+
* Permanent. The corpus blob expires 30 days after assembly; this does not, because an auditor years later must be able to obtain the record without the corpus.
|
|
2211
|
+
*/
|
|
2212
|
+
CorpusManifestResponse: {
|
|
2213
|
+
/** @description The manifest document. Every work in the Selection appears with a disposition — `delivered`, `undelivered`, or the name of its exclusion reason — because silent omission is a defect. A delivered entry additionally carries a content hash computed at capture, the licence asked for and the licence granted with its permission set, the captured licence document's path and hash, and what the Buyer was charged in micros. Cost columns are never in here. */
|
|
2214
|
+
manifest: {
|
|
2215
|
+
[key: string]: unknown;
|
|
2216
|
+
};
|
|
2217
|
+
/** @description A detached JWS (RFC 7515 with RFC 7797 `b64:false`) over the manifest's exact canonical bytes — a protected header, two dots and a signature. Detached so the manifest stays a plain readable file that a compliance tool can ingest without a crypto library. */
|
|
2218
|
+
signature: string;
|
|
2219
|
+
/** @description SHA-256 of the canonical manifest bytes, hex-encoded. */
|
|
2220
|
+
digest: string;
|
|
2221
|
+
/** @description Which key history entry to resolve. An index, never a credential — it is a 96-bit truncation, so a verifier matches on all 32 raw public-key bytes. */
|
|
2222
|
+
signing_kid: string;
|
|
2223
|
+
/** @description The head of the key history at signing time. A verifier checks that this digest appears somewhere in the chain being served — not that it equals the present head, since the history grows. What it catches is truncation or a fork since this manifest was issued, which needs no key at all, only control of the document. */
|
|
2224
|
+
key_history_head_digest: string;
|
|
2225
|
+
/**
|
|
2226
|
+
* Format: date-time
|
|
2227
|
+
* @description When the manifest was signed. Our own assertion until #989's RFC 3161 token lands, and the compromise rule is only as trustworthy as this field.
|
|
2228
|
+
*/
|
|
2229
|
+
signed_at: string;
|
|
2230
|
+
/** @description Where a verifier resolves `signing_kid`. */
|
|
2231
|
+
key_history_url?: string;
|
|
2232
|
+
};
|
|
2233
|
+
/**
|
|
2234
|
+
* @description The append-only, hash-chained log of every Ed25519 key that has signed an audit-export manifest. This is the trust anchor a verifier resolves a manifest's `kid` through.
|
|
2235
|
+
* It is a log of *events*, not a table of keys: there is no `valid_until` or `retired_reason` field. A key's window closes at the `valid_from` of the next `activate` entry, and it is compromised if a `revoke` entry names it. Those are derived by the reader, because an entry that could be edited after a later one chained to it would break the chain. See docs/audit-export-key-history.md.
|
|
2236
|
+
*/
|
|
2237
|
+
SigningKeyHistoryResponse: {
|
|
2238
|
+
/** @description Bumped when the document's shape changes in a way a reader must notice. */
|
|
2239
|
+
schema_version: number;
|
|
2240
|
+
/** @description Every entry, in chain order, starting at sequence 0. */
|
|
2241
|
+
entries: {
|
|
2242
|
+
/**
|
|
2243
|
+
* @description `activate` brings a key into service and carries `public_key` and `valid_from`. `revoke` records that the key named by `kid` was stolen and carries `compromised_at`.
|
|
2244
|
+
* @enum {string}
|
|
2245
|
+
*/
|
|
2246
|
+
kind: 'activate' | 'revoke';
|
|
2247
|
+
/** @description base64url(SHA-256(raw public key))[0, 16]. An index into this document, never a credential — it is a 96-bit truncation, so a verifier matches on all 32 raw public-key bytes instead. */
|
|
2248
|
+
kid: string;
|
|
2249
|
+
/** @description Monotonic and gapless, starting at 0. */
|
|
2250
|
+
sequence: number;
|
|
2251
|
+
/** @description The raw 32-byte Ed25519 public key, base64url-encoded without padding. Present on `activate` entries only. */
|
|
2252
|
+
public_key?: string;
|
|
2253
|
+
/**
|
|
2254
|
+
* Format: date-time
|
|
2255
|
+
* @description When this key entered service. Present on `activate` entries only.
|
|
2256
|
+
*/
|
|
2257
|
+
valid_from?: string;
|
|
2258
|
+
/**
|
|
2259
|
+
* Format: date-time
|
|
2260
|
+
* @description When the key named by `kid` is believed to have been stolen — ordinarily earlier than when it was discovered. Signatures dated before it stand; those at or after it are void. Present on `revoke` entries only.
|
|
2261
|
+
*/
|
|
2262
|
+
compromised_at?: string;
|
|
2263
|
+
/** @description SHA-256 (hex) of the previous entry's RFC 8785 canonical JSON, including its signature. Absent on the root entry alone. */
|
|
2264
|
+
previous_entry_digest?: string;
|
|
2265
|
+
/** @description base64url Ed25519 signature over this entry's canonical JSON excluding this field, made by the key in service before it — which, for a `revoke`, is not the key it names. Absent on the root entry alone. */
|
|
2266
|
+
signature?: string;
|
|
2267
|
+
}[];
|
|
2268
|
+
};
|
|
2269
|
+
/** @description x402 v2 settlement result. Base64-encoded JSON returned in the `PAYMENT-RESPONSE` header on a successful `200`. `accessToken` is present when an RS256 signing key is configured; omitted in environments without credentials. */
|
|
2270
|
+
SettlementResponse: {
|
|
2271
|
+
/** @enum {boolean} */
|
|
2272
|
+
success: true;
|
|
2273
|
+
/** @description UUID of the settled Purchase record. */
|
|
2274
|
+
transaction: string;
|
|
2275
|
+
/** @enum {string} */
|
|
2276
|
+
network: 'ledewire:v1';
|
|
2277
|
+
/** @description UUID of the buying user. */
|
|
2278
|
+
payer: string;
|
|
2279
|
+
/** @description Short-lived RS256-signed JWT for offline entitlement verification. Verifiable via `/.well-known/x402-jwks.json`. Omitted if signing key is not configured. */
|
|
2280
|
+
accessToken?: string | null;
|
|
2281
|
+
};
|
|
2282
|
+
MerchantPricingRule: {
|
|
2283
|
+
/** @description UUID of the pricing rule. */
|
|
2284
|
+
id: string;
|
|
2285
|
+
/** @description UUID of the owning store. */
|
|
2286
|
+
store_id: string;
|
|
2287
|
+
/** @description Glob URL pattern (supports * and ** wildcards). Must start with http:// or https://. */
|
|
2288
|
+
url_pattern: string;
|
|
2289
|
+
/** @description Price in cents applied to content matching this pattern. */
|
|
2290
|
+
price_cents: number;
|
|
2291
|
+
/** @description Whether the rule is currently active. Inactive rules are ignored during URL matching. */
|
|
2292
|
+
active: boolean;
|
|
2293
|
+
/** Format: date-time */
|
|
2294
|
+
created_at: string;
|
|
2295
|
+
/** Format: date-time */
|
|
2296
|
+
updated_at: string;
|
|
2297
|
+
};
|
|
2298
|
+
MerchantDomainVerification: {
|
|
2299
|
+
/** @description UUID of the domain verification record. */
|
|
2300
|
+
id: string;
|
|
2301
|
+
/** @description UUID of the owning store. */
|
|
2302
|
+
store_id: string;
|
|
2303
|
+
/** @description The verified domain (www. prefix is stripped on creation). */
|
|
2304
|
+
domain: string;
|
|
2305
|
+
/**
|
|
2306
|
+
* @description Verification status updated by DomainVerifyJob.
|
|
2307
|
+
* @enum {string}
|
|
2308
|
+
*/
|
|
2309
|
+
status: 'pending' | 'verified' | 'failed';
|
|
2310
|
+
/** @description DNS TXT record name the merchant must add (e.g. _ledewire-verify.example.com). */
|
|
2311
|
+
txt_record_name: string;
|
|
2312
|
+
/** @description DNS TXT record value the merchant must set. */
|
|
2313
|
+
txt_record_value: string;
|
|
2314
|
+
/**
|
|
2315
|
+
* Format: date-time
|
|
2316
|
+
* @description Timestamp of successful verification. Null until verified.
|
|
2317
|
+
*/
|
|
2318
|
+
verified_at?: string | null;
|
|
2319
|
+
/**
|
|
2320
|
+
* Format: date-time
|
|
2321
|
+
* @description Timestamp of the most recent verification check (success or failure).
|
|
2322
|
+
*/
|
|
2323
|
+
checked_at?: string | null;
|
|
2324
|
+
/** Format: date-time */
|
|
2325
|
+
created_at: string;
|
|
2326
|
+
};
|
|
2327
|
+
/** @description RFC 8414 Authorization Server Metadata. MCP clients fetch this to discover the authorization flow. `registration_endpoint` is what tells a client that Dynamic Client Registration is available at all — without it, clients that do not speak CIMD fall back to asking a human for a client id. */
|
|
2328
|
+
OauthAuthorizationServerMetadata: {
|
|
2329
|
+
issuer: string;
|
|
2330
|
+
authorization_endpoint: string;
|
|
2331
|
+
token_endpoint: string;
|
|
2332
|
+
revocation_endpoint?: string;
|
|
2333
|
+
/** @description RFC 7591 Dynamic Client Registration endpoint. */
|
|
2334
|
+
registration_endpoint: string;
|
|
2335
|
+
scopes_supported: string[];
|
|
2336
|
+
response_types_supported: string[];
|
|
2337
|
+
code_challenge_methods_supported: string[];
|
|
2338
|
+
client_id_metadata_document_supported?: boolean;
|
|
2339
|
+
token_endpoint_auth_methods_supported?: string[];
|
|
2340
|
+
};
|
|
2341
|
+
/** @description RFC 7591 client metadata. Only `redirect_uris` is required; unrecognised members are ignored rather than rejected, so clients sending extensions this server does not implement still register successfully. */
|
|
2342
|
+
OauthClientRegistrationRequest: {
|
|
2343
|
+
/** @description Must be https, or http on a loopback host (`localhost`, `127.0.0.1`, `[::1]`). Fragments are not permitted. These become the allowlist for the issued client_id. */
|
|
2344
|
+
redirect_uris: string[];
|
|
2345
|
+
client_name?: string;
|
|
2346
|
+
client_uri?: string;
|
|
2347
|
+
logo_uri?: string;
|
|
2348
|
+
tos_uri?: string;
|
|
2349
|
+
policy_uri?: string;
|
|
2350
|
+
contacts?: string[];
|
|
2351
|
+
software_id?: string;
|
|
2352
|
+
software_version?: string;
|
|
2353
|
+
/** @description Space-delimited. Scopes this server does not support are filtered out, and the response omits `scope` entirely when none was requested — registration decides nothing about what a token later grants. */
|
|
2354
|
+
scope?: string;
|
|
2355
|
+
grant_types?: ('authorization_code' | 'refresh_token')[];
|
|
2356
|
+
response_types?: 'code'[];
|
|
2357
|
+
/**
|
|
2358
|
+
* @description Optional, and may only be `none`. Registered clients are public — no client_secret is issued, and PKCE protects the code exchange.
|
|
2359
|
+
* @enum {string}
|
|
2360
|
+
*/
|
|
2361
|
+
token_endpoint_auth_method?: 'none';
|
|
2362
|
+
};
|
|
2363
|
+
/** @description RFC 7591 §3.2.1 client information response. Carries no `client_secret`: a registered client is public and authenticates at the token endpoint with PKCE alone. */
|
|
2364
|
+
OauthClientRegistrationResponse: {
|
|
2365
|
+
/** @description Server-assigned, opaque, `lwc_`-prefixed. Deliberately not a URL, so it is never mistaken for a Client ID Metadata Document. */
|
|
2366
|
+
client_id: string;
|
|
2367
|
+
/** @description Seconds since the Unix epoch. */
|
|
2368
|
+
client_id_issued_at: number;
|
|
2369
|
+
redirect_uris: string[];
|
|
2370
|
+
/** @enum {string} */
|
|
2371
|
+
token_endpoint_auth_method: 'none';
|
|
2372
|
+
grant_types?: string[];
|
|
2373
|
+
response_types?: string[];
|
|
2374
|
+
scope?: string;
|
|
2375
|
+
client_name?: string;
|
|
2376
|
+
client_uri?: string;
|
|
2377
|
+
logo_uri?: string;
|
|
2378
|
+
tos_uri?: string;
|
|
2379
|
+
policy_uri?: string;
|
|
2380
|
+
contacts?: string[];
|
|
2381
|
+
software_id?: string;
|
|
2382
|
+
software_version?: string;
|
|
2383
|
+
};
|
|
2384
|
+
/** @description RFC 7591 §3.2.2 client registration error response. */
|
|
2385
|
+
OauthClientRegistrationErrorResponse: {
|
|
2386
|
+
/** @enum {string} */
|
|
2387
|
+
error: 'invalid_redirect_uri' | 'invalid_client_metadata';
|
|
2388
|
+
error_description?: string;
|
|
2389
|
+
};
|
|
1332
2390
|
};
|
|
1333
2391
|
responses: never;
|
|
1334
2392
|
parameters: never;
|
|
@@ -1346,6 +2404,37 @@ export declare type ContentResponse = components['schemas']['ContentResponse'];
|
|
|
1346
2404
|
/** A piece of content with buyer access information. */
|
|
1347
2405
|
export declare type ContentWithAccessResponse = components['schemas']['ContentWithAccessResponse'];
|
|
1348
2406
|
|
|
2407
|
+
/**
|
|
2408
|
+
* The REST and x402 web-gate form of a daily-spend-cap refusal, returned with HTTP
|
|
2409
|
+
* `402 Payment Required` by `POST /v1/purchases`, `GET /v1/x402/contents/{id}`, and
|
|
2410
|
+
* acquisition authorization. This is the raw wire shape; the SDK throws it as
|
|
2411
|
+
* {@link SpendCapReachedError} rather than handing back the JSON body directly.
|
|
2412
|
+
*/
|
|
2413
|
+
export declare type DailySpendCapReachedErrorBody = components['schemas']['DailySpendCapReachedError'];
|
|
2414
|
+
|
|
2415
|
+
/**
|
|
2416
|
+
* Machine-readable reason on an API error envelope, present on refusals that carry one.
|
|
2417
|
+
* Branch on this rather than on `message`, which is prose and may be reworded.
|
|
2418
|
+
*
|
|
2419
|
+
* - `retrieval_failed` — transient; worth retrying.
|
|
2420
|
+
* - `not_licensable` — report the work as undelivered.
|
|
2421
|
+
* - `price_drifted` — re-quote before retrying.
|
|
2422
|
+
* - `client_error` — ours to fix; must never be retried unchanged.
|
|
2423
|
+
* - `insufficient_funds` — cleared by funding the wallet.
|
|
2424
|
+
* - `daily_spend_cap_reached` — deliberately **not** cleared by funding the wallet; see
|
|
2425
|
+
* {@link SpendCapReachedError}.
|
|
2426
|
+
*/
|
|
2427
|
+
export declare type ErrorType = NonNullable<components['schemas']['ErrorResponse']['error']['type']>;
|
|
2428
|
+
|
|
2429
|
+
/**
|
|
2430
|
+
* Known {@link ErrorType} values, widened to accept any other string the API
|
|
2431
|
+
* may introduce. `ErrorType` still drives editor autocomplete; a value the API
|
|
2432
|
+
* emits that isn't (yet) in the spec's enum — e.g. `selection_too_large` on
|
|
2433
|
+
* `POST /v1/acquisitions` — still type-checks and survives on {@link
|
|
2434
|
+
* LedewireError.type} instead of being narrowed away.
|
|
2435
|
+
*/
|
|
2436
|
+
declare type ErrorTypeValue = ErrorType | (string & {});
|
|
2437
|
+
|
|
1349
2438
|
/**
|
|
1350
2439
|
* Thrown when the authenticated user does not have permission
|
|
1351
2440
|
* to perform the requested operation.
|
|
@@ -1397,7 +2486,8 @@ export declare type ContentWithAccessResponse = components['schemas']['ContentWi
|
|
|
1397
2486
|
* ```
|
|
1398
2487
|
*/
|
|
1399
2488
|
export declare class ForbiddenError extends LedewireError {
|
|
1400
|
-
|
|
2489
|
+
static readonly brand: string;
|
|
2490
|
+
constructor(message: string, code?: number, type?: ErrorTypeValue, details?: Record<string, unknown>);
|
|
1401
2491
|
}
|
|
1402
2492
|
|
|
1403
2493
|
/**
|
|
@@ -1407,6 +2497,8 @@ export declare class ForbiddenError extends LedewireError {
|
|
|
1407
2497
|
* - Injects `Authorization: Bearer <token>` headers automatically
|
|
1408
2498
|
* - Maps HTTP error responses to typed `LedewireError` subclasses
|
|
1409
2499
|
* - On receiving a 401, calls `onUnauthorized` once and retries the request
|
|
2500
|
+
* - Per-request `{ auth: false }` (see {@link RequestOptions}) skips all of
|
|
2501
|
+
* the above for public endpoints
|
|
1410
2502
|
*
|
|
1411
2503
|
* This is an internal class - consumers should use the
|
|
1412
2504
|
* package-level client factories (`init` / `createClient`) instead.
|
|
@@ -1420,8 +2512,9 @@ declare class HttpClient {
|
|
|
1420
2512
|
* GET request with optional query parameters.
|
|
1421
2513
|
* @param path - API path (e.g. `/v1/wallet/balance`)
|
|
1422
2514
|
* @param params - Query string parameters. `undefined` values are omitted; numbers are coerced to strings.
|
|
2515
|
+
* @param options - Per-request overrides. Pass `{ auth: false }` for public endpoints.
|
|
1423
2516
|
*/
|
|
1424
|
-
get<T>(path: string, params?: Record<string, string | number | undefined
|
|
2517
|
+
get<T>(path: string, params?: Record<string, string | number | undefined>, options?: RequestOptions): Promise<T>;
|
|
1425
2518
|
/**
|
|
1426
2519
|
* POST request.
|
|
1427
2520
|
* @param path - API path
|
|
@@ -1446,8 +2539,28 @@ declare class HttpClient {
|
|
|
1446
2539
|
* @param path - API path
|
|
1447
2540
|
*/
|
|
1448
2541
|
delete<T = void>(path: string): Promise<T>;
|
|
2542
|
+
/**
|
|
2543
|
+
* GET request that returns the raw, unparsed `Response` instead of decoded JSON.
|
|
2544
|
+
* Used for binary downloads (e.g. `GET /v1/acquisitions/{id}/corpus/download`,
|
|
2545
|
+
* which streams a gzip archive when the corpus is ready, or a JSON
|
|
2546
|
+
* `CorpusResponse` body otherwise).
|
|
2547
|
+
*
|
|
2548
|
+
* Applies the same `Authorization` header injection and single-retry-on-401
|
|
2549
|
+
* behaviour as {@link HttpClient.get}, and maps a non-2xx response to the same
|
|
2550
|
+
* typed errors — it just skips the `response.json()` decode step so the caller
|
|
2551
|
+
* can read the body as a stream, blob, or array buffer.
|
|
2552
|
+
*
|
|
2553
|
+
* @param path - API path (e.g. `/v1/acquisitions/{id}/corpus/download`)
|
|
2554
|
+
* @returns The raw `Response`. Callers are responsible for reading its body.
|
|
2555
|
+
*/
|
|
2556
|
+
getRaw(path: string): Promise<Response>;
|
|
1449
2557
|
private buildUrl;
|
|
1450
2558
|
private request;
|
|
2559
|
+
/**
|
|
2560
|
+
* Shared auth-injection, single-401-retry, and error-mapping logic behind both
|
|
2561
|
+
* `request()` (JSON in, JSON out) and `getRaw()` (JSON in, raw `Response` out).
|
|
2562
|
+
*/
|
|
2563
|
+
private performRequest;
|
|
1451
2564
|
private throwApiError;
|
|
1452
2565
|
}
|
|
1453
2566
|
|
|
@@ -1496,6 +2609,11 @@ export declare function init(config: BrowserClientConfig): BrowserClient;
|
|
|
1496
2609
|
* All errors thrown by the SDK are instances of this class,
|
|
1497
2610
|
* making it safe to use `err instanceof LedewireError` as a type guard.
|
|
1498
2611
|
*
|
|
2612
|
+
* `instanceof` works even when `err` was constructed by a different bundled
|
|
2613
|
+
* copy of this class — e.g. an error thrown by `@ledewire/x402-client`
|
|
2614
|
+
* checked with the `SpendCapReachedError` bundled into `@ledewire/node`. See
|
|
2615
|
+
* {@link LedewireError[Symbol.hasInstance]}.
|
|
2616
|
+
*
|
|
1499
2617
|
* @example
|
|
1500
2618
|
* ```ts
|
|
1501
2619
|
* try {
|
|
@@ -1508,11 +2626,48 @@ export declare function init(config: BrowserClientConfig): BrowserClient;
|
|
|
1508
2626
|
* ```
|
|
1509
2627
|
*/
|
|
1510
2628
|
export declare class LedewireError extends Error {
|
|
2629
|
+
/**
|
|
2630
|
+
* Class-identity brand used for cross-bundle `instanceof` (see {@link
|
|
2631
|
+
* LedewireError[Symbol.hasInstance]}). Hardcoded per class — never derived
|
|
2632
|
+
* from `constructor.name` or `this.name`, either of which a minifier can
|
|
2633
|
+
* rewrite, silently breaking the brand match.
|
|
2634
|
+
*/
|
|
2635
|
+
static readonly brand: string;
|
|
1511
2636
|
/** HTTP status code returned by the API (e.g. 400, 401, 404, 422). */
|
|
1512
2637
|
readonly statusCode: number;
|
|
1513
2638
|
/** Machine-readable error code from the API error body, if present. */
|
|
1514
2639
|
readonly code: number | undefined;
|
|
1515
|
-
|
|
2640
|
+
/**
|
|
2641
|
+
* Machine-readable reason from the API error body's `error.type`, if present.
|
|
2642
|
+
* See {@link ErrorType} for the documented values and how to branch on them —
|
|
2643
|
+
* the API may emit other values it hasn't documented yet, which still land
|
|
2644
|
+
* here as a plain string rather than being dropped.
|
|
2645
|
+
*/
|
|
2646
|
+
readonly type: ErrorTypeValue | undefined;
|
|
2647
|
+
/**
|
|
2648
|
+
* Extra top-level fields from the API error response body, excluding
|
|
2649
|
+
* `error` itself. For example, a `selection_too_large` refusal from `POST
|
|
2650
|
+
* /v1/acquisitions` (422) carries `maximum` and `submitted` alongside
|
|
2651
|
+
* `error`. `undefined` when the body carried no other top-level fields,
|
|
2652
|
+
* which is the common case.
|
|
2653
|
+
*/
|
|
2654
|
+
readonly details: Readonly<Record<string, unknown>> | undefined;
|
|
2655
|
+
constructor(message: string, statusCode: number, code?: number, type?: ErrorTypeValue, details?: Record<string, unknown>);
|
|
2656
|
+
/**
|
|
2657
|
+
* Makes `err instanceof LedewireError` (and every subclass below) true even
|
|
2658
|
+
* when `err` was constructed by a *different* bundled copy of this module.
|
|
2659
|
+
* Each published package (`@ledewire/node`, `@ledewire/browser`,
|
|
2660
|
+
* `@ledewire/x402-client`) bundles its own copy of `@ledewire/core` via
|
|
2661
|
+
* tsup, so the classes are distinct objects with unrelated prototypes —
|
|
2662
|
+
* the plain prototype-chain check `instanceof` normally does would fail.
|
|
2663
|
+
*
|
|
2664
|
+
* Falls back to the brand list every instance carries under a
|
|
2665
|
+
* `Symbol.for('@ledewire/error-brands')` key (collected from the `brand`
|
|
2666
|
+
* static along the constructing class's prototype chain): true when the
|
|
2667
|
+
* ordinary check passes, OR the instance's brand list includes this
|
|
2668
|
+
* class's own `brand`.
|
|
2669
|
+
*/
|
|
2670
|
+
static [Symbol.hasInstance](instance: unknown): boolean;
|
|
1516
2671
|
}
|
|
1517
2672
|
|
|
1518
2673
|
/**
|
|
@@ -1541,6 +2696,18 @@ export declare class LedewireError extends Error {
|
|
|
1541
2696
|
*/
|
|
1542
2697
|
export declare function localStorageAdapter(key?: string): TokenStorage;
|
|
1543
2698
|
|
|
2699
|
+
/** An MCP API key record (secret is never included after creation). */
|
|
2700
|
+
export declare type McpApiKey = components['schemas']['McpApiKey'];
|
|
2701
|
+
|
|
2702
|
+
/** Request body for creating a new MCP API key. */
|
|
2703
|
+
export declare type McpApiKeyCreateRequest = components['schemas']['McpApiKeyCreateRequest'];
|
|
2704
|
+
|
|
2705
|
+
/**
|
|
2706
|
+
* Response returned once when an MCP API key is created.
|
|
2707
|
+
* The `secret` is shown exactly once and cannot be retrieved again.
|
|
2708
|
+
*/
|
|
2709
|
+
export declare type McpApiKeyCreateResponse = components['schemas']['McpApiKeyCreateResponse'];
|
|
2710
|
+
|
|
1544
2711
|
/**
|
|
1545
2712
|
* In-memory token storage (default for both packages).
|
|
1546
2713
|
* Tokens are cleared when the page unloads or the process exits.
|
|
@@ -1560,7 +2727,8 @@ export declare type NextRequiredAction = ContentAccessInfo['next_required_action
|
|
|
1560
2727
|
* Thrown when the requested resource does not exist.
|
|
1561
2728
|
*/
|
|
1562
2729
|
export declare class NotFoundError extends LedewireError {
|
|
1563
|
-
|
|
2730
|
+
static readonly brand: string;
|
|
2731
|
+
constructor(message: string, code?: number, type?: ErrorTypeValue, details?: Record<string, unknown>);
|
|
1564
2732
|
}
|
|
1565
2733
|
|
|
1566
2734
|
/**
|
|
@@ -1602,12 +2770,26 @@ export declare type PurchaseCreateRequest = components['schemas']['PurchaseCreat
|
|
|
1602
2770
|
* failure, such as a price mismatch or a duplicate purchase.
|
|
1603
2771
|
*/
|
|
1604
2772
|
export declare class PurchaseError extends LedewireError {
|
|
1605
|
-
|
|
2773
|
+
static readonly brand: string;
|
|
2774
|
+
constructor(message: string, statusCode: number, code?: number, type?: ErrorTypeValue, details?: Record<string, unknown>);
|
|
1606
2775
|
}
|
|
1607
2776
|
|
|
1608
2777
|
/** A purchase record. */
|
|
1609
2778
|
export declare type PurchaseResponse = components['schemas']['PurchaseResponse'];
|
|
1610
2779
|
|
|
2780
|
+
/**
|
|
2781
|
+
* Per-request overrides accepted by {@link HttpClient} methods.
|
|
2782
|
+
*/
|
|
2783
|
+
declare interface RequestOptions {
|
|
2784
|
+
/**
|
|
2785
|
+
* Whether to attach authentication to this request. Defaults to `true`.
|
|
2786
|
+
* Pass `false` for public endpoints: skips `getAccessToken`, sends no
|
|
2787
|
+
* `Authorization` header, and maps a `401` straight to an {@link AuthError}
|
|
2788
|
+
* without invoking `onUnauthorized`.
|
|
2789
|
+
*/
|
|
2790
|
+
auth?: boolean;
|
|
2791
|
+
}
|
|
2792
|
+
|
|
1611
2793
|
/**
|
|
1612
2794
|
* Search criteria for seller content search.
|
|
1613
2795
|
* At least one field must be supplied. All supplied fields must match (AND logic).
|
|
@@ -1656,6 +2838,59 @@ export declare interface SellerContentSearchRequest {
|
|
|
1656
2838
|
*/
|
|
1657
2839
|
export declare function sessionStorageAdapter(key?: string): TokenStorage;
|
|
1658
2840
|
|
|
2841
|
+
/**
|
|
2842
|
+
* Thrown when the buyer's daily spend cap has been reached. Returned as HTTP `402`
|
|
2843
|
+
* by `POST /v1/purchases`, `GET /v1/x402/contents/{id}`, and acquisition
|
|
2844
|
+
* authorization, whenever the API error body's `error.type` is
|
|
2845
|
+
* `'daily_spend_cap_reached'`.
|
|
2846
|
+
*
|
|
2847
|
+
* **Funding the wallet does not clear this.** Unlike a plain `insufficient_funds`
|
|
2848
|
+
* 402 — where adding money to the wallet is enough to retry — a spend cap refusal
|
|
2849
|
+
* is a daily policy limit on the buyer's account (every new buyer starts with a
|
|
2850
|
+
* default cap). It clears only when the spend window rolls over at {@link
|
|
2851
|
+
* SpendCapReachedError.resetsAt}, or when the buyer raises or removes the cap via
|
|
2852
|
+
* `user.spendCap.update()`.
|
|
2853
|
+
*
|
|
2854
|
+
* @example
|
|
2855
|
+
* ```ts
|
|
2856
|
+
* try {
|
|
2857
|
+
* await client.purchases.create({ content_id })
|
|
2858
|
+
* } catch (err) {
|
|
2859
|
+
* if (err instanceof SpendCapReachedError) {
|
|
2860
|
+
* // Do NOT prompt the buyer to fund their wallet — that won't help.
|
|
2861
|
+
* console.error(
|
|
2862
|
+
* `Spend cap reached: spent ${err.spentCents} of ${err.capCents} cents. ` +
|
|
2863
|
+
* `Resets at ${err.resetsAt}.`,
|
|
2864
|
+
* )
|
|
2865
|
+
* }
|
|
2866
|
+
* }
|
|
2867
|
+
* ```
|
|
2868
|
+
*/
|
|
2869
|
+
export declare class SpendCapReachedError extends LedewireError {
|
|
2870
|
+
static readonly brand: string;
|
|
2871
|
+
/** The buyer's daily spend cap in cents. */
|
|
2872
|
+
readonly capCents: number;
|
|
2873
|
+
/** Total spent so far in the current spend window. */
|
|
2874
|
+
readonly spentCents: number;
|
|
2875
|
+
/** Cap minus spend so far, floored at zero — what the buyer may still spend in this window. */
|
|
2876
|
+
readonly remainingCents: number;
|
|
2877
|
+
/** ISO 8601 timestamp (UTC) of the instant the current spend window rolls. */
|
|
2878
|
+
readonly resetsAt: string;
|
|
2879
|
+
/**
|
|
2880
|
+
* Whether this buyer's bulk acquisitions are exempt from the cap. When `true`,
|
|
2881
|
+
* `spentCents` and `remainingCents` describe ordinary spend only — an authorized
|
|
2882
|
+
* bulk acquisition does not consume them.
|
|
2883
|
+
*/
|
|
2884
|
+
readonly bulkExempt: boolean;
|
|
2885
|
+
constructor(message: string, capInfo: {
|
|
2886
|
+
capCents: number;
|
|
2887
|
+
spentCents: number;
|
|
2888
|
+
remainingCents: number;
|
|
2889
|
+
resetsAt: string;
|
|
2890
|
+
bulkExempt: boolean;
|
|
2891
|
+
}, code?: number);
|
|
2892
|
+
}
|
|
2893
|
+
|
|
1659
2894
|
/** Internal representation of stored authentication tokens. */
|
|
1660
2895
|
export declare interface StoredTokens {
|
|
1661
2896
|
accessToken: string;
|
|
@@ -1765,6 +3000,271 @@ export declare interface TokenStorage {
|
|
|
1765
3000
|
clearTokens(): void | Promise<void>;
|
|
1766
3001
|
}
|
|
1767
3002
|
|
|
3003
|
+
/** A buyer API key record (secret is never included after creation). */
|
|
3004
|
+
declare type UserApiKey = components['schemas']['UserApiKey'];
|
|
3005
|
+
|
|
3006
|
+
/** Request body for creating a new buyer API key. */
|
|
3007
|
+
declare type UserApiKeyCreateRequest = components['schemas']['UserApiKeyCreateRequest'];
|
|
3008
|
+
|
|
3009
|
+
/**
|
|
3010
|
+
* Response returned once when a buyer API key is created.
|
|
3011
|
+
* The `secret` is shown exactly once and cannot be retrieved again.
|
|
3012
|
+
* Store it immediately in a secrets manager.
|
|
3013
|
+
*/
|
|
3014
|
+
declare type UserApiKeyCreateResponse = components['schemas']['UserApiKeyCreateResponse'];
|
|
3015
|
+
|
|
3016
|
+
/**
|
|
3017
|
+
* Manage buyer API keys for the authenticated user.
|
|
3018
|
+
*
|
|
3019
|
+
* Buyer API keys are the authentication credential for autonomous agents — they
|
|
3020
|
+
* allow an agent to obtain a buyer JWT via `auth.loginWithBuyerApiKey()` without
|
|
3021
|
+
* requiring a username and password. Each key is named, independently revocable,
|
|
3022
|
+
* and can carry an optional `spending_limit_cents` ceiling.
|
|
3023
|
+
*
|
|
3024
|
+
* **Secret handling:** `create()` returns the `secret` exactly once. It is never
|
|
3025
|
+
* retrievable again after the response is received — store it immediately in a
|
|
3026
|
+
* secrets manager (e.g. environment variable, Vault, AWS Secrets Manager).
|
|
3027
|
+
*
|
|
3028
|
+
* Obtain via `client.user.apiKeys` — do not construct directly.
|
|
3029
|
+
*
|
|
3030
|
+
* @example
|
|
3031
|
+
* ```ts
|
|
3032
|
+
* // Create a key for an agent, with a $10 spend ceiling
|
|
3033
|
+
* const { key, secret } = await client.user.apiKeys.create({
|
|
3034
|
+
* name: 'my-rag-agent',
|
|
3035
|
+
* spending_limit_cents: 1000,
|
|
3036
|
+
* })
|
|
3037
|
+
* // Store secret immediately — it cannot be retrieved again
|
|
3038
|
+
* await secretsManager.put('LEDEWIRE_BUYER_SECRET', secret)
|
|
3039
|
+
*
|
|
3040
|
+
* // List all keys (secrets never included)
|
|
3041
|
+
* const keys = await client.user.apiKeys.list()
|
|
3042
|
+
*
|
|
3043
|
+
* // Revoke a compromised key
|
|
3044
|
+
* await client.user.apiKeys.revoke(keys[0].id)
|
|
3045
|
+
* ```
|
|
3046
|
+
*/
|
|
3047
|
+
declare class UserApiKeysNamespace {
|
|
3048
|
+
private readonly http;
|
|
3049
|
+
/* Excluded from this release type: __constructor */
|
|
3050
|
+
/**
|
|
3051
|
+
* Returns all buyer API keys for the authenticated user.
|
|
3052
|
+
* The `secret` is never included in list responses.
|
|
3053
|
+
*
|
|
3054
|
+
* @returns Array of API key records.
|
|
3055
|
+
*/
|
|
3056
|
+
list(): Promise<UserApiKey[]>;
|
|
3057
|
+
/**
|
|
3058
|
+
* Creates a new buyer API key.
|
|
3059
|
+
*
|
|
3060
|
+
* The `secret` in the response is shown exactly once and cannot be retrieved
|
|
3061
|
+
* again. Store it immediately in a secrets manager before discarding the
|
|
3062
|
+
* response object.
|
|
3063
|
+
*
|
|
3064
|
+
* @param body - Name and optional spend ceiling for the new key.
|
|
3065
|
+
* @returns The new key's public identifier and one-time secret.
|
|
3066
|
+
*
|
|
3067
|
+
* @example
|
|
3068
|
+
* ```ts
|
|
3069
|
+
* const { key, secret } = await client.user.apiKeys.create({
|
|
3070
|
+
* name: 'production-agent',
|
|
3071
|
+
* spending_limit_cents: 5000, // $50 cap
|
|
3072
|
+
* })
|
|
3073
|
+
* // ⚠️ Store secret NOW — it is shown once only
|
|
3074
|
+
* process.env.LEDEWIRE_BUYER_SECRET = secret
|
|
3075
|
+
* ```
|
|
3076
|
+
*/
|
|
3077
|
+
create(body: UserApiKeyCreateRequest): Promise<UserApiKeyCreateResponse>;
|
|
3078
|
+
/**
|
|
3079
|
+
* Revokes (permanently deletes) a buyer API key by ID.
|
|
3080
|
+
*
|
|
3081
|
+
* Any agent currently using this key will receive `401` on its next
|
|
3082
|
+
* token refresh. Revocation takes effect immediately.
|
|
3083
|
+
*
|
|
3084
|
+
* @param id - UUID of the API key to revoke.
|
|
3085
|
+
*/
|
|
3086
|
+
revoke(id: string): Promise<void>;
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
/**
|
|
3090
|
+
* Manage the authenticated buyer's MCP API keys.
|
|
3091
|
+
*
|
|
3092
|
+
* MCP API keys authenticate agent requests against the Ledewire MCP server, sent
|
|
3093
|
+
* as `Authorization: Bearer <key>:<secret>`. Each key carries an explicit set of
|
|
3094
|
+
* scopes — `can_search` (default `true`), `can_purchase` (default `false`), and
|
|
3095
|
+
* the seller-tier `can_manage_content` / `can_read_analytics`, which additionally
|
|
3096
|
+
* require `store_id` to be set to a store the user owns or authors.
|
|
3097
|
+
*
|
|
3098
|
+
* **Secret handling:** `create()` returns the `secret` exactly once. It is never
|
|
3099
|
+
* retrievable again — store it immediately, alongside the `key`, in a secrets
|
|
3100
|
+
* manager.
|
|
3101
|
+
*
|
|
3102
|
+
* **Changing permissions:** scopes are fixed at creation. To change what a key
|
|
3103
|
+
* can do, revoke it and create a replacement with the desired scopes.
|
|
3104
|
+
*
|
|
3105
|
+
* Obtain via `client.user.mcpKeys` — do not construct directly.
|
|
3106
|
+
*
|
|
3107
|
+
* @example
|
|
3108
|
+
* ```ts
|
|
3109
|
+
* // Create a search+purchase key for an autonomous agent
|
|
3110
|
+
* const { key, secret } = await client.user.mcpKeys.create({
|
|
3111
|
+
* label: 'my-rag-agent',
|
|
3112
|
+
* can_search: true,
|
|
3113
|
+
* can_purchase: true,
|
|
3114
|
+
* })
|
|
3115
|
+
* // Store immediately — the secret cannot be retrieved again
|
|
3116
|
+
* await secretsManager.put('LEDEWIRE_MCP_CREDENTIAL', `${key}:${secret}`)
|
|
3117
|
+
*
|
|
3118
|
+
* // List all keys (secrets never included)
|
|
3119
|
+
* const keys = await client.user.mcpKeys.list()
|
|
3120
|
+
*
|
|
3121
|
+
* // To change permissions: revoke and recreate
|
|
3122
|
+
* await client.user.mcpKeys.revoke(keys[0].id)
|
|
3123
|
+
* ```
|
|
3124
|
+
*/
|
|
3125
|
+
declare class UserMcpKeysNamespace {
|
|
3126
|
+
private readonly http;
|
|
3127
|
+
/* Excluded from this release type: __constructor */
|
|
3128
|
+
/**
|
|
3129
|
+
* Returns all MCP API keys for the authenticated user.
|
|
3130
|
+
* The `secret` is never included in list responses.
|
|
3131
|
+
*
|
|
3132
|
+
* @returns Array of MCP API key records.
|
|
3133
|
+
*/
|
|
3134
|
+
list(): Promise<McpApiKey[]>;
|
|
3135
|
+
/**
|
|
3136
|
+
* Creates a new MCP API key.
|
|
3137
|
+
*
|
|
3138
|
+
* The `secret` in the response is shown exactly once and cannot be retrieved
|
|
3139
|
+
* again. Store it immediately alongside `key` — the pair is used together as
|
|
3140
|
+
* `Authorization: Bearer <key>:<secret>` against the Ledewire MCP server.
|
|
3141
|
+
*
|
|
3142
|
+
* @param body - Label and scopes for the new key.
|
|
3143
|
+
* @returns The new key's public identifier, scopes, and one-time secret.
|
|
3144
|
+
*
|
|
3145
|
+
* @example
|
|
3146
|
+
* ```ts
|
|
3147
|
+
* const { key, secret } = await client.user.mcpKeys.create({
|
|
3148
|
+
* label: 'production-agent',
|
|
3149
|
+
* can_search: true,
|
|
3150
|
+
* can_purchase: true,
|
|
3151
|
+
* })
|
|
3152
|
+
* ```
|
|
3153
|
+
*/
|
|
3154
|
+
create(body: McpApiKeyCreateRequest): Promise<McpApiKeyCreateResponse>;
|
|
3155
|
+
/**
|
|
3156
|
+
* Revokes (permanently deletes) an MCP API key by ID.
|
|
3157
|
+
*
|
|
3158
|
+
* To change a key's permissions, revoke it and create a replacement with the
|
|
3159
|
+
* desired scopes — scopes cannot be edited in place.
|
|
3160
|
+
*
|
|
3161
|
+
* @param id - UUID of the MCP API key to revoke.
|
|
3162
|
+
*/
|
|
3163
|
+
revoke(id: string): Promise<void>;
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3166
|
+
/**
|
|
3167
|
+
* Authenticated buyer account operations.
|
|
3168
|
+
*
|
|
3169
|
+
* Obtain via `client.user` — do not construct directly.
|
|
3170
|
+
*/
|
|
3171
|
+
declare class UserNamespace {
|
|
3172
|
+
/**
|
|
3173
|
+
* Buyer API key management: create, list, and revoke named API keys.
|
|
3174
|
+
* Keys are used by autonomous agents to authenticate without a username/password.
|
|
3175
|
+
*/
|
|
3176
|
+
readonly apiKeys: UserApiKeysNamespace;
|
|
3177
|
+
/**
|
|
3178
|
+
* The authenticated buyer's daily spend cap: read and update the ceiling that
|
|
3179
|
+
* governs every wallet debit (MCP, REST, and the web payment gate).
|
|
3180
|
+
*/
|
|
3181
|
+
readonly spendCap: UserSpendCapNamespace;
|
|
3182
|
+
/**
|
|
3183
|
+
* MCP API key management: create, list, and revoke keys scoped for use against
|
|
3184
|
+
* the Ledewire MCP server.
|
|
3185
|
+
*/
|
|
3186
|
+
readonly mcpKeys: UserMcpKeysNamespace;
|
|
3187
|
+
/* Excluded from this release type: __constructor */
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
/**
|
|
3191
|
+
* The authenticated buyer's daily spend cap, read against the current spend window.
|
|
3192
|
+
* The cap governs every wallet debit the buyer makes — MCP, REST, or the web payment
|
|
3193
|
+
* gate — and spend is derived from completed purchases, so a refund returns allowance.
|
|
3194
|
+
*
|
|
3195
|
+
* `cap_cents`, `spent_cents`, `remaining_cents` and `resets_at` are spelled exactly as
|
|
3196
|
+
* they are in {@link DailySpendCapReachedErrorBody}, so a refusal and this resource
|
|
3197
|
+
* describe the same numbers.
|
|
3198
|
+
*/
|
|
3199
|
+
export declare type UserSpendCap = components['schemas']['UserSpendCap'];
|
|
3200
|
+
|
|
3201
|
+
/**
|
|
3202
|
+
* Manage the authenticated buyer's daily spend cap.
|
|
3203
|
+
*
|
|
3204
|
+
* Every new buyer starts with a default cap, so `null` on {@link
|
|
3205
|
+
* UserSpendCapNamespace.update} is the only way to become uncapped — there is no
|
|
3206
|
+
* separate "remove the cap" call. While capped, `cap_cents` and `remaining_cents`
|
|
3207
|
+
* are numbers; once uncapped, both read back as `null` because there is no ceiling
|
|
3208
|
+
* to report or subtract from.
|
|
3209
|
+
*
|
|
3210
|
+
* The cap governs every wallet debit the buyer makes — MCP, REST, or the web
|
|
3211
|
+
* payment gate — over a rolling window bounded by `spend_window_timezone` (an IANA
|
|
3212
|
+
* zone, UTC by default) and reset at `resets_at`. `bulk_exempt` says whether this
|
|
3213
|
+
* buyer's bulk acquisitions are excluded from that spend, in which case
|
|
3214
|
+
* `spent_cents` / `remaining_cents` describe ordinary purchases only.
|
|
3215
|
+
*
|
|
3216
|
+
* **Exceeding the cap throws {@link SpendCapReachedError}** (HTTP 402) from
|
|
3217
|
+
* `client.purchases.create()` and the x402 content gate. Funding the wallet does not
|
|
3218
|
+
* clear it — the buyer must wait for the window to roll at `resets_at`, or the cap
|
|
3219
|
+
* must be raised or cleared here.
|
|
3220
|
+
*
|
|
3221
|
+
* Obtain via `client.user.spendCap` — do not construct directly.
|
|
3222
|
+
*
|
|
3223
|
+
* @example
|
|
3224
|
+
* ```ts
|
|
3225
|
+
* const cap = await client.user.spendCap.get()
|
|
3226
|
+
* if (cap.remaining_cents !== null && cap.remaining_cents < 500) {
|
|
3227
|
+
* console.warn(`Only ${cap.remaining_cents}c left before the cap resets at ${cap.resets_at}`)
|
|
3228
|
+
* }
|
|
3229
|
+
*
|
|
3230
|
+
* // Raise the cap to $20/day
|
|
3231
|
+
* await client.user.spendCap.update({ daily_spend_limit_cents: 2000 })
|
|
3232
|
+
*
|
|
3233
|
+
* // Remove the cap entirely (become uncapped)
|
|
3234
|
+
* await client.user.spendCap.update({ daily_spend_limit_cents: null })
|
|
3235
|
+
* ```
|
|
3236
|
+
*/
|
|
3237
|
+
declare class UserSpendCapNamespace {
|
|
3238
|
+
private readonly http;
|
|
3239
|
+
/* Excluded from this release type: __constructor */
|
|
3240
|
+
/**
|
|
3241
|
+
* Returns the authenticated buyer's spend cap, read against the current spend
|
|
3242
|
+
* window.
|
|
3243
|
+
*
|
|
3244
|
+
* @returns The current spend cap, spend-to-date, and reset time.
|
|
3245
|
+
*/
|
|
3246
|
+
get(): Promise<UserSpendCap>;
|
|
3247
|
+
/**
|
|
3248
|
+
* Sets or clears the authenticated buyer's daily spend cap.
|
|
3249
|
+
*
|
|
3250
|
+
* `daily_spend_limit_cents` is required and nullable: pass a number to set the
|
|
3251
|
+
* cap, or `null` to remove it (the only way to become uncapped). A cap set below
|
|
3252
|
+
* spend already made in the current window is accepted — it just leaves
|
|
3253
|
+
* `remaining_cents` at zero until the window rolls.
|
|
3254
|
+
*
|
|
3255
|
+
* @param body - The new cap in whole cents, or `null` to remove it.
|
|
3256
|
+
* @returns The updated spend cap.
|
|
3257
|
+
*/
|
|
3258
|
+
update(body: UserSpendCapUpdateRequest): Promise<UserSpendCap>;
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3261
|
+
/**
|
|
3262
|
+
* Request body for `PATCH /v1/user/spend-cap`. `daily_spend_limit_cents` is required
|
|
3263
|
+
* and nullable: `null` is how a buyer becomes uncapped, and an omitted field is a
|
|
3264
|
+
* client error rather than a request to be uncapped.
|
|
3265
|
+
*/
|
|
3266
|
+
export declare type UserSpendCapUpdateRequest = components['schemas']['UserSpendCapUpdateRequest'];
|
|
3267
|
+
|
|
1768
3268
|
/** Current wallet balance for the authenticated buyer. */
|
|
1769
3269
|
export declare type WalletBalanceResponse = components['schemas']['WalletBalanceResponse'];
|
|
1770
3270
|
|