Paying with USDC (x402)

How an autonomous agent refills its prepaid SeqDesign credit balance by paying USDC on Base, over plain HTTP.

No MCP required. The whole flow is an HTTPS request plus an EIP-712 signature. It does not depend on any MCP x402 integration, so it works from any agent, script, or backend that can make HTTP calls and sign with a key.

The model: credit top-up, not pay-per-call

SeqDesign runs on a prepaid balance. Every job (ProteinHunter, BindCraft, Boltz, …) is billed by deducting from that balance, and a pre-flight 402 blocks a key with no credits. x402 is a way to refill the balance with USDC. It is a dedicated route, separate from job submission.

So an agent's loop is:

The crypto handshake happens only at top-up time, never on the job hot path.

Prerequisites

Endpoint

POST https://public.seq.design/v1/credits/topup
Authorization: Bearer <SEQDESIGN_API_KEY>
Content-Type: application/json

{ "amount_usd": 25 }

1 USDC = 100 credit-cents (strict 1:1). Bounded $1–$500 per request.

The handshake (x402 v1, "exact" scheme)

Step 1. Send the POST with no X-PAYMENT header. The server answers 402 with the payment terms:

{
  "x402Version": 1,
  "error": "X-PAYMENT header is required",
  "accepts": [{
    "scheme": "exact",
    "network": "base",
    "maxAmountRequired": "25000000",
    "resource": "https://public.seq.design/v1/credits/topup",
    "payTo": "0x5Cf5bBF765F7e281493549D0fe88397E7b34a58c",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "maxTimeoutSeconds": 120,
    "extra": { "name": "USD Coin", "version": "2" }
  }]
}

maxAmountRequired is the atomic USDC amount to pay ($25 → 25000000); use it verbatim. payTo is the SeqDesign receiving wallet; asset is Base-mainnet USDC. A 503 here means x402 is disabled server-side; a 401 means the API key is invalid.

Step 2. EIP-712-sign an EIP-3009 TransferWithAuthorization with the payer key:

FieldValue
domain{ name: extra.name, version: extra.version, chainId: 8453, verifyingContract: asset } (Base = 8453; Base Sepolia = 84532)
types.TransferWithAuthorizationfrom, to, value, validAfter, validBefore (uint256), nonce (bytes32)
messagefrom=payer, to=payTo, value=maxAmountRequired, validAfter=0, validBefore=now+maxTimeoutSeconds, nonce=random 32 bytes

Step 3. Resend the same POST with an X-PAYMENT header — base64 of:

{
  "x402Version": 1,
  "scheme": "exact",
  "network": "base",
  "payload": {
    "signature": "0x<65-byte sig>",
    "authorization": {
      "from": "0x<payer>",
      "to": "0x5Cf5bBF765F7e281493549D0fe88397E7b34a58c",
      "value": "25000000",
      "validAfter": "0",
      "validBefore": "<unix>",
      "nonce": "0x<32 bytes hex>"
    }
  }
}

Success is 200:

{ "data": { "credited": true, "amount_cents": 2500, "balance_cents": 2500,
            "transaction": "0x<settlement tx>", "network": "base" } }

The grant is idempotent on the settlement transaction hash, so a replayed X-PAYMENT can never double-credit.

After top-up: spending

Nothing special. Submit jobs with the same API key; each run deducts from the balance, and a pre-flight 402 blocks a run the balance can't cover. The only thing an agent has to manage is keeping the balance topped up.

Reference implementation

The signing is standard EIP-712, so any Ethereum library works (viem/ethers in JS, eth_account in Python). A working Python client (topup() + the three steps + spend caps) is available on request.