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 https://trader-reflect.com/api/v1/insights \ -H "Authorization: Bearer rk_your_key_here"
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); // 77import 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
/meThe account behind the key, plus trade and import counts.
/reportThe full coaching report: findings, psychology scores, risk state, hourly and session breakdowns.
/insights?category=riskFindings only, ranked by cost.
/performanceEquity curve, drawdown, expectancy, profit factor, streaks, per-instrument.
/trades?limit=100&offset=0&from=2026-01-01&to=2026-12-31Your trades, newest first.
/daysPer-day totals: trades, net R, net P&L, wins.
/journal?limit=100What you wrote, newest first.
/checkin?limit=60Recorded mornings: sleep, and HRV where you have it.
/reflectionThe whole point: what you said set against what you did, which state preceded which execution, and what is still missing.
/milestonesBehavioural milestones with what each one counted.
/importsEvery 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.
/journalWrite a day. Same date twice updates rather than duplicates — journalling can live in another product entirely.
/checkinRecord a morning: sleepMinutes is required, hrv and restingHr optional. Where a wearable integration belongs.
/tradesPush trades in. The natural integration point — call it as each trade closes.
/importsUpload a broker statement as CSV text and let Reflect parse it.
/imports/:idRemove a batch and every trade that came in with it.
/journal/:dateRemove one day's entry.
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
}
]
}'instrument— stringdirection— "long" or "short"openedAt— ISO 8601rMultiple— number, negative is a loss
pnl— broker currencysizeR— risk taken, defaults to 1followedPlan— defaults to truesource— 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.
Journalling somewhere else
Reflect reads two things: what your trades show, and what you said about them. The second does not have to be written here. Push the words in and read the reflection back — three calls, and the writing can live in whatever product your users already open every morning.
curl -X POST https://trader-reflect.com/api/v1/journal -H "Authorization: Bearer rk_your_key_here" -H "Content-Type: application/json" -d '{
"date": "2026-08-06",
"entry": "Stayed patient all morning and waited for the setup.",
"emotion": "calm",
"source": "money-circle"
}'Word count and sentiment are derived from the text rather than accepted from you: two products computing them separately would drift. Whether the day made money comes from the trades, not the entry — somebody recording a good day that lost is exactly the gap worth surfacing, and letting the entry declare it would erase that. The same date twice updates rather than duplicates.
emotion takes one of ten words, returned as vocabulary by /reflection so you can offer the same set rather than inventing a parallel one. Naming a discrete state lowers its intensity; rating intensity on a scale does not, which is why there is no mood slider here. A word outside the set is dropped, not refused — the entry is still worth keeping.
{
"selfReport": {
"entries": 34, "unwritten": 6,
"gaps": [{
"date": "2026-08-02",
"claim": "you described yourself as patient",
"quote": "Rough one but I stayed patient and never chased anything.",
"reality": "3 of that day's entries came within five minutes of a loss",
"kind": "contradicted"
}]
},
"emotions": [{ "emotion": "elated", "days": 7, "meanR": -0.77 }],
"vocabulary": ["calm", "focused", "confident", "…"]
}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 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
- 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.
400— malformed body401— missing or revoked key403— read key used for a write404— no such endpoint or record422— well-formed but unusable429— rate limited
{
"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.