Skip to content

DEX Trading API (0x Swap)

Decentralized exchange trading via 0x protocol. Best-execution routing across 100+ DEXes with Permit2 and Gasless V2. Authentication required (API key or x402 payment). Billed at $0.001/call, plus on-chain gas for executed swaps.

Authentication

Both methods are supported — all requests settle via x402 on-chain:

MethodHeaderDescription
API KeyAuthorization: Bearer sk-...Platform signs x402 from your HD wallet automatically
Private Key (x402)Automatic via SDKAgent signs x402 directly from its own wallet

See Agent Payments (x402) for full details on how both methods work.

Base URL

https://api.jarvisclaw.ai/v1/marketplace/dex

Pricing

Authentication (API key or x402) is required to access DEX endpoints.

ScopePrice
Every DEX endpoint, any method$0.001/call upstream

On top of the per-call fee you pay standard on-chain gas for submitted transactions. Gasless swaps remove the gas component for supported tokens, but not the per-call fee.

These endpoints are not free

Earlier docs, and some published price listings, described DEX trading as free. Every DEX call is billed. Read price.amount on the response for the exact charge.

Chains

Two separate things are easy to conflate here:

Chains
Payment — how you pay JarvisClaw for the callBase (eip155:8453) and Solana, USDC on both
Swap target — the chain you pass as chainIdForwarded to the upstream 0x router

Paying happens on Base or Solana regardless of which chain you swap on. The gateway does not maintain its own list of swap-target chains — chainId is passed through, so which values work is determined by the upstream router at call time. 8453 (Base) is verified. If you need another chain, send it and check the response rather than assuming support.

Endpoints

MethodEndpointDescriptionPrice
GET/priceIndicative swap price (no commitment)$0.001/call
GET/quoteFirm quote with calldata + Permit2 data$0.001/call
POST/gasless/submitSubmit a signed gasless swap$0.001/call
GET/gasless/status/:tradeHashTrack gasless swap status$0.001/call
POST/swap/permit2/quotePermit2 swap quote$0.001/call
POST/swap/permit2/executeExecute a Permit2 swap$0.001/call

Get Price

GET /v1/marketplace/dex/price

Get an indicative price for a token swap without committing. Use for UI display or pre-trade checks.

Parameters

ParameterTypeRequiredDescription
sellTokenstringYesToken contract address to sell
buyTokenstringYesToken contract address to buy
sellAmountstringYesAmount to sell in base units (e.g., 1000000 = 1 USDC)
chainIdintegerYesTarget chain ID
takerstringNoTaker wallet address (improves routing)

Response

json
{
  "chainId": 8453,
  "sellToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "buyToken": "0x4200000000000000000000000000000000000006",
  "sellAmount": "1000000000",
  "buyAmount": "385000000000000000",
  "price": "0.000385",
  "sources": [
    { "name": "Uniswap_V3", "proportion": "0.75" },
    { "name": "Aerodrome", "proportion": "0.25" }
  ],
  "estimatedGas": "145000",
  "gasPrice": "50000000"
}

Get Quote

GET /v1/marketplace/dex/quote

Get a firm quote with transaction calldata ready for signing. Includes EIP-712 typed data for Permit2 gasless swaps.

Parameters

ParameterTypeRequiredDescription
sellTokenstringYesToken contract address to sell
buyTokenstringYesToken contract address to buy
sellAmountstringYesAmount to sell in base units
chainIdintegerYesTarget chain ID
takerstringYesTaker wallet address (required for quote)

Response

json
{
  "chainId": 8453,
  "sellToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "buyToken": "0x4200000000000000000000000000000000000006",
  "sellAmount": "1000000000",
  "buyAmount": "384500000000000000",
  "to": "0xDef1C0ded9bec7F1a1670819833240f027b25EfF",
  "data": "0x415565b0000000000000000000...",
  "value": "0",
  "gas": "185000",
  "gasPrice": "50000000",
  "permit2": {
    "type": "Permit2",
    "hash": "0x1234abcd...",
    "eip712": {
      "types": { "...": "..." },
      "domain": { "...": "..." },
      "message": { "...": "..." },
      "primaryType": "PermitWitnessTransferFrom"
    }
  },
  "validTo": 1717243800
}

Quote Expiry

Quotes are valid for 30 seconds. After expiry, you must request a new quote.


Submit Gasless Swap

POST /v1/marketplace/dex/gasless/submit

Submit a signed gasless swap. The relayer pays gas on your behalf — the taker pays nothing beyond the swap amount.

Request

json
{
  "trade": {
    "chainId": 8453,
    "sellToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "buyToken": "0x4200000000000000000000000000000000000006",
    "sellAmount": "1000000000",
    "buyAmount": "384500000000000000",
    "to": "0xDef1C0ded9bec7F1a1670819833240f027b25EfF",
    "data": "0x415565b0...",
    "permit2": { "...": "..." }
  },
  "signature": "0xabcdef1234567890..."
}

Parameters

ParameterTypeRequiredDescription
tradeobjectYesFull quote object from /quote response
signaturestringYesEIP-712 signature from taker wallet

Response

json
{
  "tradeHash": "0x9f8e7d6c5b4a3210...",
  "status": "submitted",
  "createdAt": "2025-06-01T15:30:00Z"
}

Track Gasless Swap Status

GET /v1/marketplace/dex/gasless/status/:tradeHash

Poll the status of a submitted gasless swap.

Path Parameters

ParameterTypeRequiredDescription
tradeHashstringYesTrade hash from submit response

Response

json
{
  "tradeHash": "0x9f8e7d6c5b4a3210...",
  "status": "confirmed",
  "txHash": "0xabc123def456...",
  "blockNumber": 18500000,
  "gasUsed": "142000"
}

Status values: submitted, pending, confirmed, failed


Examples

bash
# Get indicative price (1000 USDC -> WETH on Base)
curl "https://api.jarvisclaw.ai/v1/marketplace/dex/price?\
chainId=8453&\
sellToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&\
buyToken=0x4200000000000000000000000000000000000006&\
sellAmount=1000000000" \
  -H "Authorization: Bearer sk-your-api-key"

# Get firm quote (requires taker)
curl "https://api.jarvisclaw.ai/v1/marketplace/dex/quote?\
chainId=8453&\
sellToken=0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913&\
buyToken=0x4200000000000000000000000000000000000006&\
sellAmount=1000000000&\
taker=0xYourWalletAddress" \
  -H "Authorization: Bearer sk-your-api-key"

# Submit gasless swap
curl -X POST https://api.jarvisclaw.ai/v1/marketplace/dex/gasless/submit \
  -H "Authorization: Bearer sk-your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "trade": { "...quote object..." },
    "signature": "0xYourEIP712Signature..."
  }'

# Check gasless swap status
curl "https://api.jarvisclaw.ai/v1/marketplace/dex/gasless/status/0x9f8e7d6c5b4a3210" \
  -H "Authorization: Bearer sk-your-api-key"
python
import requests
import time

BASE = "https://api.jarvisclaw.ai/v1/marketplace/dex"
HEADERS = {"Authorization": "Bearer sk-your-api-key"}

# Token addresses on Base
USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
WETH_BASE = "0x4200000000000000000000000000000000000006"

# 1. Get indicative price for 1000 USDC -> WETH
resp = requests.get(f"{BASE}/price", headers=HEADERS, params={
    "chainId": 8453,
    "sellToken": USDC_BASE,
    "buyToken": WETH_BASE,
    "sellAmount": "1000000000",  # 1000 USDC (6 decimals)
})
price = resp.json()
print(f"Buy amount: {price['buyAmount']} wei WETH")
print(f"Routed via: {[s['name'] for s in price['sources']]}")

# 2. Get firm quote
resp = requests.get(f"{BASE}/quote", headers=HEADERS, params={
    "chainId": 8453,
    "sellToken": USDC_BASE,
    "buyToken": WETH_BASE,
    "sellAmount": "1000000000",
    "taker": "0xYourWalletAddress",
})
quote = resp.json()

# 3. Sign the EIP-712 permit2 data (requires eth_account)
# signature = sign_eip712(quote["permit2"]["eip712"], private_key)

# 4. Submit gasless swap
resp = requests.post(f"{BASE}/gasless/submit", headers=HEADERS, json={
    "trade": quote,
    "signature": "0x<your-eip712-signature>",
})
trade_hash = resp.json()["tradeHash"]

# 5. Poll status
while True:
    resp = requests.get(f"{BASE}/gasless/status/{trade_hash}", headers=HEADERS)
    status = resp.json()
    if status["status"] == "confirmed":
        print(f"Swap confirmed! TX: {status['txHash']}")
        break
    elif status["status"] == "failed":
        print("Swap failed")
        break
    time.sleep(2)
python
from jarvisclaw import MarketplaceClient

# x402 agent — pays the $0.001/call fee with USDC automatically
client = MarketplaceClient(private_key="0x<agent-wallet-private-key>")

USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
WETH_BASE = "0x4200000000000000000000000000000000000006"

# Get price ($0.001 — settles over x402)
price = client.call("dex", "/price", params={
    "chainId": 8453,
    "sellToken": USDC_BASE,
    "buyToken": WETH_BASE,
    "sellAmount": "1000000000",
})
print(f"Price: {price['buyAmount']} wei for 1000 USDC")

# Get firm quote
quote = client.call("dex", "/quote", params={
    "chainId": 8453,
    "sellToken": USDC_BASE,
    "buyToken": WETH_BASE,
    "sellAmount": "1000000000",
    "taker": "0xYourWalletAddress",
})

# Submit gasless (after signing permit2 externally)
result = client.call("dex", "/gasless/submit", method="POST", json={
    "trade": quote,
    "signature": "0x<signed-permit2>",
})
print(f"Trade hash: {result['tradeHash']}")

# Poll status
status = client.call("dex", f"/gasless/status/{result['tradeHash']}")
print(f"Status: {status['status']}")
go
package main

import (
    "context"
    "fmt"
    "time"

    jarvisclaw "github.com/api-jarvisclaw/go-sdk/v2"
)

func main() {
    mc, _ := jarvisclaw.NewMarketplaceClient(jarvisclaw.WithAPIKey("sk-your-api-key"))
    ctx := context.Background()

    usdcBase := "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
    wethBase := "0x4200000000000000000000000000000000000006"

    // 1. Get indicative price
    price, err := mc.Call(ctx, "dex", "/price", jarvisclaw.WithParams(map[string]string{
        "chainId":    "8453",
        "sellToken":  usdcBase,
        "buyToken":   wethBase,
        "sellAmount": "1000000000",
    }))
    if err != nil {
        panic(err)
    }
    fmt.Printf("Buy amount: %s wei\n", price["buyAmount"])

    // 2. Get firm quote
    quote, err := mc.Call(ctx, "dex", "/quote", jarvisclaw.WithParams(map[string]string{
        "chainId":      "8453",
        "sellToken":    usdcBase,
        "buyToken":     wethBase,
        "sellAmount":   "1000000000",
        "taker": "0xYourWalletAddress",
    }))
    if err != nil {
        panic(err)
    }

    // 3. Sign permit2 EIP-712 data and submit gasless swap
    // signature := signEIP712(quote["permit2"], privateKey)

    submit, err := mc.Post(ctx, "dex", "/gasless/submit", map[string]interface{}{
        "trade":     quote,
        "signature": "0x<your-eip712-signature>",
    })
    if err != nil {
        panic(err)
    }
    tradeHash := submit["tradeHash"].(string)
    fmt.Printf("Trade hash: %s\n", tradeHash)

    // 4. Poll status
    for {
        status, _ := mc.Call(ctx, "dex",
            fmt.Sprintf("/gasless/status/%s", tradeHash),
        )
        if status["status"] == "confirmed" {
            fmt.Printf("Confirmed! TX: %s\n", status["txHash"])
            break
        }
        time.Sleep(2 * time.Second)
    }
}
go
package main

import (
    "context"
    "fmt"

    jarvisclaw "github.com/api-jarvisclaw/go-sdk/v2"
)

func main() {
    // x402 agent — settles the $0.001/call fee automatically
    mc, _ := jarvisclaw.NewMarketplaceClient(
        jarvisclaw.WithPrivateKey("0x<agent-wallet-private-key>"),
    )
    ctx := context.Background()

    usdcBase := "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
    wethBase := "0x4200000000000000000000000000000000000006"

    // Get price
    price, _ := mc.Call(ctx, "dex", "/price", jarvisclaw.WithParams(map[string]string{
        "chainId":    "8453",
        "sellToken":  usdcBase,
        "buyToken":   wethBase,
        "sellAmount": "1000000000",
    }))
    fmt.Printf("1000 USDC -> %s wei WETH\n", price["buyAmount"])

    // Get quote
    quote, _ := mc.Call(ctx, "dex", "/quote", jarvisclaw.WithParams(map[string]string{
        "chainId":      "8453",
        "sellToken":    usdcBase,
        "buyToken":     wethBase,
        "sellAmount":   "1000000000",
        "taker": "0xYourWalletAddress",
    }))

    // Sign + submit gasless swap
    result, _ := mc.Post(ctx, "dex", "/gasless/submit", map[string]interface{}{
        "trade":     quote,
        "signature": "0x<signed-permit2>",
    })
    fmt.Printf("Submitted: %s\n", result["tradeHash"])
}

Errors

Gateway-level errors use a flat shape — a single error string, no nested code:

json
{ "error": "service 'dex' is at capacity, please retry in a moment" }
HTTPMeaningResolution
401Missing or invalid API key / x402 signatureCheck Authorization, or let the SDK re-sign
402Settlement failed — could not pay for the callTop up the wallet, then retry
403Insufficient balanceTop up, or check your spend limits
404Unknown pathVerify against the endpoint table above
429Too many concurrent requestsBack off and retry
502Upstream router failedRetry; if persistent the provider is down
503Service temporarily unavailableRetry later

Swap-specific failures — insufficient liquidity, an expired quote, a bad token address, a failed signature, an unknown tradeHash, or an unsupported chainId — are raised by the upstream 0x router and passed through unchanged, so their shape and wording are the provider's, not ours.


Limitations

  • Payment is Base or Solana only — regardless of which chain you swap on, the call is paid in USDC on Base or Solana
  • Swap-target chains are the router'schainId is passed through to upstream; 8453 is verified, others depend on the router
  • Gasless requires Permit2 — Only tokens with Permit2 approval can use gasless swaps (most ERC-20s support this)
  • 30s quote expiry — Quotes are time-sensitive; sign and submit promptly
  • No limit orders — Only immediate market swaps; no conditional or scheduled orders
  • Price impact on large trades — Swaps over $100k may experience significant slippage due to DEX liquidity depth
  • Token addresses required — Use contract addresses, not symbols; verify addresses on the target chain
  • Base units only — All amounts are in the token's smallest denomination (6 decimals for USDC, 18 for ETH/WETH)
  • No partial fills — Entire trade executes or reverts; no partial execution