create_card_order
Create virtual cards for online payments using wallet balance or on-chain USDC, with options for single-use or reloadable cards.
Instructions
Advanced: create a virtual card with full control over payment mode and card type. Maps directly to POST /payment/card-orders. Most agents should use clawallex_pay or clawallex_subscribe instead.
Mode A (mode_code=100): wallet balance deduction, immediate settlement. Mode B (mode_code=200): for callers with self-custody wallets — signing is performed by the caller. x402 two-stage flow: Stage 1 (Quote): provide chain_code + token_code. The 402 response is EXPECTED (a quote, NOT an error). Returns: payee_address, asset_address, x402_reference_id, fee breakdown, payable_amount. Agent signs: construct and sign an EIP-3009 transferWithAuthorization using your own wallet/signing library. Stage 2 requires the resulting signature and your wallet address (authorization.from). authorization fields: from=your wallet, to=payee_address, value=maxAmountRequired, validAfter/validBefore=unix seconds validity window, nonce=random 32-byte hex (unique per auth). Stage 2 (Settle): reuse SAME client_request_id + provide x402_version, payment_payload, payment_requirements, extra. - payment_requirements.payTo MUST equal payee_address from Stage 1 - payment_requirements.asset MUST equal asset_address from Stage 1 - maxAmountRequired = payable_amount × 10^decimals (USDC = 6, e.g. '207.59' → '207590000'). If settle rejected, order stays pending_payment — retry with same client_request_id.
card_type: 100=flash (single-use), 200=stream (reloadable). Fee: flash = issue_fee + fx_fee; stream = issue_fee + monthly_fee + fx_fee.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mode_code | Yes | Payment mode: 100=Mode A (wallet balance), 200=Mode B (x402 on-chain USDC) | |
| card_type | Yes | Card type: 100=flash (single-use), 200=stream (reloadable via refill_card) | |
| amount | Yes | Card face amount in USD, decimal string e.g. '100.0000' | |
| client_request_id | Yes | UUID idempotency key — MUST be same for both Stage 1 and Stage 2 | |
| fee_amount | No | Fee amount in USD (optional, must match server-calculated fee if provided) | |
| 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') | |
| chain_code | No | Chain code for Mode B Stage 1 (e.g. 'ETH', 'BASE') | |
| token_code | No | Token code for Mode B Stage 1 (e.g. 'USDC') | |
| extra | No | Mode B Stage 2: { 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/cards.ts:73-121 (handler)Handler function for create_card_order that processes request parameters, constructs the request body, and calls the Clawallex API. It also includes specific handling for the Mode B (x402) flow.
async (params) => { try { if (params.mode_code === 200) { const hasX402Fields = params.x402_version !== undefined || params.payment_payload !== undefined || params.payment_requirements !== undefined; if (hasX402Fields) { 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(", ")}. All x402 fields are required for settlement.` }], 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 (e.g. chain_code='ETH', token_code='USDC')." }], isError: true as const }; } } } const body: Record<string, unknown> = { mode_code: params.mode_code, card_type: params.card_type, amount: params.amount, client_request_id: params.client_request_id, }; if (params.fee_amount !== undefined) body.fee_amount = params.fee_amount; 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); } catch (err) { // Mode B Stage 1: 402 is the challenge response, not an error if (err instanceof ClawallexApiError && err.statusCode === 402 && err.details) { return formatX402Quote(err.details as Record<string, unknown>); } return toolError(err); } }, ); - src/tools/cards.ts:24-72 (registration)Registration of the "create_card_order" MCP tool, including documentation and input schema validation using Zod.
server.tool( "create_card_order", [ "Advanced: create a virtual card with full control over payment mode and card type.", "Maps directly to POST /payment/card-orders. Most agents should use clawallex_pay or clawallex_subscribe instead.", "", "Mode A (mode_code=100): wallet balance deduction, immediate settlement.", "Mode B (mode_code=200): for callers with self-custody wallets — signing is performed by the caller. x402 two-stage flow:", " Stage 1 (Quote): provide chain_code + token_code. The 402 response is EXPECTED (a quote, NOT an error).", " Returns: payee_address, asset_address, x402_reference_id, fee breakdown, payable_amount.", " Agent signs: construct and sign an EIP-3009 transferWithAuthorization using your own wallet/signing library.", " Stage 2 requires the resulting signature and your wallet address (authorization.from).", " authorization fields: from=your wallet, to=payee_address, value=maxAmountRequired,", " validAfter/validBefore=unix seconds validity window, nonce=random 32-byte hex (unique per auth).", " Stage 2 (Settle): reuse SAME client_request_id + provide x402_version, payment_payload, payment_requirements, extra.", " - payment_requirements.payTo MUST equal payee_address from Stage 1", " - payment_requirements.asset MUST equal asset_address from Stage 1", " - maxAmountRequired = payable_amount × 10^decimals (USDC = 6, e.g. '207.59' → '207590000').", " If settle rejected, order stays pending_payment — retry with same client_request_id.", "", "card_type: 100=flash (single-use), 200=stream (reloadable).", "Fee: flash = issue_fee + fx_fee; stream = issue_fee + monthly_fee + fx_fee.", ].join("\n"), { mode_code: z .number() .int() .describe("Payment mode: 100=Mode A (wallet balance), 200=Mode B (x402 on-chain USDC)"), card_type: z .number() .int() .describe("Card type: 100=flash (single-use), 200=stream (reloadable via refill_card)"), amount: z.string().describe("Card face amount in USD, decimal string e.g. '100.0000'"), client_request_id: z .string() .max(64) .describe("UUID idempotency key — MUST be same for both Stage 1 and Stage 2"), fee_amount: z .string() .describe("Fee amount in USD (optional, must match server-calculated fee if provided)") .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(), chain_code: z.string().describe("Chain code for Mode B Stage 1 (e.g. 'ETH', 'BASE')").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: { card_amount, paid_amount }").optional(), ...x402Fields, },