Reflect API · v1

Put Reflect anywhere.

Everything the application shows you is available over HTTP as JSON, and trades can be pushed in as they close. No SDK, no webhook registration, no OAuth dance — one bearer token and ordinary REST.

Thirty seconds

Create a key in Settings, then:

curl
curl https://trader-reflect.com/api/v1/insights \
  -H "Authorization: Bearer rk_your_key_here"
javascript
const res = await fetch("https://trader-reflect.com/api/v1/insights", {
  headers: { Authorization: `Bearer ${process.env.REFLECT_KEY}` },
});
const { insights } = await res.json();

console.log(insights[0].headline);   // "You size up exactly when you should not."
console.log(insights[0].evidence);   // the numbers it rests on
console.log(insights[0].confidence); // 77
python
import os, requests

r = requests.get(
    "https://trader-reflect.com/api/v1/report",
    headers={"Authorization": f"Bearer {os.environ['REFLECT_KEY']}"},
)
report = r.json()
print(report["insights"][0]["headline"])

Authentication

Every request carries Authorization: Bearer rk_…. A key belongs to one account and can reach nothing else — there is no endpoint that takes a user id, so no key can be pointed at somebody else's data.

The key is shown once, at creation. Only a SHA-256 digest is stored, so a lost key cannot be recovered by you or by us — revoke it and make another. Keys come in two scopes: read reaches every GET endpoint, write also allows POST and DELETE. Use read wherever the caller only needs to display something.

Reading

Base URL https://trader-reflect.com/api/v1

GET
/me

The account behind the key, plus trade and import counts.

GET
/report

The full coaching report: findings, psychology scores, risk state, hourly and session breakdowns.

GET
/insights?category=risk

Findings only, ranked by cost.

GET
/performance

Equity curve, drawdown, expectancy, profit factor, streaks, per-instrument.

GET
/trades?limit=100&offset=0&from=2026-01-01&to=2026-12-31

Your trades, newest first.

GET
/journal

Per-day totals: trades, net R, net P&L, wins.

GET
/milestones

Behavioural milestones with what each one counted.

GET
/imports

Every batch of trades on the account, pushed or uploaded.

Writing

Needs a write-scoped key. Reflect never places orders — these endpoints only record trades that already happened.

POST
/trades

Push trades in. The natural integration point — call it as each trade closes.

POST
/imports

Upload a broker statement as CSV text and let Reflect parse it.

DELETE
/imports/:id

Remove a batch and every trade that came in with it.

POST /api/v1/trades
curl -X POST https://trader-reflect.com/api/v1/trades \
  -H "Authorization: Bearer rk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "source": "my-bot",
    "trades": [
      {
        "instrument":  "XAUUSD",
        "direction":   "long",
        "openedAt":    "2026-08-04T09:15:00Z",
        "rMultiple":   1.8,
        "pnl":         180.00,
        "sizeR":       1.0,
        "followedPlan": true
      }
    ]
  }'
Required per trade
  • instrument — string
  • direction — "long" or "short"
  • openedAt — ISO 8601
  • rMultiple — number, negative is a loss
Optional
  • pnl — broker currency
  • sizeR — risk taken, defaults to 1
  • followedPlan — defaults to true
  • source — names the batch

Put a zone on openedAt. Without one it is read as UTC, and a timestamp meant as local time will land in a different trading session — which changes the analysis rather than failing loudly.

A batch is written whole or not at all. The response gives the importId, how many were accepted, and the index and reason for each one that was not — so a partial payload tells you exactly which trade to fix. Sending the same batch twice creates two batches: there is no deduplication yet.

Embedding without code

If all you want is one figure inside Notion, a team dashboard or your own site, you do not need the API. Create an embed in Settings and paste the iframe.

iframe
<iframe src="https://trader-reflect.com/embed?t=re_your_token&theme=dark"
        width="360" height="220" frameborder="0"
        style="border:0;border-radius:12px"></iframe>

Four widgets: the current finding, your standing, your practice streak, and the equity curve. theme takes dark or light.

An embed token is not an API key and the difference matters. It travels in a URL that is visible in the hosting page's source, so it is read-only, bound to the single widget it was created for, revocable on its own, and rejected outright by every endpoint above. Anyone with the link sees that one figure — treat it as public.

Limits and errors

Rate limits, per key
  • 120 reads per minute
  • 30 writes per minute
  • 1000 trades per push
  • 2 MB per request body

Every response carries X-RateLimit-Remaining and X-RateLimit-Reset. A 429 also carries Retry-After.

Status codes
  • 400 — malformed body
  • 401 — missing or revoked key
  • 403 — read key used for a write
  • 404 — no such endpoint or record
  • 422 — well-formed but unusable
  • 429 — rate limited
Error shape
{
  "error": {
    "code": "read_only_key",
    "message": "This key is read-only. Create a write key in Settings."
  }
}

Branch on code, show message to a person. CORS is open, so a browser can call this directly — but a key in front-end JavaScript is a key you have published. Use a read key, or keep it on your server.

Reflect reads. It never places an order.Create a key →