3rd party API
Overview
This document describes the HTTP API that external partners can use to automate account provisioning, portfolio monitoring, trading oversight, and conversational support. All endpoints are versioned under /api/v1 and require an API key.
Need an API key? contact us on discord
Authentication
Error Handling
Every endpoint returns standard HTTP status codes. Error bodies follow this structure:
{
"error": {
"code": "string",
"message": "Human readable explanation",
"details": { "field": "optional data" }
}
}Pagination & Filtering
Collection endpoints accept
page,pageSize(default 25, max 200),sort, and resource-specific filters.
Resource Models
Below are the core objects returned by the API.
User
id, signupWalletId, wallets[] (each id, address, chain, type), provider, invitedBy, createdAt, updatedAt
{"id":"usr_123","provider":"wallet","wallets":[{"id":"wal_signup","address":"7HgJ...","chain":"solana","type":"signup"}]}
Holding
id, wallet, tokenAddress, chain, decimals, assetClass, totalHoldings, tokenUSDPrice, tokenSolPrice, totalUSDval, totalSolval, usdValueUpdatedAt, timestamps
{"id":"hld_1","wallet":"wal_1","tokenAddress":"So1111...","assetClass":"majors","totalUSDval":"200500.12"}
Transaction
id, walletId, orderId, txType (buy, sell, swap), fromToken, toToken, txAmount, toAmount, txSignature, solValue, usdValue, feeInLamports, timestamps
{"id":"txn_1","walletId":"wal_1","txType":"buy","usdValue":"2400.12","orderId":"ord_1"}
PositionThesis
id, userId, walletId, tokenAddress, tokenSymbol, thesis, riskRewardRatio, confidence, expiresAt, timestamps
{"id":"ths_1","userId":"usr_123","tokenSymbol":"HYPE","confidence":0.45}
AutoTradeLog
id, userId, log, thoughts, tokenAddress, createdAt
{"id":"log_1","userId":"usr_123","log":"Opened thesis on HYPE"}
AutoTradeInstruction
id, userId, instructions, allocation, allowList, strategy, riskTolerance, isActive, timestamps
{"id":"ati_1","userId":"usr_123","isActive":true,"riskTolerance":"balanced"}
Conversation
conversationId, userId, messages[] (each id, role, content, createdAt), updatedAt
{"conversationId":"65f...","userId":"usr_123","messages":[{"role":"user","content":"What is my PnL?"}]}
User payloads embed wallets, which mirror rows in milo.wallets and expose id, address, and chain (network, currently solana). The type field is normalized for this API: the wallet referenced by signupWalletId is labeled signup, and non-custodial wallets provisioned by Milo are labeled milo.
Wallet Structure Example
{
"id": "wal_signup",
"address": "7HgJ...signup",
"chain": "solana",
"type": "signup"
}type is either signup (the onboarding wallet) or milo (non-custodial wallets issued by Milo). Additional non-custodial wallets inherit the same structure with their respective identifiers.
Endpoints
All endpoints below require the X-API-Key header described earlier (examples omit it for brevity). User-scoped endpoints always identify the target user through the userId path parameter.
Create User
Create a trading user and the first wallet. This endpoint fails with 409 Conflict if the supplied wallet already belongs to an existing Milo user.
Method: POST
Path:
/api/v1/usersHeaders:
X-API-KeyBody:
{
"signupWallet": "7HgJ... WALLET_ADDRESS"
}Response:
{
"user": {
"id": "uuid",
"signupWalletId": "uuid",
"wallets": [
{
"id": "uuid",
"address": "7HgJ...",
"chain": "solana",
"type": "signup"
},
{
"id": "uuid",
"address": "HCm9...",
"chain": "solana",
"type": "milo"
}
],
"provider": "wallet",
"invitedBy": null,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
}Get Diary Logs
Return the short auto-trader diary entries attached to a user (auto_trade_logs).
Method: GET
Path:
/api/v1/users/{userId}/diary-logs?page=1&pageSize=20Response:
{
"diaryLogs": [
{
"id": "uuid",
"userId": "uuid",
"log": "Opened thesis on HYPE",
"thoughts": "Watching liquidity",
"tokenAddress": "So111111...",
"createdAt": "2024-01-01T00:00:00.000Z"
}
],
"page": 1,
"pageSize": 20,
"total": 58
}Get Executed Transactions
List fulfilled blockchain transactions that originated from an order (non-null orderId).
Method: GET
Path:
/api/v1/wallets/{walletId}/executed-transactions?since=2024-01-01T00:00:00ZFilters:
txType(buy,sell,swap),token,minUsdValue,since,until.Response:
{
"executions": [
{
"id": "uuid",
"walletId": "uuid",
"orderId": "uuid",
"txType": "buy",
"fromToken": "So1111...",
"toToken": "DezXAZ8z7PnrnR...",
"txAmount": "20.00",
"toAmount": "120000.00",
"txSignature": "5t7...",
"solValue": "20.4",
"usdValue": "2400.12",
"feeInLamports": 5000,
"createdAt": "2024-01-01T00:00:00.000Z"
}
]
}Get Holdings
Return the latest balance snapshot from the holdings table for a wallet or for every wallet accessible with the API key.
Method: GET
Path:
/api/v1/wallets/{walletId}/holdingsResponse:
{
"holdings": [
{
"id": "uuid",
"wallet": "uuid",
"tokenAddress": "So1111...",
"chain": "solana",
"decimals": 9,
"assetClass": "majors",
"totalHoldings": "1250000000",
"tokenUSDPrice": "160.40",
"tokenSolPrice": "1",
"totalUSDval": "200500.12",
"totalSolval": "1250.50",
"usdValueUpdatedAt": "2024-01-01T00:00:00.000Z",
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
]
}Get Positions (Theses)
Fetch the user’s open and historical theses, enriched with linked orders and PnL metrics.
Method: GET
Path:
/api/v1/users/{userId}/positions?status=activeQuery Params:
status(active,pending,not_active) optional.Response:
{
"positions": [
{
"thesisId": "ths_123",
"userId": "usr_123",
"walletId": "wal_1",
"tokenSymbol": "HYPE",
"tokenAddress": "So1111...",
"tokenCanonical": "So1111...",
"thesis": "Accumulating ahead of catalyst",
"riskRewardRatio": 3.5,
"confidence": 0.45,
"thesisExpiresAt": null,
"thesisCreatedAt": "2024-01-01T00:00:00.000Z",
"thesisUpdatedAt": "2024-01-02T00:00:00.000Z",
"entries": [
{
"orderId": "ord_entry",
"createdAt": "2024-01-01T00:00:00.000Z",
"status": "fulfilled",
"executedAvgUnitPriceUsd": 0.002,
"executedQty": 120000
}
],
"exits": [
{
"orderId": "ord_exit",
"createdAt": "2024-01-05T00:00:00.000Z",
"status": "fulfilled",
"executedAvgUnitPriceUsd": 0.0034,
"executedQty": 80000,
"type": "sell"
}
],
"takeProfits": [
{
"orderId": "ord_tp",
"createdAt": "2024-01-01T00:10:00.000Z",
"status": "active",
"executedAvgUnitPriceUsd": null,
"executedQty": null,
"triggerLevel": 0.004,
"operator": "gte",
"allocation": 0.25,
"expiresAt": null
}
],
"stopLosses": [],
"buyOrders": [],
"sellOrders": [],
"errors": [],
"investedUsd": 2400.12,
"soldUsd": 800.0,
"remainingQty": 40000,
"realisedPnlUsd": 160.5,
"currentPriceUsd": 0.0038,
"priceUpdatedAt": "2024-01-05T00:00:00.000Z",
"currentValueUsd": 152,
"remainingCostUsd": 96,
"unrealisedPnlUsd": 56,
"status": "active",
"firstBuyTime": "2024-01-01T00:00:00.000Z",
"lastTxTime": "2024-01-05T00:00:00.000Z",
"tokenLogoUri": "https://assets.../hype.png",
"tokenSocials": {
"twitter": "https://x.com/hype",
"website": "https://hype.xyz"
}
}
]
}Get Transactions
Return every on-chain confirmed transaction captured for a wallet.
Method: GET
Path:
/api/v1/wallets/{walletId}/transactions?page=1&pageSize=50Notes: Includes both executed order-linked transactions and ad-hoc transfers (
orderIdcan benull).txTypeis always one ofbuy,sell, orswap.Response:
{
"transactions": [
{
"id": "uuid",
"walletId": "uuid",
"orderId": null,
"txType": "swap",
"fromToken": "USDC",
"toToken": "USDC",
"txAmount": "5000.00",
"toAmount": "5000.00",
"txSignature": "45s...",
"solValue": "0",
"usdValue": "5000.00",
"createdAt": "2024-01-01T00:00:00.000Z"
}
],
"page": 1,
"pageSize": 50,
"total": 240
}Update Auto Trade Settings
Upsert the auto trade settings.
Method: PATCH
Path:
/api/v1/users/{userId}/auto-trade-settingsField requirements:
riskToleranceandstrategymust always be supplied.allocation,instructions, andallowListare optional.isActivecan be set totrueonly if the user’s Milo wallet currently holds at least 1 SOL.
Body:
{
"instructions": "Always ladder out",
"allocation": { "memes": 0.1, "majors": 0.3, "native": 0.6 },
"allowList": ["memes", "native"],
"strategy": "Risk-on rotation",
"riskTolerance": "balanced",
"isActive": true
}Response:
{
"autoTradeSettings": {
"id": "uuid",
"userId": "uuid",
"instructions": "Always ladder out",
"allocation": { "memes": 0.1, "majors": 0.3, "native": 0.6 },
"allowList": ["memes", "native"],
"strategy": "Risk-on rotation",
"riskTolerance": "balanced",
"isActive": true,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
}
}Get Conversation
Retrieve a conversation thread as a simple array of role-based messages.
Method: GET
Path:
/api/v1/conversations/{conversationId}Response:
{
"conversation": {
"conversationId": "65f...",
"userId": "usr_123",
"messages": [
{
"id": "msg_1",
"role": "user",
"content": "What is my PnL?",
"createdAt": "2024-01-01T00:00:00.000Z"
},
{
"id": "msg_2",
"role": "assistant",
"content": "Your realized PnL is 42.3 SOL.",
"createdAt": "2024-01-01T00:00:05.000Z"
}
],
"updatedAt": "2024-01-01T00:00:05.000Z"
}
}Send Message
Append a new message to an existing conversation. Only the conversationId and the message payload (role, content) are required; the response echoes the stored message.
Method: POST
Path:
/api/v1/messagesBody:
{
"conversationId": "65f...",
"message": {
"role": "user",
"content": "What is my PnL?"
}
}Response:
{
"conversationId": "65f...",
"message": {
"id": "msg_3",
"role": "user",
"content": "What is my PnL?",
"createdAt": "2024-01-01T00:00:10.000Z"
}
}Last updated