Authentication Guide
The RiskModels API supports four authentication modes (as of v3.0.0-agent). Choose based on your application type.
Mode 1 — Bearer Token (Direct API Key)
All external API calls use a Bearer token in the Authorization header.
Authorization: Bearer rm_agent_live_<random>_<checksum>
Token format: rm_agent_{environment}_{random}_{checksum} or rm_user_{random}_{checksum}
environment:live(production) ortest(sandbox)- Tokens are long-lived but can be rotated from the dashboard
Obtaining a Token
Option A — Dashboard:
- Get your API key (sign up if you haven't already)
- Generate a new key and copy the token
- Store securely in your environment variables
Option B — API provisioning endpoint (for AI agents):
curl -X POST https://riskmodels.app/api/auth/provision \
-H "Authorization: Bearer <session-jwt>" \
-H "Content-Type: application/json"
Plaid and Account Identity
If you plan to use GET /api/plaid/holdings, the Plaid connection and the API key must belong to the same user account.
- For dashboard signup and
POST /api/auth/provision, that account is identified by email - Sign in at riskmodels.net with that same email to connect Plaid in the web app
POST /api/auth/provision-freecreates an anonymous API account with no web login, so Plaid holdings are not available for that account
Billing
Tokens use a prepaid balance model:
- Add credit via Stripe (scroll to "Add Credit" section)
- Each metered request deducts from your balance
- Check balance:
GET /api/balance - Cached responses are free (
cost_usd: 0in the_agentblock) - Minimum top-up: $10.00 USD
Mode 2 — OAuth2 Client Credentials (Recommended for AI Agents)
New in v3.0.0-agent: OAuth2 client credentials flow for machine-to-machine authentication.
Overview
Exchange API credentials for a short-lived JWT access token (15 minutes). This is the recommended method for:
- AI agents and LLM applications
- Server-to-server integrations
- npm packages and CLI tools
- MCP clients
Benefits
- Short-lived tokens - 15-minute expiry reduces security risk
- Scoped access - Request only the scopes you need
- Standard protocol - OAuth2 is widely supported
- Automatic refresh - SDKs can refresh tokens automatically
OAuth2 Flow
Step 1: Exchange credentials for access token
curl -X POST https://riskmodels.app/api/auth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "rm_agent_live_abc123",
"client_secret": "rm_agent_live_abc123_xyz789_checksum",
"scope": "ticker-returns risk-decomposition"
}'
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900,
"scope": "ticker-returns risk-decomposition batch-analysis"
}
Step 2: Use access token in API requests
curl -X GET https://riskmodels.app/api/metrics/NVDA \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Available Scopes
| Scope | Description |
|---|---|
ticker-returns | Access ticker returns and historical data |
risk-decomposition | Access L3 risk decomposition |
batch-analysis | Perform portfolio batch analysis |
chat-risk-analyst | Use AI risk analyst |
plaid:holdings | Access Plaid-synced portfolio holdings |
* | Full API access (all scopes) |
Mode 3 — Supabase JWT (Browser / Mobile Apps)
For applications that directly query Supabase (the underlying database), use the public anon key with user authentication.
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
'https://your-project.supabase.co',
'your-anon-key' // Safe to expose in client-side code
);
// Sign in (passwordless magic link)
await supabase.auth.signInWithOtp({ email: 'user@example.com' });
// After sign-in, JWT is automatically attached to queries
const { data } = await supabase
.from('security_history_latest')
.select('symbol, returns_gross, vol_23d, l3_mkt_hr, l3_sec_hr, l3_sub_hr')
.eq('symbol', 'BW-US67066G1040')
.eq('periodicity', 'daily');
Row Level Security (RLS) is enforced — users can only access data they are authorised for.
AI Agent Provisioning Flow
Recommended pattern for LLM agents integrating with the RiskModels API:
-
Discover capabilities
GET /.well-known/agent-manifestReturns service metadata, all endpoint capabilities, pricing, and the provisioning URL.
-
Provision a token
POST /api/auth/provisionExchange a session JWT for a long-lived Bearer API key.
-
Check balance before starting a workflow
GET /api/balanceVerify
status.can_make_requestsistrueandbalance_usdis sufficient. -
Make data requests
Authorization: Bearer rm_agent_live_... -
Monitor cost per request Read
_agent.cost_usdin each response body, or theX-API-Cost-USDheader.
Rate Limits
Per-API-Key Rate Limiting: All authenticated endpoints are rate limited on a per-API-key basis using a sliding window algorithm.
| Tier | Requests / Minute | Daily Limit | Burst |
|---|---|---|---|
| Default (pay-as-you-go) | 60 | Unlimited | 100 |
Premium (rate:300 scope) | 300 | Unlimited | 500 |
| Max concurrent | 10 | — | — |
Rate Limit Headers
All responses include rate limit information:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1709856000
429 Too Many Requests
When rate limit is exceeded, you'll receive:
HTTP/1.1 429 Too Many Requests
Retry-After: 23
Best Practice: Implement exponential backoff starting at the Retry-After value.
Security Notes
- Never commit API keys to source control
- Use environment variables:
RISKMODELS_API_KEY=rm_agent_live_... - Rotate keys from the dashboard if compromised
- Service role key must never appear in browser-side code
- Test keys (
rm_agent_test_...) return simulated responses and do not deduct balance
Related
Sign up, generate your token, and add credit to get started immediately.
🏦 Plaid HoldingsSee the one-time web flow for connecting a brokerage and reusing that account through the API.
🤖 Agent IntegrationConfigure your key in Cursor, Claude Desktop, Zed, or the npm CLI.
📄 API DocsAll endpoints, costs, and response field definitions.