PeakBot Docs
Bots EndpointBot Trades

Update Transaction

Update a specific transaction within a bot trade

Update fields of a specific transaction within a bot trade. This is commonly used to update transaction status when orders are filled, update fill prices, or modify stop prices. When transaction status changes, the trade status is automatically recalculated.

Endpoint

PATCH /api/bots/:slug/trades/:tradeId/transactions/:transactionId

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)
tradeIdstringYesUUID of the trade
transactionIdstringYesUUID of the transaction to update

Slug Validation

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

Request Body

{
  status?: string;                    // Transaction status
  filledAt?: string;                  // ISO timestamp when filled
  filledQuantity?: string;           // Filled quantity
  avgFillPrice?: string;              // Average fill price
  stopPrice?: string;                  // Stop price for stop orders
  price?: string;                     // Limit price for limit orders
  brokerParentOrderId?: string;       // Broker parent order ID (for bracket orders)
  metadata?: Record<string, unknown>; // Transaction metadata
  notes?: string;                     // Notes
}

Request Body Schema

FieldTypeRequiredDescription
statusstringNoTransaction status (e.g., "open", "filled", "cancelled")
filledAtstring (ISO timestamp)NoWhen the transaction was filled
filledQuantitystringNoQuantity that was filled
avgFillPricestringNoAverage fill price
stopPricestringNoStop price for stop orders
pricestringNoLimit price for limit orders
brokerParentOrderIdstringNoBroker parent order ID (for bracket orders)
metadataobjectNoTransaction metadata
notesstringNoNotes

Validation Rules

  • At least one field must be provided
  • filledAt is converted from ISO timestamp string to Date object
  • When status is updated, the trade status is automatically recalculated
  • If trade status becomes "closed" after recalculation, netPnl and closedAt are automatically set

Allowed Fields

Only the following fields can be updated:

  • status
  • filledAt
  • filledQuantity
  • avgFillPrice
  • stopPrice
  • price
  • brokerParentOrderId
  • metadata
  • notes

Response

Success Response (200 OK)

{
  "success": true,
  "transaction": {
    "id": "222e4567-e89b-12d3-a456-426614174002",
    "botTradeId": "111e4567-e89b-12d3-a456-426614174001",
    "transactionGroup": "entry",
    "symbol": "AAPL",
    "assetType": "stock",
    "side": "buy",
    "type": "market",
    "quantity": 100,
    "status": "filled",
    "filledAt": "2024-01-15T10:30:10.000Z",
    "filledPrice": "150.25",
    "avgFillPrice": "150.25",
    "transactionDate": "2024-01-15T10:30:05.000Z"
  },
  "trade": {
    "id": "111e4567-e89b-12d3-a456-426614174001",
    "status": "open",
    "lastUpdateAt": "2024-01-15T10:30:10.000Z"
  }
}

Response Schema

FieldTypeDescription
successbooleanAlways true for successful requests
transactionobjectUpdated transaction object
tradeobjectUpdated trade object (included if status was recalculated)

Notes

  • If status is updated, the trade object is included in the response showing the recalculated trade status
  • Trade status recalculation happens automatically when transaction status changes
  • If the trade becomes "closed" after recalculation, netPnl and closedAt are set automatically

Error Responses

400 Bad Request

Invalid JSON:

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

No valid fields to update:

{
  "error": "No valid fields to update",
  "code": "BAD_REQUEST"
}

Missing required parameters:

{
  "error": "Bot slug, trade ID, and transaction ID are required",
  "code": "BAD_REQUEST"
}

Invalid slug format:

{
  "error": "Invalid slug format. Only alphanumeric characters, hyphens, and underscores are allowed.",
  "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"
}

Trade not found:

{
  "error": "Trade not found",
  "code": "NOT_FOUND"
}

Transaction not found:

{
  "error": "Transaction not found",
  "code": "NOT_FOUND"
}

500 Internal Server Error

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

Code Examples

TypeScript

async function updateBotTransaction(
  botSlug: string,
  tradeId: string,
  transactionId: string,
  apiKey: string,
  updates: {
    status?: string;
    filledAt?: string;
    filledPrice?: string;
    avgFillPrice?: string;
    filledQuantity?: string;
    stopPrice?: string;
    price?: string;
    brokerParentOrderId?: string;
    metadata?: Record<string, unknown>;
    notes?: string;
  }
) {
  const response = await fetch(
    `https://api.example.com/api/bots/${botSlug}/trades/${tradeId}/transactions/${transactionId}`,
    {
      method: "PATCH",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": apiKey,
      },
      body: JSON.stringify(updates),
    }
  );

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

  return await response.json();
}

// Example: Mark transaction as filled
const result = await updateBotTransaction(
  "my-bot",
  "111e4567-e89b-12d3-a456-426614174001",
  "222e4567-e89b-12d3-a456-426614174002",
  "your-api-key",
  {
    status: "filled",
    filledAt: new Date().toISOString(),
    filledPrice: "150.25",
    avgFillPrice: "150.25",
    filledQuantity: "100"
  }
);

console.log(`Transaction ${result.transaction.id} updated to ${result.transaction.status}`);
if (result.trade) {
  console.log(`Trade status recalculated: ${result.trade.status}`);
}

Python

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

def update_bot_transaction(
    bot_slug: str,
    trade_id: str,
    transaction_id: str,
    api_key: str,
    updates: Dict[str, Any]
) -> Dict[str, Any]:
    """
    Update a bot transaction.
    
    Args:
        bot_slug: Bot identifier
        trade_id: UUID of trade
        transaction_id: UUID of transaction to update
        api_key: Bot API key
        updates: Dictionary of fields to update
        
    Returns:
        Response dictionary with updated transaction and optionally trade
        
    Raises:
        requests.HTTPError: If the request fails
    """
    url = f"https://api.example.com/api/bots/{bot_slug}/trades/{trade_id}/transactions/{transaction_id}"
    
    headers = {
        "Content-Type": "application/json",
        "x-api-key": api_key
    }
    
    response = requests.patch(url, json=updates, headers=headers)
    response.raise_for_status()
    
    return response.json()

# Example: Mark transaction as filled
result = update_bot_transaction(
    bot_slug="my-bot",
    trade_id="111e4567-e89b-12d3-a456-426614174001",
    transaction_id="222e4567-e89b-12d3-a456-426614174002",
    api_key="your-api-key",
    updates={
        "status": "filled",
        "filledAt": datetime.now().isoformat(),
        "filledPrice": "150.25",
        "avgFillPrice": "150.25",
        "filledQuantity": "100"
    }
)

print(f"Transaction {result['transaction']['id']} updated to {result['transaction']['status']}")
if "trade" in result:
    print(f"Trade status recalculated: {result['trade']['status']}")

Use Cases

Update Fill Information

// Update transaction when order is filled
await updateBotTransaction("my-bot", tradeId, transactionId, apiKey, {
  status: "filled",
  filledAt: new Date().toISOString(),
  filledPrice: "150.25",
  avgFillPrice: "150.25",
  filledQuantity: "100"
});

Update Stop Price

# Update stop loss price as market moves
update_bot_transaction(
    bot_slug="my-bot",
    trade_id=trade_id,
    transaction_id=transaction_id,
    api_key=api_key,
    updates={
        "stopPrice": "400.00"
    }
)

Update Stop Price

// Adjust stop loss price
await updateBotTransaction("my-bot", tradeId, transactionId, apiKey, {
  stopPrice: "148.00"  // Move stop loss up
});

Add Transaction Notes

# Add notes about the transaction
update_bot_transaction(
    bot_slug="my-bot",
    trade_id=trade_id,
    transaction_id=transaction_id,
    api_key=api_key,
    updates={
        "notes": "Partial fill - remaining quantity pending",
        "metadata": {
            "partialFill": True,
            "remainingQuantity": 50
        }
    }
)

Automatic Trade Status Recalculation

// When marking exit transaction as filled, trade status is automatically recalculated
const result = await updateBotTransaction("my-bot", tradeId, exitTransactionId, apiKey, {
  status: "filled",
  filledAt: new Date().toISOString(),
  filledPrice: "155.00"
});

// Trade status may change to "closed" if all exit transactions are filled
if (result.trade && result.trade.status === "closed") {
  console.log(`Trade closed with PnL: ${result.trade.netPnl}`);
}