---
name: alphainsider
description: Use when building integrations with the AlphaInsider trading API (strategies, orders, positions, allocations, bots, webhooks, WebSockets). All user-facing strategy values and position sizes MUST be displayed in USD via `input_multiplier` when available, otherwise as percent via `strategy_value`. Canonical version at https://api.alphainsider.com/skill.md.
version: "2.2"
---

# AlphaInsider API Skill

A single reference for AI agents and developers working with AlphaInsider. Drop this file in your project root or agent skills folder (`~/.claude/skills/`, `~/.cursor/skills/`, etc.). Re-fetch periodically from `https://api.alphainsider.com/skill.md`.

- **REST base URL**: `https://alphainsider.com/api`
- **WebSocket URL**: `wss://alphainsider.com/ws`
- **Docs site**: https://api.alphainsider.com (OpenAPI explorer, MDX guides, examples)
- **OpenAPI spec**: https://api.alphainsider.com/openapi.yaml
- **AsyncAPI (WS) spec**: https://api.alphainsider.com/asyncapi.yaml

---

## 1. What AlphaInsider Does

A REST + WebSocket platform for retail and algorithmic traders. Core capabilities:

- **Strategies** — create, publish, subscribe, track performance (stocks or crypto)
- **Orders & Positions** — market / limit / stop / OCO via fixed amounts, percent allocations, or webhook signals
- **Bots** — automated execution with broker integration (Alpaca, Binance, Bitfinex)
- **Subscriptions** — follow other traders' strategies; required to get `input_multiplier`
- **Market data** — real-time quotes, search, exchange status, history
- **Timelines** — social posts per strategy (trade signals, commentary)
- **Billing & payouts** — Stripe-connected withdrawals, invoices, income tracking

---

## 2. Authentication

All protected endpoints require a JWT from https://alphainsider.com/settings/developers.

```
Authorization: <your_jwt_token>
```

No `Bearer ` prefix. A few endpoints take the token in the JSON body instead of the header and need **no** `Authorization` header: `verifyToken` (`token`), `newOrderWebhook` (`api_token`).

**Store the key as `ALPHAINSIDER_API_KEY`** — shell env var or a `.env` file in the directory the agent runs from. Never hardcode, log, or paste it into prompts.

```python
import os
from dotenv import load_dotenv
load_dotenv()
key = os.getenv("ALPHAINSIDER_API_KEY")
assert key, "Set ALPHAINSIDER_API_KEY"
```

```js
require('dotenv').config();
const key = process.env.ALPHAINSIDER_API_KEY;
if (!key) throw new Error("Set ALPHAINSIDER_API_KEY");
```

Verify any time:
```bash
curl -X POST https://alphainsider.com/api/verifyToken \
  -H "Content-Type: application/json" \
  -d "{\"token\": \"$ALPHAINSIDER_API_KEY\"}"
```

**Response shape (every endpoint)**:
- Success: `{ "success": true, "response": <data> }`
- Error: `{ "success": false, "response": "<message>" }`

### Optional: scoping env vars

Two optional env vars pin the agent to a specific strategy and/or bot. When present, the agent **MUST** use them by default on every call that takes a `strategy_id` or `bot_id` and **MUST NOT** ask the user which to use.

| Variable                     | Applies to                                                                                      |
| ---------------------------- | ----------------------------------------------------------------------------------------------- |
| `ALPHAINSIDER_STRATEGY_ID`   | Default `strategy_id` for trades, positions, allocations, orders, subscriptions, timelines, WS. |
| `ALPHAINSIDER_BOT_ID`        | Default `bot_id` for every `*Bot*` endpoint and bot-related WS channel.                         |

When a required ID env var is **not** set and the endpoint needs one, the agent **MUST** ask the user which `strategy_id` / `bot_id` to use before making the call. Do not guess, do not pick the first result from `getUserStrategies` / `getBots`, do not proceed.

```python
strategy_id = os.getenv("ALPHAINSIDER_STRATEGY_ID")  # may be None
bot_id      = os.getenv("ALPHAINSIDER_BOT_ID")       # may be None

# at call time:
if not strategy_id:
    raise SystemExit("Which strategy? Set ALPHAINSIDER_STRATEGY_ID or tell me the id.")
```

```js
const strategyId = process.env.ALPHAINSIDER_STRATEGY_ID; // may be undefined
const botId      = process.env.ALPHAINSIDER_BOT_ID;      // may be undefined
```

User-supplied IDs in the prompt override these defaults for that single call. If the user passes an ID that doesn't match the env-var scope, confirm with the user before executing — do not silently cross scopes.

---

## 3. THE DISPLAY RULE (read this before writing any code that shows numbers)

Strategies track performance as a normalized `strategy_value` (starts at `1.0`). That number is **never** what a user should see. Convert it first.

**Two forms allowed for any user-facing strategy value, position size, or P&L**:

1. **USD (preferred)** — use `input_multiplier` from the user's strategy subscription
2. **Percent (fallback)** — use `strategy_value` directly; only when `input_multiplier` is unavailable

Never show raw `strategy_value` or raw `amount` to a user.

### Formulas

**Key insight**: `price` / `bid` / `ask` / `last` are real USD. `amount` and `total` on positions are **strategy-normalized** units. Multiply by `input_multiplier` at the end to display USD.

| What to display               | USD form (preferred, needs `input_multiplier`)              | Percent fallback (no multiplier)                       |
| ----------------------------- | ----------------------------------------------------------- | ------------------------------------------------------ |
| Portfolio value               | `strategy_value × input_multiplier`                         | `strategy_value × 100` (%)                             |
| Asset position market value   | `amount × bid × input_multiplier`                           | `(amount × bid) / strategy_value × 100` (%)            |
| Liability position market value | `\|amount\| × ask × input_multiplier`                     | `(\|amount\| × ask) / strategy_value × 100` (%)        |
| Cash (USD) position           | `amount × input_multiplier` (price = 1)                     | `amount / strategy_value × 100` (%)                    |
| Cost basis per position       | `amount × price × input_multiplier`                         | —                                                      |
| Dollar return                 | `(strategy_value × input_multiplier) − input_value`         | — (use percent return below)                           |
| Return %                      | `(current_strategy_value / past_strategy_value − 1) × 100`  | same                                                   |

Get the past `strategy_value` from `getStrategyValues` (or the timeframe fields on `getStrategies`).

> **Two conversion directions — that's the whole model:**
> - **Display → User**: `strategy_units × input_multiplier` (every dollar **or share/crypto count** the user sees)
> - **Trade → API**: `user_input / input_multiplier` (for **both** `amount` (user-visible shares/crypto) **and** `total` (user USD) fields on `newOrder`)
>
> All API numerics come back as **strings** — cast with `float()` / `Number()` / `BigDecimal` before math. The canonical pitfall is showing `amount × bid` directly as dollars; it's strategy units and looks ~10,000× smaller than the real USD value. Never send raw user-visible share counts or USD amounts without dividing by `input_multiplier`.

See [trading-examples](https://api.alphainsider.com/resources/examples/trading.md) for full derivations, asset vs liability vs cash handling, fees, collateral, and allocation math.

### How to get `input_multiplier`

1. Subscribe to the strategy (even your own): `POST /newStrategySubscription` with `{strategy_id}`.
2. Fetch it: `GET /getStrategySubscriptions?strategy_id[]=<id>` (or `getStrategyCalculation`, `getUserStrategies`).
3. **Owned strategies** — `input_multiplier` is always present.
4. **Subscribed-to (non-owned) strategies** — may be `null`. When null:
   - Display in the **percent fallback** form, or
   - Prompt the user to call `POST /updateStrategyCalculation` with `input_value` + `input_date`, then re-fetch.
   - **Never** silently treat a missing multiplier as `1.0`.

### Orders: do I need multiplier math in the payload?

| Endpoint              | Payload expects                             | Multiplier math needed?                                                   |
| --------------------- | ------------------------------------------- | ------------------------------------------------------------------------- |
| `newOrder`            | `amount` (strategy-normalized shares) **or** `total` (strategy-normalized cash) | **Yes for both** when using user-visible numbers: `amount = user_shares / input_multiplier` (or `total = user_dollars / input_multiplier`). Both fields expect strategy-normalized units. |
| `newOrderAllocations` | percent of equity (`0.0`–`2.0`)             | **No** — platform derives equity from the subscription.                   |
| `newOrderWebhook`     | full position signal (buy/close/etc.)       | **No** — signal only; platform sizes.                                     |

Always call `GET /getMaxOrderSize?strategy_id=...&stock_id=...` before large trades. It already factors fees, slippage, and the user's equity.

---

## 4. Endpoint Reference

| Category           | Key operation IDs                                                                                                                            | Notes                                                                |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| **Auth**           | `verifyToken`                                                                                                                                | Body: `{token}`                                                      |
| **Users**          | `getUserInfo`, `getUsers`, `updateUserInfo`, `updateUserNotifications`                                                                       | Auth header required for private                                     |
| **Strategies**    | `newStrategy`, `updateStrategy`, `deleteStrategy`, `getStrategies`, `getUserStrategies`, `searchStrategies`, `getStrategyValues`, `getStrategyPerformance`, `getRecommendedStrategies` | `type`: `"stock"` or `"crypto"`                                      |
| **Subscriptions**  | `newStrategySubscription`, `getStrategySubscriptions`, `deleteStrategySubscription`, `updateStrategyCalculation`, `updateStrategySubscriptionNotifications` | Source of `input_multiplier`. Tier-limited.                          |
| **Trades**         | `newOrder`, `newOrderAllocations`, `newOrderWebhook`, `getOrders`, `deleteOrder`, `getPositions`, `getMaxOrderSize`                          | See decision matrix (§5). `stock_id` = internal ID **or** `SYMBOL:EXCHANGE`. |
| **Bots**           | `newBot`, `getBots`, `getBotInfo`, `startBot`, `stopBot`, `resetBot`, `resetBotPerformance`, `updateBotBrokerKeys`, `updateBotAllocations`, `getBotAllocations`, `getBotPerformance`, `getBotActivities` | Broker keys mandatory before `startBot`.                             |
| **Stocks**         | `searchStocks`, `getStocks`, `getAllStocks`, `getStockPriceHistory`, `getExchangeStatus`                                                     | `getAllStocks` is 20 req/hour — prefer `searchStocks`.               |
| **Timelines**      | `newPost`, `previewPost`, `deletePost`, `getTimelines`, `getStrategyTimelines`, `like`, `unlike`                                             | 100 posts/day/strategy, 100 likes/day.                               |
| **Withdrawals**    | `getUserBalance`, `newPayout`, `getPayouts`, `getPayoutFees`, `getStripeAccountLink`, `getIncome`                                            | Min $10 (1000 cents). Stripe linked first.                           |
| **Payments**       | `getInvoices`, `getUpcomingInvoice`, `getInvoiceItems`, `retryInvoice`, `getPaymentSources`                                                  | Pro / Premium.                                                       |
| **Webhooks**       | `newOrderWebhook`                                                                                                                            | TradingView-friendly. Full in/out only.                              |
| **WebSockets**     | Connect `wss://alphainsider.com/ws`                                                                                                          | See §7.                                                              |

For full schemas and parameters, use the OpenAPI spec at https://api.alphainsider.com/openapi.yaml.

### Stock identifiers (`stock_id`)

Accepted formats:
- Internal ID (e.g. `"yv4fbstPFFxgngHWPwnNq"`)
- Composite: `"SYMBOL:EXCHANGE"` (e.g. `"SPY:ARCX"`, `"AAPL:XNAS"`, `"ETH-USD:COINBASE"`)

Discover with `searchStocks` (preferred) or cache `getAllStocks`.

---

## 5. Order Decision Matrix

| Scenario                                   | Endpoint                     | Key rules                                                                                     |
| ------------------------------------------ | ---------------------------- | --------------------------------------------------------------------------------------------- |
| Fixed share count or fixed cash (user-visible) | `newOrder`               | Send **exactly one** of `amount` (user_shares / input_multiplier) or `total` (user_dollars / input_multiplier). Types: `market`, `limit`, `stop_market`, `stop_limit`, `oco`. |
| Rebalance portfolio to target %            | `newOrderAllocations`        | Array of `{stock_id, action, percent}`. `percent` 0.0–2.0 (2.0x leverage max).                |
| External signal (TradingView, custom)      | `newOrderWebhook`            | `{strategy_id, stock_id, action, leverage?, api_token}`. `action` ∈ buy/long/sell/short/close/flat. Full position only. |
| Recurring automated execution              | Bot + `updateBotAllocations` | Bot owns the loop. Update per-strategy `percent` (sum ≤ leverage, default 2.0).               |

**Chaining**: add `order_dependencies: ["<parent_order_id>"]` to any `newOrder` to wait for a parent fill. `newOrderAllocations` does not currently support `order_dependencies`.

**Common rules**:
- Max 100 open orders per strategy.
- Daily order limits are per strategy (see §8).
- `slippage` 0.001–0.01 on allocations (default 0.002).
- Fees: 0.25% per side for crypto, 0% for stocks (platform reserves a buffer).

---

## 6. Worked Examples

### 6.1 Display a portfolio (prefers USD, falls back to percent)

```python
sub = requests.get(
    f"{BASE}/getStrategySubscriptions",
    headers=HEADERS,
    params={"strategy_id[]": strategy_id}
).json()["response"][0]

strategy_value = float(sub["strategy_value"])
multiplier = sub.get("input_multiplier")

if multiplier is not None:
    usd = strategy_value * float(multiplier)
    print(f"Portfolio: ${usd:,.2f}")
else:
    print(f"Performance: {strategy_value * 100:.2f}%  (subscribe with updateStrategyCalculation to see USD)")
```

### 6.2 Rebalance to 80% SPY via allocations (no multiplier math in payload)

```http
POST /newOrderAllocations
Authorization: <jwt>

{
  "strategy_id": "YbKCgktxu0ugmQ1QKCfA3",
  "allocations": [
    {"stock_id": "SPY:ARCX", "action": "buy", "percent": 0.80}
  ],
  "slippage": 0.003
}
```

### 6.3 Fixed-USD market buy with `newOrder` (apply Trade → API reverse on `total`)

User wants to spend an exact USD amount. The `total` field is strategy-normalized, so divide by `input_multiplier`:

```python
multiplier = float(sub["input_multiplier"])
total_internal = 10_000 / multiplier  # Trade → API conversion

requests.post(f"{BASE}/newOrder", headers=HEADERS, json={
    "strategy_id": strategy_id,
    "stock_id": "SPY:ARCX",
    "action": "buy",
    "type": "market",
    "total": f"{total_internal:.15f}",
})
```

For percent-of-portfolio sizing, prefer `newOrderAllocations` (§6.2) — the platform does the math.

### 6.4 Chained: sell 0.5 user-visible ETH then buy BTC with proceeds

```python
multiplier = float(sub["input_multiplier"])
internal_amount = 0.5 / multiplier   # user-visible shares/crypto must be divided

requests.post(f"{BASE}/newOrder", headers=HEADERS, json={
    "strategy_id": "...",
    "stock_id": "ETH-USD:COINBASE",
    "action": "sell",
    "type": "market",
    "amount": f"{internal_amount:.15f}"
})
# → order_id = "parent-123"

POST /newOrder  # child waits for parent
{ "strategy_id": "...", "stock_id": "BTC-USD:COINBASE", "action": "buy", "type": "limit",
  "price": "40000.00", "total": "50000", "order_dependencies": ["parent-123"] }
```

### 6.5 OCO bracket exit (user-visible 100 shares)

```python
multiplier = float(sub["input_multiplier"])
internal_amount = 100 / multiplier

# Send:
{
  "strategy_id": "...",
  "stock_id": "SPY:ARCX",
  "action": "sell",
  "type": "oco",
  "price": "720.00",       // take-profit limit
  "stop_price": "650.00",  // stop-loss trigger
  "amount": f"{internal_amount:.15f}"
}
```

### 6.6 TradingView webhook receiver (Node)

```js
require('dotenv').config();
const token = process.env.ALPHAINSIDER_API_KEY;

app.post('/tv-webhook', async (req, res) => {
  const { strategy_id, stock_id, action, leverage = 1 } = req.body;
  const r = await fetch('https://alphainsider.com/api/newOrderWebhook', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ strategy_id, stock_id, action, leverage, api_token: token })
  });
  res.json(await r.json());
});
```

---

## 7. WebSockets

Connect to `wss://alphainsider.com/ws`. Send `"ping"` every 30s (server replies `"pong"`).

Send **one** subscribe message — it overwrites previous subscriptions:

```json
{
  "event": "subscribe",
  "payload": {
    "channels": [
      "wsStockPrice:SPY:ARCX",
      "wsStrategyValue:<strategy_id>",
      "wsOrders:<strategy_id>",
      "wsPositions:<strategy_id>",
      "wsTimelines:<strategy_id>",
      "wsBotStatus:<bot_id>",
      "wsBotAllocations:<bot_id>",
      "wsBotActivities:<bot_id>"
    ],
    "token": "<jwt>"
  }
}
```

### Channels

| Channel                        | Cadence   | Use                                  |
| ------------------------------ | --------- | ------------------------------------ |
| `wsStockPrice:<stock_id>`      | ~1s       | Live bid / ask / last                |
| `wsStrategyValue:<strategy_id>`| ~5s       | Updated `strategy_value` — recompute USD/percent with §3 formulas |
| `wsOrders:<strategy_id>`       | instant   | Order create / fill / cancel         |
| `wsPositions:<strategy_id>`    | instant   | Position deltas                      |
| `wsTimelines:<strategy_id>`    | instant   | New posts                            |
| `wsBotStatus:<bot_id>`         | instant   | Running / stopped / error            |
| `wsBotAllocations:<bot_id>`    | instant   | Allocation changes                   |
| `wsBotActivities:<bot_id>`     | instant   | Bot actions                          |

On `error` event: reconnect and re-subscribe. Re-fetch `input_multiplier` from the subscription if the strategy was reset.

Minimal Python client:
```python
import asyncio, json, os, websockets
async def main():
    async with websockets.connect("wss://alphainsider.com/ws") as ws:
        await ws.send(json.dumps({
            "event": "subscribe",
            "payload": {"channels": ["wsPositions:STRATEGY_ID"], "token": os.environ["ALPHAINSIDER_API_KEY"]}
        }))
        async def ping():
            while True:
                await asyncio.sleep(30); await ws.send("ping")
        asyncio.create_task(ping())
        async for msg in ws:
            print(json.loads(msg) if msg not in ("ping", "pong") else msg)
asyncio.run(main())
```

---

## 8. Bots (Automated Execution)

1. `newBot` → get `bot_id` (needs `broker`, `account_id`).
2. `updateBotBrokerKeys` → supply live/paper keys (Alpaca / Binance / Bitfinex). **Required before `startBot`.**
3. `updateBotAllocations` → `[{strategy_id, percent}]`. `percent` per allocation is `0.0001–1.0000` with a multiple of 0.0001; sum across allocations ≤ `1.0`.
4. `startBot` → begins execution loop. New allocations apply **next cycle**.
5. Monitor: `getBotInfo`, `getBotActivities`, `getBotPerformance`, `getBotAllocations`.
6. `stopBot` (optional `close_on_stop: true`). Reset with `resetBot` / `resetBotPerformance`.

See [bot-examples](https://api.alphainsider.com/resources/examples/bots.md) for the full lifecycle: creation, broker key rotation, allocation read-modify-write, start/stop flags, settings, notifications, performance/activity filtering, and end-to-end paper→live migration.

---

## 9. Limits

| Limit                      | Standard | Pro   | Premium |
| -------------------------- | -------- | ----- | ------- |
| Orders / day / strategy    | 50       | 500   | 5,000   |
| Max strategies             | 5        | 50    | 500     |
| Max subscriptions          | 10       | 100   | 1,000   |
| Max bots                   | 0        | 2     | 4       |
| Max open orders / strategy | 100      | 100   | 100     |
| Max API tokens             | 50       | 50    | 50      |
| Max sessions               | 100      | 100   | 100     |

Global caps: `newPost` 100/day/strategy · `like` 100/day · `getAllStocks` 20/hour · min withdrawal $10 (1000 cents).

On 429, back off exponentially and honor `Retry-After` if present.

---

## 10. Errors

| HTTP | Typical cause                                                                 |
| ---- | ----------------------------------------------------------------------------- |
| 400  | Missing field, `amount` + `total` both sent, bad `stock_id`, strategy not owned. Log the `response` string. |
| 401  | Bad / expired token, missing header, token lacks scope. Re-check via `verifyToken`.                          |
| 429  | Rate limit. Back off.                                                                                        |

Always check `success` before using `response`.

---

## 11. Pre-flight Checklist

- [ ] `ALPHAINSIDER_API_KEY` set (env var or `.env` in run directory); verified via `verifyToken`; token has the scopes you need.
- [ ] If `ALPHAINSIDER_STRATEGY_ID` / `ALPHAINSIDER_BOT_ID` are set, use them. If not set and the call needs one, **ask the user** — don't guess.
- [ ] For any user-facing strategy value or position size: `input_multiplier` fetched from `getStrategySubscriptions`. Owned → guaranteed. Subscribed-to → if null, either use percent fallback or prompt for `updateStrategyCalculation`. Never assume 1.0.
- [ ] Right order endpoint chosen per §5 matrix.
- [ ] For `newOrder`: exactly one of `amount` / `total`; **always** divide user-visible share count or USD amount by `input_multiplier` before sending.
- [ ] `getMaxOrderSize` checked for large trades; exchange status OK.
- [ ] `stock_id` resolved; `strategy_id` is owned or subscribed.
- [ ] Tier limits checked via `getUserInfo`; backoff path for 429.
- [ ] For bots: broker keys validated before `startBot`; allocation `percent` values are each 0.0001–1.0000, multiple of 0.0001, and sum to ≤ 1.0.
- [ ] For WS: ping every 30s; reconnect on `error`; re-fetch multiplier after strategy resets.
- [ ] Secrets never in git, logs, or prompts.

---

## 12. Further Reading

- Interactive docs & explorer: https://api.alphainsider.com
- OpenAPI: https://api.alphainsider.com/openapi.yaml
- AsyncAPI: https://api.alphainsider.com/asyncapi.yaml
- LLM listing: https://api.alphainsider.com/llms.txt
- Trading examples (deep dive): https://api.alphainsider.com/resources/examples/trading.md
- Bot examples (deep dive): https://api.alphainsider.com/resources/examples/bots.md
- How agents load this skill: https://api.alphainsider.com/resources/agent-skill

Re-fetch this file anytime:
```bash
curl -O https://api.alphainsider.com/skill.md
```