TradeLock Manager API Guide
Audience: Strategy managers and integration engineers
Use case: Server-to-server strategy management and trade submission
Version: 1.1
Last updated: 2026-09-09
This guide is a production-focused API reference for TradeLock manager workflows.
TradeLock verification access is free within reasonable usage limits.
1) Base URLs
- Production:
https://tradelock.net/api
This is the common prefix for API endpoints, not a submission endpoint by itself. The canonical submission URL is https://tradelock.net/api/v1/signals. All examples below use production URLs.
2) Authentication
TradeLock supports two auth methods on manager endpoints:
- API key (recommended for servers)
- Header:
X-Trader-Api-Key: <API_KEY>
- Firebase ID token
- Header:
Authorization: Bearer <FIREBASE_ID_TOKEN>
API key lifecycle endpoints
These endpoints require Firebase ID token auth (not API key auth):
POST /generate-api-keyGET /list-api-keysPOST /delete-api-keyPOST /revoke-api-key(same behavior as delete)
The manager app can also retrieve configured webhook relay details with GET /relay-access. This Firebase-ID-token-only endpoint returns a private, non-cacheable response containing the relay URL and shared relay key. Never expose that response in client-side logs, public alerts, or source code.
API key scopes
generate-api-key supports key scopes:
full(default): can access all strategiessandbox: can only submit to strategies marked as sandbox/test
A sandbox key calling a non-sandbox strategy returns:
403withcode: "SANDBOX_SCOPE_RESTRICTION"
3) Canonical signal publishing (recommended)
Use this section as the complete contract for building a live signal client.
Endpoint:
POST https://tradelock.net/api/v1/signals
Required headers:
Content-Type: application/json
X-Trader-Api-Key: <API_KEY>3.1 Resolve the strategy ID
For strategies created in the current TradeLock app, id is the same text as strategy_name. Clients should still read the strategy list and use the exact id value:
curl "https://tradelock.net/api/strategies?limit=100" \
-H "X-Trader-Api-Key: <API_KEY>"Relevant response fields:
{
"strategies": [
{
"id": "Momentum Core",
"strategy_name": "Momentum Core"
}
]
}Use strategies[].id as strategy_id in every canonical signal.
3.2 Resolve the symbol
Open New Trade in the manager app, type the ticker, and wait for TradeLock to confirm the listing. API clients can perform the same lookup with:
curl "https://tradelock.net/api/symbol-search?q=SPY&limit=8&include_quotes=false" \
-H "X-Trader-Api-Key: <API_KEY>"Copy the exact canonical_symbol from the selected result. U.S. stocks and ETFs normally use a bare ticker. For example, SPY:ARCA is useful as a New Trade lookup hint, but the submitted canonical symbol is SPY.
European stocks and ETFs are not supported for canonical live submission yet.
3.3 Envelope fields
The request body is strict: do not add fields that are not listed here.
| Field | Type | Required | Meaning |
|---|---|---|---|
protocol_version | string | Yes | Must be exactly "1.0" |
strategy_id | string | Yes | Exact id returned by GET /strategies; maximum 160 characters |
idempotency_key | string | Yes | Stable identifier for this intent; 1–120 characters |
payload | object | Yes | Exactly one of the three payload shapes below |
effective_at | ISO 8601 string | No | Intended effective time including Z or a numeric timezone; TradeLock assigns acceptance time when omitted |
metadata | JSON object | No | Client context such as source or tags; never put credentials here |
The complete body is limited to 256 KiB. Symbols and identifiers must not have surrounding whitespace.
3.4 Target portfolio payload
Use scope: "full" to replace the complete target set. Any current holding omitted from a full target is treated as target 0%. Use scope: "patch" to change only the supplied symbols. Each weight_pct is a final portfolio target, not an order size. Negative values represent short targets and values above 100 represent leverage.
curl -X POST "https://tradelock.net/api/v1/signals" \
-H "Content-Type: application/json" \
-H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>" \
-d '{
"protocol_version": "1.0",
"strategy_id": "<STRATEGY_DOCUMENT_ID>",
"idempotency_key": "signal-portfolio-20260909-001",
"payload": {
"type": "target_portfolio",
"scope": "full",
"targets": [
{ "symbol": "SPY", "weight_pct": 60 },
{ "symbol": "TLT", "weight_pct": 40 }
]
}
}'targets is an array of unique canonical symbols and is limited to 500 items.
3.5 Percent-of-NAV order payload
This expresses an order size, not a final target. If manager NAV is $100,000, percent_of_nav: 5 records an order to buy or sell approximately $5,000 of the instrument.
{
"protocol_version": "1.0",
"strategy_id": "<STRATEGY_DOCUMENT_ID>",
"idempotency_key": "signal-percent-buy-20260909-001",
"payload": {
"type": "percent_order",
"symbol": "AAPL",
"side": "buy",
"percent_of_nav": 5
}
}side must be buy or sell. percent_of_nav must be greater than 0 and no greater than 10000.
3.6 Quantity order payload
Use this for an explicit number of shares or units.
{
"protocol_version": "1.0",
"strategy_id": "<STRATEGY_DOCUMENT_ID>",
"idempotency_key": "signal-quantity-buy-20260909-001",
"payload": {
"type": "quantity_order",
"symbol": "AAPL",
"side": "buy",
"quantity": 10
}
}quantity must be a positive finite number.
3.7 Acceptance, retries, and errors
A new durable event returns 201 Created:
{
"event_id": "evt_...",
"strategy_sequence": 42,
"received_at": "2026-09-09T12:00:00Z",
"envelope_hash": "sha256:...",
"idempotency_key": "signal-portfolio-20260909-001"
}Store all five receipt fields. If a request times out, retry the identical body with the same idempotency_key. Do not submit the intent to another endpoint. An identical replay returns 200 and the original receipt. Reusing a key with different content returns 409 IDEMPOTENCY_PAYLOAD_CONFLICT.
Common failures:
400 INVALID_SIGNAL_ENVELOPE: wrong field, type, symbol, timestamp, or protocol version401 AUTHENTICATION_REQUIRED: missing or invalid credentials403 SANDBOX_SCOPE_RESTRICTION: sandbox key used with a non-sandbox strategy404 STRATEGY_NOT_FOUND:strategy_iddoes not match an owned strategyid409 STRATEGY_ARCHIVED: the strategy is archived409 IDEMPOTENCY_PAYLOAD_CONFLICT: key reused with changed content413 SIGNAL_CAPACITY_EXCEEDED: request exceeds 256 KiB or 500 targets422 MANAGER_NAV_UNAVAILABLE: TradeLock cannot capture the strategy value required at acceptance
Appendix A) Legacy verification-only submission modes
These endpoints remain available for existing clients but never publish to HUB subscribers:
POST /set-target-portfolioPOST /logTradewithquantity+ explicit sidePOST /logTradewith single-symbolallocation_percentand no side
Default examples below are intentionally prefilled for sandbox testing:
strategy:Sandbox Strategy- API key header:
X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>
A.1 Set full target portfolio
Behavior:
- Full-portfolio scope by default.
- If a current holding symbol is omitted from
targets, its target is0%.
curl -X POST "https://tradelock.net/api/set-target-portfolio" \
-H "Content-Type: application/json" \
-H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>" \
-d '{
"strategy": "Sandbox Strategy",
"targets": { "SPY": 33, "TLT": 33, "EEM": 10, "GSY": 15 },
"execution_anchor": "next_us_equity_open",
"open_delay_minutes": 2,
"idempotency_key": "signal-portfolio-20260308-001"
}'A.2 Quantity mode: explicit buy/sell units
curl -X POST "https://tradelock.net/api/logTrade" \
-H "Content-Type: application/json" \
-H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>" \
-d '{
"user_strategy_name": "Sandbox Strategy",
"asset": "AAPL:NASDAQ",
"trade_type": "buy",
"quantity": 10,
"idempotency_key": "signal-qty-buy-20260308-001"
}'A.3 Single-symbol target allocation (leave others unchanged)
curl -X POST "https://tradelock.net/api/logTrade" \
-H "Content-Type: application/json" \
-H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>" \
-d '{
"user_strategy_name": "Sandbox Strategy",
"asset": "AAPL:NASDAQ",
"allocation_percent": 30,
"idempotency_key": "signal-single-target-20260308-001"
}'4) Legacy request conventions
Strategy identity
A strategy is keyed by strategy_name in the manager workspace.
- Create is effectively an upsert on
strategy_name - Renaming an existing strategy name is not supported on update
Symbol/asset format
Trade assets are expected as uppercase symbols, with optional exchange hint:
AAPLAAPL:NASDAQBTC-USD
For equity and ETF submissions, a bare ticker is explicitly interpreted in the U.S. namespace. Qualify non-U.S. instruments with a supported exchange, such as VOD:LSE. Whitespace around the field and : separator is trimmed, but whitespace inside a symbol or exchange token is rejected.
If more than one of asset, symbol, and ticker is supplied, every value must resolve to the same canonical instrument. Conflicting values return 400 AMBIGUOUS_ASSET_INPUT; unsupported exchange hints return 400 UNSUPPORTED_EXCHANGE.
Time and timestamps
Responses may contain:
- ISO timestamps (string)
- Unix epoch milliseconds (number)
Idempotency (write safety)
Use idempotency on all write operations.
Accepted forms:
- Header:
Idempotency-Key: <key> - Body:
idempotency_key
For quick-trade, client_order_id is accepted and mapped to idempotency_key.
Validation and behavior:
- Length must be
8..200chars - Same key + same payload: replay prior response
- Same key + different payload:
409conflict - Same key while first request is processing:
409
For set-target-portfolio, same-key retries return the existing durable acceptance and rebalance_id when available.
Note for browser clients: pass idempotency in the JSON body. CORS allow-list does not include Idempotency-Key.
Fill policy and delay
For quick-trade and logTrade:
fill_policy:immediate_if_open(default) ornext_open_with_delayopen_delay_minutes: non-negative number
Delay precedence:
open_delay_minutesin request- client default delay
- global fallback (
5minutes)
Live vs CSV-import fields
For live trades (import_source omitted or live), do not send:
reported_dateuser_reported_pricereference_priceallocation_reference_price
These are only valid for import_source: "csv_import".
5) Error Model
Most errors use:
{ "error": "Human-readable message", "code": "OPTIONAL_MACHINE_CODE" }Common statuses:
200OK201Created (strategy created)202Accepted (trade queued or durable rebalance job stored)400Validation error401Authentication failed/missing403Authenticated but not allowed404Not found405Method not allowed409Idempotency conflict/in-progress500Internal error502Upstream provider failure (symbol search)
6) Endpoint Reference
6.1 API Keys
POST /generate-api-key
Generate a new manager API key.
Auth:
Authorization: Bearer <FIREBASE_ID_TOKEN>
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
key_name | string | No | Default: "My API Key" |
client_id | string | No | Default: current user UID |
key_scope | string | No | full (default) or sandbox |
Success (200):
{
"api_key": "uuid",
"key_id": "uuid",
"scope": "full",
"message": "API Key generated successfully"
}GET /list-api-keys
List API keys for authenticated user.
Auth:
Authorization: Bearer <FIREBASE_ID_TOKEN>
Success (200):
[
{
"id": "key-id",
"name": "Webhook Prod",
"created_at": "2026-02-20T15:00:00.000Z",
"last_used": "2026-02-27T10:11:12.000Z",
"status": "active",
"scope": "full"
}
]POST /delete-api-key (or POST /revoke-api-key)
Delete/revoke an API key.
Auth:
Authorization: Bearer <FIREBASE_ID_TOKEN>
Request body:
| Field | Type | Required |
|---|---|---|
api_key_id | string | Yes |
Success (200):
{ "message": "API Key deleted successfully" }GET /relay-access
Return the configured TradingView/no-code relay endpoint and shared gate key.
Auth:
Authorization: Bearer <FIREBASE_ID_TOKEN>only
Success (200):
{
"relay_endpoint": "https://tradelock-tv-relay.tradelock.workers.dev/webhook/tradingview",
"shared_relay_key": "private-value",
"label": "For TradingView, Zapier, Make, n8n, and similar webhook tools"
}The response is marked private, no-store. A missing server-side relay key returns 503.
6.2 Strategy Management
POST /ensure-sandbox-onboarding
Create or reuse the authenticated manager's sandbox strategy. This is useful for first-run integration setup and requires an API key or Firebase ID token.
Success (200) returns the sandbox strategy name and whether it was created:
{
"message": "Sandbox onboarding is ready.",
"sandbox": {
"strategy_name": "Sandbox Strategy",
"strategy_created": true,
"key_created": false,
"sandbox_api_key": null,
"sandbox_api_key_preview": null
}
}POST /reset-sandbox
Delete trades, daily snapshots, and pending trades belonging to the authenticated manager's sandbox strategy, then reset its verification state. This is destructive and requires an API key or Firebase ID token. It returns 404 when no sandbox strategy exists.
GET /client-config
Read the effective manager client settings used by delayed execution and allocation rebalances.
Auth:
- API key or Firebase ID token
Optional query parameter: client_id. When omitted, the authenticated client identity is used.
Success (200):
{
"client_id": "manager-client-id",
"default_open_delay_minutes": 2,
"effective_default_open_delay_minutes": 2,
"min_rebalance_notional_usd": 25,
"effective_min_rebalance_notional_usd": 25,
"source": "client",
"exists": true
}POST|PUT|PATCH /client-config/update
Update one or both client settings. The body must include at least one of default_open_delay_minutes or min_rebalance_notional_usd; both values must be non-negative numbers. Auth is API key or Firebase ID token.
Optional client_id may be supplied in the body or query string. Success (200) returns the updated values.
GET /strategies
List strategies for authenticated manager.
Auth:
- API key or ID token
Query params:
| Param | Type | Required | Notes |
|---|---|---|---|
limit | number | No | 1..100, default 50 |
page_token | string | No | Last returned strategy ID |
include_archived | boolean-like | No | true/1/yes to include soft-deleted |
Success (200):
{
"strategies": [
{
"id": "Momentum Core",
"strategy_name": "Momentum Core",
"access_mode": "workspace",
"hub_status": "not_requested",
"tags": ["momentum"],
"asset_types": ["equity"],
"initial_capital_usd": 100000
}
],
"next_page_token": null
}Notes:
- When OpenTimestamps verification anchors are enabled and the current account is eligible to see them, strategies may also include
verification_anchor_latest_v1. verification_anchor_latest_v1is the latest per-strategy anchor summary and includes:provider:opentimestampssnapshot_datestatus:pending,attested, orerroranchor_pathandproof_pathanchor_sha256stamped_at,upgraded_at,attested_at,last_error
Example:
{
"verification_anchor_latest_v1": {
"provider": "opentimestamps",
"snapshot_date": "2026-04-04",
"status": "pending",
"anchor_sha256": "f8f8...",
"anchor_path": "verification/ots/.../anchor.json",
"proof_path": "verification/ots/.../anchor.json.ots"
}
}GET /verification-anchor-file
Download the latest OpenTimestamps anchor artifact for one of your strategies.
Auth:
- ID token
Query params:
| Param | Type | Required | Notes |
|---|---|---|---|
strategyName or strategy_name | string | Yes | Target strategy |
kind | string | Yes | anchor or proof |
Behavior:
kind=anchorreturns the latestanchor.json.kind=proofreturns the latest detachedanchor.json.otsproof.- Returns
404when the strategy has no anchor yet, the feature is disabled, or the current account is not eligible to view anchor files.
Success:
200with an attachment response- Content type is
application/jsonforanchor - Content type is
application/octet-streamforproof
POST /createStrategy
Create or update a strategy by strategy_name.
Auth:
- API key or ID token
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
strategy_name | string | Yes | Strategy ID in workspace |
description | string | No | |
public_summary | string | No | Defaults to description if missing |
access_mode | string | No | workspace, shareable, or invite_only; default workspace |
hub_status | string | No | Providers may use not_requested or under_review; listed is admin-managed |
public_slug | string | No | Applied when access_mode=shareable |
tags | string[] | No | Up to 25 entries after normalization |
asset_types | string[] | No | Up to 25 entries after normalization |
metadata | object | No | Primitive/object values only |
initial_capital_usd | number | No | Must be positive if provided |
trade_hide_days | number | No | Days of recent trades hidden from public viewers. Allowed: 0 (show all), 30, 60, 90, 9999 (hide all). Default: 0 |
min_rebalance_move_pct | number | No | Drift filter for set-target-portfolio. Legs with a notional move below this % of running capital are skipped as no-ops. Range 0–100. Default: 1 |
Success:
201when created200when existing strategy is updated
{
"message": "Strategy created successfully",
"created": true,
"strategy": {
"id": "Momentum Core",
"strategy_name": "Momentum Core",
"is_deleted": false
}
}POST|PUT|PATCH /update-strategy (alias: /updateStrategy)
Patch strategy fields.
Auth:
- API key or ID token
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
strategy_id or strategy_name | string | Yes | Target strategy |
description | string | No | |
public_summary | string | No | |
access_mode | string | No | workspace, shareable, or invite_only |
hub_status | string | No | not_requested or under_review; listed is admin-managed |
public_slug | string | No | Regenerated/sanitized when needed |
tags | string[] | No | |
asset_types | string[] | No | |
metadata | object | No | |
is_deleted | boolean | No | Soft-delete toggle |
initial_capital_usd | number | No | Must be positive |
trade_hide_days | number | No | Days of recent trades hidden from public viewers. Allowed: 0, 30, 60, 90, 9999. |
min_rebalance_move_pct | number | No | Drift filter threshold 0–100. |
Constraints:
- Renaming strategy name is not supported (
400) verification_rateis server-managed and cannot be set
Success (200):
{
"message": "Strategy updated successfully",
"strategy": {
"id": "Momentum Core",
"strategy_name": "Momentum Core"
}
}POST|DELETE /delete-strategy (alias: /deleteStrategy)
Soft-delete (archive) a strategy. Archiving also cancels active pending trades for the same strategy before the archive is applied. Archived strategies are preserved indefinitely and can be restored or permanently deleted from the owner's account.
Auth:
- API key or ID token
Request body:
| Field | Type | Required |
|---|---|---|
strategy_id or strategy_name | string | Yes |
Success (200):
{
"message": "Strategy archived successfully",
"strategy_id": "Momentum Core",
"deleted": true,
"pending_trade_cancellation": {
"matched_pending_trades": 1,
"cancelled_count": 1,
"already_cancelled_count": 0,
"processing_count": 0,
"not_cancellable_count": 0,
"failed_count": 0
}
}Conflict (409):
- Returned as
ARCHIVE_BLOCKED_BY_PENDING_TRADESif one or more matching pending trades are already processing or could not be cancelled safely.
POST|DELETE /permanent-delete-strategy (alias: /permanentDeleteStrategy)
Permanently delete an archived strategy and its strategy-owned data. This removes the strategy document tree, matching pending trades, immutable trade storage files, verification snapshot files, and OpenTimestamps anchor/proof files tied to that strategy.
Auth:
- ID token only
Request body:
| Field | Type | Required |
|---|---|---|
strategy_id or strategy_name | string | Yes |
confirmation_text | string | Yes; must exactly equal the strategy ID |
target_user_id | string | Admin only; omit when deleting your own strategy |
Success (200):
{
"message": "Strategy permanently deleted",
"strategy_id": "Momentum Core",
"deleted": true,
"permanent": true
}Conflict (409):
- Returned as
STRATEGY_NOT_ARCHIVEDif the strategy has not been archived first.
API-key authentication is rejected for permanent deletion. Retrying a completed deletion returns success with already_deleted: true.
GET /strategy-audit-pack
Download a portable strategy audit ZIP that can be verified without TradeLock, Firestore, credentials, npm, or network access.
Auth:
- ID token or full-access API key
Query parameters:
| Field | Type | Required |
|---|---|---|
strategyName or strategy_id | string | Yes |
Success (200) returns application/zip. Extract the archive and run node verify.cjs . with Node.js 18 or newer.
6.3 Trade Validation and Submission
POST /validate-trade (alias: POST /dry-run-trade)
Validate and normalize a trade request without creating a trade.
Auth:
- API key or ID token
Key inputs:
- Strategy:
strategyorstrategy_nameoruser_strategy_name(optional if user has exactly one strategy) - Asset:
tickerorsymbolorasset - Side:
trade_typeorsideoraction(buy|sell) - Size: exactly one of
quantityor allocation aliases - Optional
check_market_data: trueresolves the exact listing and reportsexecutableorclosedwithout writing a trade. Other quote failures return a stablecode.
Allocation aliases:
allocation_percentallocation_pctallocationPercentageallocation%
Success (200):
{
"valid": true,
"mode": "validate_only",
"key_scope": "full",
"normalized_payload": {
"user_strategy_name": "Momentum Core",
"asset": "AAPL",
"trade_type": "buy",
"allocation_percent": 10,
"fill_policy": "immediate_if_open"
},
"notes": [
"Allocation mode with trade_type sizes this order from strategy running capital."
]
}POST /quick-trade
Manager-friendly trade submission with broad aliases.
Recommendation:
- Keep this only for backwards-compatible verification clients or historical adapters.
- New live integrations should publish exactly once to
POST /v1/signals.
Auth:
- API key or ID token
Request fields:
| Canonical field | Accepted input keys | Required | Notes |
|---|---|---|---|
| strategy | strategy, strategy_name, user_strategy_name | Conditionally | Optional only if exactly one strategy exists |
| asset | ticker, symbol, asset | Yes | SYMBOL or SYMBOL:EXCHANGE |
| trade side | trade_type, side, action | Depends | Required when using quantity |
| quantity | quantity, qty | Depends | Mutually exclusive with allocation |
| allocation | allocation_percent, allocation_pct, allocationPercentage, allocation% | Depends | Mutually exclusive with quantity |
| idempotency | idempotency_key, client_order_id | Recommended | Use in production |
| execution | fill_policy, open_delay_minutes | No | |
| tags | tags | No | string[] |
Behavior:
- Calls
logTradeinternally after normalization - Returns immediate fill (
200) or queued (202) - Pending replacement rules for same
strategy + asset: target_allocationmode (sendallocation_percentand omit side) replaces the existing active pending target-allocation intent for that symbol.quantitymode and side-basedallocation_percentmode append as separate pending orders (FIFO).
POST /set-target-portfolio
Asynchronous contract:
idempotency_key(orclient_order_id) is required. The endpoint returns202 Acceptedwith a durablerebalance_id; pollGET /rebalance-status?rebalance_id=...forcompleted,partially_completed, orfailed. A timeout is an unknown outcome—retry the identical payload with the same key. Only one rebalance may be active per strategy.
Set an authoritative target portfolio for a strategy.
- Full-portfolio semantics are default: symbols with open positions that are not in
targetsare auto-targeted to0%. - Before submitting new legs, the endpoint cancels all cancellable pending trades for the same strategy by default.
- Trade legs are submitted sequentially (sells first, then buys).
- Each leg is submitted as target-allocation logic (
allocation_percentwithout side). - Targets do not need to sum to
100. Totals below100leave residual cash uninvested. For example, an80total target is valid and leaves20%in cash. - Legs whose notional move is smaller than
min_rebalance_move_pct(set on the strategy, default1%) are silently skipped. The response marks them withdrift_filtered: trueanddrift_pct.
Pricing and sizing behavior:
set-target-portfoliosizing uses last-price lookup (getLastPrice) for each leg, not Alpaca execution quotes.- Provider order for last-price lookup:
- Crypto-like symbols:
coinbase->twelve-data->yahoo-finance2->alpha-vantage - Futures-like symbols:
twelve-data->yahoo-finance2->alpha-vantage->coinbase - Other symbols: configured default provider first, then remaining providers.
- Configured default provider:
twelve-datawhenTWELVEDATA_API_KEYorTWELVE_DATA_API_KEYis present- else
alpha-vantagewhenALPHA_VANTAGE_API_KEYis present - else
yahoo-finance2 - If no provider returns a usable quote, the endpoint returns
400with a sizing error per symbol.
Auth:
- API key or ID token
Request fields:
| Field | Type | Required | Notes |
|---|---|---|---|
strategy / strategy_name / user_strategy_name | string | Conditionally | Optional only if exactly one strategy exists |
targets | array or object map | Yes | Array: [{ "symbol": "SPY", "allocation_percent": 33 }] or map: { "SPY": 33 } |
execution_anchor | enum | No | now (default) or next_us_equity_open |
execute_on_stock_open | boolean | No | Alias for execution_anchor=next_us_equity_open |
open_delay_minutes | number | No | Applied per leg |
cancel_pending_trades_first | boolean | No | Default true; set false to preserve the current pending queue |
dry_run | boolean | No | If true, returns plan only (no submissions) |
idempotency_key / client_order_id | string | Yes | Required; timeout retries must reuse the identical payload and key |
tags | string[] | No | Applied to each submitted leg |
Example:
{
"strategy": "Sandbox Strategy",
"targets": {
"SPY": 33,
"TLT": 33,
"EEM": 10,
"GSY": 15
},
"execution_anchor": "next_us_equity_open",
"open_delay_minutes": 2,
"idempotency_key": "stp-20260308-001"
}Acceptance (202) returns after the durable job is created:
{
"message": "Rebalance accepted for asynchronous processing.",
"rebalance_id": "stp_1773763355292_ganlirnm",
"strategy": "Sandbox Strategy",
"status": "accepted",
"status_url": "/api/rebalance-status?rebalance_id=stp_1773763355292_ganlirnm"
}- Same key and identical payload returns the same
rebalance_id. - Same key with a different payload returns
409 IDEMPOTENCY_PAYLOAD_CONFLICT. - Only one rebalance can be active per strategy. Another returns
409 REBALANCE_ALREADY_ACTIVEwithactive_rebalance_id. - Pricing, sizing, pending-trade cancellation, and leg submission happen in the durable worker.
- A timeout is an unknown outcome. Retry the identical payload and key; do not submit a replacement rebalance.
GET /rebalance-status
Get the durable state and result of an accepted portfolio rebalance.
Auth: API key or ID token. The rebalance must belong to the authenticated trader.
| Param | Required | Notes |
|---|---|---|
rebalance_id / rebalanceId | Yes | ID returned by set-target-portfolio |
States:
accepted: durable job storedplanning: worker is pricing, sizing, or submitting legscompleted: all required legs were submitted or no trades were neededpartially_completed: at least one leg succeeded before a later failurefailed: job did not complete successfully
Terminal responses include result with the summary, planned and processed legs, trade or pending-trade IDs, and error details.
Client flow:
- Persist the payload and idempotency key before submission.
- On
202, persistrebalance_id. - Poll until
completed,partially_completed, orfailed. - If the connection is lost before
202, retry the identical submission with the same key.
- When
cancel_pending_trades_firstis enabled, responses also includepreflight_pending_trade_reset. - If a pending trade is already
processing, or cancellation fails during preflight, the job reachesfailedbefore submitting new legs.
Example response fragment:
{
"rebalance_id": "stp_1773763355292_ganlirnm",
"strategy": "Sandbox Strategy",
"status": "completed",
"result": {
"message": "Target portfolio submitted successfully.",
"summary": {
"immediate_count": 0,
"queued_count": 4,
"no_op_count": 0
}
}
}POST /logTrade
Advanced trade endpoint.
Auth:
- API key or ID token
Core fields:
| Field | Type | Required | Notes |
|---|---|---|---|
user_strategy_name / strategy_name / strategy | string | Conditionally | Optional only if exactly one strategy exists |
asset | string | Yes | SYMBOL or SYMBOL:EXCHANGE |
trade_type / side / action | buy|sell | Depends | Required for direct quantity mode |
quantity / qty | number | Depends | Required unless allocation is provided |
allocation_percent and aliases | number | Depends | Required unless quantity is provided |
fill_policy | enum | No | immediate_if_open (default) or next_open_with_delay |
open_delay_minutes | number | No | non-negative |
idempotency_key | string | Recommended | or Idempotency-Key header |
tags | string[] | No |
Sizing modes:
- Quantity mode
- send
quantity+ explicit side
- Allocation-percent mode
- send
allocation_percent+ side - quantity is computed from strategy running capital
- Target-allocation mode
- send
allocation_percentand omit side - endpoint computes target position delta and direction
- queued submissions in this mode replace prior active pending target-allocation intent for the same strategy+asset
CSV import-only fields (import_source: "csv_import"):
| Field | Type | Notes |
|---|---|---|
import_source | string | Must equal csv_import |
reported_date | ISO-8601 string | Optional |
user_reported_price | number | Required and must be > 0 |
reference_price | number | Optional (sizing reference) |
allocation_reference_price | number | Optional (sizing reference) |
Optional enrichment fields:
rankable_strategy_id,isin,tick_size,multiplier,point_value,margin,commission
Live execution quote behavior:
logTradeuses execution quote lookup (getExecutionQuote) when processing non-CSV trades.- U.S. equity/ETF execution uses
Tradier -> Alpaca -> EODHDby default; eToro is reserved for exchange-qualified non-U.S. equities/ETFs. - EODHD-style EU symbols submitted by StrategyLab are preserved as source identifiers and may resolve to an equivalent eToro-supported cross-listing. Audit fields record the source symbol, resolved quote symbol, quote exchange, and ISIN when available; ambiguous mappings fail closed.
- Alpaca remains opt-in through
ALPACA_EQUITY_ENABLED; Tradier is independently opt-in throughTRADIER_EQUITY_ENABLED. Merely configuringTRADIER_ACCESS_TOKENdoes not activate it. - Alpaca and Tradier quotes use top-of-book side pricing for U.S. listings: buy -> ask, sell -> bid. eToro is reserved for exchange-qualified non-U.S. listings. Stale/crossed/missing side quotes are rejected.
- If an execution-quote provider fails, the next enabled provider is tried. If all fail, execution falls back to last-price providers.
- Fallback executions are marked with
execution_basis: "last"and includequote_fallback_reason. - If no quote is available (or market is not open), the trade is queued (
202) for delayed processing; failed delayed attempts can move toerror_processing.
Example provider configuration:
ALPACA_EQUITY_ENABLED=true
TRADIER_EQUITY_ENABLED=true
TRADIER_ACCESS_TOKEN=your-production-token
EXECUTION_QUOTE_PROVIDER_ORDER=tradier,alpacaTradier uses the production consolidated feed. TRADIER_API_KEY is accepted as an alias for TRADIER_ACCESS_TOKEN. Its sandbox feed is delayed and is not used by this integration.
Success patterns:
Immediate/logged (200):
{
"message": "Trade logged successfully!",
"tradeId": "abc123",
"execution": {
"fill_policy": "immediate_if_open",
"resolved_open_delay_minutes": 5
},
"sizing": {
"mode": "allocation_percent",
"allocation_percent": 10,
"quantity": 42
},
"hybrid": {
"verified": true,
"storageRef": "strategies/.../snapshot.json",
"hash": "..."
},
"price_data": {
"price": 201.12,
"market_state": "REGULAR"
}
}Queued (202):
{
"message": "Trade received and queued for processing when market opens.",
"pendingTradeId": "pnd_456",
"current_market_state": "CLOSED",
"execution": {
"fill_policy": "next_open_with_delay",
"waiting_for_next_market_session": false,
"resolved_open_delay_minutes": 5
}
}No-op target allocation (200):
{
"message": "No trade created. Strategy is already at the requested target allocation.",
"no_op": true
}6.4 Trade Status and History
GET /trade-status
Get lifecycle/timeline for a trade or pending trade.
Auth:
- API key or ID token
Query params:
| Param | Required | Notes |
|---|---|---|
strategyName or strategy_name | Yes | Strategy name |
tradeId or trade_id | Yes | tradeId or pendingTradeId from submit response |
Success (200) returns timeline-style response with:
source:pending_tradesorstrategy_tradecurrent_status: e.g.queued,pending_delay,filled,immutable_stored,verified,error_*snapshot_freshness:not_ready,fresh,stale,unknownexecution,filled,timeline
GET /strategy-trades
Get strategy trade history (and optionally pending queue).
Auth:
- API key or ID token
Query params:
| Param | Required | Notes |
|---|---|---|
strategy_name | Yes | Strategy name |
limit | No | Default 100 |
include_pending | No | true/1/yes to include active pending trades |
Success (200):
- Without pending:
{ "trades": [...] } - With pending:
{ "trades": [...], "pending_trades": [...] }
POST /cancel-pending-trade
Cancel one queued pending trade before execution.
Auth:
- API key or ID token
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
strategy_name | string | Yes | Strategy name |
pending_trade_id | string | Yes | ID from queued trade response |
reason | string | No | Optional cancellation note |
Success (200):
{
"message": "Pending trade cancelled successfully.",
"pending_trade_id": "pnd_456",
"strategy_name": "Sandbox Strategy",
"status": "cancelled"
}Possible conflicts:
409if order is alreadyprocessingor in another non-cancellable status404if pending trade does not belong to caller/strategy
POST /cancel-all-pending-trades
Cancel all cancellable pending trades for one strategy.set-target-portfolio now performs this queue reset automatically by default, so use this endpoint when you want to clear the queue explicitly without submitting a new target portfolio.
Auth:
- API key or ID token
Request body:
| Field | Type | Required | Notes |
|---|---|---|---|
strategy_name | string | Yes | Strategy name to clear |
reason | string | No | Optional cancellation note applied to all cancelled rows |
Success (200):
{
"message": "Cancelled 3 pending trade(s) for strategy 'Sandbox Strategy'.",
"strategy_name": "Sandbox Strategy",
"matched_pending_trades": 5,
"cancelled_count": 3,
"already_cancelled_count": 1,
"processing_count": 1,
"not_cancellable_count": 0,
"failed_count": 0
}6.5 Market Data Utilities
GET|POST /symbol-search
Lookup symbols across providers.
Default routing aggregates Twelve Data, Yahoo Finance, and configured Alpha Vantage metadata. An exact U.S. listing is returned without contacting eToro. When no exact U.S. listing exists and metadata identifies a supported European exchange, TradeLock queries eToro for live-supported listings. Alpaca and Tradier are used for quote confirmation, not text search. Supplying provider still forces that search provider.
Auth:
- Required
- Send either:
X-Trader-Api-Key: <API_KEY>Authorization: Bearer <FIREBASE_ID_TOKEN>
Inputs:
| Field | Type | Required | Notes |
|---|---|---|---|
q | string | Yes | query text |
provider | string | No | yahoo-finance2, alpha-vantage, twelve-data, coinbase, eodhd, etoro |
limit | number | No | default 10, max 25 |
exchange | string | No | requested TradeLock exchange code |
symbology | string | No | tradelock, eodhd, or etoro; enables namespace-specific suffix parsing |
include_quotes | boolean | No | defaults to true for compatibility; use false while typing |
Success (200):
{
"query": "AAPL",
"count": 1,
"provider_used": "twelve-data",
"attempts": [
{ "provider": "twelve-data", "status": "success" }
],
"results": [
{
"symbol": "AAPL",
"canonical_symbol": "AAPL",
"name": "Apple Inc",
"exchange": "NASDAQ",
"type": "Common Stock",
"provider": "twelve-data"
}
]
}If all providers fail: 502 with provider attempt details.
Legacy European symbol lookup (not available for canonical live submission):
- Search the source symbol, for example
q=LQQ.PA&symbology=eodhd&include_quotes=false. - Select the exact returned
canonical_symbol. Alternative name matches are markedunverified_nameand require explicit selection. - Submit that canonical symbol unchanged in one
/v1/signalsenvelope.
European stocks and ETFs are not supported for canonical live submission yet. Historical-data coverage does not imply that the exact listing has a live eToro quote. Bare tickers such as SPY, TLT, EEM, and AAPL retain the existing U.S. behavior and do not require a prior search.
Market-data failures use stable codes: INSTRUMENT_UNRESOLVED, INSTRUMENT_AMBIGUOUS, UNSUPPORTED_EXCHANGE, QUOTE_CURRENCY_UNKNOWN, QUOTE_STALE, QUOTE_FUTURE_TIMESTAMP, QUOTE_UNAVAILABLE, MARKET_CLOSED, or PROVIDER_FAILURE.
GET|POST /fetch-price (alias: /fetchPrice)
Get last/current price and market state.
Auth:
- Required
- Send either:
X-Trader-Api-Key: <API_KEY>Authorization: Bearer <FIREBASE_ID_TOKEN>
Inputs:
| Field | Type | Required | Notes |
|---|---|---|---|
symbol | string | Yes | e.g. AAPL |
provider | string | No | provider hint |
When market is closed, endpoint can still return 200 with last available price and note.
Provider routing notes:
- Crypto symbol normalization for Coinbase:
BTC/USDis normalized toBTC-USD- bare symbols like
BTCare normalized toBTC-USD - Crypto symbols are routed to Coinbase first, then fallback providers.
7) Legacy verification-only cURL reference
The examples in this section document existing-client compatibility. For new live integrations, use the canonical /v1/signals examples in section 3.
1. Legacy set portfolio targets
curl -X POST "https://tradelock.net/api/set-target-portfolio" \
-H "Content-Type: application/json" \
-H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>" \
-d '{
"strategy": "Sandbox Strategy",
"targets": {
"SPY": 33,
"TLT": 33,
"EEM": 10,
"GSY": 15
},
"execution_anchor": "next_us_equity_open",
"open_delay_minutes": 2,
"idempotency_key": "signal-portfolio-20260308-001"
}'2. Buy by quantity
curl -X POST "https://tradelock.net/api/logTrade" \
-H "Content-Type: application/json" \
-H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>" \
-d '{
"user_strategy_name": "Sandbox Strategy",
"asset": "AAPL:NASDAQ",
"trade_type": "buy",
"quantity": 10,
"idempotency_key": "signal-qty-buy-20260308-001"
}'3. Individual target allocation (single symbol)
curl -X POST "https://tradelock.net/api/logTrade" \
-H "Content-Type: application/json" \
-H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>" \
-d '{
"user_strategy_name": "Sandbox Strategy",
"asset": "AAPL:NASDAQ",
"allocation_percent": 30,
"idempotency_key": "signal-single-target-20260308-001"
}'4. Poll status
curl "https://tradelock.net/api/trade-status?strategyName=Sandbox%20Strategy&tradeId=<TRADE_OR_PENDING_ID>" \
-H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>"8) Integration Checklist
- Use one API key per integration (webhook, backend service, ETL).
- Read
GET /strategiesand use the selected strategy's exactid. - Resolve the instrument with
GET /symbol-searchand use its exactcanonical_symbol. - Send one of the three strict payloads to
POST /v1/signals. - Create a new
idempotency_keyfor a new intent; reuse it only to retry the identical body. - Store the complete acceptance receipt.
- Alert on repeated
4xxresponses and do not fall back to a legacy submission endpoint. - Separate sandbox and production strategies and API keys.
9) Changelog
- 1.1 (2026-09-09)
- Made the canonical contract self-contained for human and LLM integration builders.
- Added exact strategy ID and symbol discovery, payload constraints, receipt handling, retries, and error codes.
- Corrected the symbol lookup route to
/symbol-searchand documented the current European-instrument limitation.
- 0.8 (2026-08-16)
- Documented the authenticated webhook relay access endpoint.
- Documented sandbox onboarding and sandbox reset endpoints.
- Documented client execution configuration read/update endpoints.
- Clarified exchange qualification and conflicting asset-field behavior.
- 0.7 (2026-07-13)
- Documented durable asynchronous portfolio jobs and required idempotency.
- Added
GET /rebalance-status, terminal states, polling, and timeout recovery.
- 0.6 (2026-04-22)
- Added
trade_hide_daysfield tocreateStrategyandupdate-strategy. Controls how many days of recent trades are hidden from public viewers (0,30,60,90,9999). - Added
min_rebalance_move_pctfield tocreateStrategyandupdate-strategy. Legs inset-target-portfoliowhose notional move is below this % of running capital are skipped. Default1. - Documented drift filter response fields (
drift_filtered,drift_pct) inset-target-portfolio.
- 0.5 (2026-03-17)
- Documented
set-target-portfoliopreflight cancellation of existing pending trades. - Documented
cancel_pending_trades_first=falseopt-out andpreflight_pending_trade_resetresponse field. - Clarified request-level replay behavior for
set-target-portfolioidempotency retries.
- 0.4 (2026-03-08)
- Added
POST /cancel-all-pending-tradesfor strategy-scoped queue reset. - Documented bulk-cancel response counters (
cancelled_count,processing_count, etc.).
- 0.3 (2026-03-08)
- Added clear recommended submission order with
set-target-portfolioas primary. - Added copy-paste sandbox defaults (
Sandbox Strategy,<YOUR_SANDBOX_API_KEY>). - Clarified three manager submission modes: full portfolio targets, quantity buy/sell, and single-symbol target allocation.
- 0.2 (2026-02-27)
- Rewrote guide into endpoint-reference format.
- Corrected strategy endpoint requirements and status codes.
- Corrected auth requirements for utility endpoints.
- Added API key lifecycle endpoints and sandbox scope behavior.
- Clarified sizing modes, idempotency behavior, and queue semantics.
- 0.1 (2026-02-27)
- Initial manager-focused API guide.