# Seller Integration

Use this page when you operate the paid x402 resource server and want merchant USDC income swept into Divigent after settlement.

Divigent does not replace your resource server or facilitator. It attaches to the x402 server lifecycle and deposits merchant wallet USDC above a reserve after a successful x402 settlement.

{% hint style="info" %}
Base mainnet uses real Circle USDC and real x402 settlement. Use small prices while testing.
{% endhint %}

## Install

```bash
npm install @divigent/sdk viem @x402/core @x402/express @x402/evm express
```

## Environment

```bash
BASE_MAINNET_RPC_URL="https://..."
MERCHANT_PRIVATE_KEY="0x..."
X402_FACILITATOR_URL="https://..."
```

Use a facilitator that supports Base mainnet (`eip155:8453`) and Circle USDC. If your facilitator requires authentication, configure its bearer token or client options according to that facilitator's docs.

## Complete Seller Code

```ts
import type { Server } from 'node:http';
import express from 'express';
import {
  Divigent,
  evmAddress,
  formatUsdc,
  parseUsdc,
  x402UsdcPrice,
} from '@divigent/sdk';
import { HTTPFacilitatorClient } from '@x402/core/server';
import { ExactEvmScheme as ExactEvmServer } from '@x402/evm/exact/server';
import { paymentMiddleware, x402ResourceServer } from '@x402/express';
import { createPublicClient, createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

const account = privateKeyToAccount(process.env.MERCHANT_PRIVATE_KEY as `0x${string}`);
const rpcUrl = process.env.BASE_MAINNET_RPC_URL!;
const facilitatorUrl = process.env.X402_FACILITATOR_URL!;

const publicClient = createPublicClient({
  chain: base,
  transport: http(rpcUrl),
});

const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(rpcUrl),
});

const divigent = Divigent.create({
  publicClient,
  walletClient,
  chain: 'base',
});

const merchantWallet = evmAddress(account.address);
await divigent.verifyAddresses();
await divigent.ensureInitializedAndWait({ wallet: merchantWallet });

const app = express();
app.use(express.json());

const resourceServer = new x402ResourceServer(
  new HTTPFacilitatorClient({ url: facilitatorUrl }),
)
  .register('eip155:8453', new ExactEvmServer())
  .onAfterSettle(async (ctx) => {
    console.log(`settled x402 tx: ${ctx.result.transaction}`);
    console.log(`payer: ${ctx.result.payer ?? 'unknown'}`);
  });

const incomeHandle = divigent.attachToResourceServer(resourceServer, {
  minIdleThreshold: parseUsdc('1'),
  onIdleDeposit: (ctx) => {
    console.log(`seller deposited: ${formatUsdc(ctx.idleAmount)} USDC`);
    console.log(`seller kept liquid: ${formatUsdc(ctx.reserveFloor)} USDC`);
    console.log(`deposit tx: ${ctx.txHash}`);
  },
  onNonFatalError: (ctx) => {
    console.warn(`Divigent seller ${ctx.phase}: ${ctx.error.message}`);
  },
});

app.use(paymentMiddleware(
  {
    'GET /paid': {
      accepts: {
        scheme: 'exact',
        network: 'eip155:8453',
        payTo: merchantWallet,
        price: x402UsdcPrice({
          chain: 'base',
          amount: parseUsdc('0.001'),
          asset: divigent.addresses.usdc,
        }),
        maxTimeoutSeconds: 300,
      },
      description: 'Paid endpoint',
      mimeType: 'application/json',
      unpaidResponseBody: () => ({
        contentType: 'application/json',
        body: { error: 'x402 payment required' },
      }),
      settlementFailedResponseBody: (_ctx, settle) => ({
        contentType: 'application/json',
        body: {
          error: 'x402 settlement failed',
          reason: settle.errorReason,
          message: settle.errorMessage,
        },
      }),
    },
  },
  resourceServer,
  {
    appName: 'Divigent seller',
    testnet: false,
  },
));

app.get('/paid', (_req, res) => {
  res.json({
    ok: true,
    message: 'Paid with x402; seller idle USDC can be swept into Divigent.',
  });
});

const server: Server = app.listen(4021, '127.0.0.1', () => {
  console.log('paid endpoint: http://127.0.0.1:4021/paid');
});

process.on('SIGINT', () => {
  incomeHandle.detach();
  server.close();
});
```

## What Happens

The seller flow is:

1. the buyer calls the paid endpoint;
2. the x402 middleware requests payment;
3. the buyer retries with a signed payment payload;
4. the resource server settles through the facilitator;
5. after successful settlement, Divigent deposits merchant wallet USDC above the seller reserve.

The seller-side API is:

```ts
const incomeHandle = divigent.attachToResourceServer(resourceServer, {
  minIdleThreshold: parseUsdc('1'),
});
```

This is different from buyer-side `attachTo(x402Client, config)`. Buyer-side hooks manage outgoing payment liquidity. Seller-side hooks manage incoming merchant income.

## Price Metadata

Use `x402UsdcPrice(...)` when building the seller payment requirement.

```ts
const price = x402UsdcPrice({
  chain: 'base',
  amount: parseUsdc('0.001'),
  asset: divigent.addresses.usdc,
});
```

On Base mainnet, this includes Circle USDC EIP-3009 metadata:

```ts
{
  name: 'USD Coin',
  version: '2',
  assetTransferMethod: 'eip3009',
}
```

## Manual Seller Deposit

Use the seller handle if you want to sweep merchant USDC outside a request:

```ts
await incomeHandle.depositIdle();
```

Or use the SDK facade directly:

```ts
await divigent.depositIdle({
  wallet: merchantWallet,
  minIdleThreshold: parseUsdc('1'),
});
```

## Base Sepolia

For Base Sepolia:

* import `baseSepolia` from `viem/chains`;
* use `BASE_SEPOLIA_RPC_URL`;
* set `chain: 'base-sepolia'`;
* register x402 network `eip155:84532`;
* set `testnet: true` in x402 middleware options;
* use `divigent.addresses.usdc` as the payment asset.

Base Sepolia uses Divigent's configured test USDC metadata for x402.

## Next Steps

* [Buyer Integration](/divigent-docs/integration/buyer-integration.md)
* [SDK Integration](/divigent-docs/integration/sdk-integration.md)
* [API Reference](/divigent-docs/sdk/api-reference.md)


---

# Agent Instructions: 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://divigent.gitbook.io/divigent-docs/integration/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.
