Skip to main content
The Agent API lets autonomous trading bots and AI agents interact with Adrena perpetuals programmatically. Agents can query market data, check competition standings, and generate unsigned transactions for leveraged trading — all through a simple REST interface.

Two-Tier Architecture

The API has two tiers depending on how your agent operates:
TierEndpointLLM RequiredBest For
ExecutePOST /api/agent/executeNoAutomated bots, scripted strategies, low-latency trading
ChatPOST /api/agent/chatYes (GPT-4o)Conversational agents, reasoning-first trading, market analysis
Both tiers use the same authentication and the same set of tools. The difference is whether an LLM decides which tool to call (Chat) or your code does (Execute).

Authentication

All endpoints require an API key in the Authorization header:
Authorization: Bearer shoot_ak_<key>

Creating an API key

API keys are bound to a Solana wallet. To create one, sign a challenge message with your wallet’s private key:
1

Build the challenge message

The message format is shoot-agent-key-create:<unix_timestamp_ms>. The timestamp must be within 5 minutes of the server’s clock.
2

Sign with your wallet

Sign the message bytes using Ed25519 (the standard Solana signing algorithm). Base58-encode the signature.
3

POST to /api/agent/keys

Send the wallet address, signature, timestamp, and an optional label.
curl -X POST https://your-domain.com/api/agent/keys \
  -H "Content-Type: application/json" \
  -d '{
    "wallet": "YourSolanaWalletAddress",
    "signature": "Base58EncodedSignature",
    "timestamp": 1711500000000,
    "label": "my-trading-bot"
  }'
Response (201):
{
  "id": "clxyz123",
  "key": "shoot_ak_T3cm6zZhEUUgsLdQv4pHqvZdy75ROxUyJYNviZ-B7GI"
}
The plaintext key is only returned once at creation. Store it securely. The server stores a SHA-256 hash — there is no way to recover the key later.

Key creation example (TypeScript)

import { Keypair } from "@solana/web3.js";
import bs58 from "bs58";
import nacl from "tweetnacl";

const wallet = Keypair.fromSecretKey(/* your secret key */);
const timestamp = Date.now();
const message = new TextEncoder().encode(`shoot-agent-key-create:${timestamp}`);
const signature = nacl.sign.detached(message, wallet.secretKey);

const res = await fetch("https://your-domain.com/api/agent/keys", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    wallet: wallet.publicKey.toBase58(),
    signature: bs58.encode(signature),
    timestamp,
    label: "my-bot",
  }),
});

const { key } = await res.json();
// key = "shoot_ak_..."

Key creation example (Python)

import time, requests, base58
from solders.keypair import Keypair

wallet = Keypair()  # or load from file
timestamp = int(time.time() * 1000)
message = f"shoot-agent-key-create:{timestamp}".encode()
signature = wallet.sign_message(message)

res = requests.post("https://your-domain.com/api/agent/keys", json={
    "wallet": str(wallet.pubkey()),
    "signature": base58.b58encode(bytes(signature)).decode(),
    "timestamp": timestamp,
    "label": "python-bot",
})

api_key = res.json()["key"]

Managing keys

List active keys — requires authentication with any active key for the wallet:
curl https://your-domain.com/api/agent/keys \
  -H "Authorization: Bearer shoot_ak_..."
{
  "keys": [
    {
      "id": "clxyz123",
      "label": "my-trading-bot",
      "lastUsedAt": "2026-03-26T10:30:00.000Z",
      "createdAt": "2026-03-25T08:00:00.000Z"
    }
  ]
}
Revoke a key — only the owning wallet can revoke:
curl -X DELETE https://your-domain.com/api/agent/keys \
  -H "Authorization: Bearer shoot_ak_..." \
  -H "Content-Type: application/json" \
  -d '{ "keyId": "clxyz123" }'
{ "revoked": true }

Rate Limits

Requests are rate-limited per API key using a sliding window:
Tool CategoryLimitWindow
Read tools60 requests1 minute
Trading tools10 requests1 minute
When you exceed the limit, the API returns 429 Too Many Requests with a Retry-After header (in seconds).

Tier A: Execute Endpoint

Direct tool dispatch — your code picks the tool and passes parameters. No LLM involved, zero latency overhead.
POST /api/agent/execute
Authorization: Bearer shoot_ak_...
Content-Type: application/json

Request format

{
  "tool": "openLong",
  "params": {
    "collateralAmount": 50,
    "collateralTokenSymbol": "USDC",
    "tokenSymbol": "JITOSOL",
    "leverage": 3
  }
}

Response format

Success (200):
{
  "result": {
    "requiresSignature": true,
    "quote": {
      "entryPrice": 142.35,
      "size": 0.001052,
      "fee": 0.05
    },
    "transaction": "AQAAAA...base64..."
  }
}
Error (400/401/429/500):
{
  "error": "Unknown tool \"foo\". Available: getPositions, getPoolStats, ..."
}

Tier B: Chat Endpoint

Conversational AI endpoint using OpenAI GPT-4o with all tools registered. The LLM reasons about your request and calls tools on your behalf. Returns a Server-Sent Events (SSE) stream.
POST /api/agent/chat
Authorization: Bearer shoot_ak_...
Content-Type: application/json

Request format

{
  "messages": [
    { "role": "user", "content": "What are the current pool stats on Adrena?" }
  ]
}

Response

SSE stream following the Vercel AI SDK UI Message Stream Protocol. The LLM may call multiple tools within a single response (up to 5 steps).

Chat example (TypeScript with AI SDK)

import { useChat } from "ai/react";

const { messages, input, handleInputChange, handleSubmit } = useChat({
  api: "https://your-domain.com/api/agent/chat",
  headers: {
    Authorization: "Bearer shoot_ak_...",
  },
});

Chat example (Python — raw SSE)

import requests

res = requests.post(
    "https://your-domain.com/api/agent/chat",
    headers={
        "Authorization": "Bearer shoot_ak_...",
        "Content-Type": "application/json",
    },
    json={
        "messages": [
            {"role": "user", "content": "Open a 3x long on SOL with 50 USDC"}
        ]
    },
    stream=True,
)

for line in res.iter_lines():
    if line:
        print(line.decode())

Available Tools

All tools are scoped to the authenticated wallet. The account parameter is always injected from your API key — you cannot generate transactions for wallets you don’t own.

Read Tools

Fetch open and historical trading positions for your wallet on Adrena.Rate limit tier: Read (60/min)Parameters:
ParameterTypeRequiredDefaultDescription
limitintegerNo100Max positions to return (1–500)
Example request:
{ "tool": "getPositions", "params": { "limit": 10 } }
Example response:
{
  "result": {
    "positions": [
      {
        "mint": "So11111111111111111111111111111111111111112",
        "side": "long",
        "size": 0.5,
        "collateral": 100,
        "entryPrice": 142.3,
        "currentPrice": 145.5,
        "pnl": 2.24,
        "leverage": 2.0,
        "status": "open"
      }
    ]
  }
}
Get aggregated Adrena pool statistics: daily/total volume, fees, and pool name.Rate limit tier: Read (60/min)Parameters:
ParameterTypeRequiredDefaultDescription
endDatestringNoEnd date filter in YYYY-MM-DD format
Example request:
{ "tool": "getPoolStats", "params": {} }
Example response:
{
  "result": {
    "pool_name": "main-pool",
    "daily_volume_usd": 15420000,
    "total_volume_usd": 892000000,
    "daily_fees_usd": 4250,
    "total_fees_usd": 267000
  }
}
Get real-time per-custody liquidity breakdown: TVL, utilization, and target ratios.Rate limit tier: Read (60/min)Parameters: NoneExample request:
{ "tool": "getLiquidityInfo", "params": {} }
Example response:
{
  "result": {
    "custodies": [
      {
        "symbol": "USDC",
        "aumUsd": "45000000.50",
        "targetRatio": "0.40",
        "currentRatio": "0.38",
        "utilizationRate": "0.65"
      },
      {
        "symbol": "SOL",
        "aumUsd": "32000000.00",
        "targetRatio": "0.30",
        "currentRatio": "0.31",
        "utilizationRate": "0.72"
      }
    ]
  }
}
Get competition leaderboard standings for a specific cohort, ranked by tournament score.Rate limit tier: Read (60/min)Parameters:
ParameterTypeRequiredDescription
cohortIdstringYesThe competition cohort ID
Example request:
{ "tool": "getLeaderboard", "params": { "cohortId": "cohort_abc123" } }
Example response:
{
  "result": {
    "standings": [
      {
        "wallet": "Abc123...",
        "rank": 1,
        "tournamentScore": 85.4,
        "pnlPercent": 12.3,
        "volume": 150000,
        "tradeCount": 45
      }
    ]
  }
}
List all live and upcoming trading competitions you can join.Rate limit tier: Read (60/min)Parameters: NoneExample request:
{ "tool": "getActiveCohorts", "params": {} }
Example response:
{
  "result": {
    "cohorts": [
      {
        "id": "cohort_abc123",
        "name": "Weekly Sprint #42",
        "status": "live",
        "startsAt": "2026-03-24T00:00:00.000Z",
        "endsAt": "2026-03-31T00:00:00.000Z",
        "enrollmentCount": 128
      }
    ]
  }
}
List all competitions your wallet is enrolled in.Rate limit tier: Read (60/min)Parameters: NoneExample request:
{ "tool": "getMyEnrollments", "params": {} }
Example response:
{
  "result": {
    "enrollments": [
      {
        "cohortId": "cohort_abc123",
        "wallet": "YourWallet...",
        "enrolledAt": "2026-03-24T01:30:00.000Z",
        "status": "active"
      }
    ]
  }
}

Trading Tools

All trading tools return unsigned Solana transactions. Your agent must:
  1. Decode the base64 transaction
  2. Sign it with the wallet’s private key
  3. Submit it to a Solana RPC endpoint
Generate an unsigned transaction to open a leveraged long position on Adrena.Rate limit tier: Trade (10/min)Parameters:
ParameterTypeRequiredDescription
collateralAmountnumberYesCollateral amount in token units (must be positive)
collateralTokenSymbolstringYesCollateral token: USDC, SOL
tokenSymbolstringYesMarket to trade: SOL, BTC, ETH, BONK, JITOSOL, XAU, XAG, EUR, GBP
leveragenumberYesLeverage multiplier (1.1–100)
takeProfitnumberNoTake profit price
stopLossnumberNoStop loss price
Example request:
{
  "tool": "openLong",
  "params": {
    "collateralAmount": 50,
    "collateralTokenSymbol": "USDC",
    "tokenSymbol": "JITOSOL",
    "leverage": 3,
    "stopLoss": 130
  }
}
Example response:
{
  "result": {
    "requiresSignature": true,
    "quote": {
      "entryPrice": 142.35,
      "size": 0.001052,
      "fee": 0.05,
      "liquidationPrice": 95.6
    },
    "transaction": "AQAAAA...base64..."
  }
}
Generate an unsigned transaction to open a leveraged short position on Adrena.Rate limit tier: Trade (10/min)Parameters:
ParameterTypeRequiredDescription
collateralAmountnumberYesCollateral amount in token units (must be positive)
collateralTokenSymbolstringYesCollateral token: USDC, SOL
tokenSymbolstringYesMarket to trade: SOL, BTC, ETH, BONK, JITOSOL, XAU, XAG, EUR, GBP
leveragenumberYesLeverage multiplier (1.1–100)
takeProfitnumberNoTake profit price
stopLossnumberNoStop loss price
Example request:
{
  "tool": "openShort",
  "params": {
    "collateralAmount": 100,
    "collateralTokenSymbol": "USDC",
    "tokenSymbol": "BTC",
    "leverage": 5,
    "takeProfit": 55000
  }
}
Example response:
{
  "result": {
    "requiresSignature": true,
    "quote": {
      "entryPrice": 67250.0,
      "size": 0.00745,
      "fee": 0.12
    },
    "transaction": "AQAAAA...base64..."
  }
}
Generate an unsigned transaction to close (fully or partially) a long position.Rate limit tier: Trade (10/min)Parameters:
ParameterTypeRequiredDescription
collateralTokenSymbolstringYesCollateral token symbol of the position
tokenSymbolstringYesMarket token symbol of the position
percentagenumberNoPercentage of position to close (1–100, default: 100)
Example request:
{
  "tool": "closeLong",
  "params": {
    "collateralTokenSymbol": "USDC",
    "tokenSymbol": "SOL",
    "percentage": 50
  }
}
Example response:
{
  "result": {
    "requiresSignature": true,
    "quote": {
      "exitPrice": 145.2,
      "pnl": 3.5,
      "fee": 0.03
    },
    "transaction": "AQAAAA...base64..."
  }
}
Generate an unsigned transaction to close (fully or partially) a short position.Rate limit tier: Trade (10/min)Parameters:
ParameterTypeRequiredDescription
collateralTokenSymbolstringYesCollateral token symbol of the position
tokenSymbolstringYesMarket token symbol of the position
percentagenumberNoPercentage of position to close (1–100, default: 100)
Example request:
{
  "tool": "closeShort",
  "params": {
    "collateralTokenSymbol": "USDC",
    "tokenSymbol": "BTC"
  }
}
Example response:
{
  "result": {
    "requiresSignature": true,
    "quote": {
      "exitPrice": 66800.0,
      "pnl": 4.5,
      "fee": 0.08
    },
    "transaction": "AQAAAA...base64..."
  }
}
Generate an unsigned transaction to place a limit order for a long position. Executes when the market hits your trigger price.Rate limit tier: Trade (10/min)Parameters:
ParameterTypeRequiredDescription
collateralAmountnumberYesCollateral amount
collateralTokenSymbolstringYesCollateral token symbol
tokenSymbolstringYesMarket token symbol
leveragenumberYesLeverage multiplier (1.1–100)
triggerPricenumberYesPrice at which the order triggers
limitPricenumberNoMaximum execution price
Example request:
{
  "tool": "openLimitLong",
  "params": {
    "collateralAmount": 100,
    "collateralTokenSymbol": "USDC",
    "tokenSymbol": "ETH",
    "leverage": 2,
    "triggerPrice": 3200
  }
}
Example response:
{
  "result": {
    "requiresSignature": true,
    "quote": {
      "triggerPrice": 3200,
      "leverage": 2,
      "estimatedSize": 0.0625
    },
    "transaction": "AQAAAA...base64..."
  }
}
Generate an unsigned transaction to place a limit order for a short position. Executes when the market hits your trigger price.Rate limit tier: Trade (10/min)Parameters:
ParameterTypeRequiredDescription
collateralAmountnumberYesCollateral amount
collateralTokenSymbolstringYesCollateral token symbol
tokenSymbolstringYesMarket token symbol
leveragenumberYesLeverage multiplier (1.1–100)
triggerPricenumberYesPrice at which the order triggers
limitPricenumberNoMinimum execution price
Example request:
{
  "tool": "openLimitShort",
  "params": {
    "collateralAmount": 200,
    "collateralTokenSymbol": "USDC",
    "tokenSymbol": "SOL",
    "leverage": 4,
    "triggerPrice": 160,
    "limitPrice": 158
  }
}
Example response:
{
  "result": {
    "requiresSignature": true,
    "quote": {
      "triggerPrice": 160,
      "leverage": 4,
      "estimatedSize": 5.0
    },
    "transaction": "AQAAAA...base64..."
  }
}

Tool Summary

ToolCategoryRate LimitDescription
getPositionsRead60/minFetch wallet’s open and historical positions
getPoolStatsRead60/minAdrena pool volume, fees, TVL
getLiquidityInfoRead60/minPer-custody liquidity breakdown
getLeaderboardRead60/minCompetition standings by cohort
getActiveCohortsRead60/minLive and upcoming competitions
getMyEnrollmentsRead60/minWallet’s enrolled competitions
openLongTrade10/minOpen leveraged long position
openShortTrade10/minOpen leveraged short position
closeLongTrade10/minClose (full/partial) a long position
closeShortTrade10/minClose (full/partial) a short position
openLimitLongTrade10/minLimit order for long position
openLimitShortTrade10/minLimit order for short position

Transaction Signing Flow

Trading tools return unsigned transactions. Here’s the complete flow:
Agent                           Shoot API                    Solana
  │                                │                           │
  │  POST /api/agent/execute       │                           │
  │  { tool: "openLong", ... }     │                           │
  │ ──────────────────────────────>│                           │
  │                                │ fetchOpenLong(wallet, ..) │
  │                                │ ────────────────────────> │
  │                                │ <──── unsigned tx ─────── │
  │  { quote, transaction }        │                           │
  │ <──────────────────────────────│                           │
  │                                                            │
  │  decode base64 tx                                          │
  │  sign with private key                                     │
  │  ─────────────────────────────────────────────────────────>│
  │                                                  tx landed │
  │  <─────────────────────────────────────────────────────────│

Signing example (TypeScript)

import { Connection, Transaction, Keypair } from "@solana/web3.js";
import bs58 from "bs58";

const API_KEY = "shoot_ak_...";
const wallet = Keypair.fromSecretKey(/* your key */);
const connection = new Connection("https://api.mainnet-beta.solana.com");

// 1. Get unsigned transaction
const res = await fetch("https://your-domain.com/api/agent/execute", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    tool: "openLong",
    params: {
      collateralAmount: 50,
      collateralTokenSymbol: "USDC",
      tokenSymbol: "JITOSOL",
      leverage: 3,
    },
  }),
});

const { result } = await res.json();

// 2. Decode and sign
const tx = Transaction.from(Buffer.from(result.transaction, "base64"));
tx.sign(wallet);

// 3. Submit to Solana
const signature = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(signature);

console.log("Trade executed:", signature);

Signing example (Python)

import base64, requests
from solders.keypair import Keypair
from solders.transaction import Transaction
from solana.rpc.api import Client

API_KEY = "shoot_ak_..."
wallet = Keypair()  # or load from file
client = Client("https://api.mainnet-beta.solana.com")

# 1. Get unsigned transaction
res = requests.post(
    "https://your-domain.com/api/agent/execute",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json={
        "tool": "openLong",
        "params": {
            "collateralAmount": 50,
            "collateralTokenSymbol": "USDC",
            "tokenSymbol": "JITOSOL",
            "leverage": 3,
        },
    },
)

result = res.json()["result"]

# 2. Decode and sign
tx_bytes = base64.b64decode(result["transaction"])
tx = Transaction.from_bytes(tx_bytes)
signed_tx = wallet.sign_message(tx.message_data())

# 3. Submit to Solana
sig = client.send_raw_transaction(bytes(tx))
print(f"Trade executed: {sig.value}")

Security Model

Non-Custodial

The server never holds private keys. Trading tools return unsigned transactions that agents sign client-side. Your keys stay on your machine.

Wallet-Scoped

Every tool call is scoped to the wallet bound to the API key. Even if an agent sends a different account in params, the server injects the authenticated wallet. You cannot generate transactions for wallets you don’t own.

Key Isolation

API keys are SHA-256 hashed before storage. Plaintext is shown once at creation. Revoked keys are soft-deleted and immediately stop authenticating.

Rate Limited

Per-key sliding window rate limits prevent abuse. Trading operations are throttled more aggressively (10/min) than reads (60/min).

Error Codes

StatusMeaningCommon Causes
400Bad RequestMissing tool field, unknown tool name, invalid params
401UnauthorizedMissing or invalid API key, revoked key
429Rate LimitedToo many requests — check Retry-After header
500Server ErrorAdrena API failure, tool execution error
All error responses follow the format:
{ "error": "Human-readable error message" }

Available Markets

SymbolAssetType
SOLSolanaCrypto
BTCBitcoinCrypto
ETHEthereumCrypto
BONKBonkCrypto
JITOSOLJito Staked SOLCrypto
XAUGoldCommodity
XAGSilverCommodity
EUREuroForex
GBPBritish PoundForex
Collateral tokens: USDC, SOL