clawallex_subscribe
Create a reloadable virtual card for managing recurring subscription payments, with options for wallet-based or on-chain funding.
Instructions
Set up a reloadable virtual card for recurring/subscription payments. Creates a stream card (card_type=200) that stays active and can be refilled via clawallex_refill.
Mode A (mode_code=100, default): wallet balance → stream card. Immediate settlement. Mode B (mode_code=200): for callers with self-custody wallets — signing is performed by the caller. Same x402 two-stage flow as clawallex_pay. The 402 response is EXPECTED (a quote, not an error). See clawallex_pay for full Stage 1/2 details.
Fee structure: fee_amount = issue_fee_amount + monthly_fee_amount + fx_fee_amount.
Example: clawallex_subscribe({ initial_amount: 100, description: 'AWS monthly billing' })
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| initial_amount | Yes | Initial deposit in USD | |
| description | Yes | Subscription purpose | |
| mode_code | No | 100=wallet (default), 200=x402 on-chain | |
| tx_limit | No | Per-transaction limit in USD (optional, default 100.0000) | |
| allowed_mcc | No | MCC whitelist, comma-separated (optional, e.g. '5734,5815') | |
| blocked_mcc | No | MCC blacklist, comma-separated (optional, e.g. '7995') | |
| client_request_id | No | UUID idempotency key (<=64 chars). Mode B Stage 2: MUST reuse from Stage 1. | |
| chain_code | No | Chain code for Mode B Stage 1 (e.g. 'ETH') | |
| token_code | No | Token code for Mode B Stage 1 (e.g. 'USDC') | |
| extra | No | Mode B Stage 2 (required): { card_amount, paid_amount } | |
| x402_reference_id | No | x402 reference ID. Card creation Stage 1: optional (server generates if omitted). Stage 2: use value from 402 response. Refill Mode B: required, serves as idempotency key. | |
| x402_version | No | x402 version (Mode B Stage 2, required) | |
| payment_payload | No | x402 payment payload (Mode B Stage 2, required) | |
| payment_requirements | No | x402 payment requirements (Mode B Stage 2, required) | |
| payer_address | No | Payer wallet address (optional, final value from verify) |
Implementation Reference
- src/tools/payment.ts:103-181 (handler)The registration and handler implementation for the 'clawallex_subscribe' tool. It sets up a subscription card (card_type=200) and handles Mode A (wallet) or Mode B (x402) payment workflows.
server.tool( "clawallex_subscribe", [ "Set up a reloadable virtual card for recurring/subscription payments.", "Creates a stream card (card_type=200) that stays active and can be refilled via clawallex_refill.", "", "Mode A (mode_code=100, default): wallet balance → stream card. Immediate settlement.", "Mode B (mode_code=200): for callers with self-custody wallets — signing is performed by the caller. Same x402 two-stage flow as clawallex_pay.", " The 402 response is EXPECTED (a quote, not an error). See clawallex_pay for full Stage 1/2 details.", "", "Fee structure: fee_amount = issue_fee_amount + monthly_fee_amount + fx_fee_amount.", "", "Example: clawallex_subscribe({ initial_amount: 100, description: 'AWS monthly billing' })", ].join("\n"), { initial_amount: z.number().describe("Initial deposit in USD"), description: z.string().describe("Subscription purpose"), mode_code: z.number().int().describe("100=wallet (default), 200=x402 on-chain").optional(), tx_limit: z.string().describe("Per-transaction limit in USD (optional, default 100.0000)").optional(), allowed_mcc: z.string().describe("MCC whitelist, comma-separated (optional, e.g. '5734,5815')").optional(), blocked_mcc: z.string().describe("MCC blacklist, comma-separated (optional, e.g. '7995')").optional(), client_request_id: z.string().max(64).describe("UUID idempotency key (<=64 chars). Mode B Stage 2: MUST reuse from Stage 1.").optional(), chain_code: z.string().describe("Chain code for Mode B Stage 1 (e.g. 'ETH')").optional(), token_code: z.string().describe("Token code for Mode B Stage 1 (e.g. 'USDC')").optional(), extra: z.record(z.unknown()).describe("Mode B Stage 2 (required): { card_amount, paid_amount }").optional(), ...x402Fields, }, async (params) => { try { const modeCode = params.mode_code ?? 100; if (modeCode === 200) { const hasX402 = params.x402_version !== undefined || params.payment_payload !== undefined || params.payment_requirements !== undefined; if (hasX402) { const missing: string[] = []; if (params.x402_version === undefined) missing.push("x402_version"); if (params.payment_payload === undefined) missing.push("payment_payload"); if (params.payment_requirements === undefined) missing.push("payment_requirements"); if (params.extra === undefined) missing.push("extra (must include card_amount and paid_amount)"); if (missing.length > 0) { return { content: [{ type: "text" as const, text: `Mode B Stage 2 missing required fields: ${missing.join(", ")}.` }], isError: true as const }; } } else { if (!params.chain_code || !params.token_code) { return { content: [{ type: "text" as const, text: "Mode B Stage 1 requires chain_code and token_code." }], isError: true as const }; } } } const body: Record<string, unknown> = { mode_code: modeCode, card_type: 200, amount: params.initial_amount.toFixed(4), client_request_id: params.client_request_id ?? randomUUID(), }; if (params.tx_limit) body.tx_limit = params.tx_limit; if (params.allowed_mcc) body.allowed_mcc = params.allowed_mcc; if (params.blocked_mcc) body.blocked_mcc = params.blocked_mcc; if (params.chain_code) body.chain_code = params.chain_code; if (params.token_code) body.token_code = params.token_code; if (params.x402_reference_id !== undefined) body.x402_reference_id = params.x402_reference_id; if (params.x402_version !== undefined) body.x402_version = params.x402_version; if (params.payment_payload !== undefined) body.payment_payload = params.payment_payload; if (params.payment_requirements !== undefined) body.payment_requirements = params.payment_requirements; if (params.extra !== undefined) body.extra = params.extra; if (params.payer_address !== undefined) body.payer_address = params.payer_address; const result = await client.post<unknown>("/payment/card-orders", body); return toolOk({ ...(result as Record<string, unknown>), _hint: `Stream card created for: ${params.description}. Use clawallex_refill when balance is low.`, }); } catch (err) { if (err instanceof ClawallexApiError && err.statusCode === 402 && err.details) { return formatX402Quote(err.details as Record<string, unknown>); } return toolError(err); } }, );