@curless/agentbank-merchant-sdk 0.9.0 → 0.9.2
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
CHANGED
|
@@ -9,17 +9,21 @@ and you get:
|
|
|
9
9
|
- **`checkout.openUCP`** — merchant-quoted **card** checkout over the **UCP** wire ([ucp.dev](https://ucp.dev)) — the UCP twin of `openACP` (same card settlement; reaches agents in the UCP ecosystem).
|
|
10
10
|
- **`checkout.openX402`** — merchant-quoted **USDC (x402)** checkout. You set the authoritative USDC amount; the gateway freezes it and returns the x402 challenge; a buyer agent signs an EIP-3009 authorization and pays `{ sessionId }` on-chain. Settlement is on Base (mainnet or Sepolia, decided by your account/key) — your USDC lands at your address. The stablecoin twin of `openACP`.
|
|
11
11
|
- **`orders`** — read your settled orders: `orders.list({ status, protocol, currency, from, to, limit, offset })` (filtered + paginated, with a total), `orders.get(id)` (one order in full + the card it was paid with), `orders.summary({…})` (count + gross by currency + breakdowns by protocol/status — a dashboard in one call).
|
|
12
|
-
- **`
|
|
12
|
+
- **`orders` refunds** — work the refund queue: `orders.listRefundRequests({ status })` (buyers' refund requests on your orders), `orders.approveRefund(id)` (approve → forwarded to Curless), `orders.rejectRefund(id, { note })`, and `orders.refund(orderId, { amount, reason })` (merchant-initiated direct refund, no buyer request). See **Refunds** below.
|
|
13
|
+
- **`AgentbankMerchant`** — typed client; also exposes `PaymentIntents` (create/get/capture/list/ledger-entries across ACP / x402 / AP2 / UCP / A2A), `PaymentLinks`, `Customers`, `BalanceTransactions`, and `WebhookEndpoints`. (`PaymentIntents` has no `refund()` — the refund flow lives on `orders`.)
|
|
13
14
|
- **`verifyWebhook` / `parseVerifiedWebhook`** — HMAC-SHA256 signature verification (Stripe-style `t=…,v1=…`), constant-time, **edge-safe** (Web Crypto, runs on Vercel Edge / Cloudflare Workers). Async — `await` them.
|
|
14
15
|
- **`x402`** — emit/parse payments yourself (`buildChallenge()`, `decodeXPaymentHeader()`) **plus zero-crypto-knowledge helpers**: `usdc(network)` (contract + EIP-712 domain + decimals — no hardcoded hex), `isMainnet/isTestnet(network)`, `explorerTxUrl(network, txHash)` (a basescan / sepolia.basescan receipt link), `formatUsdc(baseUnits)` (exact 6-dp string, no float drift).
|
|
15
16
|
|
|
16
17
|
agentbank never stores your catalog — the price you pass is authoritative, and you accept every agent-payment protocol with zero protocol code. One runtime dependency (`@curless/agentbank-core`). **Edge-safe** — Web Crypto only, no `node:` builtins. Node 18+.
|
|
17
18
|
|
|
18
|
-
> **Refunds**:
|
|
19
|
-
>
|
|
20
|
-
>
|
|
21
|
-
>
|
|
22
|
-
>
|
|
19
|
+
> **Refunds**: a buyer opens a refund request, or the merchant refunds directly
|
|
20
|
+
> via `orders.refund(orderId)`. The merchant works the queue with
|
|
21
|
+
> `orders.listRefundRequests` / `approveRefund` / `rejectRefund`. Approve forwards
|
|
22
|
+
> the refund to Curless (which holds the money and executes the card refund); the
|
|
23
|
+
> order flips to `refunded` / `partially_refunded` once Curless confirms via
|
|
24
|
+
> webhook. Read the resulting state via `orders.list({ status: 'refunded' })` or
|
|
25
|
+
> `paymentIntents.get()`. (agentbank never touches the rail directly — Curless
|
|
26
|
+
> originates the actual money movement.)
|
|
23
27
|
|
|
24
28
|
## Fast path — open a merchant-quoted checkout
|
|
25
29
|
|
|
@@ -14,6 +14,14 @@ export type OpenCheckoutInput = {
|
|
|
14
14
|
currency: string;
|
|
15
15
|
/** Overrides the client's configured `merchantId` for this call. */
|
|
16
16
|
merchantId?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Stripe-style idempotency key. Send the SAME value when retrying a checkout
|
|
19
|
+
* you're unsure completed — the gateway returns the original session instead of
|
|
20
|
+
* opening (and charging) a second one. Recommended for any retry-on-timeout
|
|
21
|
+
* path. (The gateway also auto-dedups identical checkouts within a short window
|
|
22
|
+
* even without a key, but an explicit key is exact-once.)
|
|
23
|
+
*/
|
|
24
|
+
idempotencyKey?: string;
|
|
17
25
|
};
|
|
18
26
|
export type Checkout = {
|
|
19
27
|
/** The checkout id the buyer agent completes to pay. */
|
|
@@ -42,6 +50,8 @@ export type OpenX402CheckoutInput = {
|
|
|
42
50
|
amount: number;
|
|
43
51
|
/** Overrides the client's configured `merchantId` for this call. */
|
|
44
52
|
merchantId?: string;
|
|
53
|
+
/** Stripe-style idempotency key — send the same value on a retry to dedup. */
|
|
54
|
+
idempotencyKey?: string;
|
|
45
55
|
};
|
|
46
56
|
export type X402Checkout = {
|
|
47
57
|
/** The session id the buyer pays with `{ sessionId }`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/resources/checkout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../../src/resources/checkout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,6BAA6B;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAKF,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,iBAAiB;IAKhD,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAkCpD,QAAQ,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,YAAY,CAAC;IA6B7D,OAAO,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC;CAqC3D;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC"}
|
|
@@ -15,6 +15,7 @@ export class CheckoutResource {
|
|
|
15
15
|
throw new Error('merchantId is required — set it on AgentbankMerchant({ merchantId }) or pass it to openACP()');
|
|
16
16
|
}
|
|
17
17
|
const session = await this.client.request('POST', `/acp/${encodeURIComponent(merchantId)}/checkout_sessions`, {
|
|
18
|
+
idempotencyKey: input.idempotencyKey,
|
|
18
19
|
body: {
|
|
19
20
|
currency: input.currency,
|
|
20
21
|
items: input.items.map((it) => ({
|
|
@@ -40,6 +41,7 @@ export class CheckoutResource {
|
|
|
40
41
|
throw new Error('merchantId is required — set it on AgentbankMerchant({ merchantId }) or pass it to openX402()');
|
|
41
42
|
}
|
|
42
43
|
return this.client.request('POST', `/x402/${encodeURIComponent(merchantId)}/checkout_sessions`, {
|
|
44
|
+
idempotencyKey: input.idempotencyKey,
|
|
43
45
|
body: {
|
|
44
46
|
amount: input.amount,
|
|
45
47
|
items: input.items.map((it) => ({
|
|
@@ -61,6 +63,7 @@ export class CheckoutResource {
|
|
|
61
63
|
throw new Error('merchantId is required — set it on AgentbankMerchant({ merchantId }) or pass it to openUCP()');
|
|
62
64
|
}
|
|
63
65
|
const session = await this.client.request('POST', `/ucp/${encodeURIComponent(merchantId)}/checkout-sessions`, {
|
|
66
|
+
idempotencyKey: input.idempotencyKey,
|
|
64
67
|
body: {
|
|
65
68
|
// UCP wire: { item: { id, title, price: { amount, currency } }, quantity }
|
|
66
69
|
// — quantity sits outside `item`; the merchant prices each item.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkout.js","sourceRoot":"","sources":["../../src/resources/checkout.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"checkout.js","sourceRoot":"","sources":["../../src/resources/checkout.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@curless/agentbank-merchant-sdk",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Merchant-side SDK for agentbank — accept agent payments: open a merchant-quoted card (ACP / UCP) or USDC (x402) checkout you price, list/summarize orders, PaymentIntents, edge-safe webhook verification, and x402 helpers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|