Portal
Documentation: all sections

Paying with USDT

Sable runs on prepaid credit. You fund a balance with USDT on a supported EVM chain: Ethereum mainnet (chain_id: 1) and Arbitrum One (42161) today, or on Solana, and inference and sandbox compute draw it down. There is no card, no invoice, and no signup call.

How settlement works

  1. Send USDT to the treasury address from a wallet linked to your account.
  2. Submit the transaction hash.
  3. The gateway verifies the transfer against its own RPC node and credits your balance once it has enough confirmations.

GET /v1/billing/methods is public and returns the treasury address, the supported chains, each chain's USDT contract and decimals, and the confirmation requirement. That response (or the portal's Billing page) is the authoritative source for the treasury address: addresses can rotate, so never hardcode one.

# 1. Discover where and how to pay (no credentials needed)
curl https://api.buildsable.com/v1/billing/methods

# 2. After sending USDT, submit the transaction hash
curl https://api.buildsable.com/v1/billing/deposits \
-H "authorization: Bearer $SABLE_SESSION" \
-H 'content-type: application/json' \
-d '{"chain_id": 1, "tx_hash": "0xabc…"}'

# 3. Check the balance
curl https://api.buildsable.com/v1/billing/balance \
-H "authorization: Bearer $SABLE_SESSION"

Why the sending wallet matters

A deposit is credited only if it came from a wallet already linked to your account. This applies to every settlement path, including the inline X-PAYMENT header below. Without that rule, anyone watching the treasury could claim someone else's deposit by submitting its hash first. A transfer from an unlinked wallet is refused with "that transfer was not sent from a wallet linked to this account"; the remedy is to link the paying wallet first under Portal → Wallets (linking requires a browser SIWE signature, which is what proves ownership) and then re-submit the same hash: the funds are not lost, just uncredited until the wallet is yours on record.

One transaction can carry several treasury-bound transfers (a batched or contract-mediated payment, say), and each qualifying transfer in it is credited individually.

Replay safety

Each on-chain transfer can be credited exactly once, globally: enforced by a unique constraint on (chain_id, tx_hash, log_index), not by application logic. Submitting the same hash repeatedly is safe and is in fact how you poll a deposit that hasn't confirmed yet.

Confirmations

Below the chain's confirmation threshold a deposit comes back pending with its current count. Re-submit (or use POST /v1/billing/deposits/refresh) and it credits once confirmed. Waiting for confirmations is what stops a reorg from handing out credit that was never really paid.

USDT on Solana

Sable also accepts USDT on Solana (chain_id: 501), live on the production deployment. Check GET /v1/billing/methods for the solana block; that response is authoritative for the current treasury address and mint (they can rotate, so never hardcode them). On a self-hosted deployment the rail is config-gated: if the block is absent, that deployment does not accept Solana deposits, and nothing below applies.

{
  "solana": {
    "chain_id": 501,
    "usdt_mint": "…",
    "treasury_address": "…",
    "decimals": 6,
    "commitment": "finalized",
    "memo_required": true
  }
}

⚠️ Put your Sable account id in the transaction memo: a transfer without it cannot be attributed automatically. Solana wallets can't SIWE-link the way EVM wallets do, so attribution is memo-based instead of linked-wallet-based: attach your Sable account id (shown in the portal) as the transaction's memo when you send the USDT. Then submit the signature:

curl https://api.buildsable.com/v1/billing/deposits \
-H "authorization: Bearer $SABLE_SESSION" \
-H 'content-type: application/json' \
-d '{"chain_id": 501, "tx_hash": "<base58 transaction signature>"}'

How verification differs from the EVM rail:

Everything else is the same as the EVM rail: the same replay guard (each transfer credits exactly once, globally), the same fail-closed sanctions screening, and the same exactly-once ledger crediting.

Paying in SABL

Sable is priced in dollars and settled in USDT, the way the rest of this page describes. A second, optional way to pay is rolling out: you will be able to pay for Sable compute and Sable Pro subscriptions in SABL, Sable's community token on Solana. Paying in SABL burns it and earns a discount.

This rail is not live on the production deployment yet. It is being built, and this section describes what it will do, not something you can do today. Until it ships, USDT and the on-chain USDT flows above remain the way to fund a balance.

A few things are worth being precise about, because paying in a token is easy to overstate:

The API shape

GET /v1/billing/methods already reports a sabl block. Until the operator enables the rail it reads {"status": "rolling out"}, and nothing below is callable. When enabled, the block carries the concrete terms:

{
  "sabl": {
    "chain_id": 502,
    "mint": "DaPayqzdCXcrmvgz9Wx7MySipXxcSofGPtkMgVdqpump",
    "burn_address": "…",
    "decimals": 6,
    "micro_usd_per_token": 1500,
    "discount_bps": 500,
    "memo_required": true
  }
}

micro_usd_per_token is the operator-set rate for one whole SABL, and discount_bps is the bonus applied for paying in SABL, in basis points. As with the treasury addresses elsewhere on this page, these can change, so read them from GET /v1/billing/methods rather than hardcoding them.

Once enabled, paying works exactly like a Solana USDT deposit: send SABL to the burn_address with your Sable account id in the transaction memo, then submit the signature.

curl https://api.buildsable.com/v1/billing/deposits \
-H "authorization: Bearer $SABLE_SESSION" \
-H 'content-type: application/json' \
-d '{"chain_id": 502, "tx_hash": "<base58 transaction signature>"}'

The transfer is verified at Solana's finalized commitment against the official mint only, so a lookalike token credits nothing. It credits once and is replay-safe on the same (chain_id, tx_hash, log_index) guard as every other rail. The credit is the SABL amount times the rate, plus the discount.

The only official SABL mint is DaPayqzdCXcrmvgz9Wx7MySipXxcSofGPtkMgVdqpump on Solana; anything else using the name is an impersonation.

The ledger

Your balance is the signed sum of an append-only ledger: deposits, grants, and one debit per metered request. Nothing is ever overwritten, so every movement is auditable, and GET /v1/billing/ledger returns it.

Debits are idempotent per usage event: a retried metering write can't bill you twice, because the database rejects the duplicate rather than trusting the code to remember.

Agents: paying inline with x402

An out-of-credit request returns 402 with an accepts array describing how to pay, so an autonomous agent can top itself up and retry without a human:

{
  "error": { "message": "account is out of credit…", "type": "insufficient_credit" },
  "x402Version": 1,
  "accepts": [{
    "scheme": "sable-usdt-onchain",
    "network": "eip155:1",
    "asset": "0xdac1…",
    "payTo": "0x…",
    "maxAmountRequired": "5000000",
    "extra": { "minConfirmations": 12, "settleHeader": "x-payment" }
  }]
}

maxAmountRequired is a suggested minimum top-up, $5, expressed in the asset's base units (5000000 for 6-decimal USDT), not a per-request price.

To settle, replay the request with an X-PAYMENT header carrying {"chain_id": 1, "tx_hash": "0x…"} (raw JSON or base64). The transfer is verified and credited before the handler runs, so the retry succeeds in one round trip. The linked-wallet rule above applies here too: an X-PAYMENT transfer sent from a wallet that isn't already linked to the account is refused with "that transfer was not sent from a wallet linked to this account", and linking requires a browser SIWE signature, so link the agent's paying wallet before it needs to settle autonomously.

curl https://api.buildsable.com/v1/chat/completions \
-H "authorization: Bearer $SABLE_API_KEY" \
-H "x-payment: $(echo -n '{"chain_id":1,"tx_hash":"0xabc…"}' | base64)" \
-H 'content-type: application/json' \
-d '{"model":"sable-llama-3.3-70b","messages":[{"role":"user","content":"hi"}]}'

On the scheme name

The scheme is sable-usdt-onchain, not x402's canonical exact. Canonical exact settlement is a gasless pull: the client signs an EIP-3009 transferWithAuthorization and a facilitator pulls the funds. USDT predates EIP-3009 and implements neither it nor EIP-2612 permit on the chains that matter, so that flow simply isn't available for USDT. Rather than advertise compatibility we don't have, the settlement step is named for what it actually is. The 402 envelope and discovery shape are unchanged.

For most agents the cheaper pattern is to deposit once and draw down the prepaid balance: one on-chain transaction total, instead of one per call.

Pricing

Per-model prices are published in GET /v1/models and the exact cost of every call rides along in its receipt. Sandbox compute bills in vCPU-seconds and GB-seconds of memory. See Sandbox compute.

Peg note: USDT is credited at face value, treating 1 USDT as $1. That's a deliberate simplification: it keeps a price oracle out of the payment path.