Bots EndpointUser Trade Participations
Create Participation
Create user trade participations linking bot trades to user broker accounts
Create user trade participations that link bot trades to specific user broker accounts. Participations track which users are participating in which bot trades and their broker order IDs. The system uses an outbox pattern to asynchronously fetch order details from brokers.
Endpoint
POST /api/bots/:slug/participationsAuthentication
All requests require bot API key authentication via the x-api-key header.
headers: {
'x-api-key': 'your-bot-api-key'
}Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
slug | string | Yes | Bot identifier (alphanumeric, hyphens, underscores only) |
Slug Validation
The slug must match the regex pattern: /^[a-zA-Z0-9_-]+$/
Request Body
{
participations: Array<{
botTradeId: string; // Required: UUID of bot trade
userId: string; // Required: UUID of user
brokerAccountId: string; // Required: UUID of user broker account
brokerOrderId: string; // Required: Broker order ID
childOrderIds?: string[]; // Optional: Array of child order IDs
units?: number; // Optional: Number of units (defaults to 1)
}>;
}Request Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
participations | array | Yes | Array of participation objects (must not be empty) |
participations[].botTradeId | string (UUID) | Yes | UUID of the bot trade |
participations[].userId | string (UUID) | Yes | UUID of the user |
participations[].brokerAccountId | string (UUID) | Yes | UUID of the user broker account |
participations[].brokerOrderId | string | Yes | Broker order ID from the broker API |
participations[].childOrderIds | string[] | No | Array of child order IDs (for complex orders) |
participations[].units | number | No | Number of units/contracts (defaults to 1) |
Validation Rules
participationsmust be a non-empty array- Each
botTradeIdmust be a valid UUID string - Each
userIdmust be a valid UUID string - Each
brokerAccountIdmust be a valid UUID string - Each
brokerOrderIdmust be a non-empty string childOrderIdsmust be an array of strings if provided- Each participation is validated independently:
- Bot trade must exist
- Bot trade must belong to the specified bot
- User broker account must exist for the specified user
- Participations are processed independently using
Promise.allSettled, so partial failures are handled gracefully
Response
Success Response (200 OK)
{
"success": true,
"summary": {
"total": 3,
"succeeded": 2,
"failed": 1
},
"results": [
{
"status": "success",
"data": {
"participationId": "111e4567-e89b-12d3-a456-426614174001",
"userId": "789e4567-e89b-12d3-a456-426614174002",
"botTradeId": "222e4567-e89b-12d3-a456-426614174003"
}
},
{
"status": "success",
"data": {
"participationId": "333e4567-e89b-12d3-a456-426614174004",
"userId": "444e4567-e89b-12d3-a456-426614174005",
"botTradeId": "222e4567-e89b-12d3-a456-426614174003"
}
},
{
"status": "error",
"error": "Bot trade '555e4567-e89b-12d3-a456-426614174006' does not belong to bot 'my-bot'"
}
]
}Response Schema
| Field | Type | Description |
|---|---|---|
success | boolean | Always true for successful requests (even with partial failures) |
summary | object | Summary of participation creation results |
summary.total | number | Total number of participations attempted |
summary.succeeded | number | Number of successful participations |
summary.failed | number | Number of failed participations |
results | array | Array of individual participation results |
results[].status | string | Either "success" or "error" |
results[].data | object | (Success only) Created participation data |
results[].data.participationId | string | UUID of the created participation |
results[].data.userId | string | UUID of the user |
results[].data.botTradeId | string | UUID of the bot trade |
results[].error | string | (Error only) Error message |
Notes
- Participations are processed independently, so some may succeed while others fail
- If a participation already exists, it is retrieved rather than creating a duplicate
- An outbox event is created for each successful participation to asynchronously fetch order details from the broker
- The system validates that bot trades belong to the specified bot and that broker accounts belong to the specified user
Error Responses
400 Bad Request
Invalid JSON:
{
"error": "Invalid JSON in request body",
"code": "BAD_REQUEST"
}Missing participations array:
{
"error": "participations is required and must be a non-empty array",
"code": "BAD_REQUEST"
}Invalid botTradeId:
{
"error": "participations[0].botTradeId is required and must be a string",
"code": "BAD_REQUEST"
}Invalid userId:
{
"error": "participations[0].userId is required and must be a string",
"code": "BAD_REQUEST"
}Invalid brokerAccountId:
{
"error": "participations[0].brokerAccountId is required and must be a string",
"code": "BAD_REQUEST"
}Invalid childOrderIds:
{
"error": "participations[0].childOrderIds must be an array of strings",
"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"
}500 Internal Server Error
{
"error": "Internal server error",
"code": "INTERNAL_SERVER_ERROR"
}Code Examples
TypeScript
interface Participation {
botTradeId: string;
userId: string;
brokerAccountId: string;
brokerOrderId: string;
childOrderIds?: string[];
units?: number;
}
async function createParticipations(
botSlug: string,
apiKey: string,
participations: Participation[]
) {
const response = await fetch(
`https://api.example.com/api/bots/${botSlug}/participations`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": apiKey,
},
body: JSON.stringify({ participations }),
}
);
if (!response.ok) {
const error = await response.json();
throw new Error(`Failed to create participations: ${error.error}`);
}
return await response.json();
}
// Example usage - create participations for multiple users
const participations = [
{
botTradeId: "222e4567-e89b-12d3-a456-426614174003",
userId: "789e4567-e89b-12d3-a456-426614174002",
brokerAccountId: "550e8400-e29b-41d4-a716-446655440000",
brokerOrderId: "TRADIER-ORDER-12345",
units: 1
},
{
botTradeId: "222e4567-e89b-12d3-a456-426614174003",
userId: "444e4567-e89b-12d3-a456-426614174005",
brokerAccountId: "550e8400-e29b-41d4-a716-446655440001",
brokerOrderId: "TRADIER-ORDER-12346",
childOrderIds: ["TRADIER-ORDER-12347", "TRADIER-ORDER-12348"],
units: 2
}
];
const result = await createParticipations("my-bot", "your-api-key", participations);
console.log(`Created ${result.summary.succeeded} of ${result.summary.total} participations`);
// Check for failures
const failures = result.results.filter(r => r.status === "error");
if (failures.length > 0) {
console.error("Some participations failed:", failures);
}Python
from typing import List, Dict, Any, Optional
import requests
def create_participations(
bot_slug: str,
api_key: str,
participations: List[Dict[str, Any]]
) -> Dict[str, Any]:
"""
Create user trade participations.
Args:
bot_slug: Bot identifier
api_key: Bot API key
participations: List of participation dictionaries, each containing:
- botTradeId: UUID of bot trade
- userId: UUID of user
- brokerAccountId: UUID of user broker account
- brokerOrderId: Broker order ID
- childOrderIds: Optional list of child order IDs
- units: Optional number of units (defaults to 1)
Returns:
Response dictionary with participation results
Raises:
requests.HTTPError: If the request fails
"""
url = f"https://api.example.com/api/bots/{bot_slug}/participations"
payload = {
"participations": participations
}
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 usage - create participations for multiple users
participations = [
{
"botTradeId": "222e4567-e89b-12d3-a456-426614174003",
"userId": "789e4567-e89b-12d3-a456-426614174002",
"brokerAccountId": "550e8400-e29b-41d4-a716-446655440000",
"brokerOrderId": "TRADIER-ORDER-12345",
"units": 1
},
{
"botTradeId": "222e4567-e89b-12d3-a456-426614174003",
"userId": "444e4567-e89b-12d3-a456-426614174005",
"brokerAccountId": "550e8400-e29b-41d4-a716-446655440001",
"brokerOrderId": "TRADIER-ORDER-12346",
"childOrderIds": ["TRADIER-ORDER-12347", "TRADIER-ORDER-12348"],
"units": 2
}
]
result = create_participations("my-bot", "your-api-key", participations)
print(f"Created {result['summary']['succeeded']} of {result['summary']['total']} participations")
# Check for failures
failures = [r for r in result["results"] if r["status"] == "error"]
if failures:
print("Some participations failed:", failures)Use Cases
Link Trade to User Account
// After executing a trade, link it to user accounts
const participations = await createParticipations("my-bot", apiKey, [
{
botTradeId: tradeId,
userId: userId,
brokerAccountId: accountId,
brokerOrderId: brokerOrderId,
units: 1
}
]);Complex Order with Child Orders
# Link trade with bracket order (parent + child orders)
participations = create_participations(
bot_slug="my-bot",
api_key=api_key,
participations=[{
"botTradeId": trade_id,
"userId": user_id,
"brokerAccountId": account_id,
"brokerOrderId": parent_order_id,
"childOrderIds": [stop_loss_order_id, take_profit_order_id],
"units": 1
}]
)Bulk Participation Creation
// Create participations for multiple users in the same trade
const userAccounts = [
{ userId: "user1", accountId: "account1", orderId: "order1" },
{ userId: "user2", accountId: "account2", orderId: "order2" },
{ userId: "user3", accountId: "account3", orderId: "order3" }
];
const participations = userAccounts.map(ua => ({
botTradeId: tradeId,
userId: ua.userId,
brokerAccountId: ua.accountId,
brokerOrderId: ua.orderId,
units: 1
}));
const result = await createParticipations("my-bot", apiKey, participations);
console.log(`Successfully linked ${result.summary.succeeded} users to trade`);