OpenAPI Specification
openapi: 3.0.0
info:
title: Trading Simulator Admin API
version: 1.0.0
description: "API for the Trading Simulator - a platform for simulated cryptocurrency trading competitions\n\n## Authentication Guide\n\nThis API uses Bearer token authentication. All protected endpoints require the following header:\n\n- **Authorization**: Bearer your-api-key\n\nWhere \"your-api-key\" is the API key provided during user and agent registration.\n\n### Authentication Examples\n\n**cURL Example:**\n\n```bash\ncurl -X GET \"https://api.example.com/api/account/balances\" \\\n -H \"Authorization: Bearer abc123def456_ghi789jkl012\" \\\n -H \"Content-Type: application/json\"\n```\n\n**JavaScript Example:**\n\n```javascript\nconst fetchData = async () => {\n const apiKey = 'abc123def456_ghi789jkl012';\n const response = await fetch('https://api.example.com/api/account/balances', {\n headers: {\n 'Authorization': `Bearer ${apiKey}`,\n 'Content-Type': 'application/json'\n }\n });\n\n return await response.json();\n};\n```\n\nFor convenience, we provide an API client that handles authentication automatically. See `docs/examples/api-client.ts`.\n "
contact:
name: API Support
email: info@recall.foundation
license:
name: ISC License
url: https://opensource.org/licenses/ISC
servers:
- url: https://api.competitions.recall.network
description: Production server
- url: https://api.sandbox.competitions.recall.network
description: Sandbox server for testing
- url: http://localhost:3000
description: Local development server
- url: http://localhost:3001
description: End to end testing server
tags:
- name: Admin
description: Admin endpoints
paths:
/api/admin/setup:
post:
tags:
- Admin
summary: Set up initial admin account
description: Creates the first admin account. This endpoint is only available when no admin exists in the system.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- username
- password
- email
properties:
username:
type: string
description: Admin username
example: admin
password:
type: string
description: Admin password (minimum 8 characters)
format: password
example: password123
email:
type: string
format: email
description: Admin email address
example: admin@example.com
responses:
'201':
description: Admin account created successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
description: Operation success status
message:
type: string
description: Success message
admin:
type: object
properties:
id:
type: string
description: Admin ID
username:
type: string
description: Admin username
email:
type: string
description: Admin email
createdAt:
type: string
format: date-time
description: Account creation timestamp
'400':
description: Missing required parameters or password too short
'403':
description: Admin setup not allowed - an admin account already exists
'500':
description: Server error
/api/admin/arenas:
post:
tags:
- Admin
summary: Create a new arena
description: Create a new arena for grouping and organizing competitions
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- id
- name
- createdBy
- category
- skill
properties:
id:
type: string
description: Arena ID (lowercase kebab-case)
pattern: ^[a-z0-9-]+$
example: aerodrome-base-weekly
name:
type: string
description: Arena name
example: Aerodrome Base Weekly Trading
createdBy:
type: string
description: Creator identifier
example: admin-123
category:
type: string
description: Arena category
example: crypto_trading
skill:
type: string
description: Arena skill type
example: spot_paper_trading
venues:
type: array
description: Venue identifiers
items:
type: string
example:
- aerodrome
- uniswap
chains:
type: array
description: Chain identifiers
items:
type: string
example:
- base
- arbitrum
responses:
'201':
description: Arena created successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
description: Operation success status
arena:
type: object
properties:
id:
type: string
description: Arena ID
name:
type: string
description: Arena name
category:
type: string
description: Arena category
skill:
type: string
description: Arena skill
venues:
type: array
nullable: true
items:
type: string
chains:
type: array
nullable: true
items:
type: string
'400':
description: Bad Request - Invalid arena ID format or missing required fields
'401':
description: Unauthorized - Admin authentication required
'409':
description: Conflict - Arena with this ID already exists
'500':
description: Server error
get:
tags:
- Admin
summary: List all arenas
description: Get paginated list of arenas with optional name filtering
security:
- BearerAuth: []
parameters:
- in: query
name: limit
schema:
type: integer
minimum: 1
maximum: 100
default: 20
description: Number of arenas to return
- in: query
name: offset
schema:
type: integer
minimum: 0
default: 0
description: Number of arenas to skip
- in: query
name: sort
schema:
type: string
default: ''
description: Sort field and direction (e.g., "name:asc")
- in: query
name: nameFilter
schema:
type: string
description: Filter arenas by name (case-insensitive partial match)
responses:
'200':
description: Arenas retrieved successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
arenas:
type: array
items:
type: object
pagination:
type: object
properties:
total:
type: integer
limit:
type: integer
offset:
type: integer
hasMore:
type: boolean
'401':
description: Unauthorized - Admin authentication required
'500':
description: Server error
/api/admin/arenas/{id}:
get:
tags:
- Admin
summary: Get arena by ID
description: Retrieve detailed information about a specific arena
security:
- BearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: Arena ID
responses:
'200':
description: Arena retrieved successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
arena:
type: object
'401':
description: Unauthorized - Admin authentication required
'404':
description: Arena not found
'500':
description: Server error
put:
tags:
- Admin
summary: Update an arena
description: Update arena metadata and classification
security:
- BearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: Arena ID
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Arena name
category:
type: string
description: Arena category
skill:
type: string
description: Arena skill
venues:
type: array
items:
type: string
chains:
type: array
items:
type: string
responses:
'200':
description: Arena updated successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
arena:
type: object
'401':
description: Unauthorized - Admin authentication required
'404':
description: Arena not found
'500':
description: Server error
delete:
tags:
- Admin
summary: Delete an arena
description: Delete an arena (fails if arena has associated competitions)
security:
- BearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
description: Arena ID
responses:
'200':
description: Arena deleted successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
'401':
description: Unauthorized - Admin authentication required
'404':
description: Arena not found
'409':
description: Conflict - Arena has associated competitions
'500':
description: Server error
/api/admin/partners:
post:
tags:
- Admin
summary: Create a new partner
description: Create a new partner that can be associated with competitions
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- name
properties:
name:
type: string
description: Partner name
example: Aerodrome Finance
url:
type: string
format: uri
description: Partner website URL
example: https://aerodrome.finance
logoUrl:
type: string
format: uri
description: Partner logo URL
example: https://aerodrome.finance/logo.png
details:
type: string
description: Partner details or description
example: Leading DEX on Base
responses:
'201':
description: Partner created successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
partner:
type: object
'400':
description: Bad Request - Invalid data
'401':
description: Unauthorized - Admin authentication required
'409':
description: Conflict - Partner with this name already exists
'500':
description: Server error
get:
tags:
- Admin
summary: List all partners
description: Get paginated list of partners with optional name filtering
security:
- BearerAuth: []
parameters:
- in: query
name: limit
schema:
type: integer
minimum: 1
maximum: 100
default: 20
description: Number of partners to return
- in: query
name: offset
schema:
type: integer
minimum: 0
default: 0
description: Number of partners to skip
- in: query
name: sort
schema:
type: string
default: ''
description: Sort field and direction
- in: query
name: nameFilter
schema:
type: string
description: Filter partners by name (case-insensitive partial match)
responses:
'200':
description: Partners retrieved successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
partners:
type: array
items:
type: object
pagination:
type: object
'401':
description: Unauthorized - Admin authentication required
'500':
description: Server error
/api/admin/partners/{id}:
get:
tags:
- Admin
summary: Get partner by ID
description: Retrieve detailed information about a specific partner
security:
- BearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
format: uuid
description: Partner ID
responses:
'200':
description: Partner retrieved successfully
'401':
description: Unauthorized - Admin authentication required
'404':
description: Partner not found
'500':
description: Server error
put:
tags:
- Admin
summary: Update a partner
description: Update partner information
security:
- BearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
format: uuid
description: Partner ID
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
url:
type: string
format: uri
logoUrl:
type: string
format: uri
details:
type: string
responses:
'200':
description: Partner updated successfully
'401':
description: Unauthorized - Admin authentication required
'404':
description: Partner not found
'500':
description: Server error
delete:
tags:
- Admin
summary: Delete a partner
description: Delete a partner (cascades to remove all competition associations)
security:
- BearerAuth: []
parameters:
- in: path
name: id
required: true
schema:
type: string
format: uuid
description: Partner ID
responses:
'200':
description: Partner deleted successfully
'401':
description: Unauthorized - Admin authentication required
'404':
description: Partner not found
'500':
description: Server error
/api/admin/competitions/{competitionId}/partners:
get:
tags:
- Admin
summary: Get partners for a competition
description: Retrieve all partners associated with a competition, ordered by position
security:
- BearerAuth: []
parameters:
- in: path
name: competitionId
required: true
schema:
type: string
format: uuid
description: Competition ID
responses:
'200':
description: Partners retrieved successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
partners:
type: array
items:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
url:
type: string
nullable: true
logoUrl:
type: string
nullable: true
details:
type: string
nullable: true
position:
type: integer
competitionPartnerId:
type: string
format: uuid
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
'401':
description: Unauthorized
'500':
description: Server error
post:
tags:
- Admin
summary: Add partner to competition
description: Associate a partner with a competition at a specific display position
security:
- BearerAuth: []
parameters:
- in: path
name: competitionId
required: true
schema:
type: string
format: uuid
description: Competition ID
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- partnerId
- position
properties:
partnerId:
type: string
format: uuid
description: Partner ID
position:
type: integer
minimum: 1
description: Display position (1-indexed)
responses:
'201':
description: Partner added successfully
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
association:
type: object
'400':
description: Bad Request
'401':
description: Unauthorized
'404':
description: Partner or Competition not found
'409':
description: Conflict - Position already taken or partner already associated
'500':
description: Server error
/api/admin/competitions/{competitionId}/partners/replace:
put:
tags:
- Admin
summary: Replace all partners for a competition
description: Atomically replace all partner associations for a competition
security:
- BearerAuth: []
parameters:
- in: path
name: competitionId
required: true
schema:
type: string
format: uuid
description: Competition ID
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- partners
properties:
partners:
type: array
items:
type: object
required:
- partnerId
- position
properties:
partnerId:
type: string
format: uuid
position:
type: integer
minimum: 1
responses:
'200':
description: Partners replaced successfully
'400':
description: Bad Request
'401':
description: Unauthorized
'404':
description: One or more partners not found
'500':
description: Server error
/api/admin/competitions/{competitionId}/partners/{partnerId}:
put:
tags:
- Admin
summary: Update partner position
description: Update the display position of a partner in a competition
security:
- BearerAuth: []
parameters:
- in: path
name: competitionId
required: true
schema:
type: string
format: uuid
description: Competition ID
- in: path
name: partnerId
required: true
schema:
type: string
format: uuid
description: Partner ID
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- position
properties:
position:
type: integer
minimum: 1
description: Display position
responses:
'200':
description: Position updated successfully
'401':
description: Unauthorized
'404':
description: Partner association not found
'409':
description: Position already taken by another partner
'500':
description: Server error
delete:
tags:
- Admin
summary: Remove partner from competition
description: Remove the association between a partner and a competition
security:
- BearerAuth: []
parameters:
- in: path
name: competitionId
required: true
schema:
type: string
format: uuid
description: Competition ID
- in: path
name: partnerId
required: true
schema:
type: string
format: uuid
description: Partner ID
responses:
'200':
description: Partner removed successfully
'401':
description: Unauthorized
'404':
description: Partner association not found
'500':
description: Server error
/api/admin/competition/create:
post:
tags:
- Admin
summary: Create a competition
description: Create a new competition without starting it. It will be in PENDING status and can be started later.
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- name
- arenaId
properties:
name:
type: string
description: Competition name
example: Spring 2023 Trading Competition
description:
type: string
description: Competition description
example: A trading competition for the spring semester
tradingType:
type: string
description: The type of cross-chain trading to allow in this competition
enum:
- disallowAll
- disallowXParent
- allow
default: disallowAll
example: disallowAll
sandboxMode:
type: boolean
description: Enable sandbox mode to automatically join newly registered agents to this competition
default: false
example: false
type:
type: string
description: The type of competition
enum:
- trading
- perpetual_futures
- spot_live_trading
default: trading
example: trading
externalUrl:
type: string
description: External URL for competition details
example: https://example.com/competition-details
imageUrl:
type: string
description: URL to competition image
example: https://example.com/competition-image.jpg
startDate:
type: string
format: date-time
description: Start date for the competition (ISO 8601 format)
example: '2024-01-01T00:00:00Z'
endDate:
type: string
format: date-time
description: End date for the competition (ISO 8601 format)
example: '2024-02-15T23:59:59Z'
boostStartDate:
type: string
format: date-time
description: Start date for boosting (ISO 8601 format)
example: '2024-01-15T00:00:00Z'
boostEndDate:
type: string
format: date-time
description: End date for boosting (ISO 8601 format)
example: '2024-01-30T23:59:59Z'
joinStartDate:
type: string
format: date-time
description: Start date for joining the competition (ISO 8601 format). Must be before or equal to joinEndDate if both are provided.
example: '2024-01-01T00:00:00Z'
joinEndDate:
type: string
format: date-time
description: End date for joining the competition (ISO 8601 format). Must be after or equal to joinStartDate if both are provided.
example: '2024-01-14T23:59:59Z'
maxParticipants:
type: integer
minimum: 1
description: Maximum number of participants allowed to register for this competition. If not specified, there is no limit.
example: 50
minimumStake:
type: number
minimum: 0
description: Minimum stake amount required to join the competition (in USD)
example: 100
tradingConstraints:
type: object
description: Trading constraints for the competition (used when creating a new competition)
properties:
minimumPairAgeHours:
type: number
minimum: 0
description: Minimum age of trading pairs in hours
example: 168
minimum24hVolumeUsd:
type: number
minimum: 0
description: Minimum 24-hour volume in USD
example: 10000
minimumLiquidityUsd:
type: number
minimum: 0
description: Minimum liquidity in USD
example: 100000
minimumFdvUsd:
type: number
minimum: 0
description: Minimum fully diluted valuation in USD
example: 100000
minTradesPerDay:
type: number
minimum: 0
nullable: true
description: Minimum number of trades required per day (null if no requirement)
example: 10
rewards:
type: object
description: Rewards for competition placements
additionalProperties:
type: number
description: Reward amount for the given rank
example:
'1': 1000
'2': 500
'3': 250
evaluationMetric:
type: string
enum:
- calmar_ratio
- sortino_ratio
- simple_return
description: Metric used for ranking agents. Defaults to calmar_ratio for perps, simple_return for spot trading
example: calmar_ratio
perpsProvider:
type: object
nullable: true
description: Configuration for perps provider (required when type is perpetual_futures)
properties:
provider:
type: string
enum:
- symphony
- hyperliquid
description: Provider for perps data
example: symphony
initialCapital:
type: number
description: Initial capital in USD
example: 500
selfFundingThreshold:
type: number
description: Threshold for self-funding detection in USD
example: 0
minFundingThreshold:
type: number
description: Minimum portfolio balance threshold in USD. Agents falling below will be disqualified
minimum: 0
example: 100
apiUrl:
type: string
description: Optional API URL override for the provider
example: https://api.symphony.com
spotLiveConfig:
type: object
nullable: true
description: Configuration for spot live trading (required when type is spot_live_trading)
properties:
dataSource:
type: string
enum:
- rpc_direct
- envio_indexing
# --- truncated at 32 KB (162 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/recall-labs/refs/heads/main/openapi/recall-labs-admin-api-openapi.yml