# OpenCard API Documentation

**x402-Powered Virtual Card Issuance for AI Agents**

OpenCard lets AI agents autonomously purchase virtual prepaid cards by paying with USDC via the x402 payment protocol.

**No accounts. No API keys. No signups. Payment is authentication.**

## Base URL

```
https://api.opencard.dev
```

## Overview

OpenCard exposes a REST API with three classes of endpoints:

| Type | Auth Method | Cost | Use Case |
|------|-------------|------|----------|
| Public | None | Free | Health checks, pricing info, tier discovery |
| Paid (x402) | USDC payment | Varies by tier | Creating cards |
| Wallet-signed | Ed25519/ECDSA signature | Free | Viewing cards |

### Supported Networks

- **BNB** (preferred) — Lower fees, faster confirmation
- **Base** — EVM alternative

---

## SDK

The official client SDK wraps the raw x402 flow into one-liner methods.

### Install

```bash
npm install @opencardcode/opencard-sdk @bnb/web3.js
```

### Quick Start (BNB)

```typescript
import { OpenCardClient } from '@opencardcode/opencard-sdk';

const client = new OpenCardClient({
  bnbPrivateKey: 'base58-private-key',
  network: 'bnb',  // default
});

const result = await client.createCard({
  amount: 10,               // $10 tier
  nameOnCard: 'AI AGENT',
  email: 'agent@example.com',
});

console.log(result.order);  // { cardId, status: 'processing' }
// Card details delivered via webhook (5-15 min)
```

### Quick Start (Base)

```typescript
import { OpenCardClient } from '@opencardcode/opencard-sdk';

const client = new OpenCardClient({
  privateKey: '0x...',  // Base wallet with USDC
  network: 'base',
});
```

### Configuration

`new OpenCardClient(config)`

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `network` | `"bnb" \| "base"` | No | Payment network (default: `"bnb"`) |
| `bnbPrivateKey` | `string` | One of | Base58-encoded BNB secret key |
| `bnbKeypair` | `Keypair` | One of | @bnb/web3.js Keypair instance |
| `privateKey` | `0x${string}` | One of | EVM hex private key (for Base) |
| `walletClient` | `WalletClient` | One of | viem WalletClient (for Base) |
| `baseUrl` | `string` | No | API URL (default: `https://api.opencard.dev`) |
| `timeout` | `number` | No | Request timeout in ms (default: 60000) |

### Methods

#### `client.createCard(params): Promise<CardResult>`

Create a virtual card. Pays USDC automatically.

```typescript
const result = await client.createCard({
  amount: 50,    // 10 | 25 | 50 | 100 | 200 | 500
  nameOnCard: 'AI AGENT',
  email: 'agent@example.com',
  webhookUrl: 'https://your-agent.com/card-callback',  // optional
});
```

#### `client.getTiers(): Promise<Tier[]>`

Get pricing tiers and fee breakdown (no payment required).

#### `client.health(): Promise<{ status: string }>`

Check if the OpenCard API is reachable.

#### `client.address: string`

The wallet address being used for payments.

### Error Handling

```typescript
import {
  OpenCardClient,
  InsufficientBalanceError,
  PaymentError,
  ConfigError,
  ApiError,
} from '@opencardcode/opencard-sdk';

try {
  const result = await client.createCard({ ... });
} 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}`);
  } else if (error instanceof ConfigError) {
    console.log(`Configuration error: ${error.message}`);
  } else if (error instanceof ApiError) {
    console.log(`Server error ${error.status}:`, error.body);
  }
}
```

---

## Authentication

### x402 Payment Flow

Paid endpoints use the [x402 protocol](https://x402.org) — your agent pays USDC, and the payment itself serves as authentication.

**Step 1 — Request without payment**

```bash
curl -X POST https://api.opencard.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**

```json
{
  "x402Version": 1,
  "accepts": [
    {
      "scheme": "exact",
      "network": "bnb:mainnet",
      "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "maxAmountRequired": "11800000",
      "payTo": "6NsXb5ChS8fxH9N3qvtMzGNZ6k2RABxuq3fgwB9hnnB",
      "maxTimeoutSeconds": 300,
      "extra": { "chainName": "BNB" }
    },
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "maxAmountRequired": "11800000",
      "payTo": "0x6A119204301bF22E7358f30A6DA0BFbF7A6B9E68",
      "maxTimeoutSeconds": 300,
      "extra": { "chainName": "Base" }
    }
  ]
}
```

| Field | Description |
|-------|-------------|
| `network` | `bnb:mainnet` or `eip155:8453` (Base) |
| `asset` | USDC contract/mint address |
| `maxAmountRequired` | Amount in USDC (6 decimals): 11800000 = $11.80 |
| `payTo` | Treasury wallet address |

**Step 3 — Agent pays USDC**

Send the specified USDC amount to the `payTo` address on your chosen network.

**Step 4 — Retry with payment proof**

Resend the original request with the `X-Payment` header containing a base64-encoded JSON payload:

```json
{
  "scheme": "exact",
  "network": "bnb:mainnet",
  "payload": {
    "authorization": {
      "from": "YourAgentWalletPublicKey",
      "to": "TreasuryPublicKey",
      "value": "11800000"
    },
    "txHash": "YourTransactionSignature..."
  }
}
```

### Wallet Signature (Free Endpoints)

For read operations, authenticate by signing a message with your wallet.

**Required Headers:**

| Header | Description |
|--------|-------------|
| `X-WALLET-ADDRESS` | Your wallet public key |
| `X-WALLET-SIGNATURE` | Signature (base58 for BNB, hex for EVM) |
| `X-WALLET-TIMESTAMP` | Unix timestamp (within 5 minutes) |

**Message Format:**

```
opencard-auth:<unix_timestamp>
```

> Timestamps older than 5 minutes are rejected. Always generate a fresh timestamp for each request.

---

## Pricing

Cards are **single-use prepaid cards** (not reloadable).

| Card Value | Total Cost | Endpoint |
|------------|------------|----------|
| $10 | ~$11.80 | `/cards/create/tier/10` |
| $25 | ~$28.00 | `/cards/create/tier/25` |
| $50 | ~$55.00 | `/cards/create/tier/50` |
| $100 | ~$109.00 | `/cards/create/tier/100` |
| $200 | ~$217.00 | `/cards/create/tier/200` |
| $500 | ~$541.00 | `/cards/create/tier/500` |

Prices are estimates. The 402 response contains the exact amount required.

**Fee Breakdown:**
- Provider fee (~6%)
- Service fee (2%)
- Safety buffer ($0.50)

---

## Endpoints

### Public Endpoints

These require no authentication.

#### `GET /health`

Health check.

```json
{
  "status": "ok",
  "timestamp": "2026-02-27T00:00:00.000Z",
  "version": "2.0.0",
  "service": "OpenCard"
}
```

#### `GET /pricing`

Full pricing breakdown.

```json
{
  "cardCreation": {
    "providerFeePercent": 6,
    "ourMarkupPercent": 2,
    "safetyBuffer": 0.5,
    "example": {
      "loadAmount": 50,
      "totalCostUsd": 55
    }
  },
  "network": "base",
  "asset": "USDC",
  "tiers": {
    "creation": [
      { "loadAmount": 10, "totalCost": 11.8, "endpoint": "/cards/create/tier/10" }
    ]
  }
}
```

#### `GET /cards/tiers`

Available tiers with fee breakdowns.

---

### Paid Endpoints (x402)

These endpoints require USDC payment via the x402 protocol.

#### `POST /cards/create/tier/:amount`

Create a new virtual card.

**Tiers:** 10, 25, 50, 100, 200, 500

**Request Body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `nameOnCard` | string | Yes | Cardholder name (auto-uppercased) |
| `email` | string | Yes | Email for card delivery |
| `webhookUrl` | string | No | URL to receive card details when ready |

**Response (202 Accepted):**

```json
{
  "success": true,
  "order": {
    "cardId": "550e8400-e29b-41d4-a716-446655440000",
    "tradeId": "abc123",
    "status": "processing",
    "loadAmount": 10,
    "createdAt": "2026-02-27T00:00:00.000Z"
  },
  "delivery": {
    "method": "webhook",
    "webhookUrl": "https://your-agent.com/callback",
    "estimatedWait": "5-15 minutes",
    "statusEndpoint": "/cards/550e8400.../status"
  },
  "payment": {
    "amountCharged": 11.8,
    "txHash": "...",
    "network": "bnb"
  }
}
```

> **Note:** Card details are delivered asynchronously via webhook (5-15 minutes). The response contains an order status, not card details.

---

### Wallet-Signed Endpoints

These endpoints are free but require wallet signature authentication.

#### `GET /cards`

List all cards owned by the authenticated wallet.

```json
{
  "cards": [{
    "cardId": "550e8400-...",
    "nameOnCard": "AGENT ALPHA",
    "loadAmount": 10,
    "status": "completed",
    "createdAt": "2026-02-27T00:00:00.000Z"
  }]
}
```

#### `GET /cards/:cardId`

Get card details. If completed, includes decrypted card info.

```json
{
  "cardId": "550e8400-...",
  "status": "completed",
  "details": {
    "cardNumber": "4111111111111111",
    "cvv": "123",
    "expiryMonth": "12",
    "expiryYear": "2028",
    "billingAddress": { ... }
  }
}
```

#### `GET /cards/:cardId/status`

Lightweight status check (no card details).

---

## Webhooks

When a card is ready, OpenCard POSTs to your `webhookUrl`:

**Success:**

```json
{
  "orderId": "550e8400-...",
  "status": "completed",
  "cardDetails": {
    "cardNumber": "4111111111111111",
    "cvv": "123",
    "expiryMonth": "12",
    "expiryYear": "2028",
    "billingAddress": { ... }
  },
  "timestamp": "2026-02-27T00:15:00.000Z"
}
```

**Failure:**

```json
{
  "orderId": "550e8400-...",
  "status": "failed",
  "error": "Card provider rejected the order",
  "timestamp": "2026-02-27T00:15:00.000Z"
}
```

---

## Errors

| Status | Meaning |
|--------|---------|
| 400 | Invalid request body or parameters |
| 401 | Missing or invalid authentication |
| 402 | Payment required — follow the x402 flow |
| 404 | Card not found |
| 429 | Rate limit exceeded |
| 500 | Internal server error |

---

## Rate Limits

| Scope | Limit |
|-------|-------|
| General API | 30 requests / min per IP |
| Paid endpoints | 10 requests / min per IP |
| Webhook endpoint | 30 requests / min per IP |

---

## Architecture

```
AI Agent (BNB/Base wallet + USDC)
        |
        v
   HTTP Request (no auth)
        |
        v
+------------------------------+
|        OpenCard API          |
|     (Express + x402)         |
|                              |
|  x402 paid:                  |
|   POST /cards/create/tier/N  |
|                              |
|  Wallet-signed (free):       |
|   GET  /cards                |
|   GET  /cards/:id            |
|   GET  /cards/:id/status     |
|                              |
|  Public:                     |
|   GET  /health               |
|   GET  /pricing              |
|   GET  /cards/tiers          |
+----------+-------------------+
           |
     +-----+-----+
     v           v
 Treasury     Card
 (USDC)       Provider
     |             |
     +------+------+
            v
      Card Delivered
      via Webhook
```
