# TradeLock Getting Started

This guide is for managers and integration builders who want a first successful TradeLock submission without choosing between several overlapping docs.

TradeLock verification access is free within reasonable usage limits. Submitted strategy signals are used
solely to verify and preserve intent inside TradeLock and are not reused or
shared outside TradeLock without the manager's explicit approval.

**Doc version:** `3.2`

**Updated:** `2026-09-19`

Use this order:
1. Create or select a strategy.
2. Create a sandbox API key.
3. Choose one canonical submission path:
   - Direct API with **`POST /api/v1/signals`** (recommended)
   - TradingView alerts through the **Cloudflare relay**
4. Confirm the first submission succeeds.
5. Use the full API reference for detailed endpoint behavior.

---

## 0) What you need first

1. A TradeLock manager account
2. A strategy in your workspace (examples below use `Sandbox Strategy`)
3. A sandbox API key from `https://app.tradelock.net/app/api-keys` (examples use `<YOUR_SANDBOX_API_KEY>`)
4. The strategy `id` returned by TradeLock
5. A confirmed U.S. symbol

Before publishing, open **New Trade**, type the ticker, and wait for TradeLock
to confirm the listing. Use the confirmed `canonical_symbol` in the API
payload. U.S. stocks and ETFs normally use the bare ticker, such as `AAPL` or
`SPY`. You may type `SPY:ARCA` in New Trade to help find the correct listing,
but the canonical symbol submitted to the API is `SPY`.

European stocks and ETFs are not supported for canonical live submission yet.

API base URL (the common prefix for the endpoints below):

`https://tradelock.net/api`

All calls use this same API base, but they do not use the same endpoint path.
Account and strategy setup use the existing management paths, while new trade
intent is submitted only through the versioned canonical signal path:

| Purpose | Method and path | Authentication |
|---|---|---|
| Create an API key | `POST /api/generate-api-key` | Firebase ID token |
| List strategies | `GET /api/strategies` | API key or Firebase ID token |
| Create a strategy | `POST /api/createStrategy` | API key or Firebase ID token |
| Update a strategy | `PATCH /api/update-strategy` | API key or Firebase ID token |
| Archive a strategy | `POST /api/delete-strategy` | API key or Firebase ID token |
| Delete an API key | `POST /api/delete-api-key` | Firebase ID token |
| Publish canonical intent | `POST /api/v1/signals` | API key |
| Check canonical processing | `GET /api/v1/signals?event_id=...` | API key |

The `/v1` prefix versions the strict signal contract. Management endpoints
predate that contract and remain current; they are not alternative or legacy
signal-submission methods.

### Finding the strategy ID

For strategies created in the current TradeLock app, the strategy ID is the
same as the strategy name. Integrations should still use the exact
`id` returned by `GET /api/strategies`, because the ID is the authoritative
value:

```bash
curl "https://tradelock.net/api/strategies?limit=100" \
  -H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>"
```

You can also select a strategy on the **Integrations** page; its copyable
examples are filled with the correct ID automatically.

---

## 1) Direct API path (recommended)

For most managers, the best first test is a canonical full target portfolio.

### 1.1 Resolve a canonical symbol

```bash
curl "https://tradelock.net/api/symbol-search?q=SPY&limit=1&include_quotes=false" \
  -H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>"
```

Use the returned `canonical_symbol`; do not derive it from a provider suffix.

### 1.2 Publish a full target portfolio

Endpoint: `POST /api/v1/signals`

Headers:
- `Content-Type: application/json`
- `X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>`

Body:

```json
{
  "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 }
    ]
  }
}
```

Notes:
1. `scope: "full"` means symbols omitted from `targets` are treated as target `0%`.
2. Use `scope: "patch"` when only the supplied symbols should change.
3. Targets do not need to sum to `100`; unused weight stays in cash.
4. The accepted envelope feeds verification and entitled HUB delivery independently.

cURL:

```bash
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}
      ]
    }
  }'
```

Successful durable acceptance returns `201` for a new event or `200` for an idempotent replay:

```json
{
  "event_id": "evt_...",
  "strategy_sequence": 42,
  "received_at": "2026-09-09T12:00:00Z",
  "envelope_hash": "sha256:...",
  "idempotency_key": "signal-portfolio-20260909-001"
}
```

Save the receipt. Acceptance does not wait for verification or subscriber delivery.

Check whether TradeLock submitted the orders with the receipt's `event_id`:

```bash
curl "https://tradelock.net/api/v1/signals?event_id=evt_..." \
  -H "X-Trader-Api-Key: <YOUR_SANDBOX_API_KEY>"
```

Poll until `status` is `submitted`, `no_op`, or `failed`. A `submitted` signal
can contain queued orders. Each queued entry in `orders` includes a
`trade_status_path`; poll it with the same API key until that order fills or
reaches another final state. The full response and failure handling are in the
manager API reference.

### 1.3 Explicit quantity order

Use this when you need a direct buy or sell in shares or units.

```json
{
  "protocol_version": "1.0",
  "strategy_id": "<STRATEGY_DOCUMENT_ID>",
  "idempotency_key": "signal-qty-buy-20260909-001",
  "payload": {
    "type": "quantity_order",
    "symbol": "AAPL",
    "side": "buy",
    "quantity": 10
  }
}
```

### 1.4 Percent-of-NAV order

This sends an order sized from the strategy's value at submission time. In the
example below, if the strategy value is `$100,000`, TradeLock records an order
to buy approximately `$5,000` of AAPL. It does **not** mean “make AAPL 5% of the
final portfolio.” A sell order with `percent_of_nav: 5` reduces exposure by
approximately `$5,000`. To set a final holding percentage, use the
single-symbol target allocation in section 1.5 instead.

```json
{
  "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
  }
}
```

### 1.5 Single-symbol target allocation

Use this when you want to retarget one symbol without resetting the rest of the portfolio.

```json
{
  "protocol_version": "1.0",
  "strategy_id": "<STRATEGY_DOCUMENT_ID>",
  "idempotency_key": "signal-single-target-20260909-001",
  "payload": {
    "type": "target_portfolio",
    "scope": "patch",
    "targets": [{ "symbol": "AAPL", "weight_pct": 30 }]
  }
}
```

---

## 2) TradingView via Cloudflare relay

Use this when TradingView is generating the signal and you want a relay between TradingView and TradeLock.

Flow:
1. TradingView sends JSON to the Cloudflare Worker relay.
2. The relay validates a shared relay gate key.
3. The relay forwards the payload to TradeLock.

Current example endpoint:

`https://tradelock-tv-relay.tradelock.workers.dev/webhook/tradingview`

### 2.1 What stays private

Never publish the real values for:
- the shared relay gate key
- the TradeLock API key

For the current Cloudflare relay example:
1. Open `API Keys` in the app and reveal the shared relay gate key only when you are configuring TradingView, Zapier, Make, n8n, or a similar webhook tool
2. Use that same shared value only inside your private alert or webhook message sent to the TradeLock relay endpoint
3. Do not put the real secret in public docs, screenshots, source control, or examples

Important:
- The shared relay gate key is only there to stop random public use of the relay. It is not used to identify users.
- The current relay example also expects `api_key` in the TradingView webhook body.
- That means the TradeLock API key must also stay private and is the value that identifies the manager.
- Use a dedicated TradeLock API key for this relay.

### 2.2 Quantity-mode TradingView payload

```json
{
  "secret": "YOUR_WEBHOOK_SHARED_SECRET",
  "api_key": "YOUR_TRADELOCK_API_KEY",
  "strategy_id": "<STRATEGY_DOCUMENT_ID>",
  "ticker": "{{ticker}}",
  "action": "{{strategy.order.action}}",
  "quantity": "{{strategy.order.contracts}}",
  "client_order_id": "{{strategy.order.id}}"
}
```

### 2.3 Allocation-mode TradingView payload

```json
{
  "secret": "YOUR_WEBHOOK_SHARED_SECRET",
  "api_key": "YOUR_TRADELOCK_API_KEY",
  "strategy_id": "<STRATEGY_DOCUMENT_ID>",
  "canonical_symbol": "SPY",
  "allocation_percent": 10,
  "client_order_id": "{{strategy.order.id}}"
}
```

### 2.4 Duplicate protection

Every canonical relay submission requires a stable order identifier:

```json
{
  "secret": "YOUR_WEBHOOK_SHARED_SECRET",
  "api_key": "YOUR_TRADELOCK_API_KEY",
  "strategy_id": "<STRATEGY_DOCUMENT_ID>",
  "ticker": "{{ticker}}",
  "action": "{{strategy.order.action}}",
  "quantity": "{{strategy.order.contracts}}",
  "client_order_id": "{{strategy.order.id}}"
}
```

The relay also accepts `idempotency_key` directly.

---

## 3) Preserve the acceptance receipt

Store `event_id`, `strategy_sequence`, `received_at`, `envelope_hash`, and
`idempotency_key`. The receipt proves that TradeLock durably accepted the exact
manager envelope. Verification status remains visible in the manager app and
does not block acceptance.

---

## 4) Unique Trade ID (`idempotency_key`)

Always send `idempotency_key` on write requests.

Rules:
1. New signal = new key
2. Retry same signal = reuse same key
3. Valid length: `1..120`, without surrounding whitespace

If submission times out or the connection drops, the outcome is unknown: retry the **identical envelope with the same key**. Do not create a replacement key merely because the client did not receive a receipt.

For TradingView relay submissions, `client_order_id` is also accepted and mapped into the same duplicate-protection flow.

---

## 5) Live trade field policy

For live submissions, do **not** send:
- `reported_date`
- `user_reported_price`
- `reference_price`
- `allocation_reference_price`

These are only valid for CSV-import flows.

---

## 5a) Strategy settings that affect execution

Two optional strategy-level settings:

**`trade_hide_days`** — hides recent trades from public viewers for the specified number of days. Allowed values: `0` (show all, default), `30`, `60`, `90`, `9999` (hides all trades from public). You as the manager always see the full history.

**`min_rebalance_move_pct`** — a drift filter for canonical target-portfolio
signals. Any derived leg whose notional move is smaller than this percentage
of running capital is skipped as a no-op. Default is `1` (1%). Set to `0` to
disable filtering.

Set these on `createStrategy` or `update-strategy`:

```json
{
  "strategy_name": "Sandbox Strategy",
  "trade_hide_days": 30,
  "min_rebalance_move_pct": 2
}
```

---

## 6) Next step: API reference

After the first successful signal, use:

- `/docs/manager-api-reference/` for full endpoint behavior
- `https://app.tradelock.net/app/integrations` for in-app templates and copy-paste examples

---

## 7) Version notes

- `3.2` (2026-09-19)
1. Clarified that management calls and canonical signal publishing share one API base but use different endpoint paths.
2. Separated current management APIs from the canonical submission contract.
3. Removed alternative submission formats from the public workflow.

- `3.1` (2026-09-09)
1. Simplified symbol guidance and clarified that `SPY:ARCA` is a lookup hint while `SPY` is the submitted symbol.
2. Added strategy ID discovery, a percent-of-NAV example, and the current European-instrument limitation.
3. Clarified the API base URL and corrected symbol lookup to `/symbol-search`.

- `2.2` (2026-07-13)
1. Documented asynchronous portfolio acceptance and `rebalance_id` polling.
2. Added safe timeout and same-key retry guidance.

- `2.1` (2026-04-22)
1. Added section on `trade_hide_days` and `min_rebalance_move_pct` strategy settings.

- `2.0` (2026-04-06)
1. Reframed the quickstart as the single public getting-started guide.
2. Added TradingView submission guidance through the Cloudflare relay.
3. Added explicit public guidance on where the webhook secret should stay private.
