@agentspend/sdk 0.2.0 → 0.3.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 ADDED
@@ -0,0 +1,86 @@
1
+ # @agentspend/sdk
2
+
3
+ SDK for services to accept AI agent payments — cards (Stripe) and crypto (x402/USDC on Base).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @agentspend/sdk
9
+ ```
10
+
11
+ ## Paywall middleware (Hono)
12
+
13
+ Add a paywall to any endpoint. Accepts both card and crypto payments automatically.
14
+
15
+ ```ts
16
+ import { createAgentSpend, getPaymentContext } from "@agentspend/sdk";
17
+
18
+ const spend = createAgentSpend({
19
+ serviceApiKey: process.env.AGENTSPEND_SERVICE_API_KEY,
20
+ crypto: {
21
+ receiverAddress: "0x...", // your USDC address on Base
22
+ },
23
+ });
24
+
25
+ app.post("/api/generate", spend.paywall({ amount: 100 }), async (c) => {
26
+ const payment = getPaymentContext(c);
27
+ // payment.method === "card" | "crypto"
28
+ // payment.amount_cents === 100
29
+ return c.json({ result: "..." });
30
+ });
31
+ ```
32
+
33
+ ### Dynamic pricing
34
+
35
+ ```ts
36
+ // Read amount from request body field
37
+ spend.paywall({ amount: "amount_cents" });
38
+
39
+ // Custom pricing function
40
+ spend.paywall({ amount: (body) => calculatePrice(body) });
41
+ ```
42
+
43
+ ## Direct charge (card only)
44
+
45
+ ```ts
46
+ const result = await spend.charge("card_abc123", {
47
+ amount_cents: 500,
48
+ description: "API call",
49
+ });
50
+ ```
51
+
52
+ ## How agents pay
53
+
54
+ **Card:** Agent sends `x-card-id: card_xxx` header or `card_id` in the request body.
55
+
56
+ **Crypto:** Agent sends `x-payment` header with a signed x402 payment payload.
57
+
58
+ If neither is provided, the service returns `402 Payment Required` with x402 payment requirements.
59
+
60
+ ## Configuration
61
+
62
+ ```ts
63
+ const spend = createAgentSpend({
64
+ // Stripe card payments (get key from service onboarding)
65
+ serviceApiKey: "sk_...",
66
+
67
+ // Crypto payments (optional)
68
+ crypto: {
69
+ receiverAddress: "0x...", // static payTo address
70
+ network: "eip155:8453", // default: Base
71
+ facilitatorUrl: "https://...", // default: x402.org
72
+ },
73
+
74
+ // Override platform API URL (optional)
75
+ platformApiBaseUrl: "https://api.agentspend.co",
76
+ });
77
+ ```
78
+
79
+ At least one of `serviceApiKey` or `crypto` must be provided.
80
+
81
+ ## Environment variables
82
+
83
+ | Variable | Description |
84
+ |----------|-------------|
85
+ | `AGENTSPEND_API_URL` | Platform API base URL (default: `https://api.agentspend.co`) |
86
+ | `AGENTSPEND_SERVICE_API_KEY` | Service API key (from service onboarding) |
package/dist/index.d.ts CHANGED
@@ -1,5 +1,35 @@
1
- import type { ChargeResponse, PaywallPaymentContext } from "@agentspend/types";
2
- export type { ChargeRequest, ChargeResponse, ErrorResponse, PaymentMethod, PaywallPaymentContext } from "@agentspend/types";
1
+ export interface ChargeRequest {
2
+ card_id: string;
3
+ amount_cents: number;
4
+ currency?: string;
5
+ description?: string;
6
+ metadata?: Record<string, string>;
7
+ idempotency_key?: string;
8
+ }
9
+ export interface ChargeResponse {
10
+ charged: true;
11
+ card_id: string;
12
+ amount_cents: number;
13
+ currency: string;
14
+ remaining_limit_cents: number;
15
+ stripe_payment_intent_id: string;
16
+ stripe_charge_id: string;
17
+ charge_attempt_id: string;
18
+ }
19
+ export interface ErrorResponse {
20
+ error: string;
21
+ }
22
+ export type PaymentMethod = "card" | "crypto";
23
+ export interface PaywallPaymentContext {
24
+ method: PaymentMethod;
25
+ amount_cents: number;
26
+ currency: string;
27
+ card_id?: string;
28
+ remaining_limit_cents?: number;
29
+ transaction_hash?: string;
30
+ payer_address?: string;
31
+ network?: string;
32
+ }
3
33
  export interface AgentSpendOptions {
4
34
  /**
5
35
  * Base URL for the AgentSpend Platform API.
@@ -40,21 +70,26 @@ export interface HonoContextLike {
40
70
  url: string;
41
71
  method: string;
42
72
  };
43
- json(body: unknown, status?: number): unknown;
73
+ json(body: unknown, status?: number): Response;
44
74
  header(name: string, value: string): void;
45
75
  set(key: string, value: unknown): void;
46
76
  get(key: string): unknown;
47
77
  }
48
78
  export interface PaywallOptions {
79
+ /**
80
+ * Amount in cents.
81
+ * - number: fixed price (e.g. 500 = $5.00)
82
+ * - string: body field name to read amount from (e.g. "amount_cents")
83
+ * - function: custom dynamic pricing (body: unknown) => number
84
+ */
85
+ amount: number | string | ((body: unknown) => number);
49
86
  currency?: string;
50
87
  description?: string;
51
88
  metadata?: (body: unknown) => Record<string, unknown>;
52
- /** Dynamic pricing: derive amount from the parsed request body. */
53
- amountFromRequest?: (body: unknown) => number;
54
89
  }
55
90
  export declare function getPaymentContext(c: HonoContextLike): PaywallPaymentContext | null;
56
91
  export interface AgentSpend {
57
- charge(walletId: string, opts: ChargeOptions): Promise<ChargeResponse>;
58
- paywall(amountCents: number, opts?: PaywallOptions): (c: HonoContextLike, next: () => Promise<void>) => Promise<unknown>;
92
+ charge(cardId: string, opts: ChargeOptions): Promise<ChargeResponse>;
93
+ paywall(opts: PaywallOptions): (c: HonoContextLike, next: () => Promise<void>) => Promise<Response | void>;
59
94
  }
60
95
  export declare function createAgentSpend(options: AgentSpendOptions): AgentSpend;
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
+ // ---------------------------------------------------------------------------
3
+ // Types (inlined from @agentspend/types to avoid cross-repo publish)
4
+ // ---------------------------------------------------------------------------
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.AgentSpendChargeError = void 0;
4
7
  exports.getPaymentContext = getPaymentContext;
@@ -54,19 +57,19 @@ function createAgentSpend(options) {
54
57
  // -------------------------------------------------------------------
55
58
  // charge() — card-only, unchanged
56
59
  // -------------------------------------------------------------------
57
- async function charge(walletIdInput, opts) {
60
+ async function charge(cardIdInput, opts) {
58
61
  if (!options.serviceApiKey) {
59
62
  throw new AgentSpendChargeError("charge() requires serviceApiKey", 500);
60
63
  }
61
- const walletId = toWalletId(walletIdInput);
62
- if (!walletId) {
63
- throw new AgentSpendChargeError("wallet_id must start with wal_", 400);
64
+ const cardId = toCardId(cardIdInput);
65
+ if (!cardId) {
66
+ throw new AgentSpendChargeError("card_id must start with card_", 400);
64
67
  }
65
68
  if (!Number.isInteger(opts.amount_cents) || opts.amount_cents <= 0) {
66
69
  throw new AgentSpendChargeError("amount_cents must be a positive integer", 400);
67
70
  }
68
71
  const payload = {
69
- wallet_id: walletId,
72
+ card_id: cardId,
70
73
  amount_cents: opts.amount_cents,
71
74
  currency: opts.currency ?? "usd",
72
75
  ...(opts.description ? { description: opts.description } : {}),
@@ -90,41 +93,49 @@ function createAgentSpend(options) {
90
93
  // -------------------------------------------------------------------
91
94
  // paywall() — unified card + crypto middleware
92
95
  // -------------------------------------------------------------------
93
- function paywall(amountCents, opts) {
94
- // Allow amountCents === 0 when amountFromRequest is provided (dynamic pricing)
95
- if (!opts?.amountFromRequest) {
96
- if (!Number.isInteger(amountCents) || amountCents <= 0) {
97
- throw new AgentSpendChargeError("amountCents must be a positive integer", 500);
96
+ function paywall(opts) {
97
+ const { amount } = opts;
98
+ // Validate fixed-price amount at creation time
99
+ if (typeof amount === "number") {
100
+ if (!Number.isInteger(amount) || amount <= 0) {
101
+ throw new AgentSpendChargeError("amount must be a positive integer", 500);
98
102
  }
99
103
  }
100
104
  return async function paywallMiddleware(c, next) {
101
105
  // Step 1: Parse body once (Decision 11)
102
106
  const body = await c.req.json().catch(() => ({}));
103
107
  // Step 2: Determine effective amount
104
- let effectiveAmount = amountCents;
105
- if (opts?.amountFromRequest) {
106
- effectiveAmount = opts.amountFromRequest(body);
107
- if (!Number.isInteger(effectiveAmount) || effectiveAmount <= 0) {
108
- return c.json({ error: "Could not determine payment amount from request" }, 400);
109
- }
108
+ let effectiveAmount;
109
+ if (typeof amount === "number") {
110
+ effectiveAmount = amount;
111
+ }
112
+ else if (typeof amount === "string") {
113
+ const raw = body?.[amount];
114
+ effectiveAmount = typeof raw === "number" ? raw : 0;
115
+ }
116
+ else {
117
+ effectiveAmount = amount(body);
118
+ }
119
+ if (!Number.isInteger(effectiveAmount) || effectiveAmount <= 0) {
120
+ return c.json({ error: "Could not determine payment amount from request" }, 400);
110
121
  }
111
- const currency = opts?.currency ?? "usd";
122
+ const currency = opts.currency ?? "usd";
112
123
  // Step 3: Check for x-payment header → crypto payment
113
124
  const paymentHeader = c.req.header("x-payment");
114
125
  if (paymentHeader) {
115
126
  return handleCryptoPayment(c, next, paymentHeader, effectiveAmount, currency, body, opts);
116
127
  }
117
- // Step 4: Check for x-wallet-id header or body.wallet_id → card payment
118
- const walletIdFromHeader = c.req.header("x-wallet-id");
119
- let walletId = walletIdFromHeader ? toWalletId(walletIdFromHeader) : null;
120
- if (!walletId) {
121
- const bodyWalletId = typeof body?.wallet_id === "string"
122
- ? body.wallet_id
128
+ // Step 4: Check for x-card-id header or body.card_id → card payment
129
+ const cardIdFromHeader = c.req.header("x-card-id");
130
+ let cardId = cardIdFromHeader ? toCardId(cardIdFromHeader) : null;
131
+ if (!cardId) {
132
+ const bodyCardId = typeof body?.card_id === "string"
133
+ ? body.card_id
123
134
  : null;
124
- walletId = toWalletId(bodyWalletId);
135
+ cardId = toCardId(bodyCardId);
125
136
  }
126
- if (walletId) {
127
- return handleCardPayment(c, next, walletId, effectiveAmount, currency, body, opts);
137
+ if (cardId) {
138
+ return handleCardPayment(c, next, cardId, effectiveAmount, currency, body, opts);
128
139
  }
129
140
  // Step 5: Neither → return 402 with Payment-Required header (Decision 8)
130
141
  return return402Response(c, effectiveAmount, currency);
@@ -133,23 +144,23 @@ function createAgentSpend(options) {
133
144
  // -------------------------------------------------------------------
134
145
  // handleCardPayment — existing charge() flow
135
146
  // -------------------------------------------------------------------
136
- async function handleCardPayment(c, next, walletId, amountCents, currency, body, opts) {
147
+ async function handleCardPayment(c, next, cardId, amountCents, currency, body, opts) {
137
148
  if (!options.serviceApiKey) {
138
149
  return c.json({ error: "Card payments require serviceApiKey" }, 500);
139
150
  }
140
151
  try {
141
- const chargeResult = await charge(walletId, {
152
+ const chargeResult = await charge(cardId, {
142
153
  amount_cents: amountCents,
143
154
  currency,
144
- description: opts?.description,
145
- metadata: opts?.metadata ? toStringMetadata(opts.metadata(body)) : undefined,
155
+ description: opts.description,
156
+ metadata: opts.metadata ? toStringMetadata(opts.metadata(body)) : undefined,
146
157
  idempotency_key: c.req.header("x-request-id") ?? c.req.header("idempotency-key") ?? undefined
147
158
  });
148
159
  const paymentContext = {
149
160
  method: "card",
150
161
  amount_cents: amountCents,
151
162
  currency,
152
- wallet_id: walletId,
163
+ card_id: cardId,
153
164
  remaining_limit_cents: chargeResult.remaining_limit_cents
154
165
  };
155
166
  c.set(PAYMENT_CONTEXT_KEY, paymentContext);
@@ -258,7 +269,7 @@ function createAgentSpend(options) {
258
269
  }
259
270
  }
260
271
  // -------------------------------------------------------------------
261
- // resolvePayToAddress — static wallet or Stripe Machine Payments
272
+ // resolvePayToAddress — static address or Stripe Machine Payments
262
273
  // -------------------------------------------------------------------
263
274
  async function resolvePayToAddress() {
264
275
  // Static address for crypto-only services
@@ -297,12 +308,12 @@ function createAgentSpend(options) {
297
308
  // ---------------------------------------------------------------------------
298
309
  // Helpers (unchanged from original)
299
310
  // ---------------------------------------------------------------------------
300
- function toWalletId(input) {
311
+ function toCardId(input) {
301
312
  if (typeof input !== "string") {
302
313
  return null;
303
314
  }
304
315
  const trimmed = input.trim();
305
- if (!trimmed.startsWith("wal_")) {
316
+ if (!trimmed.startsWith("card_")) {
306
317
  return null;
307
318
  }
308
319
  return trimmed;
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@agentspend/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
9
9
  "dependencies": {
10
- "@agentspend/types": "^0.2.0",
11
10
  "@x402/core": "^2.3.1"
12
11
  },
13
12
  "scripts": {
package/src/index.ts CHANGED
@@ -1,18 +1,43 @@
1
- import type {
2
- ChargeRequest,
3
- ChargeResponse,
4
- ErrorResponse,
5
- PaymentMethod,
6
- PaywallPaymentContext
7
- } from "@agentspend/types";
8
-
9
- export type {
10
- ChargeRequest,
11
- ChargeResponse,
12
- ErrorResponse,
13
- PaymentMethod,
14
- PaywallPaymentContext
15
- } from "@agentspend/types";
1
+ // ---------------------------------------------------------------------------
2
+ // Types (inlined from @agentspend/types to avoid cross-repo publish)
3
+ // ---------------------------------------------------------------------------
4
+
5
+ export interface ChargeRequest {
6
+ card_id: string;
7
+ amount_cents: number;
8
+ currency?: string;
9
+ description?: string;
10
+ metadata?: Record<string, string>;
11
+ idempotency_key?: string;
12
+ }
13
+
14
+ export interface ChargeResponse {
15
+ charged: true;
16
+ card_id: string;
17
+ amount_cents: number;
18
+ currency: string;
19
+ remaining_limit_cents: number;
20
+ stripe_payment_intent_id: string;
21
+ stripe_charge_id: string;
22
+ charge_attempt_id: string;
23
+ }
24
+
25
+ export interface ErrorResponse {
26
+ error: string;
27
+ }
28
+
29
+ export type PaymentMethod = "card" | "crypto";
30
+
31
+ export interface PaywallPaymentContext {
32
+ method: PaymentMethod;
33
+ amount_cents: number;
34
+ currency: string;
35
+ card_id?: string;
36
+ remaining_limit_cents?: number;
37
+ transaction_hash?: string;
38
+ payer_address?: string;
39
+ network?: string;
40
+ }
16
41
 
17
42
  // ---------------------------------------------------------------------------
18
43
  // x402 imports – server-side only (HTTP calls to facilitator, no crypto deps)
@@ -82,7 +107,7 @@ export interface HonoContextLike {
82
107
  url: string;
83
108
  method: string;
84
109
  };
85
- json(body: unknown, status?: number): unknown;
110
+ json(body: unknown, status?: number): Response;
86
111
  header(name: string, value: string): void;
87
112
  set(key: string, value: unknown): void;
88
113
  get(key: string): unknown;
@@ -93,11 +118,16 @@ export interface HonoContextLike {
93
118
  // ---------------------------------------------------------------------------
94
119
 
95
120
  export interface PaywallOptions {
121
+ /**
122
+ * Amount in cents.
123
+ * - number: fixed price (e.g. 500 = $5.00)
124
+ * - string: body field name to read amount from (e.g. "amount_cents")
125
+ * - function: custom dynamic pricing (body: unknown) => number
126
+ */
127
+ amount: number | string | ((body: unknown) => number);
96
128
  currency?: string;
97
129
  description?: string;
98
130
  metadata?: (body: unknown) => Record<string, unknown>;
99
- /** Dynamic pricing: derive amount from the parsed request body. */
100
- amountFromRequest?: (body: unknown) => number;
101
131
  }
102
132
 
103
133
  // ---------------------------------------------------------------------------
@@ -116,11 +146,8 @@ export function getPaymentContext(c: HonoContextLike): PaywallPaymentContext | n
116
146
  // ---------------------------------------------------------------------------
117
147
 
118
148
  export interface AgentSpend {
119
- charge(walletId: string, opts: ChargeOptions): Promise<ChargeResponse>;
120
- paywall(
121
- amountCents: number,
122
- opts?: PaywallOptions
123
- ): (c: HonoContextLike, next: () => Promise<void>) => Promise<unknown>;
149
+ charge(cardId: string, opts: ChargeOptions): Promise<ChargeResponse>;
150
+ paywall(opts: PaywallOptions): (c: HonoContextLike, next: () => Promise<void>) => Promise<Response | void>;
124
151
  }
125
152
 
126
153
  // ---------------------------------------------------------------------------
@@ -163,21 +190,21 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
163
190
  // charge() — card-only, unchanged
164
191
  // -------------------------------------------------------------------
165
192
 
166
- async function charge(walletIdInput: string, opts: ChargeOptions): Promise<ChargeResponse> {
193
+ async function charge(cardIdInput: string, opts: ChargeOptions): Promise<ChargeResponse> {
167
194
  if (!options.serviceApiKey) {
168
195
  throw new AgentSpendChargeError("charge() requires serviceApiKey", 500);
169
196
  }
170
197
 
171
- const walletId = toWalletId(walletIdInput);
172
- if (!walletId) {
173
- throw new AgentSpendChargeError("wallet_id must start with wal_", 400);
198
+ const cardId = toCardId(cardIdInput);
199
+ if (!cardId) {
200
+ throw new AgentSpendChargeError("card_id must start with card_", 400);
174
201
  }
175
202
  if (!Number.isInteger(opts.amount_cents) || opts.amount_cents <= 0) {
176
203
  throw new AgentSpendChargeError("amount_cents must be a positive integer", 400);
177
204
  }
178
205
 
179
206
  const payload: ChargeRequest = {
180
- wallet_id: walletId,
207
+ card_id: cardId,
181
208
  amount_cents: opts.amount_cents,
182
209
  currency: opts.currency ?? "usd",
183
210
  ...(opts.description ? { description: opts.description } : {}),
@@ -212,31 +239,39 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
212
239
  // paywall() — unified card + crypto middleware
213
240
  // -------------------------------------------------------------------
214
241
 
215
- function paywall(amountCents: number, opts?: PaywallOptions) {
216
- // Allow amountCents === 0 when amountFromRequest is provided (dynamic pricing)
217
- if (!opts?.amountFromRequest) {
218
- if (!Number.isInteger(amountCents) || amountCents <= 0) {
219
- throw new AgentSpendChargeError("amountCents must be a positive integer", 500);
242
+ function paywall(opts: PaywallOptions) {
243
+ const { amount } = opts;
244
+
245
+ // Validate fixed-price amount at creation time
246
+ if (typeof amount === "number") {
247
+ if (!Number.isInteger(amount) || amount <= 0) {
248
+ throw new AgentSpendChargeError("amount must be a positive integer", 500);
220
249
  }
221
250
  }
222
251
 
223
252
  return async function paywallMiddleware(
224
253
  c: HonoContextLike,
225
254
  next: () => Promise<void>
226
- ): Promise<unknown> {
255
+ ): Promise<Response | void> {
227
256
  // Step 1: Parse body once (Decision 11)
228
257
  const body: unknown = await c.req.json().catch(() => ({}));
229
258
 
230
259
  // Step 2: Determine effective amount
231
- let effectiveAmount = amountCents;
232
- if (opts?.amountFromRequest) {
233
- effectiveAmount = opts.amountFromRequest(body);
234
- if (!Number.isInteger(effectiveAmount) || effectiveAmount <= 0) {
235
- return c.json({ error: "Could not determine payment amount from request" }, 400);
236
- }
260
+ let effectiveAmount: number;
261
+ if (typeof amount === "number") {
262
+ effectiveAmount = amount;
263
+ } else if (typeof amount === "string") {
264
+ const raw = (body as Record<string, unknown>)?.[amount];
265
+ effectiveAmount = typeof raw === "number" ? raw : 0;
266
+ } else {
267
+ effectiveAmount = amount(body);
268
+ }
269
+
270
+ if (!Number.isInteger(effectiveAmount) || effectiveAmount <= 0) {
271
+ return c.json({ error: "Could not determine payment amount from request" }, 400);
237
272
  }
238
273
 
239
- const currency = opts?.currency ?? "usd";
274
+ const currency = opts.currency ?? "usd";
240
275
 
241
276
  // Step 3: Check for x-payment header → crypto payment
242
277
  const paymentHeader = c.req.header("x-payment");
@@ -244,19 +279,19 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
244
279
  return handleCryptoPayment(c, next, paymentHeader, effectiveAmount, currency, body, opts);
245
280
  }
246
281
 
247
- // Step 4: Check for x-wallet-id header or body.wallet_id → card payment
248
- const walletIdFromHeader = c.req.header("x-wallet-id");
249
- let walletId = walletIdFromHeader ? toWalletId(walletIdFromHeader) : null;
250
- if (!walletId) {
251
- const bodyWalletId =
252
- typeof (body as { wallet_id?: unknown })?.wallet_id === "string"
253
- ? (body as { wallet_id: string }).wallet_id
282
+ // Step 4: Check for x-card-id header or body.card_id → card payment
283
+ const cardIdFromHeader = c.req.header("x-card-id");
284
+ let cardId = cardIdFromHeader ? toCardId(cardIdFromHeader) : null;
285
+ if (!cardId) {
286
+ const bodyCardId =
287
+ typeof (body as { card_id?: unknown })?.card_id === "string"
288
+ ? (body as { card_id: string }).card_id
254
289
  : null;
255
- walletId = toWalletId(bodyWalletId);
290
+ cardId = toCardId(bodyCardId);
256
291
  }
257
292
 
258
- if (walletId) {
259
- return handleCardPayment(c, next, walletId, effectiveAmount, currency, body, opts);
293
+ if (cardId) {
294
+ return handleCardPayment(c, next, cardId, effectiveAmount, currency, body, opts);
260
295
  }
261
296
 
262
297
  // Step 5: Neither → return 402 with Payment-Required header (Decision 8)
@@ -271,22 +306,22 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
271
306
  async function handleCardPayment(
272
307
  c: HonoContextLike,
273
308
  next: () => Promise<void>,
274
- walletId: string,
309
+ cardId: string,
275
310
  amountCents: number,
276
311
  currency: string,
277
312
  body: unknown,
278
- opts?: PaywallOptions
279
- ): Promise<unknown> {
313
+ opts: PaywallOptions
314
+ ): Promise<Response | void> {
280
315
  if (!options.serviceApiKey) {
281
316
  return c.json({ error: "Card payments require serviceApiKey" }, 500);
282
317
  }
283
318
 
284
319
  try {
285
- const chargeResult = await charge(walletId, {
320
+ const chargeResult = await charge(cardId, {
286
321
  amount_cents: amountCents,
287
322
  currency,
288
- description: opts?.description,
289
- metadata: opts?.metadata ? toStringMetadata(opts.metadata(body)) : undefined,
323
+ description: opts.description,
324
+ metadata: opts.metadata ? toStringMetadata(opts.metadata(body)) : undefined,
290
325
  idempotency_key:
291
326
  c.req.header("x-request-id") ?? c.req.header("idempotency-key") ?? undefined
292
327
  });
@@ -295,7 +330,7 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
295
330
  method: "card",
296
331
  amount_cents: amountCents,
297
332
  currency,
298
- wallet_id: walletId,
333
+ card_id: cardId,
299
334
  remaining_limit_cents: chargeResult.remaining_limit_cents
300
335
  };
301
336
  c.set(PAYMENT_CONTEXT_KEY, paymentContext);
@@ -323,8 +358,8 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
323
358
  amountCents: number,
324
359
  currency: string,
325
360
  _body: unknown,
326
- _opts?: PaywallOptions
327
- ): Promise<unknown> {
361
+ _opts: PaywallOptions
362
+ ): Promise<Response | void> {
328
363
  if (!facilitator) {
329
364
  return c.json({ error: "Crypto payments not configured" }, 500);
330
365
  }
@@ -410,7 +445,7 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
410
445
  c: HonoContextLike,
411
446
  amountCents: number,
412
447
  currency: string
413
- ): Promise<unknown> {
448
+ ): Promise<Response> {
414
449
  try {
415
450
  const payTo = await resolvePayToAddress();
416
451
 
@@ -453,7 +488,7 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
453
488
  }
454
489
 
455
490
  // -------------------------------------------------------------------
456
- // resolvePayToAddress — static wallet or Stripe Machine Payments
491
+ // resolvePayToAddress — static address or Stripe Machine Payments
457
492
  // -------------------------------------------------------------------
458
493
 
459
494
  async function resolvePayToAddress(): Promise<string> {
@@ -504,12 +539,12 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
504
539
  // Helpers (unchanged from original)
505
540
  // ---------------------------------------------------------------------------
506
541
 
507
- function toWalletId(input: unknown): string | null {
542
+ function toCardId(input: unknown): string | null {
508
543
  if (typeof input !== "string") {
509
544
  return null;
510
545
  }
511
546
  const trimmed = input.trim();
512
- if (!trimmed.startsWith("wal_")) {
547
+ if (!trimmed.startsWith("card_")) {
513
548
  return null;
514
549
  }
515
550
  return trimmed;