> For the complete documentation index, see [llms.txt](https://docs.silverbackdefi.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.silverbackdefi.app/silverback-ai-agent/seller-integration.md).

# Seller Integration

How to accept multi-token x402 payments on your own endpoints using the Silverback Facilitator.

***

## Overview

If you run an API and want to charge per-request using x402, the Silverback Facilitator handles all the payment complexity for you. You just need to:

1. Return the right **402 response** when a client hasn't paid
2. Point to the **Silverback Facilitator** as your payment processor
3. Choose which **tokens** you want to accept

The facilitator handles signature verification, on-chain settlement, fee splitting, and transaction confirmation. You focus on your API.

***

## What You Need

* A wallet address on Base to receive payments
* An Express.js server (or any HTTP server)
* The `@x402/express` package (or build your own 402 responses)

***

## Step 1: Install Dependencies

```bash
npm install @x402/express
```

***

## Step 2: Configure Your Server

Set these environment variables:

```bash
# Required
X402_WALLET_ADDRESS=0xYourWalletAddress      # Where you receive payments

# Facilitator
SILVERBACK_FACILITATOR_URL=https://facilitator.silverbackdefi.app
```

***

## Step 3: Set Up Payment Middleware

### Option A: Using the x402 Express Package

```javascript
import express from 'express';
import { paymentMiddleware } from '@x402/express';

const app = express();

// Configure the Silverback facilitator
const facilitatorUrl = 'https://facilitator.silverbackdefi.app';

// Define your paid routes with prices
const paidRoutes = {
  '/api/v1/my-endpoint': {
    price: '$0.01',
    network: 'eip155:8453',
    config: {
      description: 'My paid endpoint'
    }
  }
};

// Add payment middleware
app.use(paymentMiddleware(
  facilitatorUrl,
  paidRoutes,
  { walletAddress: process.env.X402_WALLET_ADDRESS }
));

// Your endpoint logic (only runs after payment is verified)
app.get('/api/v1/my-endpoint', (req, res) => {
  res.json({ success: true, data: 'Your response here' });
});

app.listen(3000);
```

### Option B: Build Your Own 402 Response

If you're not using Express or want full control, return an HTTP 402 response with the `payment-required` header:

```javascript
app.get('/api/v1/my-endpoint', (req, res) => {
  // Check if request has a valid payment
  const paymentHeader = req.headers['payment-signature'];

  if (!paymentHeader) {
    // Return 402 with payment options
    const paymentRequired = {
      x402Version: 2,
      error: 'Payment required',
      accepts: buildAcceptsArray('$0.01'),
      facilitatorUrl: 'https://facilitator.silverbackdefi.app'
    };

    const encoded = Buffer.from(JSON.stringify(paymentRequired)).toString('base64');

    return res.status(402)
      .set('payment-required', encoded)
      .set('Cache-Control', 'no-store, no-cache, must-revalidate, private')
      .json({ error: 'Payment required' });
  }

  // Payment exists — verify with facilitator, then serve response
  // ...
});
```

***

## Step 4: Build Your Payment Options

The `accepts` array in your 402 response tells clients which tokens you accept. Each entry is one payment option.

### Accept Only USDC (Simplest)

```javascript
function buildAcceptsArray(usdPrice) {
  const priceNum = parseFloat(usdPrice.replace('$', ''));
  const usdcAmount = Math.floor(priceNum * 1e6); // USDC has 6 decimals

  return [{
    scheme: 'exact',
    network: 'eip155:8453',
    amount: usdcAmount.toString(),
    asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',  // USDC on Base
    payTo: process.env.X402_WALLET_ADDRESS,
    maxTimeoutSeconds: 300,
    extra: {
      name: 'USD Coin',
      version: '2'
    }
  }];
}
```

### Accept Multiple Tokens

To accept more tokens, add additional entries to the `accepts` array. Each token needs its amount converted from USD at the current market rate.

```javascript
// Token registry with addresses and decimals
const TOKENS = {
  USDC:    { address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', decimals: 6,  stable: true },
  USDT:    { address: '0xfde4C96c8593536E31F229EA8f37b2ADa2699bb2', decimals: 6,  stable: true },
  DAI:     { address: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb', decimals: 18, stable: true },
  VIRTUAL: { address: '0x0b3e328455c4059EEb9e3f84b5543F74E24e7E1b', decimals: 18, stable: false },
  WETH:    { address: '0x4200000000000000000000000000000000000006', decimals: 18, stable: false },
  cbBTC:   { address: '0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf', decimals: 8,  stable: false },
  BACK:    { address: '0x558881c4959e9cf961a7E1815FCD6586906babd2', decimals: 18, stable: false, discount: 0.20 },
};

function buildAcceptsArray(usdPrice) {
  const priceNum = parseFloat(usdPrice.replace('$', ''));
  const accepts = [];

  for (const [symbol, token] of Object.entries(TOKENS)) {
    // Get token price (stablecoins = $1, others fetched from API)
    const tokenPrice = token.stable ? 1.0 : getTokenPrice(symbol);
    if (!tokenPrice) continue;

    // Apply discount for BACK
    const effectivePrice = token.discount
      ? priceNum * (1 - token.discount)
      : priceNum;

    // Convert USD to token base units
    const tokenAmount = effectivePrice / tokenPrice;
    const baseUnits = BigInt(Math.floor(tokenAmount * (10 ** token.decimals)));

    accepts.push({
      scheme: 'exact',
      network: 'eip155:8453',
      amount: baseUnits.toString(),
      asset: token.address,
      payTo: process.env.X402_WALLET_ADDRESS,
      maxTimeoutSeconds: 300,
      extra: {
        name: symbol,
        version: '2',
        ...(token.discount ? { discount: `${token.discount * 100}%` } : {})
      }
    });
  }

  return accepts;
}
```

### Use the Facilitator's Price API

Instead of fetching prices yourself, use the facilitator's built-in converter:

```bash
# Convert $0.02 to BACK token amount
curl https://facilitator.silverbackdefi.app/supported/convert?usd=0.02&token=BACK

# Response:
# { "usdAmount": 0.02, "tokenAmount": "206172839506173", "token": "BACK", "decimals": 18 }
```

```bash
# Get all token prices at once
curl https://facilitator.silverbackdefi.app/supported/tokens

# Response includes priceUsd for each token
```

***

## Step 5: Using the Fee Splitter (Optional)

If you want Silverback to handle fee splitting automatically, point `payTo` to the Fee Splitter contract instead of your own wallet. The fee splitter takes a small percentage and forwards the rest to your wallet.

```javascript
const FEE_SPLITTER = '0x6FDf52EA446B54508f50C35612210c69Ef1C1d9a';

// In your accepts array:
{
  scheme: 'exact',
  network: 'eip155:8453',
  amount: '2000',
  asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
  payTo: FEE_SPLITTER,                    // Route through fee splitter
  maxTimeoutSeconds: 300,
  extra: {
    name: 'USD Coin',
    version: '2',
    actualRecipient: '0xYourWalletAddress'  // You receive the net amount
  }
}
```

**Fee rates:**

* $BACK: 0% (fee-exempt)
* Stablecoins (USDC, USDT, DAI): 0.1%
* Ecosystem tokens (VIRTUAL): 0.1%
* Blue-chip assets (WETH, cbBTC): 0.25%

***

## Step 6: Register in the Discovery Bazaar (Optional)

Make your endpoints discoverable by other agents and clients through the Silverback Bazaar.

The facilitator's discovery service at `/discovery/resources` lets clients browse available x402 endpoints. To register your endpoints, publish a resource description that includes:

```json
{
  "resource": "https://your-server.com/api/v1/your-endpoint",
  "x402Version": 2,
  "description": "What your endpoint does",
  "category": "defi",
  "tags": ["swap", "quote", "base"],
  "accepts": [
    { "scheme": "exact", "network": "eip155:8453", "amount": "2000", "asset": "0x833589..." }
  ],
  "metadata": {
    "provider": "Your Project Name",
    "method": "POST",
    "inputSchema": {
      "type": "object",
      "properties": {
        "token": { "type": "string", "description": "Token address or symbol" }
      },
      "required": ["token"]
    }
  }
}
```

**Discovery endpoints on the facilitator:**

* `GET /discovery/resources` — Browse all registered endpoints
* `GET /discovery/categories` — List categories (defi, trading, analytics, etc.)
* `GET /discovery/tags` — List all tags
* `GET /discovery/info` — Service metadata

***

## Important Rules

### Amount Conversion

Amounts in the `accepts` array must be in **base units** (smallest denomination), not human-readable amounts:

| Token              | Decimals | $0.01 in base units     |
| ------------------ | -------- | ----------------------- |
| USDC               | 6        | `10000`                 |
| USDT               | 6        | `10000`                 |
| DAI                | 18       | `10000000000000000`     |
| WETH (at $2,100)   | 18       | `4761904761904`         |
| cbBTC (at $70,000) | 8        | `14`                    |
| BACK (at $0.00008) | 18       | `100000000000000000000` |

Getting decimals wrong is the most common integration mistake.

### Cache Control

Always set `Cache-Control: no-store, no-cache, must-revalidate, private` on 402 responses. Without this, CDNs may cache the payment options and serve stale prices.

### Timeout

Set `maxTimeoutSeconds: 300` (5 minutes) in each payment option. This gives clients enough time to sign and submit payment without the authorization expiring.

### x402 Version

Always set `x402Version: 2` in your 402 response. Version 2 supports both ERC-3009 (USDC) and Permit2 (all other tokens).

***

## How the Client Pays

You don't need to implement this — the x402 SDK handles it automatically on the client side. But for reference:

1. Client receives your 402 response
2. SDK picks a token the client has sufficient balance for
3. **USDC** — SDK signs an ERC-3009 `transferWithAuthorization` (no prior approval needed)
4. **Any other token** — SDK signs a Permit2 `permitWitnessTransferFrom` (requires one-time Permit2 approval)
5. SDK sends the signed payment to the facilitator for verification
6. Facilitator confirms the payment is valid
7. SDK re-sends the original request with the payment proof in the `PAYMENT-SIGNATURE` header
8. Your server receives the request, facilitator settles on-chain, and you serve the response

***

## What You Handle vs What the Facilitator Handles

| You (the seller)                | Silverback Facilitator           |
| ------------------------------- | -------------------------------- |
| Return 402 with `accepts` array | Verify payment signatures        |
| Set prices in USD               | Convert USD to token amounts     |
| Choose which tokens to accept   | Settle payments on-chain         |
| Serve your API response         | Split fees automatically         |
| Keep token prices updated       | Manage Permit2 and ERC-3009      |
|                                 | Provide discovery/bazaar         |
|                                 | Handle transaction confirmations |

***

## Testing

### On Testnet (Base Sepolia)

Use `network: 'eip155:84532'` in your `accepts` array and test with Sepolia tokens.

### On Mainnet

Start with low-value endpoints ($0.001) and test with the [x402 SDK](https://www.x402.org):

```javascript
import { wrapFetchWithPaymentFromConfig } from '@x402/fetch';
import { ExactEvmScheme } from '@x402/evm/exact/client';

const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{
    x402Version: 2,
    network: 'eip155:8453',
    client: new ExactEvmScheme(yourWalletSigner)
  }]
});

const res = await fetchWithPayment('https://your-server.com/api/v1/my-endpoint');
console.log(await res.json());
```

### Verify Facilitator Connectivity

```bash
# Check the facilitator is reachable
curl https://facilitator.silverbackdefi.app/health

# Check supported tokens and current prices
curl https://facilitator.silverbackdefi.app/supported/tokens

# Test price conversion
curl "https://facilitator.silverbackdefi.app/supported/convert?usd=0.01&token=BACK"
```

***

## Troubleshooting

| Problem                                | Solution                                                                               |
| -------------------------------------- | -------------------------------------------------------------------------------------- |
| Client gets 402 but can't pay          | Check `accepts` array format — amounts must be strings in base units                   |
| Payment fails with "unsupported token" | Token must be on the facilitator's whitelist (check `/supported/tokens`)               |
| Wrong amount charged                   | Verify decimal conversion: `amount = usdPrice * 10^decimals`                           |
| Stale prices for volatile tokens       | Refresh prices every 5 minutes, or use the facilitator's `/supported/convert` endpoint |
| 402 response cached by CDN             | Add `Cache-Control: no-store` header to 402 responses                                  |
| Settlement timeout                     | Check that `maxTimeoutSeconds` is at least 300                                         |

***

## Need Help?

* **Facilitator status:** [facilitator.silverbackdefi.app/health](https://facilitator.silverbackdefi.app/health)
* **Supported tokens:** [facilitator.silverbackdefi.app/supported/tokens](https://facilitator.silverbackdefi.app/supported/tokens)
* **x402 protocol docs:** [x402.org](https://www.x402.org)
* **Community:** [Silverback Discord](https://discord.gg/silverback)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.silverbackdefi.app/silverback-ai-agent/seller-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
