PeakBot Docs
Bots EndpointBot Trades

Create Trade

Create a bot trade with associated transactions

Create a new bot trade with one or more entry transactions. This endpoint creates both the trade record and all associated transactions atomically in a database transaction. Note: Exit transactions (stop losses, take profits, trailing stops, trim exits) should be added separately using the Add Transactions endpoint after the trade is created.

Endpoint

POST /api/bots/:slug/trades

Authentication

All requests require bot API key authentication via the x-api-key header.

headers: {
  'x-api-key': 'your-bot-api-key'
}

Path Parameters

ParameterTypeRequiredDescription
slugstringYesBot identifier (alphanumeric, hyphens, underscores only)

Slug Validation

The slug must match the regex pattern: /^[a-zA-Z0-9_-]+$/

Request Body

{
  symbol: string;                    // Required: Trade symbol
  tradeType: string;                 // Required: Type of trade
  status: string;                     // Required: Trade status
  signalAt: string;                   // Required: ISO timestamp when signal was generated
  openedAt?: string;                 // Optional: ISO timestamp when trade opened
  closedAt?: string;                 // Optional: ISO timestamp when trade closed
  expirationDate?: string;           // Optional: Expiration date for options/derivatives
  netPnl?: string;                    // Optional: Net profit/loss
  errorMessage?: string;              // Optional: Error message if trade failed
  errorAt?: string;                   // Optional: ISO timestamp when error occurred
  lastUpdateAt?: string;              // Optional: ISO timestamp of last update
  metadata?: Record<string, unknown>;  // Optional: Additional metadata
  transactions: Array<{                // Required: Array of transactions
    transactionGroup: "entry" | "exit";
    exitType?: string;                 // Required for exit transactions
    trimLevel?: number;                // Required for trim exits
    symbol: string;                    // Required: Transaction symbol
    assetType: string;                 // Required: "stock", "option", etc.
    side: string;                      // Required: "buy", "sell"
    type: string;                      // Required: Order type
    quantity: number;                  // Required: Quantity
    transactionDate: string;           // Required: ISO timestamp
    stopPrice?: string;                // Optional: Stop price
    price?: string;                    // Optional: Limit price
    optionType?: string;               // Optional: "call" or "put" for options
    strikePrice?: string;              // Optional: Strike price for options
    expirationDate?: string;           // Optional: Expiration for options
    status?: string;                   // Optional: Transaction status
    filledAt?: string;                 // Optional: ISO timestamp when filled
    filledPrice?: string;              // Optional: Fill price
    filledQuantity?: string;           // Optional: Filled quantity
    avgFillPrice?: string;             // Optional: Average fill price
    broker?: string;                    // Optional: Broker code
    brokerAccountNumber?: string;       // Optional: Broker account number
    brokerOrderId?: string;            // Optional: Broker order ID
    brokerParentOrderId?: string;      // Optional: Broker parent order ID (for bracket orders)
    notes?: string;                    // Optional: Notes
    metadata?: Record&lt;string, unknown&gt;; // Optional: Transaction metadata
  }>;
}

Request Body Schema

Trade Fields

FieldTypeRequiredDescription
symbolstringYesPrimary symbol for the trade
tradeTypestringYesType of trade (e.g., "long", "short", "spread")
statusstringYesTrade status (e.g., "open", "closed", "error")
signalAtstring (ISO timestamp)YesWhen the trading signal was generated
openedAtstring (ISO timestamp)NoWhen the trade was opened
closedAtstring (ISO timestamp)NoWhen the trade was closed
expirationDatestringNoExpiration date for options/derivatives
netPnlstringNoNet profit/loss as decimal string
errorMessagestringNoError message if trade failed
errorAtstring (ISO timestamp)NoWhen the error occurred
lastUpdateAtstring (ISO timestamp)NoLast update timestamp
metadataobjectNoAdditional metadata (defaults to {})
transactionsarrayYesArray of transactions (must not be empty)

Transaction Fields

FieldTypeRequiredDescription
transactionGroup"entry" | "exit"YesWhether this is an entry or exit transaction
exitTypestringYes*Exit type (required if transactionGroup is "exit")
trimLevelnumberYes**Trim level (required if exitType is "trim")
symbolstringYesTransaction symbol (may differ from trade symbol for options)
assetTypestringYesAsset type (e.g., "stock", "option")
sidestringYesSide of transaction ("buy" or "sell")
typestringYesOrder type (e.g., "market", "limit", "stop")
quantitynumberYesQuantity/shares
transactionDatestring (ISO timestamp)YesTransaction date/time
stopPricestringNoStop price for stop orders
pricestringNoLimit price for limit orders
optionTypestringNoOption type ("call" or "put")
strikePricestringNoStrike price for options
expirationDatestringNoExpiration date for options
statusstringNoTransaction status (e.g., "open", "filled")
filledAtstring (ISO timestamp)NoWhen transaction was filled
filledPricestringNoFill price
filledQuantitystringNoFilled quantity
avgFillPricestringNoAverage fill price
brokerstringNoBroker code
brokerAccountNumberstringNoBroker account number
brokerOrderIdstringNoBroker order ID
brokerParentOrderIdstringNoBroker parent order ID (for bracket orders)
notesstringNoNotes
metadataobjectNoTransaction metadata (defaults to {})

* Required when transactionGroup is "exit"
** Required when exitType is "trim"

Validation Rules

Trade Level:

  • symbol must be a non-empty string
  • tradeType must be a non-empty string
  • status must be a non-empty string
  • signalAt must be a valid ISO timestamp string
  • transactions must be a non-empty array

Transaction Level:

  • transactionGroup must be exactly "entry" or "exit"
  • If transactionGroup is "exit", exitType is required
  • If exitType is "trim", trimLevel is required and must be a number
  • symbol, assetType, side, type must be non-empty strings
  • quantity must be a number
  • transactionDate must be a valid ISO timestamp string

Option Symbol Parsing:

  • For options with assetType: "option", the system automatically extracts the underlying symbol from Tradier format: TICKER + YYMMDD + C/P + STRIKE
  • Example: "AAPL230120C00150000" extracts underlying symbol "AAPL"

Response

Success Response (200 OK)

{
  "success": true,
  "data": {
    "botTrade": {
      "id": "111e4567-e89b-12d3-a456-426614174001",
      "botId": "123e4567-e89b-12d3-a456-426614174000",
      "symbol": "AAPL",
      "tradeType": "long",
      "status": "open",
      "signalAt": "2024-01-15T10:30:00.000Z",
      "openedAt": "2024-01-15T10:30:05.000Z",
      "netPnl": null,
      "metadata": {}
    },
    "transactions": [
      {
        "id": "222e4567-e89b-12d3-a456-426614174002",
        "botTradeId": "111e4567-e89b-12d3-a456-426614174001",
        "transactionGroup": "entry",
        "symbol": "AAPL",
        "underlyingSymbol": "AAPL",
        "assetType": "stock",
        "side": "buy",
        "type": "market",
        "quantity": 100,
        "status": "open",
        "transactionDate": "2024-01-15T10:30:05.000Z"
      },
      {
        "id": "333e4567-e89b-12d3-a456-426614174003",
        "botTradeId": "111e4567-e89b-12d3-a456-426614174001",
        "transactionGroup": "exit",
        "exitType": "stop",
        "symbol": "AAPL",
        "underlyingSymbol": "AAPL",
        "assetType": "stock",
        "side": "sell",
        "type": "stop",
        "stopPrice": "145.00",
        "quantity": 100,
        "status": "open",
        "transactionDate": "2024-01-15T10:30:05.000Z"
      }
    ]
  }
}

Response Schema

FieldTypeDescription
successbooleanAlways true for successful requests
dataobjectCreated trade and transactions
data.botTradeobjectCreated bot trade object
data.transactionsarrayArray of created transaction objects

Error Responses

400 Bad Request

Invalid JSON:

{
  "error": "Invalid JSON in request body",
  "code": "BAD_REQUEST"
}

Missing required field:

{
  "error": "symbol is required and must be a string",
  "code": "BAD_REQUEST"
}

Invalid transaction group:

{
  "error": "transactions[0].transactionGroup must be 'entry' or 'exit'",
  "code": "BAD_REQUEST"
}

Missing exit type:

{
  "error": "transactions[0].exitType is required for exit transactions",
  "code": "BAD_REQUEST"
}

Missing trim level:

{
  "error": "transactions[0].trimLevel is required for trim exits",
  "code": "BAD_REQUEST"
}

Empty transactions array:

{
  "error": "transactions array cannot be empty",
  "code": "BAD_REQUEST"
}

401 Unauthorized

Missing API key:

{
  "message": "API key required. Include x-api-key header."
}

403 Forbidden

Invalid API key:

{
  "message": "Invalid API key for this bot"
}

404 Not Found

Bot not found:

{
  "error": "Bot with slug 'my-bot' not found",
  "code": "NOT_FOUND"
}

500 Internal Server Error

{
  "error": "Internal server error",
  "code": "INTERNAL_SERVER_ERROR"
}

Code Examples

TypeScript

interface Transaction {
  transactionGroup: "entry" | "exit";
  exitType?: string;
  trimLevel?: number;
  symbol: string;
  assetType: string;
  side: string;
  type: string;
  quantity: number;
  transactionDate: string;
  stopPrice?: string;
  price?: string;
  // ... other optional fields
}

async function createBotTrade(
  botSlug: string,
  apiKey: string,
  trade: {
    symbol: string;
    tradeType: string;
    status: string;
    signalAt: string;
    transactions: Transaction[];
    openedAt?: string;
  }
) {
  const response = await fetch(`https://api.example.com/api/bots/${botSlug}/trades`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": apiKey,
    },
    body: JSON.stringify(trade),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Failed to create trade: ${error.error}`);
  }

  return await response.json();
}

// Example: Simple long trade with entry transaction
const trade = await createBotTrade("my-bot", apiKey, {
  symbol: "AAPL",
  tradeType: "long",
  status: "open",
  signalAt: new Date().toISOString(),
  openedAt: new Date().toISOString(),
  transactions: [
    {
      transactionGroup: "entry",
      symbol: "AAPL",
      assetType: "stock",
      side: "buy",
      type: "market",
      quantity: 100,
      transactionDate: new Date().toISOString(),
      status: "filled",
      filledAt: new Date().toISOString(),
      filledPrice: "150.25"
    }
  ]
});

console.log(`Trade created: ${trade.data.botTrade.id}`);
// Note: Exit transactions (stop loss, take profit, etc.) should be added separately
// using the add-transactions endpoint

Python

from typing import List, Dict, Any, Optional
from datetime import datetime
import requests

def create_bot_trade(
    bot_slug: str,
    api_key: str,
    symbol: str,
    trade_type: str,
    status: str,
    signal_at: str,
    transactions: List[Dict[str, Any]],
    opened_at: Optional[str] = None
) -> Dict[str, Any]:
    """
    Create a bot trade with transactions.
    
    Args:
        bot_slug: Bot identifier
        api_key: Bot API key
        symbol: Trade symbol
        trade_type: Type of trade
        status: Trade status
        signal_at: ISO timestamp when signal was generated
        transactions: List of transaction dictionaries
        opened_at: Optional ISO timestamp when trade opened
        
    Returns:
        Response dictionary with created trade and transactions
        
    Raises:
        requests.HTTPError: If the request fails
    """
    url = f"https://api.example.com/api/bots/{bot_slug}/trades"
    
    payload = {
        "symbol": symbol,
        "tradeType": trade_type,
        "status": status,
        "signalAt": signal_at,
        "transactions": transactions
    }
    
    if opened_at:
        payload["openedAt"] = opened_at
    
    headers = {
        "Content-Type": "application/json",
        "x-api-key": api_key
    }
    
    response = requests.post(url, json=payload, headers=headers)
    response.raise_for_status()
    
    return response.json()

# Example: Simple long trade with entry transaction
trade = create_bot_trade(
    bot_slug="my-bot",
    api_key="your-api-key",
    symbol="AAPL",
    trade_type="long",
    status="open",
    signal_at=datetime.now().isoformat(),
    opened_at=datetime.now().isoformat(),
    transactions=[
        {
            "transactionGroup": "entry",
            "symbol": "AAPL",
            "assetType": "stock",
            "side": "buy",
            "type": "market",
            "quantity": 100,
            "transactionDate": datetime.now().isoformat(),
            "status": "filled",
            "filledAt": datetime.now().isoformat(),
            "filledPrice": "150.25"
        }
    ]
)

print(f"Trade created: {trade['data']['botTrade']['id']}")
# Note: Exit transactions (stop loss, take profit, etc.) should be added separately
# using the add-transactions endpoint

Use Cases

Simple Long Trade with Stop Loss

// Entry buy + stop loss exit
await createBotTrade("my-bot", apiKey, {
  symbol: "AAPL",
  tradeType: "long",
  status: "open",
  signalAt: new Date().toISOString(),
  transactions: [
    {
      transactionGroup: "entry",
      symbol: "AAPL",
      assetType: "stock",
      side: "buy",
      type: "market",
      quantity: 100,
      transactionDate: new Date().toISOString()
    },
    {
      transactionGroup: "exit",
      exitType: "stop",
      symbol: "AAPL",
      assetType: "stock",
      side: "sell",
      type: "stop",
      stopPrice: "145.00",
      quantity: 100,
      transactionDate: new Date().toISOString()
    }
  ]
});

Options Trade

# Options trade with call option
trade = create_bot_trade(
    bot_slug="my-bot",
    api_key=api_key,
    symbol="AAPL230120C00150000",  # Tradier option format
    trade_type="long_call",
    status="open",
    signal_at=datetime.now().isoformat(),
    transactions=[
        {
            "transactionGroup": "entry",
            "symbol": "AAPL230120C00150000",
            "assetType": "option",
            "side": "buy",
            "type": "limit",
            "price": "5.50",
            "quantity": 10,
            "optionType": "call",
            "strikePrice": "150.00",
            "expirationDate": "2023-01-20",
            "transactionDate": datetime.now().isoformat()
        }
    ]
)

Multiple Entry Transactions

// Create trade with multiple entry transactions (e.g., scaling in)
const trade = await createBotTrade("my-bot", apiKey, {
  symbol: "TSLA",
  tradeType: "long",
  status: "open",
  signalAt: new Date().toISOString(),
  transactions: [
    {
      transactionGroup: "entry",
      symbol: "TSLA",
      assetType: "stock",
      side: "buy",
      type: "limit",
      price: "240.00",
      quantity: 50,
      transactionDate: new Date().toISOString()
    },
    {
      transactionGroup: "entry",
      symbol: "TSLA",
      assetType: "stock",
      side: "buy",
      type: "limit",
      price: "238.00",
      quantity: 50,
      transactionDate: new Date().toISOString()
    }
  ]
});

Note: Exit transactions (stop losses, take profits, trailing stops, trim exits) should be added after trade creation using the Add Transactions endpoint.