ASG Card Documentation
Virtual card issuance for AI agents. Pay via Stellar x402 (USDC) or Stripe Machine Payments — get a card in seconds.
https://api.asgcard.dev
Overview
ASG Card exposes a REST API with five classes of endpoints:
| Type | Auth | Description |
|---|---|---|
| Public | None | Health check, pricing, tiers |
| Paid (x402) | USDC payment on Stellar via x402 | Create/fund cards (Stellar edition) |
| Wallet-signed | Ed25519 signature | Card management (Stellar edition) |
| Stripe Session | X-STRIPE-SESSION header |
Session, payment requests, card management (Stripe edition) |
| Stripe Approval | One-time token in URL | Owner approval and payment (Stripe edition) |
SDK
The official client SDK wraps the raw x402 flow (402 → parse challenge → pay USDC → retry with proof) into one-liner methods. No need to handle the payment handshake yourself.
Install
npm install @asgcard/sdk
Quick Start
import { ASGCardClient } from '@asgcard/sdk';
const client = new ASGCardClient({
privateKey: '<stellar_secret_seed>',
baseUrl: 'https://api.asgcard.dev',
rpcUrl: 'https://mainnet.sorobanrpc.com',
});
// One line — SDK handles payment automatically
const card = await client.createCard({
amount: 10, // $10 tier
nameOnCard: 'AI AGENT',
email: 'agent@example.com',
});
console.log(card.details); // { cardNumber, cvv, expiry, … }
Configuration
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
privateKey |
string |
One of two | — | Stellar secret seed (for signing) |
walletAdapter |
WalletAdapter |
One of two | — | Stellar wallet adapter (publicKey + signTransaction) |
baseUrl |
string |
No | https://api.asgcard.dev |
API base URL |
rpcUrl |
string |
No | https://horizon.stellar.org |
Stellar Horizon or RPC endpoint |
timeout |
number |
No | 60000 |
Request timeout in milliseconds |
Methods
client.createCard(params): Promise<CardResult>
Create a virtual card. Pays USDC automatically.
| Field | Type | Values |
|---|---|---|
amount | number | Any amount $5–$5,000 |
nameOnCard | string | Name embossed on card |
email | string | Delivery email |
const result = await client.createCard({
amount: 50,
nameOnCard: 'AI AGENT',
email: 'agent@example.com',
});
client.fundCard(params): Promise<FundResult>
Fund an existing card.
| Field | Type | Values |
|---|---|---|
amount | number | Any amount $5–$5,000 |
cardId | string | UUID of existing card |
const result = await client.fundCard({
amount: 25,
cardId: 'card-uuid',
});
client.getPricing(): Promise<PricingResponse>
Get pricing info: card $10, top-up 3.5% (no payment required).
client.health(): Promise<HealthResponse>
Check if the ASG Card API is reachable.
client.address: string
The Stellar wallet address being used for payments.
Error Handling
import {
ASGCardClient,
InsufficientBalanceError,
PaymentError,
ApiError,
TimeoutError,
} from '@asgcard/sdk';
try {
const card = await client.createCard({ amount: 50, nameOnCard: 'AI', email: 'a@b.com' });
} catch (error) {
if (error instanceof InsufficientBalanceError) {
console.log(`Need ${error.required}, have ${error.available}`);
} else if (error instanceof PaymentError) {
console.log(`Payment failed: ${error.message}, tx: ${error.txHash}`);
} else if (error instanceof ApiError) {
console.log(`Server error ${error.status}:`, error.body);
} else if (error instanceof TimeoutError) {
console.log('Request timed out');
}
}
| Class | Fields | When |
|---|---|---|
InsufficientBalanceError | required, available | USDC balance < required |
PaymentError | message, txHash? | Stellar tx failed |
ApiError | status, body | Server returned non-2xx |
TimeoutError | message | Request exceeded timeout |
Low-Level x402 Utilities
For full control over the payment flow:
import {
parseChallenge,
checkBalance,
executePayment,
buildPaymentPayload,
buildPaymentTransaction,
handleX402Payment,
} from '@asgcard/sdk';
| Function | Signature | Description |
|---|---|---|
parseChallenge |
(input: unknown) → X402Accept |
Parse 402 challenge, returns first accepted method |
checkBalance |
(params) → Promise<void> |
Throws InsufficientBalanceError if USDC < required |
executePayment |
(params) → Promise<string> |
Sends USDC on Stellar, returns txHash |
buildPaymentPayload |
(accepted, signedXDR) → string |
Builds base64-encoded X-PAYMENT header value |
buildPaymentTransaction |
(params) → Promise<string> |
Build + sign a Soroban SAC USDC transfer |
handleX402Payment |
(params) → Promise<string> |
Full cycle: parse → pay → build proof |
How It Works
Sequence diagram showing the SDK flow:
SDK handles the 402 → pay → retry cycle automatically.
MCP Server
The @asgcard/mcp-server package exposes 9 tools via the Model Context Protocol, enabling AI agents to manage ASG Card programmatically.
~/.asgcard/wallet.json automatically. Run asgcard wallet create once, and all MCP clients pick it up.
Agent Quick Start
One command — creates wallet, configures MCP, installs skill:
npx @asgcard/cli onboard -y
First-Class Clients
One-click installer included:
asgcard install --client codex # OpenAI Codex
asgcard install --client claude # Claude Code
asgcard install --client cursor # Cursor
Compatible Agent Runtimes
OpenClaw, Manus, Perplexity Computer, and other MCP-compatible agents work via manual config or the bundled SDK:
Codex (~/.codex/config.toml):
[mcp_servers.asgcard]
command = "npx"
args = ["-y", "@asgcard/mcp-server"]
Cursor / generic MCP (mcp.json):
{
"mcpServers": {
"asgcard": {
"command": "npx",
"args": ["-y", "@asgcard/mcp-server"]
}
}
}
SDK / direct API: Use @asgcard/sdk for agents without MCP support.
Tools
All 9 tools exposed by the MCP server:
| Tool | Description | Auth |
|---|---|---|
get_wallet_status | Use FIRST — wallet address, USDC balance, readiness | None |
create_card | Create a virtual MasterCard ($5–$5,000) | x402 |
fund_card | Add funds to an existing card | x402 |
list_cards | List all cards owned by the wallet | Wallet |
get_card | Get card summary (balance, status) | Wallet |
get_card_details | Retrieve PAN, CVV, expiry | Wallet + Nonce |
freeze_card | Temporarily block all transactions | Wallet |
unfreeze_card | Re-enable a frozen card | Wallet |
get_pricing | View pricing (card $10, top-up 3.5%) | None |
Example — create a card via your AI agent:
Agent Skill (x402)
The CLI bundles a product-owned asgcard skill that is automatically installed during asgcard onboard.
asgcard onboard installs the skill to ~/.agents/skills/asgcard/Compatible runtimes: For OpenClaw, Manus, custom LLM pipelines — use the x402-payments-skill or call the SDK/API directly.
CLI
The @asgcard/cli package provides a terminal interface for ASG Card — onboard, create, fund, freeze, and inspect virtual cards from your command line.
Install
npm install -g @asgcard/cli
Agent Quick Start:
# Full onboarding (wallet + MCP + skill)
asgcard onboard -y
# Then install for your client:
asgcard install --client codex # or claude, cursor
# Or step by step:
asgcard wallet create
asgcard wallet info
asgcard card:create -a 10 -n "AGENT ALPHA" -e agent@example.com
Commands
| Command | Description |
|---|---|
asgcard wallet create | Generate new Stellar keypair, save to ~/.asgcard/wallet.json |
asgcard wallet import | Import an existing Stellar secret key |
asgcard wallet info | Show public key, USDC balance, deposit instructions |
asgcard install --client <c> | Configure MCP for codex, claude, or cursor |
asgcard onboard [-y] | Full onboarding: wallet + MCP + skill + next step |
asgcard doctor | Diagnose setup (key, API, RPC, balance, MCP configs) |
asgcard login | Configure Stellar private key (legacy) |
asgcard whoami | Display wallet public key |
asgcard cards | List all cards for the wallet |
asgcard card <id> | Show card summary (balance, status) |
asgcard card:details <id> | Retrieve PAN, CVV, expiry (nonce-protected) |
asgcard card:create | Create a new card (x402 payment) |
asgcard card:fund <id> | Top up an existing card |
asgcard card:freeze <id> | Freeze a card |
asgcard card:unfreeze <id> | Unfreeze a card |
asgcard pricing | View pricing (card $10, top-up 3.5%) |
asgcard health | Check API health status |
Authentication
ASG Card uses two authentication modes depending on the endpoint.
x402 Payment Flow
Paid endpoints (POST /cards/create/tier/:amount, POST /cards/fund/tier/:amount) use the x402 protocol on Stellar. The flow has 4 steps:
Step 1 — Request without payment
curl -X POST https://api.asgcard.dev/cards/create/tier/10 \
-H "Content-Type: application/json" \
-d '{"nameOnCard": "AGENT ALPHA", "email": "agent@example.com"}'
Step 2 — Receive 402 with payment instructions
The server responds with HTTP 402 and a challenge JSON:
{
"x402Version": 2,
"resource": {
"url": "https://api.asgcard.dev/cards/create/tier/100",
"description": "Create ASG Card with $100 load",
"mimeType": "application/json"
},
"accepts": [{
"scheme": "exact",
"network": "stellar:pubnet",
"asset": "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
"amount": "1135000000",
"payTo": "GAHYHA55RTD2J4LAVJILTNHWMF2H2YVK5QXLQT3CHCJSVET3VRWPOCW6",
"maxTimeoutSeconds": 300,
"extra": { "areFeesSponsored": true }
}]
}
| Field | Description |
|---|---|
scheme | Always "exact" |
network | "stellar:pubnet" |
asset | USDC SAC on Stellar mainnet |
amount | Amount in atomic USDC (7 decimals). 1 USDC = 10,000,000 |
payTo | ASG Treasury public key |
maxTimeoutSeconds | Payment window (300s) |
Step 3 — Agent pays USDC on Stellar
Parse the accepts array and send the specified USDC amount to the payTo address on Stellar, then proceed with facilitator verification if enabled.
Step 4 — Retry with X-PAYMENT header
Re-send the original request with an X-PAYMENT header containing base64-encoded JSON (x402 PaymentPayload):
{
"x402Version": 2,
"accepted": {
"scheme": "exact",
"network": "stellar:pubnet"
},
"payload": {
"transaction": "<BASE64_STELLAR_TX_ENVELOPE>"
}
}
X-PAYMENT: base64(JSON) — the SDK handles this automatically. The facilitator verifies and settles the transaction.
Stripe Machine Payments Flow
The Stripe MPP flow is an owner-in-the-loop model. The agent creates a payment request, and a human owner approves and pays via Stripe.
Step 1 — Create a session
curl -X POST https://api.asgcard.dev/stripe-beta/session \
-H "Content-Type: application/json" \
-d '{"email": "owner@company.com"}'
Response: {"sessionId": "sess_abc123", ...}
Step 2 — Create a payment request
curl -X POST https://api.asgcard.dev/stripe-beta/payment-requests \
-H "Content-Type: application/json" \
-H "X-STRIPE-SESSION: sess_abc123" \
-d '{"amountUsd": 100, "cardholderName": "AI Agent", "email": "owner@company.com"}'
Response includes status: "approval_required" and an approvalUrl.
Step 3 — Owner approves and pays
The owner opens the approvalUrl (at stripe.asgcard.dev/approve), reviews the request, and completes payment via Stripe checkout.
Step 4 — Agent polls for completion
curl https://api.asgcard.dev/stripe-beta/payment-requests/pr_xyz789 \
-H "X-STRIPE-SESSION: sess_abc123"
When status changes to completed, the card is ready. Use GET /stripe-beta/cards to retrieve card details.
Wallet Signature — Free Endpoints
Wallet-signed endpoints (card management) require Ed25519 signature authentication.
Required Headers
| Header | Description |
|---|---|
X-WALLET-ADDRESS | Stellar public key |
X-WALLET-SIGNATURE | Ed25519 detached signature |
X-WALLET-TIMESTAMP | Unix timestamp (seconds) |
Signature Protocol
message = "asgcard-auth:<unixTimestamp>"
algorithm = Ed25519 detached
validity window = ±5 minutes
const timestamp = Math.floor(Date.now() / 1000);
const message = `asgcard-auth:${timestamp}`;
// wallet.signMessage should return detached Ed25519 signature bytes
const signature = await wallet.signMessage(new TextEncoder().encode(message));
const response = await fetch('https://api.asgcard.dev/cards', {
headers: {
'X-WALLET-ADDRESS': wallet.publicKey,
'X-WALLET-SIGNATURE': Buffer.from(signature).toString('base64'),
'X-WALLET-TIMESTAMP': String(timestamp),
},
});
Pricing
(initial load optional)
That's it. Load any amount from $5.00 to $5000.00.
Card Creation
Load $100.00 onto a new card — you pay $113.50 total. Same pricing on both Stellar and Stripe rails.
Card Funding
Top up $200.00 later — just $207.00. No card fee on top-ups.
Endpoints
Public Endpoints
No authentication required.
/health
Health check. No authentication required.
Response 200:{
"status": "ok",
"timestamp": "2026-02-11T14:00:00.000Z",
"version": "1.0.0"
}
/pricing
Returns current pricing: $10 flat card creation, 3.5% on loads. Initial load optional.
Response 200:{
"cardFee": 10,
"topUpPercent": 3.5,
"minAmount": 5,
"maxAmount": 5000,
"description": "$10 flat card creation. Initial load optional. 3.5% on loads."
}
/cards/tiers
Alias for /pricing. Returns the same pricing info.
{
"cardFee": 10,
"topUpPercent": 3.5,
"minAmount": 5,
"maxAmount": 5000,
"description": "$10 flat card creation. Initial load optional. 3.5% on loads."
}
Paid Endpoints — x402
These endpoints require USDC payment via the x402 protocol on Stellar. See Authentication → x402 Payment Flow.
/cards/create/tier/:amount
Create a new virtual card. Amount 0 = card-only ($10 flat fee). Amount $5–$5,000 = card with initial load ($10 + amount + 3.5%).
Amount range: $5 – $5,000
| Field | Type | Required | Description |
|---|---|---|---|
nameOnCard | string | Yes | Min 1 char |
email | string | Yes | Valid email |
{
"success": true,
"card": {
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"nameOnCard": "AGENT ALPHA",
"balance": 10,
"status": "active",
"createdAt": "2026-02-11T14:00:00.000Z"
},
"payment": {
"amountCharged": 20.35,
"txHash": "<stellar_tx_hash>",
"network": "stellar"
},
"detailsEnvelope": {
"cardNumber": "5395000000007890",
"expiryMonth": 12,
"expiryYear": 2028,
"cvv": "123",
"billingAddress": {
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94105",
"country": "US"
},
"oneTimeAccess": true,
"expiresInSeconds": 300,
"note": "Store securely. Use GET /cards/:id/details with X-AGENT-NONCE for subsequent access."
}
}
/cards/fund/tier/:amount
Add funds to an existing card.
Request body:| Field | Type | Required | Description |
|---|---|---|---|
cardId | string | Yes | UUID of existing card |
{
"success": true,
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"fundedAmount": 25,
"newBalance": 35.0,
"payment": {
"amountCharged": 29.5,
"txHash": "<stellar_tx_hash>",
"network": "stellar"
}
}
Wallet-Signed Endpoints
These endpoints are free but require wallet signature authentication. See Authentication → Wallet Signature.
/cards
List all cards owned by the authenticated wallet.
Response 200:{
"cards": [{
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"nameOnCard": "AGENT ALPHA",
"lastFour": "7890",
"balance": 10.0,
"status": "active",
"createdAt": "2026-02-11T14:00:00.000Z"
}]
}
/cards/:cardId
Get detailed info for a specific card.
Response 200:{
"card": {
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"nameOnCard": "AGENT ALPHA",
"email": "agent@example.com",
"balance": 8.5,
"initialAmountUsd": 10,
"status": "active",
"createdAt": "2026-02-11T14:00:00.000Z",
"updatedAt": "2026-02-11T15:30:00.000Z"
}
}
/cards/:cardId/details
Retrieve sensitive card details — full card number, CVV, expiry, and billing address. See Agent-First Details for the full protocol.
X-AGENT-NONCE header (UUID v4). Rate limited to 5 unique nonces per card per hour. Returns 409 on replay, 403 if owner revoked access.
| Header | Description |
|---|---|
X-WALLET-ADDRESS | Stellar public key |
X-WALLET-SIGNATURE | Ed25519 detached signature |
X-WALLET-TIMESTAMP | Unix timestamp (seconds) |
X-AGENT-NONCE | UUID v4 — unique per request, anti-replay |
{
"details": {
"cardNumber": "5395000000007890",
"expiryMonth": 12,
"expiryYear": 2028,
"cvv": "123",
"billingAddress": {
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94105",
"country": "US"
}
}
}
| Code | When | Body |
|---|---|---|
403 | Owner revoked details access | {"error":"Details access revoked by card owner"} |
409 | Nonce already used (replay) | {"error":"Nonce already used (replay detected)","code":"REPLAY_REJECTED"} |
429 | Rate limit exceeded | {"error":"Card details rate limit exceeded (5 requests / hour)"} |
/cards/:cardId/freeze
Freeze a card. Blocks all transactions until unfrozen.
Response 200:{
"success": true,
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"status": "frozen"
}
/cards/:cardId/unfreeze
Unfreeze a previously frozen card.
Response 200:{
"success": true,
"cardId": "550e8400-e29b-41d4-a716-446655440000",
"status": "active"
}
Stripe MPP Endpoints
These endpoints use session-based authentication via X-STRIPE-SESSION header. See Authentication → Stripe MPP Flow.
/stripe-beta/session
Create a managed session. Returns sessionKey (store securely — shown only once).
{ "email": "owner@company.com" }
{
"sessionId": "abc123...",
"ownerId": "owner_xyz...",
"sessionKey": "sk_sess_...",
"managedWalletAddress": "G...",
"note": "Store this sessionKey securely. It will not be shown again."
}
/stripe-beta/payment-requests
Create a payment request. Amount 0 = card-only ($10). Amount $5–$5,000 = card with initial load.
Request body:{
"amountUsd": 100,
"nameOnCard": "AI Agent",
"description": "Virtual card for agent"
}
{
"status": "approval_required",
"requestId": "pr_...",
"approvalUrl": "https://stripe.asgcard.dev/approve?id=pr_...&token=...",
"expiresAt": "2026-03-21T..."
}
/stripe-beta/payment-requests/:id
Poll payment request status. Returns pending, approved, completed, rejected, expired, or failed.
/stripe-beta/approve/:id?token=...
Get approval page data. Token-based auth — no session needed.
/stripe-beta/approve/:id
Approve or reject a payment request. Body: {"action": "approve", "token": "..."}
/stripe-beta/cards
List all cards created in this session.
/stripe-beta/cards/:id/details
Retrieve PAN, CVV, expiry for a Stripe-edition card. Requires X-AGENT-NONCE header.
Agent-First Details Access
ASG Card uses an agent-first model for sensitive card data. Card details (number, CVV, expiry) are delivered via two mechanisms designed for autonomous agents.
Details Envelope
When a card is created via POST /cards/create/tier/:amount, the 201 response includes a detailsEnvelope field with full card details:
{
"success": true,
"card": { "cardId": "...", "status": "active" },
"payment": { "txHash": "...", "network": "stellar" },
"detailsEnvelope": {
"cardNumber": "5395000000007890",
"expiryMonth": 12,
"expiryYear": 2028,
"cvv": "123",
"billingAddress": {
"street": "123 Main St",
"city": "San Francisco",
"state": "CA",
"zip": "94105",
"country": "US"
},
"oneTimeAccess": true,
"expiresInSeconds": 300
}
}
detailsEnvelope is returned only in the initial 201 response. It is not stored server-side. Agents should persist card details securely on their side.
GET /cards/:cardId/details
If the agent loses the initial envelope, card details can be retrieved via GET /cards/:cardId/details using wallet signature authentication plus a unique nonce.
Required Headers
| Header | Type | Description |
|---|---|---|
X-WALLET-ADDRESS | string | Stellar public key (G...) |
X-WALLET-SIGNATURE | string | Ed25519 detached signature (base64) |
X-WALLET-TIMESTAMP | string | Unix timestamp (seconds) |
X-AGENT-NONCE | string | UUID v4 — must be unique per request |
import { v4 as uuid } from 'uuid';
const nonce = uuid();
const timestamp = Math.floor(Date.now() / 1000);
const message = `asgcard-auth:${timestamp}`;
const signature = await wallet.signMessage(new TextEncoder().encode(message));
const res = await fetch('https://api.asgcard.dev/cards/<cardId>/details', {
headers: {
'X-WALLET-ADDRESS': wallet.publicKey,
'X-WALLET-SIGNATURE': Buffer.from(signature).toString('base64'),
'X-WALLET-TIMESTAMP': String(timestamp),
'X-AGENT-NONCE': nonce,
},
});
if (res.status === 409) {
// Nonce replay detected — generate a new UUID and retry
}
if (res.status === 403) {
// Card owner has revoked details access
}
Nonce & Anti-Replay (409)
Every call to GET /cards/:cardId/details requires a fresh X-AGENT-NONCE (UUID v4). If a nonce has already been used for the same card, the server returns:
HTTP/1.1 409 Conflict
{
"error": "Nonce already used (replay detected)",
"code": "REPLAY_REJECTED"
}
This prevents replay attacks and ensures each details retrieval is intentional. Combined with the 5-request-per-hour rate limit per card, this protects cardholder data.
Revoke / Restore
Card owners can control whether agents (or themselves, via the portal) can retrieve card details:
| Action | Endpoint | Effect |
|---|---|---|
| Revoke | POST /cards/:cardId/revoke-details |
Blocks all future GET /details → returns 403 |
| Restore | POST /cards/:cardId/restore-details |
Re-enables GET /details access |
Both endpoints require wallet signature authentication (same headers as card management). Revoked status returns:
HTTP/1.1 403 Forbidden
{
"error": "Details access revoked by card owner"
}
Errors
All non-2xx responses return:
{ "error": "Human-readable error message" }
| HTTP Code | When | Example |
|---|---|---|
400 |
Unsupported tier, invalid body | {"error":"Unsupported tier amount"} |
401 |
Invalid wallet auth or X-Payment proof | {"error":"Invalid wallet signature"} |
402 |
x402 challenge (no X-Payment header) |
Challenge JSON (see x402 Flow) |
403 |
Details access revoked by card owner | {"error":"Details access revoked by card owner"} |
404 |
Card not found | {"error":"Card not found"} |
409 |
Nonce replay detected | {"error":"Nonce already used (replay detected)","code":"REPLAY_REJECTED"} |
429 |
Details endpoint rate limit | {"error":"Card details rate limit exceeded (5 requests / hour)"} |
503 |
Provider capacity unavailable (issuer cannot fund requested tier) | {"error":"Service temporarily unavailable","reason":"provider_capacity","retryAfter":60} |
500 |
Unexpected internal error | {"error":"Internal server error"} |
Rate Limits
| Endpoint | Limit | Window |
|---|---|---|
GET /cards/:cardId/details | 5 requests per card | 1 hour |
| All other endpoints | Standard per-IP limits apply | — |
Exceeding a rate limit returns 429 Too Many Requests. If the response includes a Retry-After header, wait the indicated duration before retrying.
Architecture
Request Lifecycle
End-to-end sequence for a paid card creation via x402.
x402 payment lifecycle — agent pays USDC on Stellar, API verifies on-chain before issuing the card.
Runtime Components
Internal routing and middleware layout of the ASG Card API.
Public routes require no auth. Paid routes pass through x402. Wallet routes use Ed25519 signatures. All converge on Card Service.