> For the complete documentation index, see [llms.txt](https://docs.trezalabs.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.trezalabs.com/api/x402-payments.md).

# x402 Payments

Treza integrates the [x402 protocol](https://docs.cdp.coinbase.com/x402/welcome) to enable instant, autonomous stablecoin micropayments for API access. AI agents and developers can pay for Treza services programmatically using USDC on Base, with no API keys, subscriptions, or manual billing required.

Two endpoints are payable:

* [**Pay-per-video**](#pay-per-video): send a prompt and a payment, get a finished clip back. No Treza account required.
* [**Credit top-up**](#funding-an-account-without-a-human): add to the prepaid balance that pipeline runs draw from.

### What is x402?

x402 is an open payment protocol built by [Coinbase](https://docs.cdp.coinbase.com/x402/welcome) that uses the HTTP `402 Payment Required` status code. When a client requests a paid resource:

1. The server responds with `402` and payment instructions (price, network, recipient)
2. The client signs a USDC payment
3. The client retries the request with a `Payment-Signature` header
4. The server verifies the payment, returns the data, and settles on-chain

Payments are instant, permissionless, and settled in USDC on Base (L2).

### How Treza Uses x402

#### Paid Endpoints

| Endpoint                    | Method | Price      | Description                                                                         |
| --------------------------- | ------ | ---------- | ----------------------------------------------------------------------------------- |
| `/api/x402/video`           | POST   | from $0.42 | Generate a video from a prompt and return it. Priced per second of output, by model |
| `/api/billing/credits/x402` | POST   | $5.00      | Top up a prepaid credit balance                                                     |

### Pay-Per-Video

`POST /api/x402/video` generates a video from a text prompt and returns it. Pay once per clip. No Treza account, API key, or signup is required. The payment is the only credential.

#### Price

Price is quoted per request and scales with clip length and the model you pick. Read it off the 402 challenge rather than hard-coding it.

| Clip length | `minimax-h3` (default) | `seedance-2.5` |
| ----------- | ---------------------- | -------------- |
| 5 seconds   | $0.42                  | $1.64          |
| 10 seconds  | $0.84                  | $3.27          |
| 15 seconds  | $1.26                  | $4.90          |

`16:9` and `9:16` cost the same.

#### Models

Send `model` to pick one. Omit it and the default renders.

| `model`                | What you get                                                       | Worth knowing                                                                                                                                                                                                                       |
| ---------------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `minimax-h3` (default) | 768p, native audio, the fewest prompt refusals of anything we run  | The right choice unless you have a reason to pay more                                                                                                                                                                               |
| `seedance-2.5`         | 720p, native audio, higher fidelity, at about four times the price | Its content filter is strict: prompts that resemble a brand, a broadcast, or a famous scene are refused. A refusal is not charged, and the status response carries a `retryUrl` that renders a reworded prompt without paying again |

A `model` value that is not on this list is refused with a `400` before any payment moves, naming the ones that are. Nothing is ever silently swapped for the default.

To read the current list and ladder programmatically, `GET /api/x402/video` with no query parameters. It returns the models on sale and what each is for, the sizes and prices, the request shape, and the limits. No payment or credential is needed.

```bash
curl https://www.trezalabs.com/api/x402/video
```

```json
{
  "service": "Treza pay-per-video",
  "howToBuy": {
    "method": "POST",
    "body": { "prompt": "a manta ray gliding over a coral reef", "seconds": 5, "aspectRatio": "16:9", "model": "minimax-h3" }
  },
  "models": [
    { "id": "minimax-h3", "label": "MiniMax Hailuo 3", "default": true, "note": "...", "prices": [{ "seconds": 5, "priceUsd": 0.42 }, { "seconds": 10, "priceUsd": 0.84 }, { "seconds": 15, "priceUsd": 1.26 }] },
    { "id": "seedance-2.5", "label": "ByteDance Seedance 2.5", "default": false, "note": "...", "prices": [{ "seconds": 5, "priceUsd": 1.64 }, { "seconds": 10, "priceUsd": 3.27 }, { "seconds": 15, "priceUsd": 4.9 }] }
  ],
  "offers": [
    { "model": "minimax-h3", "seconds": 5, "aspectRatio": "16:9", "priceUsd": 0.42 },
    { "model": "minimax-h3", "seconds": 10, "aspectRatio": "16:9", "priceUsd": 0.84 },
    { "model": "minimax-h3", "seconds": 15, "aspectRatio": "16:9", "priceUsd": 1.26 },
    { "model": "seedance-2.5", "seconds": 5, "aspectRatio": "16:9", "priceUsd": 1.64 }
  ],
  "limits": { "maxPromptChars": 2000, "seconds": [5, 10, 15], "aspectRatio": ["16:9", "9:16"], "model": ["minimax-h3", "seedance-2.5"] }
}
```

#### Request

```json
{
  "prompt": "a manta ray gliding over a sunlit coral reef, slow cinematic drift",
  "seconds": 5,
  "aspectRatio": "16:9",
  "model": "minimax-h3"
}
```

| Field         | Required | Default      | Notes                                                                   |
| ------------- | -------- | ------------ | ----------------------------------------------------------------------- |
| `prompt`      | Yes      | —            | What the video should show. Max 2000 characters                         |
| `seconds`     | No       | `5`          | One of `5`, `10`, `15`. Drives the price                                |
| `aspectRatio` | No       | `16:9`       | `16:9` or `9:16`                                                        |
| `model`       | No       | `minimax-h3` | `minimax-h3` or `seedance-2.5`. Drives the price. See [Models](#models) |

These four fields are the whole request. A request asking for a size or model that is not on sale, or carrying any field the endpoint does not read, is refused with a `400` **before the payment settles**, so a malformed call costs nothing, and nothing you send can be silently ignored and paid for.

#### Flow

Renders take a few minutes, so a paid call returns `202` immediately with a run id and a `statusUrl` containing a signed token. Poll that URL for the result.

```bash
# 1. Ask. With no payment you get the challenge back.
curl -X POST https://www.trezalabs.com/api/x402/video \
  -H 'content-type: application/json' \
  -d '{"prompt":"a manta ray gliding over a sunlit coral reef","seconds":5}'

# HTTP/2 402
# Payment-Required: <base64 challenge carrying price, network and payTo>
```

Any x402 client signs and retries for you. On success:

```json
{
  "runId": "2026-08-23T18:01:22.045Z#9df91f98",
  "status": "running",
  "statusUrl": "https://www.trezalabs.com/api/x402/video?runId=...&token=...",
  "pollAfterMs": 15000,
  "paidUsd": 0.42,
  "model": "minimax-h3",
  "seconds": 5,
  "aspectRatio": "16:9",
  "network": "eip155:8453",
  "transaction": "0x6d9154...",
  "payer": "0x0ac0ab..."
}
```

Poll `statusUrl` until `status` is no longer `running`. The token in the URL is the only credential it needs.

```json
{
  "runId": "2026-08-23T18:01:22.045Z#9df91f98",
  "status": "success",
  "durationMs": 260672,
  "video": "https://www.trezalabs.com/api/media/generated/x402_video/....mp4?s=...",
  "outputs": { "video": "https://..." }
}
```

#### When a render fails

A render can fail after the payment has settled, most often because the model declined the prompt. Nothing is charged for a failed render, so the payment stays on your wallet's account and the retry spends it instead of costing you again.

The status response for a failed run carries what went wrong and what to do about it:

```json
{
  "runId": "2026-09-03T17:29:52.032Z#4509944a",
  "status": "partial",
  "error": "The prompt was declined by the model.",
  "failedStep": "Video Generation",
  "reason": "prompt_refused",
  "retryable": true,
  "retryUrl": "https://www.trezalabs.com/api/x402/video/retry?runId=...&token=...",
  "balanceUsd": 5.9
}
```

| Field        | Notes                                                                                                                                                |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `reason`     | `prompt_refused` means the model declined the prompt, so reword it. `render_failed` means the render did not finish, and the same prompt may succeed |
| `retryable`  | `true` until the run's one free retry has been used                                                                                                  |
| `retryUrl`   | Where to retry. It carries the same signed ticket, so it needs no other credential                                                                   |
| `balanceUsd` | Credit left on your wallet's account, which the retry spends                                                                                         |

`POST` the `retryUrl` to render again without paying twice. Send `{"prompt": "..."}` to reword, which is the fix for `prompt_refused`, or send no body to run the original prompt again. Each failed run can be retried once. The answer is a `202` with a new `runId` and `statusUrl`, exactly like the paid POST.

```bash
curl -X POST "$RETRY_URL" \
  -H 'content-type: application/json' \
  -d '{"prompt":"a manta ray gliding over a coral reef at dawn"}'
```

#### Billing

Your payment credits an account keyed to your wallet address, and the render is charged against that balance. Anything left over stays as credit for your next call. The same wallet always maps to the same account.

A failed render is not charged, so the payment remains available for a retry.

#### Full example

```typescript
import { x402Client } from '@x402/core/client';
import { registerExactEvmScheme } from '@x402/evm/exact/client';
import { safeBase64Encode, safeBase64Decode } from '@x402/core/utils';
import { privateKeyToAccount } from 'viem/accounts';

const ENDPOINT = 'https://www.trezalabs.com/api/x402/video';
const body = JSON.stringify({ prompt: 'a manta ray gliding over a coral reef', seconds: 5 });

const post = (paymentHeader?: string) =>
  fetch(ENDPOINT, {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      ...(paymentHeader ? { 'PAYMENT-SIGNATURE': paymentHeader } : {}),
    },
    body,
  });

// 1. Unpaid request returns the challenge, priced for this clip length.
const challenge = await post();
const paymentRequired = JSON.parse(safeBase64Decode(challenge.headers.get('payment-required')!));

// 2. Sign a payment for it.
const client = new x402Client();
registerExactEvmScheme(client, { signer: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`) });
const payload = await client.createPaymentPayload(paymentRequired);

// 3. Pay, then poll the ticket you get back.
const paid = await post(safeBase64Encode(JSON.stringify(payload)));
const { statusUrl, pollAfterMs } = await paid.json();

while (true) {
  await new Promise((r) => setTimeout(r, pollAfterMs));
  const run = await (await fetch(statusUrl)).json();
  if (run.status !== 'running') {
    console.log(run.video);
    break;
  }
}
```

A worked example is at [trezalabs.com/x402](https://www.trezalabs.com/x402).

### Funding an Account Without a Human

This is the one most agents want. Pipeline runs draw a prepaid credit balance, and an agent holding a wallet can refill that balance itself, with nobody signing in to a billing page.

Ask what the balance is and how to add to it, using [`get_credit_balance`](/api/mcp-server.md) over MCP or `GET /api/account/balance` with an API key:

```json
{
  "balanceUsd": 1.13,
  "typicalVideoChargeUsd": 1.06,
  "topUpUrl": "https://www.trezalabs.com/platform/settings",
  "x402": {
    "url": "https://www.trezalabs.com/api/billing/credits/x402",
    "topUpPerCallUsd": 5,
    "network": "eip155:8453"
  }
}
```

An `x402` block means agent-native top-up is available on this deployment. `topUpUrl` is the human path; the rest of this page is the other one.

**Paying the endpoint**

`PAYMENT-SIGNATURE` carries the payment and is the only required header.

`Authorization` is optional and selects which account is credited. Send a Treza credential (API key, OAuth token, or session) to credit that account; send none and the credits go to an account keyed to the paying wallet address.

```typescript
import { x402Client } from '@x402/core/client';
import { registerExactEvmScheme } from '@x402/evm/exact/client';
import { safeBase64Encode, safeBase64Decode } from '@x402/core/utils';
import { privateKeyToAccount } from 'viem/accounts';

const ENDPOINT = 'https://www.trezalabs.com/api/billing/credits/x402';
const headers = { authorization: `Bearer ${process.env.TREZA_API_KEY}` };

// 1. Ask, and get the terms back.
const challenge = await fetch(ENDPOINT, { method: 'POST', headers });
const paymentRequired = JSON.parse(
  safeBase64Decode(challenge.headers.get('payment-required')!)
);

// 2. Sign a payment for exactly those terms.
const client = new x402Client();
registerExactEvmScheme(client, { signer: privateKeyToAccount(process.env.WALLET_KEY) });
const payload = await client.createPaymentPayload(paymentRequired);

// 3. Ask again, paying.
const paid = await fetch(ENDPOINT, {
  method: 'POST',
  headers: { ...headers, 'PAYMENT-SIGNATURE': safeBase64Encode(JSON.stringify(payload)) },
});
console.log(await paid.json());
```

A successful call returns the grant and the transaction that paid for it:

```json
{
  "grantedUsd": 5,
  "duplicate": false,
  "balanceUsd": 16.13,
  "network": "eip155:8453",
  "transaction": "0x3e08158c2933cf4174d4f6b7429cdebd2df23b91f135c5a59eaef11a6cbd6450",
  "payer": "0x0Ac0AB6C04C3A92C929e35b39Be88E445360c199"
}
```

Call it again to add another $5. The credits are spendable immediately.

{% hint style="info" %}
The wallet needs USDC on Base mainnet (`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`). The facilitator broadcasts the transfer, so the wallet does not need ETH for gas.
{% endhint %}

**Paying twice for the same thing is not possible**

The ledger entry is keyed to the settled transaction hash, so a repeated request credits once. A replayed payment does not even reach that check: the authorization nonce is already spent on-chain, and the facilitator rejects it.

```json
{ "error": "invalid_payload: authorization nonce already submitted; transaction already on-chain" }
```

**When a payment is refused**

The response says why, rather than repeating the challenge:

| Message                                                  | Meaning                                                    |
| -------------------------------------------------------- | ---------------------------------------------------------- |
| `invalid_payload: ... execution reverted`                | The wallet cannot cover the payment                        |
| `invalid_payload: authorization nonce already submitted` | This payment was already spent                             |
| `Invalid or expired credentials`                         | The bearer is wrong, or the key lacks a `pipelines:` scope |
| `x402 payments are not configured on this deployment`    | Agent-native top-up is off here; use `topUpUrl`            |

Authorization is checked before the payment settles, so a request refused for a bad bearer costs nothing.

#### Payment Flow

```
Client                          Treza API                     Facilitator         Base L2
  │                                │                              │                  │
  │── POST /api/x402/video ───────▶│                              │                  │
  │                                │                              │                  │
  │◀── 402 Payment Required ───────│                              │                  │
  │    price: $0.42                │                              │                  │
  │    network: eip155:8453        │                              │                  │
  │    payTo: 0xTreza...           │                              │                  │
  │                                │                              │                  │
  │── Sign USDC payment ──┐        │                              │                  │
  │◀── Payment-Signature ─┘        │                              │                  │
  │                                │                              │                  │
  │── POST /api/x402/video ───────▶│                              │                  │
  │    + Payment-Signature         │                              │                  │
  │                                │── Verify payment ───────────▶│                  │
  │                                │◀── Valid ─────────────────── │                  │
  │                                │                              │                  │
  │◀── 202 runId + statusUrl ──────│                              │                  │
  │                                │── Settle payment ───────────▶│── USDC tx ──────▶│
  │                                │                              │                  │
```

### Client-Side: Paying for Treza Services

#### Using the Treza SDK (Enclave as Wallet)

A Treza Enclave can act as the payment wallet itself, keeping the private key inside the hardware-isolated TEE. This is optional; any viem-compatible account works just as well.

**Install Dependencies**

```bash
npm install @treza/sdk @x402/core @x402/evm @x402/fetch
```

**Auto-Paying Fetch**

The simplest approach. `createEnclaveFetch` returns a `fetch` function that automatically handles 402 responses:

```typescript
import { TrezaClient, createEnclaveFetch } from '@treza/sdk';

const treza = new TrezaClient({
  baseUrl: 'https://trezalabs.com',
});

const paidFetch = await createEnclaveFetch(treza, {
  enclaveId: 'enc_abc123',
  verifyAttestation: true,  // verify enclave integrity before each payment
});

// Payments are handled automatically
const response = await paidFetch('https://www.trezalabs.com/api/x402/video', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ prompt: 'a manta ray gliding over a coral reef', seconds: 5 }),
});
const { statusUrl } = await response.json();
```

**x402 Client (Advanced)**

For more control, use the x402 client directly:

```typescript
import { TrezaClient, createEnclaveX402Client } from '@treza/sdk';

const treza = new TrezaClient({
  baseUrl: 'https://trezalabs.com',
});

const { x402, account } = await createEnclaveX402Client(treza, {
  enclaveId: 'enc_abc123',
  verifyAttestation: true,
});

// account.address → the enclave's signing address (fund this with USDC)
console.log('Payment wallet:', account.address);
```

**Enclave Account (Low-Level)**

Create a viem-compatible account backed by the enclave for use with any x402 library:

```typescript
import { TrezaClient, createEnclaveAccount } from '@treza/sdk';

const treza = new TrezaClient({
  baseUrl: 'https://trezalabs.com',
});

const account = await createEnclaveAccount(treza, {
  enclaveId: 'enc_abc123',
  verifyAttestation: true,
});

// Use with x402 directly
import { x402Client } from '@x402/core/client';
import { registerExactEvmScheme } from '@x402/evm/exact/client';

const client = new x402Client();
registerExactEvmScheme(client, { signer: account });
```

#### Using Any x402 Client (External Wallet)

You don't need the Treza SDK to pay. Any x402-compatible wallet works:

```typescript
import { wrapFetchWithPayment } from '@x402/fetch';
import { x402Client } from '@x402/core/client';
import { registerExactEvmScheme } from '@x402/evm/exact/client';
import { privateKeyToAccount } from 'viem/accounts';

const account = privateKeyToAccount('0xYourPrivateKey...');

const client = new x402Client();
registerExactEvmScheme(client, { signer: account });

const paidFetch = wrapFetchWithPayment(fetch, client);

const response = await paidFetch('https://www.trezalabs.com/api/x402/video', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ prompt: 'a manta ray gliding over a coral reef', seconds: 5 }),
});
```

#### Using curl (Manual)

To inspect the 402 response without paying:

```bash
curl -i -X POST https://www.trezalabs.com/api/x402/video \
  -d '{"prompt":"a manta ray gliding over a coral reef","seconds":5}'

# HTTP/2 402
# Payment-Required: <base64 challenge>
#
# Decoded, the challenge carries the price for the clip length you asked for:
# {"accepts":[{"scheme":"exact","amount":"420000","network":"eip155:8453","payTo":"0x..."}],...}
```

Amounts are in token atomic units, so `420000` is 0.42 USDC.

### Server-Side: Adding x402 to Your Own Endpoints

If you're building on the Treza platform and want to monetize your own API endpoints, use the `withX402Payment` wrapper.

#### Basic Usage

```typescript
import { NextRequest, NextResponse } from 'next/server';
import { withX402Payment } from '@/lib/x402';

async function handleGET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
): Promise<NextResponse> {
  // Your endpoint logic here
  return NextResponse.json({ data: 'your response' });
}

export const GET = withX402Payment(handleGET, {
  price: '0.001',       // USDC price per request
  description: 'Get resource data',
});
```

#### With Bazaar Discovery

Make your endpoint discoverable by AI agents on the [x402 Bazaar](https://docs.cdp.coinbase.com/x402/bazaar):

```typescript
export const POST = withX402Payment(handlePOST, {
  // A fixed price, or a function of the request body for per-request pricing.
  price: (body) => `$${priceFor(body).toFixed(2)}`,
  // Name the route. Without this it registers as `*`, which the Bazaar
  // publishes under a generated template like `:var1`.
  routePattern: 'POST /api/x402/video',
  serviceName: 'Treza',
  tags: ['video', 'text-to-video', 'ai'],
  description: 'Generate a video from a text prompt and get the file back.',
  discovery: {
    method: 'POST',
    bodyType: 'json',
    input: { prompt: 'a manta ray gliding over a coral reef', seconds: 5 },
    inputSchema: {
      type: 'object',
      properties: {
        prompt: { type: 'string' },
        seconds: { type: 'number', enum: [5, 10, 15] },
      },
      required: ['prompt'],
    },
    output: {
      example: { runId: '...', status: 'running', statusUrl: 'https://...' },
    },
  },
});
```

Declare `method` and `bodyType` for any route that takes a request body. Without them the listing describes the route as query-parameterized, and an agent will send its arguments in the URL of a request that only reads JSON.

#### Environment Variables

| Variable               | Required          | Default                                         | Description                                                  |
| ---------------------- | ----------------- | ----------------------------------------------- | ------------------------------------------------------------ |
| `X402_ENABLED`         | No                | `false`                                         | Set to `true` to enable x402 payment gating                  |
| `TREZA_X402_PAY_TO`    | Yes (if enabled)  | none                                            | Wallet address that receives USDC payments                   |
| `X402_NETWORK`         | No                | `eip155:8453`                                   | Network identifier (Base mainnet)                            |
| `X402_FACILITATOR_URL` | No                | `https://api.cdp.coinbase.com/platform/v2/x402` | Payment verification facilitator                             |
| `X402_CDP_API_KEY`     | Yes (CDP mainnet) | none                                            | CDP API key id; the CDP facilitator authenticates every call |
| `X402_CDP_API_SECRET`  | Yes (CDP mainnet) | none                                            | CDP API key secret                                           |
| `X402_TOPUP_USD`       | No                | `5`                                             | USD credited per successful top-up call                      |

{% hint style="warning" %}
Mainnet settlement runs through Coinbase's facilitator, which authenticates every verify and settle call. Without `X402_CDP_API_KEY` and `X402_CDP_API_SECRET` the endpoint fails closed with a 503 and stops advertising itself, rather than answering payments it cannot settle.
{% endhint %}

**Testnet Configuration**

```env
X402_ENABLED=true
TREZA_X402_PAY_TO=0xYourTestnetAddress
X402_NETWORK=eip155:84532
X402_FACILITATOR_URL=https://www.x402.org/facilitator
```

**Mainnet Configuration**

```env
X402_ENABLED=true
TREZA_X402_PAY_TO=0xYourWalletAddress
X402_NETWORK=eip155:8453
X402_FACILITATOR_URL=https://api.cdp.coinbase.com/platform/v2/x402

# Pay-per-video. Each model and clip size on sale is its own published
# pipeline, because model and duration live in a video-gen node's saved
# config. Keys are <model>-<seconds>s-<aspect>. Unset leaves it off.
X402_VIDEO_PIPELINES={"minimax-h3-5s-16x9":"...","minimax-h3-5s-9x16":"...","seedance-2.5-5s-16x9":"..."}
# Provider cost per generated second on the default model. Price is this times
# the credits markup.
X402_VIDEO_PER_SECOND_USD=0.06
# Per-model overrides, keyed by public model id, for re-pricing one model
# without a deploy when its provider rate moves.
X402_VIDEO_MODEL_RATES_USD={"seedance-2.5":0.233}
```

### Discovering Payable Services

AI agents can discover Treza's x402-payable endpoints through the Bazaar:

```typescript
import { discoverPayableServices } from '@treza/sdk';

const services = await discoverPayableServices({
  maxPrice: '0.01',          // filter by max price per call
  network: 'eip155:8453',   // filter by network
});

services.forEach(service => {
  console.log(service.url, service.description, service.accepts);
});
```

### Security Model

| Layer                        | Protection                                                                                                                  |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **TEE Signing**              | Payment signatures are created inside the hardware-isolated enclave, so private keys never leave the Nitro Enclave boundary |
| **Attestation Verification** | Optional pre-signing attestation check ensures the enclave is untampered before authorizing payments                        |
| **Facilitator Verification** | Payment signatures are verified by the Coinbase facilitator before the server returns data                                  |
| **On-Chain Settlement**      | Payments settle as real USDC transfers on Base, providing an immutable audit trail                                          |
| **Replay Protection**        | Each payment signature is bound to a specific request and cannot be reused                                                  |

### Architecture

```
┌─────────────────────────────────────────────────────────┐
│  AI Agent / Client                                      │
│  ┌───────────────┐  ┌──────────────┐                    │
│  │  @treza/sdk   │  │  @x402/fetch │                    │
│  │  createEnclave│──│  auto-pay    │                    │
│  │  Fetch()      │  │  on 402      │                    │
│  └───────┬───────┘  └──────────────┘                    │
│          │                                              │
│  ┌───────▼───────┐                                      │
│  │ EnclaveAccount│  Signs payments inside TEE           │
│  └───────┬───────┘                                      │
└──────────│──────────────────────────────────────────────┘
           │
           ▼
┌──────────────────┐     ┌──────────────────┐     ┌──────┐
│  Treza Platform  │────▶│  Facilitator     │────▶│ Base │
│  withX402Payment │     │  (Coinbase/x402) │     │  L2  │
│  402 → verify →  │     │  verify + settle │     │ USDC │
│  respond + settle│     │                  │     │      │
└──────────────────┘     └──────────────────┘     └──────┘
```

### FAQ

**Do I need USDC to use Treza?** Only if x402 is enabled on the endpoint you're calling. During development and on testnet, x402 is disabled by default.

**Which network are payments on?** Base (Coinbase L2). Testnet uses Base Sepolia, mainnet uses Base mainnet. Both settle in USDC.

**Can I use a regular wallet instead of an enclave?** Yes. Any viem-compatible account or x402 client works. The enclave-as-wallet pattern is optional; it just adds the security of TEE-based key management.

**How much do API calls cost?** Video generation is priced per second of output and by model, from $0.42 for a five-second clip on the default model; the 402 challenge quotes the exact figure for what you asked for, and `GET /api/x402/video` lists every model's ladder. Credit top-up is $5.00 per call.

**Do I need a Treza account?** No, for either x402 endpoint. Video generation needs only the payment, and credit top-up without a bearer credits an account keyed to your wallet address. An account is required for the pipeline API.

**What if the render fails?** A failed render is not charged. The payment stays as credit on your wallet's account, and the status response carries a `retryUrl` you can POST to render again without paying twice, optionally with a reworded prompt. See [When a render fails](#when-a-render-fails).

**Is there a minimum balance?** No minimum. You just need enough USDC in your wallet to cover the call price.

### Related

* [x402 Protocol Documentation](https://docs.cdp.coinbase.com/x402/welcome)
* [x402 Bazaar](https://docs.cdp.coinbase.com/x402/bazaar)
* [Coinbase Payments MCP](https://docs.cdp.coinbase.com/payments-mcp/welcome)
* [Pay-per-video walkthrough](https://www.trezalabs.com/x402)
* [Treza SDK README](https://github.com/treza-labs/treza-sdk)
* [Agent Commerce Guide](https://github.com/treza-labs/treza-sdk/blob/main/docs/AGENT_COMMERCE_GUIDE.md)
