XATAAPIAgent Access

Venue Setup

Configure trading venues using one of two setup models: Prepare+Confirm or User Credentials

XATA supports two venue configuration models depending on each venue's native delegation capabilities.

Model 1: Prepare + Confirm

Venues: Hyperliquid, HyENA, AsterDex, Paradex, GRVT

A two-step process: XATA generates a keypair, the user registers it in the venue's web UI, then confirms the setup. Your main wallet private key is never exposed to XATA.

Step 1: Prepare

POST /v2/account/venues/{venue}/prepare

Where {venue} is hyperliquid, hyena, aster, paradex, or grvt.

Request: Empty JSON body {}

Response:

{
  "venue": "aster",
  "wallet_address": "0x5555555555555555555555555555555555555555",
  "status": "pending_user_action",
  "instructions": "Go to https://www.asterdex.com/api-wallet and add 0x555... as API wallet"
}
  • For Hyperliquid / HyENA, the response includes agent_name (derived from the first 10 characters of your API key). You'll use this name when approving the agent in the Hyperliquid UI.
  • For Paradex, the response returns public_key instead of wallet_address (Starknet keypair).
  • For GRVT, the response returns signer_address.

Step 2: User Action

Follow the instructions in the response to register the generated address in the venue's web UI:

  • Hyperliquid / HyENA: Go to https://app.hyperliquid.xyz/API, find "Approve Agent", enter the agent_name and wallet_address, and set an expiry
  • AsterDex: Go to the API wallet page and add the address
  • Paradex: Go to Account Security → Key Management → Add New Subkey
  • GRVT: Go to API Keys → Create → Input the signer address

Step 3: Confirm

POST /v2/account/venues/{venue}/confirm

The confirm request body varies by venue:

Hyperliquid / HyENA / AsterDex

{
  "main_wallet_address": "0xYourMainWalletAddress..."
}

Paradex

{}

GRVT

GRVT requires additional credentials obtained during the UI setup:

{
  "grvt_api_key": "grvt_live_abc123def456",
  "sub_account_id": "sub_account_1"
}

Confirm Response

{
  "venue": "aster",
  "status": "active",
  "wallet_address": "0x5555555555555555555555555555555555555555"
}

Venue-Specific Details

Hyperliquid / HyENA

  • Uses EVM keypair; the generated address is approved as an "agent wallet" via the Hyperliquid API page
  • Agent wallets have trade-only permissions — cannot withdraw or transfer (enforced by Hyperliquid protocol)
  • The agent_name is derived from the first 10 characters of your API key
  • User controls the expiry when approving the agent in the UI
  • Revocation: revoke the agent in the Hyperliquid UI or let it expire

AsterDex

  • Uses EVM keypair; the generated address is added as an "API wallet" in the AsterDex UI
  • Trading requests are signed with the API wallet private key using Keccak256 + ECDSA
  • Revocation: remove the API wallet in the AsterDex UI

Paradex

  • Uses Starknet keypair; the public key is registered as a "subkey"
  • Subkeys can place/cancel orders and view balances but cannot withdraw, transfer, or manage other subkeys
  • Revocation: remove the subkey in the Paradex UI

GRVT

  • Uses EVM keypair as the "signer address"
  • Requires a GRVT API key and sub-account ID (created in the GRVT UI alongside the signer)
  • Trading uses EIP-712 signing
  • Revocation: delete the API key in the GRVT UI

Python Example: Complete Hyperliquid Flow

import requests

api_key = "api_..."
headers = {
    "x-api-key": api_key,
    "Content-Type": "application/json",
}

# Step 1: Prepare
resp = requests.post(
    "https://api.x.ata.network/v2/account/venues/hyperliquid/prepare",
    headers=headers,
    json={},
)
prepare_data = resp.json()
print(f"Generated wallet: {prepare_data['wallet_address']}")
print(f"Agent name: {prepare_data['agent_name']}")
print(f"Instructions: {prepare_data['instructions']}")

# Step 2: Approve agent in Hyperliquid UI (manual step)
# Go to https://app.hyperliquid.xyz/API and approve the agent wallet
input("Press Enter after approving the agent in Hyperliquid UI...")

# Step 3: Confirm
resp = requests.post(
    "https://api.x.ata.network/v2/account/venues/hyperliquid/confirm",
    headers=headers,
    json={"main_wallet_address": "0xYourMainWalletAddress..."},
)
print(f"Status: {resp.json()['status']}")

Model 2: User-Provided Credentials

Venues: Lighter, Kuru, Nado

Submit your venue-specific credentials directly. XATA encrypts them using AES-256-GCM and stores them securely.

Endpoint

POST /v2/account/venues/{venue}/credentials

Where {venue} is lighter, kuru, or nado.

Lighter

{
  "credentials": {
    "api_key_private_key": "0xdeadbeef...",
    "api_key_index": 2,
    "account_index": 0,
    "l1_address": "0x1234567890abcdef1234567890abcdef12345678"
  }
}
FieldTypeDescription
api_key_private_keystringYour Lighter API key private key
api_key_indexintegerAPI key index (e.g., 2)
account_indexintegerAccount index (usually 0)
l1_addressstringYour L1 wallet address

Kuru

{
  "credentials": {
    "private_key": "0xdeadbeef..."
  }
}
FieldTypeDescription
private_keystringYour Kuru trading account private key

Nado

{
  "credentials": {
    "private_key": "0xdeadbeef...",
    "subaccount": "default"
  }
}
FieldTypeDescription
private_keystringYour Nado trading account private key
subaccountstringSubaccount name (e.g., "default")

Response

{
  "venue": "lighter",
  "status": "active",
  "account_address": "0x1234567890abcdef1234567890abcdef12345678"
}

Credentials are encrypted before storage but you should treat them with the same care as private keys. Use environment variables or secrets vaults to manage them.

Python Example: Setup Lighter

import requests

api_key = "api_..."
headers = {
    "x-api-key": api_key,
    "Content-Type": "application/json",
}

resp = requests.post(
    "https://api.x.ata.network/v2/account/venues/lighter/credentials",
    headers=headers,
    json={
        "credentials": {
            "api_key_private_key": "0x...",
            "api_key_index": 2,
            "account_index": 0,
            "l1_address": "0x1234567890abcdef1234567890abcdef12345678",
        }
    },
)

if resp.status_code == 200:
    print(f"Lighter setup complete: {resp.json()}")
else:
    print(f"Error: {resp.status_code}{resp.text}")

On this page