Building with the API? Open the developer docs
Finmagine API & MCP — free tier to test • Pro/Max for full access • REST + MCP
Master BYO LLM key management through a complete learning overview and interactive flashcards
Both the Investment Committee and Strategy Lab Research Presets need a real LLM provider to run — and Finmagine never bills its own LLM spend to you for those features. Instead, you bring your own provider key (BYO). This guide covers the 5 API/MCP operations that manage that key end to end, and — because a provider API key is a genuine secret — the real security engineering behind how it's stored, transmitted, and audited.
Click any card to reveal the answer. Use the search box to find a specific topic.
All 5 live under /account/byo-key/* (plus one GET at /account/byo-keys), available as both REST and MCP, and — notably — none of them carry a subscription tier gate. Saving and managing a key is account configuration, not data consumption, so it's available on Free tier same as any paid tier.
| Operation | REST | MCP tool | What it does |
|---|---|---|---|
| List | GET /account/byo-keys | list_byo_keys | Lists saved keys (masked) and the current preferred provider |
| Save | POST /account/byo-key/save | save_byo_key | Saves or overwrites a key for one provider |
| Test | POST /account/byo-key/test | test_byo_key | Live-verifies a key against the real provider (~15s) |
| Set Preferred | POST /account/byo-key/set-preferred | set_preferred_byo_key | Sets the account-wide default provider |
| Remove | POST /account/byo-key/remove | remove_byo_key | Deletes a saved key (clears preferred if it was set) |
| Provider ID | Display Name | Default Model | Real Endpoint Called |
|---|---|---|---|
anthropic | Claude (Anthropic) | claude-3-5-sonnet-20241022 | api.anthropic.com/v1/messages |
openai | GPT (OpenAI) | gpt-4o-mini | api.openai.com/v1/chat/completions |
gemini | Gemini (Google) | gemini-2.5-flash | generativelanguage.googleapis.com |
groq | Llama (Groq) | llama-3.3-70b-versatile | api.groq.com/openai/v1/chat/completions |
deepseek | DeepSeek | deepseek-v4-flash | api.deepseek.com/anthropic/v1/messages |
openrouter | OpenRouter | google/gemma-4-31b-it:free | openrouter.ai/api/v1/chat/completions |
/anthropic/v1/messages) rather than the OpenAI-style chat-completions shape every other non-Anthropic provider here uses. Finmagine's integration calls it exactly like Anthropic's own endpoint, just pointed at DeepSeek's host — worth remembering if you ever build your own DeepSeek integration elsewhere and wonder why the request shape looks like Claude's, not GPT's.
The model field is always user-editable at save time — the defaults above are presets, not hard requirements. OpenRouter's default specifically points at a free-tier model (:free suffix) so a first-time OpenRouter save doesn't accidentally assume a paid model.
A provider API key is a real secret — if it leaked, someone else could spend against your account with your provider. Here's exactly what happens to it, not a vague "we encrypt it" claim:
sodium_crypto_secretbox (libsodium) when available, falling back to AES-256-GCM via OpenSSL — both are authenticated encryption, meaning tampering with the stored ciphertext is detectable, not just unreadableS1 for the sodium path, A1 for the OpenSSL fallback), so decryption always knows which algorithm to use — including gracefully failing if sodium was available at save time but has since been disabled on the serverbyo_key_{provider} (e.g. byo_key_anthropic, byo_key_deepseek) — never one blob holding all providers togethersk-ant-...a1b2 style) without ever decrypting the real secret just to display a hint••••, then the real last 4 — enough to recognise which key is saved at a glance, never enough to reconstruct it.
These are the first credential-mutating endpoints on Finmagine's API, and they're deliberately held to a stricter standard than the normal per-tier request limits.
Every other endpoint on the API accepts ?apiKey= as one of three valid auth methods. These 5 don't:
| Action | Limit | Why |
|---|---|---|
| Save | 20/account/hour | Prevents rapid key-cycling abuse |
| Test | 10/account/hour | Each test makes a real, billable-to-you outbound call to your provider — capped independently of your normal API rate limit |
test_and_save counts against the stricter 10/hour test quota, not the looser 20/hour save quota. A test-and-save call makes exactly the same real provider call a standalone test does — letting it slip through under the save quota alone would effectively allow 20 live verifications per hour instead of 10, quietly bypassing the limit that exists specifically to cap real outbound provider calls.
Every save/test/remove action writes one row to an audit log: user, action, provider name, success flag, a hashed IP address (SHA-256, not the raw IP), and user agent. The raw or masked key itself is never written to this log — by design, the audit trail can prove that an action happened and which provider, without ever becoming a second place a leaked secret could be recovered from.
Saving a key fires a fire-and-forget security notification email to the account holder — "your BYO key for [provider] was just saved." It never blocks the API response if sending fails, but it does mean an unexpected key-save shows up in your inbox, not just silently in an audit table only you'd think to check.
| Mode | What it verifies | Makes a real provider call? |
|---|---|---|
| Save alone | Format only (e.g. non-empty, matches expected shape) — not that the key actually works | No |
| Test alone | Live-verifies an already-saved key, or an ad-hoc value, against the real provider | Yes (~15s) |
Save with test_and_save: true | Both — saves, then immediately live-verifies in the same call | Yes (~15s) |
save_byo_key with test_and_save: true, the key is still saved successfully — the response's test.error field explains that verification was skipped due to the rate limit, rather than failing the whole request. If you need to guarantee a key actually works before relying on it, check the response's test field rather than assuming saved: true alone means it's valid.
test_byo_key has a safer mode worth knowing about: pass just {provider} alone to re-verify the already-saved key — no secret is transmitted in that call at all, since the server reads its own stored (encrypted) copy. Passing {provider, model, key} tests an ad-hoc value instead, without saving it, but does require sending the raw key again.
set_preferred_byo_key sets an account-wide default — used whenever a Committee or Preset run doesn't specify which provider to use. It's deliberately an account default, not a per-task control.
Both save_byo_key and test_byo_key (ad-hoc mode) carry an explicit warning baked directly into their MCP tool descriptions — visible to any agent or human reading the tool schema before calling it:
The concern is specific and real: some MCP client implementations log every tool call's arguments — for debugging, for conversation history, or for telemetry — and a provider API key passed as a plain-text tool argument would end up captured wherever that logging goes, entirely outside Finmagine's control.
| Path | Recommended for |
|---|---|
| REST endpoint directly (your own code, curl, the API Explorer) | Actually saving or ad-hoc testing a raw key — not subject to an MCP client's own argument logging |
MCP test_byo_key with {provider} only | Re-verifying an already-saved key from within an agent conversation — safe, since no secret is transmitted in that call |
MCP save_byo_key / ad-hoc test_byo_key | Only in an MCP client you fully control and trust not to log arguments |
With a provider key saved and verified, the next two guides cover what it's actually for:
See the API & Agent Integration hub for the full 12-guide roadmap.
Finmagine gives you 30+ computed financial ratios, sector benchmarks, FII/DII flows, the Finmagine Score, and AI-powered analysis — all in one place.