# User Data — Finradar API > Version: 3.61.0 | Generated: 2026-06-20 | Content Hash: 98fc077d > Fetch this file at: https://uat.finradarapi.com/llms/user-data.txt ## Authentication All endpoints require an API key. Pass it via query parameter `?apiKey=YOUR_KEY` or header `X-API-Key: YOUR_KEY`. WebSocket endpoints accept the key in the `token` auth payload or query parameter. --- ## User Data Manage user profile and settings. ### GET /api/v1/user/ Get the authenticated user's profile, API key, and embedded subscription state. EXEMPT (`cost: 0`). JWT auth required. **Token cost:** 0 (EXEMPT — auth / billing / account / admin / health) **Response fields:** - `user` (object): Authenticated user profile (matches the `user` field in the /auth/login response). Built by `User.to_dict(include_relations=True)` — includes the three relationship rows (`Userplan`, `UserDocumentLimit`, `UserDeviceLimit`) inline. - `user.uuid` (string): Stable user identifier (UUIDv4 string). Foreign-key target in every per-user table; treat as the canonical user PK. - `user.email` (string): Lowercased registration email. Unique across `users`. Used as the login identifier. - `user.usertype` (string): Role enum value — `user` (default) or `admin`. Use to gate admin-only UI surfaces. Distinct from `billing_admin` (a finer-grained flag for billing-operator dashboard access). - `user.api_key` (string): API key for server-to-server billed calls (32-char concatenation of two UUIDs with hyphens removed). Pass as `X-API-Key: ` header on `/api/v1/sec/*`, `/api/insiders/*`, etc. Distinct from the JWT `token` (issued by /auth/login) — JWT is for browsing the dashboard, API key is for server-to-server calls. - `user.verify_email` (boolean): True if the user has clicked the verification email link. Always true here — login is gated by this flag, so the JWT bearer must already be verified. - `user.has_uat_access` (boolean): True if the user is allowed onto the UAT environment (separate cohort gate from the production access flag). Use to render UAT-environment banners or to gate UAT-only feature flags. - `user.billing_admin` (boolean): Phase 56-02 RBAC flag — true if the user can access the billing-operator dashboard (`/admin/billing/*` routes). Distinct from `usertype === 'admin'` (which grants full admin access). - `user.credit_balance` (number): Stripe-paid top-up balance in USD (not in cents). Used by [POST /api/v1/billing/quota](/docs/account/billing-and-subscription/post-billing-quota) for buying additional API quota at 100 requests / $1. NOT the same as the token balance (see [GET /api/v1/account/balance](/docs/account/token-pricing/get-account-balance) for that). - `user.webhook_url` (string (nullable)): User-configured HTTPS URL for sniper-hit webhook callbacks. Null when the user has not configured one (most users). PUT /api/v1/user/ with `webhook_url` to update. - `user.notify_email` (boolean): True if email notifications are enabled. Default true. Toggle via PUT /api/v1/user/. - `user.notify_browser` (boolean): True if in-browser push notifications are enabled. Default true. Toggle via PUT /api/v1/user/. - `user.created_at` (string): ISO-8601 UTC timestamp the user account was created (set by /auth/register). - `user.updated_at` (string): ISO-8601 UTC timestamp the user row was last modified (`onupdate=datetime.utcnow`). Bumped on profile edits, login (last-seen), and admin role changes. - `user.Userplan` (object (nullable)): Embedded subscription state — `total_limit_api` (monthly request quota), `reach_limit_api` (consumed this cycle), `plan` (`free`/`weekly`/`monthly`/`pro`/`yearly`), `status` (`active`/`canceled`/`past_due`), `current_period_end`. Null in legacy edge cases where the relationship row was never seeded; /auth/register seeds this for new users. - `user.UserDocumentLimit` (object (nullable)): Embedded document-quota state for the (legacy) RAG document-upload feature — `total_limit_GB` and `reach_limit_GB`. Most users do not consume document quota. - `user.UserDeviceLimit` (object (nullable)): Embedded device-limit state — `device_limit` (max concurrent JWT sessions, default 2) and `user_login_device` (JSON-serialized array of active session_ids). When a third login lands the oldest session_id is evicted from the array. **Since:** v1.0.0 **Utility:** Authenticated 'who am I?' probe — returns full user profile plus embedded subscription (`Userplan`), document-quota (`UserDocumentLimit`), and device-limit (`UserDeviceLimit`) relationship rows. EXEMPT (`cost: 0`). Identical shape to the `user` field in the /auth/login response (both invoke `User.to_dict(include_relations=True)`). Use to bootstrap dashboard state on app load — the JWT cookie is presumed valid; if it expired the endpoint returns 401 and the SPA should redirect to /auth/login. Includes `api_key` (32-char) for the dashboard's 'API Keys' page; the user's `credit_balance` (USD top-up wallet, NOT tokens); subscription `plan` (`free` / `weekly` / `monthly` / `pro` / `yearly`); and notification preferences (`webhook_url`, `notify_email`, `notify_browser`). **Use case:** Dashboard SPA bootstraps on load by calling this endpoint to populate user state. Server-side automation should never call this — use the user's `api_key` directly for billed endpoints, no profile fetch needed. **Sample response:** ```json { "user": { "id": 42, "uuid": "0f14ed05-3a2e-4b76-9c11-1a7c8b3f6de2", "email": "user@example.com", "usertype": "user", "api_key": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6", "verify_email": true, "is_online": true, "has_uat_access": false, "billing_admin": false, "credit_balance": 12.5, "notify_email": true, "notify_browser": true, "webhook_url": "https://your-app.example.com/webhooks/finradar", "created_at": "2026-04-15T10:00:00.000Z", "updated_at": "2026-05-02T15:51:00.000Z", "Userplan": { "id": 42, "userId": "0f14ed05-3a2e-4b76-9c11-1a7c8b3f6de2", "total_limit_api": 100, "reach_limit_api": 12, "plan": "free", "status": "active", "current_period_end": null, "created_at": "2026-04-15T10:00:00.000Z", "updated_at": "2026-05-02T15:51:00.000Z" }, "UserDocumentLimit": { "id": 42, "userId": "0f14ed05-3a2e-4b76-9c11-1a7c8b3f6de2", "total_limit_GB": 5, "reach_limit_GB": "0.42", "created_at": "2026-04-15T10:00:00.000Z", "updated_at": "2026-05-02T15:51:00.000Z" }, "UserDeviceLimit": { "id": 42, "userId": "0f14ed05-3a2e-4b76-9c11-1a7c8b3f6de2", "device_limit": 2, "user_login_device": "[\"sess-abc-123\",\"sess-def-456\"]", "created_at": "2026-04-15T10:00:00.000Z", "updated_at": "2026-05-02T15:51:00.000Z" } } } ``` ### PUT /api/v1/user/ Update the authenticated user's notification preferences (`webhook_url`, `notify_email`, `notify_browser`). EXEMPT (`cost: 0`). Other profile fields are immutable via this endpoint. **Token cost:** 0 (EXEMPT — auth / billing / account / admin / health) **Response fields:** - `message` (string): Top-level result. `Profile updated successfully` on 200. On error (400): the underlying exception message. On 404: `User not found` (defensive — JWT was valid but user was deleted between auth and now). - `user` (object): Full updated user profile (same shape as GET /api/v1/user/'s `user` field). Reflects the post-update state of the three mutable fields plus the bumped `updated_at`. Use to patch SPA state without re-fetching. - `user.webhook_url` (string (nullable)): Updated webhook URL. Null if the request body cleared it (passed empty string) or if the user had never set one and this PUT did not include `webhook_url`. - `user.notify_email` (boolean): Updated email-notification preference. Reflects the body's `notify_email` if present; otherwise unchanged from the prior value. - `user.notify_browser` (boolean): Updated in-browser push-notification preference. Same merge semantics as `notify_email`. - `user.updated_at` (string): Bumped to the current UTC timestamp on every successful PUT (`onupdate=datetime.utcnow` on the User model). **Since:** v1.0.0 **Utility:** Update the authenticated user's notification preferences. EXEMPT (`cost: 0`). Only three fields are mutable here: `webhook_url`, `notify_email`, `notify_browser` — all other user fields (email, password, api_key, role, plan) are immutable via this endpoint by design (the handler hard-codes the allowlist). To change email/password use the dedicated /auth/* flows; to change subscription tier use [POST /api/v1/payment/create-checkout-session](/docs/account/billing-and-subscription/post-payment-create-checkout-session). The endpoint returns the full updated user object (same shape as GET /api/v1/user/) so dashboards can patch local state from the response without re-fetching. **Use case:** Dashboard 'Settings → Notifications' page submit handler: user toggles email/browser notifications + pastes their webhook URL → PUT here → backend persists + returns updated profile → SPA patches React state from the response. **Parameters:** - `webhook_url` (body, optional): HTTPS URL for POST callbacks when sniper targets fire. Pass an empty string to clear. Validated client-side as `^https://`; server stores as-is up to 512 chars. Webhook payload shape is documented at the Webhooks section. - `notify_email` (body, optional): Boolean — true to enable email notifications, false to disable. Default true on signup. Affects sniper-hit emails, billing-event emails, and product-update emails. - `notify_browser` (body, optional): Boolean — true to enable in-browser push notifications via the Web Push API, false to disable. Default true on signup. Browser must have granted notification permission separately for this to take effect. **Sample response:** ```json { "message": "Profile updated successfully", "user": { "id": 42, "uuid": "0f14ed05-3a2e-4b76-9c11-1a7c8b3f6de2", "email": "user@example.com", "usertype": "user", "api_key": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6", "verify_email": true, "is_online": true, "has_uat_access": false, "billing_admin": false, "credit_balance": 12.5, "notify_email": false, "notify_browser": true, "webhook_url": "https://your-app.example.com/webhooks/finradar", "created_at": "2026-04-15T10:00:00.000Z", "updated_at": "2026-05-02T15:51:00.000Z" } } ```