Firmhound API Endpoints
Auto-generated: 2025-12-15 02:43:20Run python scripts/generate_api_docs.py to update.
Summary
Total Endpoints: 139
| Method | Count |
|---|---|
| GET | 78 |
| POST | 42 |
| PUT | 5 |
| PATCH | 4 |
| DELETE | 10 |
| Category | Count |
|---|---|
| Admin | 39 |
| User | 22 |
| GPs | 19 |
| Notifications | 14 |
| Auth | 13 |
| Search | 10 |
| People Intelligence | 6 |
| API Keys | 5 |
| Billing | 5 |
| Other | 5 |
| Legal | 4 |
| Export | 3 |
| Funds | 3 |
| Enrichment | 3 |
| LPs | 3 |
| People | 3 |
| Settings | 3 |
| Usage | 3 |
Endpoints by Category
Auth
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /auth/forgot-password | 🌐 | Request a password reset email. |
POST | /auth/login | 🌐 | Authenticate user and return JWT tokens. |
POST | /auth/logout | 🔒 | Logout user. |
GET | /auth/me | 🔒 | Get current authenticated user info (FS-7104: returns both a... |
PATCH | /auth/me/onboarding | 🔒 | Update user's onboarding progress (FS-9052). |
POST | /auth/refresh | 🌐 | Refresh access token using refresh token. |
POST | /auth/register | 🌐 | Register a new user with 7 fields and automatic tier detecti... |
POST | /auth/resend-verification | 🔒 | Resend verification email to the authenticated user. |
POST | /auth/reset-password | 🌐 | Reset password using token from email. |
DELETE | /auth/sessions | 🔒 | Terminate all other sessions (except current). |
GET | /auth/sessions | 🔒 | List all active sessions for the current user. |
DELETE | /auth/sessions/{session_id} | 🔒 | Terminate a specific session. |
POST | /auth/verify-email | 🌐 | Verify user's email address using token from verification em... |
GPs
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /gps | 🌐 | Search fund managers (GPs) with 21+ filters. |
GET | /gps/{crd} | 🌐 | Get a single fund manager by CRD number. |
GET | /gps/{crd}/alumni | 🔒 | Get alumni (former employees) for a GP with PDL enrichment. |
POST | /gps/{crd}/alumni/unlock | 🔒 | Unlock alumni network data for a GP. |
GET | /gps/{crd}/amendments | 🌐 | Get ADV filing amendment history for a GP. |
POST | /gps/{crd}/careers/unlock-all | 🔒 | Bulk unlock career histories for a GP (20% discount). |
GET | /gps/{crd}/changes | 🌐 | Get derived field changes over time for a GP. |
POST | /gps/{crd}/enrich | 🔒 | Enrich a GP's control persons with education and employment ... |
GET | /gps/{crd}/enrich/status/{job_id} | 🌐 | Poll status of async enrichment job. |
GET | /gps/{crd}/enrichment-info | 🌐 | Check if a GP has been enriched without triggering enrichmen... |
GET | /gps/{crd}/filings | 🌐 | Get SEC filings for a specific GP. |
GET | /gps/{crd}/funds | 🌐 | Get funds managed by a specific GP. |
GET | /gps/{crd}/hiring | 🌐 | Get job postings and hiring velocity for a GP. |
GET | /gps/{crd}/metrics | 🌐 | Get derived firm metrics for a GP. |
GET | /gps/{crd}/related | 🌐 | Find similar GPs based on strategy, geography, and AUM band. |
GET | /gps/{crd}/stats | 🌐 | Get statistics for a specific GP. |
GET | /gps/{crd}/team | 🔒 | Get team roster for a GP with PDL enrichment. |
GET | /gps/{crd}/team/preview | 🔒 | Get team preview/teaser for People Intelligence UI. |
POST | /gps/{crd}/team/unlock | 🔒 | Unlock team roster data for a GP (People Intelligence purcha... |
Funds
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /funds | 🌐 | Search private funds. |
GET | /funds/{fund_id} | 🌐 | Get a single fund by fund ID. |
GET | /funds/{fund_id}/amendments | 🌐 | Get amendment history for a private fund. |
LPs
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /lps | 🌐 | Search and list LP entities. |
GET | /lps/{lp_id} | 🌐 | Get detailed information about a specific LP entity. |
GET | /lps/{lp_id}/investments | 🌐 | Get investment portfolio for a specific LP. |
People
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /people/search | 🌐 | Search people by name. |
GET | /people/{person_uid} | 🌐 | Get individual person profile. |
GET | /people/{person_uid}/history | 🌐 | Get full career history for a person. |
Search
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /me/searches | 🔒 | List user's saved searches. |
POST | /me/searches | 🔒 | Create a new saved search. |
DELETE | /me/searches/{search_id} | 🔒 | Delete a saved search. |
GET | /me/searches/{search_id} | 🔒 | Get a specific saved search. |
PUT | /me/searches/{search_id} | 🔒 | Update a saved search. |
GET | /me/searches/{search_id}/run | 🔒 | Execute a saved search and return results. |
GET | /search | 🌐 | Unified search across GPs and funds. |
GET | /search/aggregate | 🌐 | Market aggregations for data analysis and benchmarking. |
GET | /search/autocomplete | 🌐 | Fast prefix matching for search UI typeahead. |
GET | /search/suggestions | 🌐 | Get search term suggestions based on popular/recent searches... |
User
| Method | Endpoint | Auth | Description |
|---|---|---|---|
DELETE | /me/account | 🔒 | Request account deletion (soft delete with 30-day recovery w... |
GET | /me/account/export | 🔒 | Export all user data (GDPR compliance). |
POST | /me/account/recover | 🌐 | Recover a deleted account within the 30-day recovery window. |
GET | /me/activity | 🔒 | Get activity feed aggregating recent events for user's saved... |
GET | /me/collections | 🔒 | List user's collections. |
POST | /me/collections | 🔒 | Create a new collection. |
DELETE | /me/collections/{collection_id} | 🔒 | Delete a collection and all its items. |
GET | /me/collections/{collection_id} | 🔒 | Get a collection with its items. |
PATCH | /me/collections/{collection_id} | 🔒 | Update collection name and/or description. |
POST | /me/collections/{collection_id}/items | 🔒 | Add a GP to a collection. |
DELETE | /me/collections/{collection_id}/items/{crd} | 🔒 | Remove a GP from a collection. |
GET | /me/notifications/preferences | 🔒 | Get user's email notification preferences. |
PUT | /me/notifications/preferences | 🔒 | Update user's email notification preferences. |
POST | /me/notifications/test | 🔒 | Send a test email to the authenticated user. |
POST | /me/notifications/unsubscribe | 🌐 | Unsubscribe from emails using the token from email footer. |
GET | /me/preferences | 🔒 | Get user's People Intelligence preferences. |
PATCH | /me/preferences | 🔒 | Update user's People Intelligence preferences. |
GET | /me/purchases | 🔒 | List all People Intelligence purchases for the current user. |
GET | /me/purchases/gp/{crd} | 🔒 | Get all People Intelligence purchases for a specific GP. |
GET | /me/watchlist | 🔒 | List user's watchlist items. |
POST | /me/watchlist | 🔒 | Add a GP to the watchlist. |
DELETE | /me/watchlist/{item_id} | 🔒 | Remove an item from the watchlist. |
Billing
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /billing/checkout | 🔒 | Create a Stripe Checkout session for tier upgrade. |
GET | /billing/free-tier-status | 🌐 | Get free tier usage status for the current API key (FS-6010)... |
POST | /billing/portal | 🔒 | Create a Stripe Customer Portal session for invoice/payment ... |
GET | /billing/subscription | 🔒 | Get current subscription status for the authenticated user. |
POST | /billing/webhook | 🌐 | Stripe webhook handler for payment events. |
API Keys
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /api-keys | 🔒 | List all API keys for the current user. |
POST | /api-keys | 🔒 | Create a new API key. |
DELETE | /api-keys/{key_id} | 🔒 | Revoke an API key. |
GET | /api-keys/{key_id} | 🔒 | Get details of a specific API key. |
PATCH | /api-keys/{key_id} | 🔒 | Update API key name. |
Export
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /export/csv | 🔒 | Export search results to CSV. |
GET | /export/fields | 🌐 | List available fields for export. |
Usage
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /usage | 🌐 | Get usage statistics for the current API key. |
GET | /usage/daily | 🌐 | Get daily usage breakdown for the current API key. |
GET | /usage/endpoints | 🌐 | Get statistics grouped by endpoint for the current API key. |
Settings
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /settings/spending-cap | 🔒 | Get current spending cap and usage. |
PUT | /settings/spending-cap | 🔒 | Update monthly spending cap. |
PUT | /settings/spending-cap/alerts | 🔒 | Update spending cap alert thresholds. |
Admin
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /admin/dataops/dashboard | 🔒 | Get combined command center dashboard data. |
GET | /admin/dataops/extractions | 🔒 | Get recent extraction runs. |
POST | /admin/dataops/extractions/trigger | 🔒 | Trigger an extraction for a source. |
GET | /admin/dataops/extractions/{run_id} | 🔒 | Get full details of an extraction run including diffs. |
GET | /admin/dataops/freshness | 🔒 | Get freshness summary by entity type and source. |
GET | /admin/dataops/freshness/queue | 🔒 | Get refresh queue status. |
POST | /admin/dataops/freshness/queue | 🔒 | Queue an entity for refresh. |
POST | /admin/dataops/freshness/queue/process | 🔒 | Trigger processing of the refresh queue. |
GET | /admin/dataops/freshness/stale | 🔒 | Get stale entities ordered by staleness. |
GET | /admin/dataops/health | 🔒 | Get overall system health status. |
GET | /admin/dataops/overrides | 🔒 | Get manual override records. |
POST | /admin/dataops/overrides | 🔒 | Create a manual data override. |
DELETE | /admin/dataops/overrides/{override_id} | 🔒 | Soft-delete a manual override. |
GET | /admin/dataops/quality | 🔒 | Get current data quality metrics. |
GET | /admin/dataops/quality/alerts | 🔒 | Get data quality alerts. |
POST | /admin/dataops/quality/alerts/{alert_id}/acknowledge | 🔒 | Acknowledge a quality alert. |
POST | /admin/dataops/quality/alerts/{alert_id}/resolve | 🔒 | Resolve a quality alert. |
GET | /admin/dataops/quality/trends | 🔒 | Get quality metric trends over time. |
GET | /admin/dataops/sources | 🔒 | Get status of all data sources. |
POST | /admin/jobs/daily-digest | 🔒 | Send daily digest emails. |
POST | /admin/jobs/market-intel | 🔒 | Send weekly market intelligence to Premier users. |
POST | /admin/jobs/payment-check | 🔒 | Check for payment failures and send dunning emails. |
POST | /admin/jobs/process-queue | 🔒 | Process the notification queue. |
POST | /admin/jobs/trial-check | 🔒 | Check for expiring trials and queue notifications. |
GET | /admin/notifications/ | 🔒 | List all notification types in the registry. |
POST | /admin/notifications/ | 🔒 | Create a new notification type. |
GET | /admin/notifications/analytics/overview | 🔒 | Get overview analytics for all notifications. |
GET | /admin/notifications/export | 🔒 | Export the entire notification registry as JSON. |
POST | /admin/notifications/import | 🔒 | Import notification definitions from JSON. |
GET | /admin/notifications/stats | 🔒 | Get aggregate notification statistics. |
GET | /admin/notifications/summary | 🔒 | Get summary statistics of the notification registry. |
GET | /admin/notifications/table | 🔒 | Get formatted table view of all notifications (text/plain). |
POST | /admin/notifications/test | 🔒 | Send a test notification to a specific email. |
DELETE | /admin/notifications/{notification_id} | 🔒 | Delete a notification type. |
GET | /admin/notifications/{notification_id} | 🔒 | Get full details of a notification. |
PUT | /admin/notifications/{notification_id} | 🔒 | Update a notification's settings. |
POST | /admin/notifications/{notification_id}/disable | 🔒 | Disable a notification. |
POST | /admin/notifications/{notification_id}/enable | 🔒 | Enable a notification. |
GET | /admin/notifications/{notification_id}/stats | 🔒 | Get analytics for a specific notification type. |
Other
| Method | Endpoint | Auth | Description |
|---|---|---|---|
POST | /hbs/survey | 🔒 | Submit monthly HBS feedback survey. |
POST | /hbs/verify | 🌐 | Verify HBS student email for free tier access. |
GET | /track/click/{tracking_id} | 🌐 | Click tracking endpoint. |
GET | /track/open/{tracking_id}.png | 🌐 | Tracking pixel endpoint. |
GET | /unsubscribe/{token} | 🌐 | One-click unsubscribe endpoint (GET for email client compati... |
Legal
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET | /legal/entity-info | 🌐 | Get legal entity information. |
GET | /legal/privacy | 🌐 | Get the Privacy Policy (when available). |
GET | /legal/terms | 🌐 | Get the API Terms of Service. |
GET | /legal/terms/version | 🌐 | Get current ToS version metadata. |
Detailed Reference
Auth
POST /auth/forgot-password
Request a password reset email.
Generates a time-limited token (1 hour) and sends reset link. Rate limited: 3 requests per email per hour. Always returns success (to prevent email enumeration).
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | ForgotPasswordRequest |
| Source | auth.py:507 |
POST /auth/login
Authenticate user and return JWT tokens.
Validates credentials against database and returns access + refresh tokens. FS-7101: Creates new session and terminates all other sessions (single-device enforcement).
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | LoginRequest |
| Source | auth.py:107 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
http_request | request | Yes | - | - |
POST /auth/logout
Logout user.
For stateless JWT, we just acknowledge logout. Client should discard tokens.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | auth.py:340 |
GET /auth/me
Get current authenticated user info (FS-7104: returns both app and API tiers, FS-9052: includes onboarding status).
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | auth.py:355 |
PATCH /auth/me/onboarding
Update user's onboarding progress (FS-9052).
- step: Set current step (1-3). Can only increment (1→2→3). - completed: Mark onboarding as complete (auto-sets when step=3). Rules: 1. Steps can only be incremented (not decremented) 2. Setting step=3 automatically marks completed=true 3. Once completed=true, onboarding cannot be reset
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | UpdateOnboardingRequest |
| Source | auth.py:399 |
POST /auth/refresh
Refresh access token using refresh token.
Validates refresh token and issues new access token.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | auth.py:296 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
refresh_token | str | Yes | - | - |
POST /auth/register
Register a new user with 7 fields and automatic tier detection.
Tier Detection: - @mbaYYYY.hbs.edu -> hbs_student tier (free until graduation) - *.edu -> student tier (discounted) - Other -> free_trial tier (14 days)
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | RegisterRequest |
| Source | auth.py:177 |
POST /auth/resend-verification
Resend verification email to the authenticated user.
Rate limited: 3 requests per hour per user. Only works if user is not already verified.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | auth.py:730 |
POST /auth/reset-password
Reset password using token from email.
Validates token, updates password, and invalidates all sessions. Token expires after 1 hour and is single-use.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | ResetPasswordRequest |
| Source | auth.py:577 |
DELETE /auth/sessions
Terminate all other sessions (except current).
Used for "Sign out all devices" functionality in Settings. Requires current session ID in request headers (X-Session-ID).
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | auth.py:878 |
GET /auth/sessions
List all active sessions for the current user.
Returns sessions with device info and activity timestamps. Used in Settings > Security & Sessions page.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | auth.py:829 |
DELETE /auth/sessions/{session_id}
Terminate a specific session.
Used to sign out a specific device from Settings > Security & Sessions.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | auth.py:854 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
session_id | str | Yes | - | - |
POST /auth/verify-email
Verify user's email address using token from verification email.
Token is valid for 24 hours and is single-use. Upon verification, user gets full access to the platform.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | VerifyEmailRequest |
| Source | auth.py:654 |
GPs
GET /gps
Search fund managers (GPs) with 21+ filters.
Examples: /v1/gps?q=blackstone&min_aum=1000000000 /v1/gps?strategy=PE&state=NY&has_funds=true /v1/gps?aum_band=>10B&per_page=50 /v1/gps?min_employees=100&max_employees=500 /v1/gps?year_founded_min=2010&state_of_incorporation=DE /v1/gps?vintage_min=2020&fund_type=3c7&has_auditor=true /v1/gps?launched_within_months=24&exemption_type=506c /v1/gps?fund_size_min=100000000&min_investors=50 /v1/gps?manager_type=pe_vc&state=CA /v1/gps?manager_type=hedge_fund&min_aum=500000000
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Source | gps.py:59 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
q | optional | No | None | Search name/DBA |
city | optional | No | None | Filter by city |
state | optional | No | None | Filter by state (US) |
country | optional | No | None | Filter by country |
min_aum | optional | No | None | Minimum AUM ($) |
max_aum | optional | No | None | Maximum AUM ($) |
aum_band | optional | No | None | AUM band: <100M, 100M-500M, 500M-1B, 1B-10B, >10B |
strategy | optional | No | None | Strategy: PE, VC, Hedge, RealEstate, Credit |
registration_status | optional | No | None | registered, exempt_reporting |
has_funds | optional | No | None | Only GPs with private funds |
min_fund_count | optional | No | None | Minimum fund count |
max_fund_count | optional | No | None | Maximum fund count |
min_employees | optional | No | None | Minimum employees |
max_employees | optional | No | None | Maximum employees |
jurisdiction | optional | No | None | Primary jurisdiction: US, UK, SG, HK |
registered_after | optional | No | None | YYYY-MM-DD |
registered_before | optional | No | None | YYYY-MM-DD |
year_founded_min | optional | No | None | Minimum year founded |
year_founded_max | optional | No | None | Maximum year founded |
vintage_min | optional | No | None | Minimum fund vintage year |
vintage_max | optional | No | None | Maximum fund vintage year |
launched_within_months | optional | No | None | Funds launched within N months |
fund_size_min | optional | No | None | Minimum fund GAV ($) |
fund_size_max | optional | No | None | Maximum fund GAV ($) |
min_investors | optional | No | None | Minimum total investors across funds |
max_investors | optional | No | None | Maximum total investors across funds |
exemption_type | optional | No | None | Form D exemption: 506b, 506c, 3c1, 3c7 |
fund_type | optional | No | None | Fund type: 3c1 or 3c7 |
state_of_incorporation | optional | No | None | State where adviser is organized |
has_auditor | optional | No | None | Has auditor for any fund |
auditor_name | optional | No | None | Search by auditor name |
manager_type | optional | No | None | Manager type: pe_vc, hedge_fund, real_estate, other |
page | int | No | 1 | Page number |
per_page | int | No | 25 | Results per page |
sort | optional | No | None | Sort: name, aum, fund_count, employees |
order | optional | No | asc | asc or desc |
GET /gps/{crd}
Get a single fund manager by CRD number.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | gps.py:464 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
GET /gps/{crd}/alumni
Get alumni (former employees) for a GP with PDL enrichment.
Returns former employees with their current positions, filtered and paginated. Cost: $0.50 per person returned. Parameters: - crd: GP CRD number - limit: Max results (default 50, max 100 for cost protection) - offset: Pagination offset - departed_after: Filter by departure date (YYYY-MM-DD) - current_role: Filter by current position type Response includes: - Alumni with PDL-enriched profiles - Pagination metadata (total_count, has_more) - Cost estimate Example: GET /v1/gps/12345/alumni?limit=25&departed_after=2020-01-01 → Returns up to 25 alumni who departed after 2020 → Cost: 25 × $0.50 = $12.50
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | Optional |
| Pricing | Cost: $0.50 |
| Source | gps.py:1637 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
limit | int | No | 50 | Max results (default 50, max 100) |
offset | int | No | 0 | Pagination offset |
departed_after | optional | No | None | Filter by departure date (YYYY-MM-DD) |
current_role | optional | No | None | Filter by current position type |
POST /gps/{crd}/alumni/unlock
Unlock alumni network data for a GP.
Returns former employees with their current positions. Pricing: $0.50 per person
| Property | Value |
|---|---|
| Auth Required | Yes |
| Pricing | Pricing: $0.50 |
| Source | gps.py:1715 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
GET /gps/{crd}/amendments
Get ADV filing amendment history for a GP.
Returns chronological list of ADV filings and amendments with metadata. Shows filing dates, amendment types (annual/material/initial), and processing status. Pricing: $0.25 per request (flat fee, not per record)
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | Pricing: $0.25 |
| Source | gps.py:1866 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
limit | int | No | 50 | Max amendments to return |
POST /gps/{crd}/careers/unlock-all
Bulk unlock career histories for a GP (20% discount).
If person_ids is provided, unlock those specific people. Otherwise, unlock all team members the user has already purchased. Pricing: $0.75/person (20% discount = $0.60/person for bulk)
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | CareerBulkUnlockRequest |
| Pricing | $0.75/person |
| Source | gps.py:1527 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
GET /gps/{crd}/changes
Get derived field changes over time for a GP.
Tracks changes in computed/derived fields like AUM, employee count, strategy, etc. by comparing snapshots taken at different filing dates. Pricing: $0.25 per request (flat fee, not per record)
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | Pricing: $0.25 |
| Source | gps.py:1936 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
limit | int | No | 50 | Max change records to return |
POST /gps/{crd}/enrich
Enrich a GP's control persons with education and employment data from PDL.
Supports two modes: - Synchronous (default): Blocks until enrichment completes, returns result immediately - Asynchronous (async_mode=true): Returns 202 Accepted with job_id for polling
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | EnrichRequest |
| Source | gps.py:833 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
GET /gps/{crd}/enrich/status/{job_id}
Poll status of async enrichment job.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | gps.py:969 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
job_id | str | Yes | - | - |
GET /gps/{crd}/enrichment-info
Check if a GP has been enriched without triggering enrichment.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | gps.py:1015 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
GET /gps/{crd}/filings
Get SEC filings for a specific GP.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Source | gps.py:718 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
form_type | optional | No | None | Form type: D, D/A |
year | optional | No | None | Filing year |
page | int | No | 1 | - |
per_page | int | No | 25 | - |
GET /gps/{crd}/funds
Get funds managed by a specific GP.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Source | gps.py:582 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
status | optional | No | None | active, liquidating |
fund_type | optional | No | None | 3c1, 3c7, all |
min_gav | optional | No | None | Minimum GAV |
page | int | No | 1 | - |
per_page | int | No | 25 | - |
GET /gps/{crd}/hiring
Get job postings and hiring velocity for a GP.
Returns active job postings from Adzuna + career page scraping, along with hiring velocity metrics.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Pricing | $0.10/request |
| Source | gps_hiring.py:67 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
role | optional | No | None | Filter by seniority: partner, md, vp, associate, analyst |
department | optional | No | None | Filter by department: investment, operations, ir, legal, finance |
posted_after | optional | No | None | Filter by posted date (YYYY-MM-DD) |
limit | int | No | 50 | Max results (default 50, max 100) |
GET /gps/{crd}/metrics
Get derived firm metrics for a GP.
Returns computed analytics: - AUM growth rate (YoY, 3Y CAGR) - Fund launch cadence - Average fund size trend - Employee growth rate Pricing: $0.15/request (flat fee, analytics endpoint type)
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | $0.15/request |
| Source | gps_analytics.py:23 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
GET /gps/{crd}/related
Find similar GPs based on strategy, geography, and AUM band.
Similarity factors: - Primary strategy match - Geographic proximity (state/country) - AUM band overlap - Fund count similarity Pricing: $0.15/request (flat fee, analytics endpoint type)
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | $0.15/request |
| Source | gps_analytics.py:146 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
limit | int | No | 10 | Max similar GPs to return |
GET /gps/{crd}/stats
Get statistics for a specific GP.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | gps.py:666 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
GET /gps/{crd}/team
Get team roster for a GP with PDL enrichment.
Returns team members with their profiles, filtered by role and paginated. Cost: $0.50 per person returned. Parameters: - crd: GP CRD number - limit: Max results (default 50, max 100 for cost protection) - offset: Pagination offset - role: Filter by role (partner, md, vp, associate, other) - sort: Sort order (seniority, tenure, name) Response includes: - Team members with PDL-enriched profiles - Pagination metadata (total_count, has_more) - Cost estimate Example: GET /v1/gps/12345/team?role=partner&limit=25 → Returns up to 25 partners → Cost: 25 × $0.50 = $12.50
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | Optional |
| Pricing | Cost: $0.50 |
| Source | gps.py:1234 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
limit | int | No | 50 | Max results (default 50, max 100) |
offset | int | No | 0 | Pagination offset |
role | optional | No | None | Filter by role: partner, md, vp, associate, other |
sort | str | No | seniority | Sort by: seniority, tenure, name |
GET /gps/{crd}/team/preview
Get team preview/teaser for People Intelligence UI.
Returns aggregate counts and structure WITHOUT revealing names. This enables the blurred teaser state showing titles visible, names blurred. FREE endpoint - no charge. Response includes: - Total team count - Count by seniority level (partner, md, vp, associate, other) - Tenure range (min/max years) - Alumni availability and count - Career data availability
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | gps.py:1074 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
POST /gps/{crd}/team/unlock
Unlock team roster data for a GP (People Intelligence purchase).
Tier options: - senior: Partners & Managing Directors only - investment_team: Partners through Associates (RECOMMENDED) - complete: All identified team members - custom: Specify count (system selects by seniority) Pricing: $0.50 per person Returns the unlocked team data and records the purchase.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | TeamUnlockRequest |
| Pricing | Pricing: $0.50 |
| Source | gps.py:1354 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
Funds
GET /funds
Search private funds.
Examples: /v1/funds?q=capital partners /v1/funds?gp_crd=148826&fund_type=3c7 /v1/funds?min_vintage=2020&min_gav=100000000
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Source | funds.py:23 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
q | optional | No | None | Search fund name |
gp_crd | optional | No | None | Filter by GP CRD |
gp_id | optional | No | None | Filter by canonical GP ID |
fund_type | optional | No | None | 3c1, 3c7, or all |
is_master | optional | No | None | Filter master funds |
is_feeder | optional | No | None | Filter feeder funds |
min_gav | optional | No | None | Minimum gross asset value |
max_gav | optional | No | None | Maximum gross asset value |
vintage_year | optional | No | None | Exact vintage year |
min_vintage | optional | No | None | Minimum vintage year |
max_vintage | optional | No | None | Maximum vintage year |
jurisdiction | optional | No | None | State/country of organization |
status | optional | No | None | active, liquidating |
has_auditor | optional | No | None | Has auditor info |
page | int | No | 1 | - |
per_page | int | No | 25 | - |
sort | optional | No | None | name, gav, vintage_year |
order | optional | No | asc | asc or desc |
GET /funds/{fund_id}
Get a single fund by fund ID.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | funds.py:200 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
fund_id | str | Yes | - | - |
GET /funds/{fund_id}/amendments
Get amendment history for a private fund.
Tracks changes to fund data from Form ADV Section 7.B amendments. Shows when fund data was updated via adviser ADV filings. Pricing: $0.25 per request (flat fee, not per record)
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | Pricing: $0.25 |
| Source | funds.py:266 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
fund_id | str | Yes | - | - |
limit | int | No | 50 | Max amendments to return |
LPs
GET /lps
Search and list LP entities.
Returns limited partners (investors) extracted from Form D filings, with optional filters for entity type and investment activity. Examples: /v1/lps?q=pension /v1/lps?entity_type=endowment&min_investments=5 /v1/lps?invested_with_crd=12345 /v1/lps?sort=investment_count&order=desc Pricing: $0.10/request (flat fee)
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Pricing | $0.10/request |
| Source | lps.py:73 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
q | optional | No | None | Search LP name |
entity_type | optional | No | None | Filter by type: pension, endowment, family_office, fund_of_funds, insurance, sovereign_wealth, corporate, other |
min_investments | optional | No | None | Minimum number of investments |
invested_with_crd | optional | No | None | Filter LPs who invested with specific GP (CRD) |
page | int | No | 1 | Page number |
per_page | int | No | 25 | Results per page |
sort | optional | No | name | Sort: name, investment_count, created_at |
order | optional | No | asc | asc or desc |
GET /lps/{lp_id}
Get detailed information about a specific LP entity.
Returns LP details including all investment relationships.
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | $0.10/request |
| Source | lps.py:229 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
lp_id | int | Yes | - | - |
GET /lps/{lp_id}/investments
Get investment portfolio for a specific LP.
Returns all investments made by this LP across different GPs/funds.
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | $0.10/request |
| Source | lps.py:309 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
lp_id | int | Yes | - | - |
page | int | No | 1 | - |
per_page | int | No | 25 | - |
People
GET /people/search
Search people by name.
Uses fuzzy matching (trigram similarity) for name search. Only returns cached people (from prior enrichments).
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Pricing | Pricing: $0.50 |
| Source | people.py:122 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
q | str | No | Ellipsis | Name search query |
company | optional | No | None | Filter by company |
limit | int | No | 20 | Max results |
GET /people/{person_uid}
Get individual person profile.
Returns cached PDL enrichment data including education, experience, and contact information.
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | $0.50/request |
| Source | people.py:35 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
person_uid | str | Yes | - | - |
force_refresh | bool | No | False | Force cache refresh from PDL |
GET /people/{person_uid}/history
Get full career history for a person.
Returns chronological timeline of education and employment.
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | $0.75/request |
| Source | people.py:79 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
person_uid | str | Yes | - | - |
Search
GET /me/searches
List user's saved searches.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:93 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
page | int | No | 1 | - |
per_page | int | No | 25 | - |
POST /me/searches
Create a new saved search.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | SavedSearchCreate |
| Source | user.py:112 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
search | savedsearchcreate | Yes | - | - |
DELETE /me/searches/{search_id}
Delete a saved search.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:164 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
search_id | int | Yes | - | - |
GET /me/searches/{search_id}
Get a specific saved search.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:123 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
search_id | int | Yes | - | - |
PUT /me/searches/{search_id}
Update a saved search.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | SavedSearchUpdate |
| Source | user.py:136 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
search_id | int | Yes | - | - |
update | savedsearchupdate | Yes | - | - |
GET /me/searches/{search_id}/run
Execute a saved search and return results.
Loads the saved search filters and executes the GP search with those parameters. Updates last_run_at and last_match_count after execution. Flow: 1. Retrieves saved search by ID (verifies user ownership) 2. Extracts stored filter criteria from the saved search 3. Executes search using the same logic as GET /v1/gps 4. Updates last_run_at timestamp and last_match_count 5. Returns results in same format as /v1/gps with additional metadata Response includes: - data: Array of GP results matching the saved filters - meta.total: Total number of matching GPs - meta.page: Current page number - meta.per_page: Results per page - meta.saved_search_id: ID of the executed saved search - meta.saved_search_name: Name of the executed saved search Example: GET /v1/me/searches/123/run Response: { "data": [ { "crd": "12345", "name": "Example Capital", "aum": 5000000000, ... } ], "meta": { "total": 42, "page": 1, "per_page": 25, "saved_search_id": 123, "saved_search_name": "Large PE firms in NYC" } } Error Cases: - 404: Saved search not found or user doesn't own it - 401: User not authenticated
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:181 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
search_id | int | Yes | - | - |
GET /search
Unified search across GPs and funds.
Example: /v1/search?q=blackstone&types=gp,fund
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Source | search.py:19 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
q | str | No | Ellipsis | Search query |
types | optional | No | None | Comma-separated: gp,fund |
limit | int | No | 5 | Results per type |
GET /search/aggregate
Market aggregations for data analysis and benchmarking.
Aggregation options: - strategy: AUM and fund count by primary strategy - state: Geographic distribution by US state - vintage: Fund count by vintage year - aum_band: GP count by AUM band Pricing: $0.15/request (flat fee, analytics endpoint type) Examples: /v1/search/aggregate?group_by=strategy /v1/search/aggregate?group_by=vintage
| Property | Value |
|---|---|
| Auth Required | No |
| Pricing | $0.15/request |
| Source | search.py:203 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
group_by | str | No | Ellipsis | Group by: strategy, state, vintage, aum_band |
GET /search/autocomplete
Fast prefix matching for search UI typeahead.
Uses PostgreSQL trigram index for fast fuzzy matching. Example: /v1/search/autocomplete?q=black&type=gp
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Source | search.py:91 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
q | str | No | Ellipsis | Partial query |
type | optional | No | None | gp, fund, or all |
limit | int | No | 10 | Max suggestions |
GET /search/suggestions
Get search term suggestions based on popular/recent searches.
For MVP, returns matching GP names as suggestions.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | search.py:173 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
q | str | No | Ellipsis | Partial query |
limit | int | No | 5 | Max suggestions |
User
DELETE /me/account
Request account deletion (soft delete with 30-day recovery window).
Process: 1. User confirms by typing "DELETE" and providing password 2. Account is soft-deleted (marked with deleted_at timestamp) 3. User has 30 days to recover the account 4. After 30 days, account is permanently deleted via scheduled job What's preserved during recovery window: - Saved searches - Watchlist - Export history - All account data What happens immediately: - All active sessions are invalidated - User is logged out - Subscription is cancelled (if active)
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | AccountDeleteRequest |
| Source | user.py:1371 |
GET /me/account/export
Export all user data (GDPR compliance).
Returns all user data in a structured format for download.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:1552 |
POST /me/account/recover
Recover a deleted account within the 30-day recovery window.
This endpoint doesn't require authentication (since the user is logged out). Instead, it verifies the email and password.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | AccountRecoverRequest |
| Source | user.py:1468 |
GET /me/activity
Get activity feed aggregating recent events for user's saved GPs and searches.
Activity Types: - new_filing: New SEC filings (ADV/Form D) for watchlist GPs - new_fund: New funds added for watchlist GPs Query Parameters: - types: Filter by comma-separated activity types (optional) - limit: Results per page (default 50, max 100) - offset: Pagination offset (default 0) - since: ISO 8601 datetime for filtering recent events (default: last 30 days) Response Format: json { "data": [ { "type": "new_filing", "crd": "123456", "gp_name": "Blackstone Group", "event_date": "2025-12-15T10:30:00Z", "details": { "form_type": "ADV" } }, { "type": "new_fund", "crd": "789012", "gp_name": "KKR", "event_date": "2025-12-14T15:00:00Z", "details": { "fund_name": "KKR Global Impact Fund III" } } ], "meta": { "total": 127, "limit": 50, "offset": 0, "types_included": ["new_filing", "new_fund"] } }
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | Optional |
| Source | user.py:1148 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
types | optional | No | None | Comma-separated activity types: new_filing,new_fund |
limit | int | No | 50 | Results per page |
offset | int | No | 0 | Pagination offset |
since | optional | No | None | Only events after this timestamp |
GET /me/collections
List user's collections.
Returns all collections with item counts.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:524 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
page | int | No | 1 | - |
per_page | int | No | 25 | - |
POST /me/collections
Create a new collection.
Max 20 collections per user.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | CollectionCreate |
| Source | user.py:584 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
collection | collectioncreate | Yes | - | - |
DELETE /me/collections/{collection_id}
Delete a collection and all its items.
CASCADE delete removes all collection_items automatically.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:754 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
collection_id | int | Yes | - | - |
GET /me/collections/{collection_id}
Get a collection with its items.
Returns collection details and paginated list of GPs.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:631 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
collection_id | int | Yes | - | - |
page | int | No | 1 | - |
per_page | int | No | 100 | - |
PATCH /me/collections/{collection_id}
Update collection name and/or description.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | CollectionUpdate |
| Source | user.py:704 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
collection_id | int | Yes | - | - |
update | collectionupdate | Yes | - | - |
POST /me/collections/{collection_id}/items
Add a GP to a collection.
Max 500 items per collection.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | CollectionItemCreate |
| Source | user.py:780 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
collection_id | int | Yes | - | - |
item | collectionitemcreate | Yes | - | - |
DELETE /me/collections/{collection_id}/items/{crd}
Remove a GP from a collection.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:845 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
collection_id | int | Yes | - | - |
crd | str | Yes | - | - |
GET /me/notifications/preferences
Get user's email notification preferences.
Creates default preferences if none exist.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | EmailPreferencesResponse |
| Source | notifications.py:97 |
PUT /me/notifications/preferences
Update user's email notification preferences.
Any field not provided will keep its current value.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | EmailPreferences |
| Response | EmailPreferencesResponse |
| Source | notifications.py:144 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
prefs | emailpreferences | Yes | - | - |
POST /me/notifications/test
Send a test email to the authenticated user.
Useful for verifying email delivery is working.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | TestEmailRequest |
| Source | notifications.py:235 |
POST /me/notifications/unsubscribe
Unsubscribe from emails using the token from email footer.
Can unsubscribe from a specific category or all emails.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | UnsubscribeRequest |
| Source | notifications.py:382 |
GET /me/preferences
Get user's People Intelligence preferences.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:1051 |
PATCH /me/preferences
Update user's People Intelligence preferences.
- one_click_enabled: Skip confirmation for purchases under threshold - one_click_threshold: Dollar amount threshold ($5-$500) - email_receipts: Send email receipt for each purchase - weekly_digest: Weekly summary of enrichment spend
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | PIPreferencesUpdate |
| Source | user.py:1088 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
update | pipreferencesupdate | Yes | - | - |
GET /me/purchases
List all People Intelligence purchases for the current user.
Returns purchase history with GP names, types, and amounts.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:896 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
page | int | No | 1 | - |
per_page | int | No | 25 | - |
GET /me/purchases/gp/{crd}
Get all People Intelligence purchases for a specific GP.
This is used by the GP Profile page to determine what data the user has already unlocked (show unlocked state vs teaser).
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:972 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
crd | str | Yes | - | - |
GET /me/watchlist
List user's watchlist items.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:397 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
page | int | No | 1 | - |
per_page | int | No | 25 | - |
POST /me/watchlist
Add a GP to the watchlist.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | WatchlistItemCreate |
| Source | user.py:416 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
item | watchlistitemcreate | Yes | - | - |
DELETE /me/watchlist/{item_id}
Remove an item from the watchlist.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | user.py:457 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
item_id | int | Yes | - | - |
Billing
POST /billing/checkout
Create a Stripe Checkout session for tier upgrade.
Authentication: Session token (JWT) required Redirects user to Stripe Checkout for payment. After successful payment, a webhook will upgrade the user's tier.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | CheckoutRequest |
| Response | CheckoutResponse |
| Source | billing.py:159 |
GET /billing/free-tier-status
Get free tier usage status for the current API key (FS-6010).
Returns current usage against the 1,000 free API call limit: - Total calls used - Calls remaining - Percentage used - Whether limit is exceeded Authentication: API key required Note: Only applies to free tier keys. Paid tiers have different limits.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | ApiKeyAuth |
| Response | FreeTierStatus |
| Source | billing.py:346 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
api_key | apikeyauth | No | - | - |
POST /billing/portal
Create a Stripe Customer Portal session for invoice/payment management.
Authentication: Session token (JWT) required The Customer Portal allows users to: - View invoice history - Update payment methods - Cancel subscriptions - Download receipts
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | CustomerPortalRequest |
| Response | CustomerPortalResponse |
| Source | billing.py:230 |
GET /billing/subscription
Get current subscription status for the authenticated user.
Authentication: Session token (JWT) required Returns subscription details including tier, status, and billing period.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | SubscriptionResponse |
| Source | billing.py:291 |
POST /billing/webhook
Stripe webhook handler for payment events.
Authentication: Stripe signature verification (no JWT required) SECURITY: This endpoint MUST verify Stripe webhook signatures using the webhook secret. Never process events without verification! Handles events: - checkout.session.completed - Upgrade user tier - customer.subscription.updated - Update subscription status - customer.subscription.deleted - Downgrade to free tier - invoice.payment_succeeded - Record successful payment - invoice.payment_failed - Handle failed payment
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Request |
| Response | WebhookResponse |
| Source | billing.py:429 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
stripe_signature | str | No | - | - |
API Keys
GET /api-keys
List all API keys for the current user.
By default, only shows active keys. Use include_revoked=true to show all.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | ApiKeyListResponse |
| Source | api_keys.py:152 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
include_revoked | bool | No | False | - |
POST /api-keys
Create a new API key.
IMPORTANT: The full API key is returned ONLY ONCE. Save it immediately - it cannot be retrieved later. Key Modes: - live: Production keys (fh_live_...) - real usage, real billing - test: Test keys (fh_test_...) - sandbox, no billing Rate Limits by Tier: - Starter: 100 requests/day - Growth: 10,000 requests/day - Scale: Unlimited Maximum Keys: 10 active keys per user
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | ApiKeyCreate |
| Response | ApiKeyCreateResponse |
| Source | api_keys.py:48 |
DELETE /api-keys/{key_id}
Revoke an API key.
The key will be marked as inactive and cannot be used for authentication. The key record is kept for audit purposes.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | api_keys.py:317 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
key_id | str | Yes | - | - |
GET /api-keys/{key_id}
Get details of a specific API key.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | ApiKeyResponse |
| Source | api_keys.py:208 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
key_id | str | Yes | - | - |
PATCH /api-keys/{key_id}
Update API key name.
Only the name can be updated. Tier and other fields are immutable. To change tier, create a new key and revoke the old one.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | ApiKeyUpdate |
| Response | ApiKeyResponse |
| Source | api_keys.py:257 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
key_id | str | Yes | - | - |
Export
POST /export/csv
Export search results to CSV.
Pro tier: max 1,000 rows Advanced tier: max 10,000 rows Example: json { "type": "gps", "filters": {"state": "NY", "min_aum": 1000000000}, "fields": ["name", "city", "state", "total_aum", "fund_count"] }
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | ExportRequest |
| Source | export.py:75 |
GET /export/fields
List available fields for export.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | export.py:222 |
Usage
GET /usage
Get usage statistics for the current API key.
Returns overall usage metrics including: - Total requests (all-time) - Requests today and this month - Average response time - Last request timestamp - Per-record billing info (FS-6030) - Tier limits and remaining quota Authentication: API key required
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | ApiKeyAuth |
| Response | UsageStats |
| Source | usage.py:205 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
api_key | apikeyauth | No | - | - |
GET /usage/daily
Get daily usage breakdown for the current API key.
Returns detailed daily statistics including: - Request counts (total, successful, failed) - Response time metrics (avg, min, max, p95) - Top endpoints for each day Authentication: API key required Date Range: Last 7 days by default, max 90 days
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | ApiKeyAuth |
| Response | DailyUsageResponse |
| Source | usage.py:283 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
days | int | No | 7 | Number of days to retrieve (1-90) |
api_key | apikeyauth | No | - | - |
GET /usage/endpoints
Get statistics grouped by endpoint for the current API key.
Returns aggregated metrics for each endpoint: - Total request count - Average response time - Success rate (percentage) Authentication: API key required Date Range: Last 30 days by default, max 90 days
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | ApiKeyAuth |
| Response | EndpointStatsResponse |
| Source | usage.py:367 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
days | int | No | 30 | Number of days to analyze (1-90) |
api_key | apikeyauth | No | - | - |
Settings
GET /settings/spending-cap
Get current spending cap and usage.
Returns the user's monthly spending cap, current spend for the period, percentage used, alert thresholds, and reset date.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | SpendingCapResponse |
| Source | settings.py:163 |
PUT /settings/spending-cap
Update monthly spending cap.
Sets the user's monthly spending cap. Minimum is $10, no maximum. Cap resets on the first day of each month.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | SpendingCapUpdate |
| Response | SpendingCapResponse |
| Source | settings.py:191 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
update | spendingcapupdate | Yes | - | - |
PUT /settings/spending-cap/alerts
Update spending cap alert thresholds.
Sets the percentage thresholds at which to send spending alerts. Thresholds must be between 0-100 and will be automatically sorted.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | AlertThresholdsUpdate |
| Response | SpendingCapResponse |
| Source | settings.py:232 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
update | alertthresholdsupdate | Yes | - | - |
Admin
GET /admin/dataops/dashboard
Get combined command center dashboard data.
Single endpoint returning all data needed for a dashboard view.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | DashboardData |
| Source | dataops_admin.py:766 |
GET /admin/dataops/extractions
Get recent extraction runs.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | Optional |
| Source | dataops_admin.py:431 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
source | optional | No | None | Filter by source |
limit | int | No | 20 | - |
POST /admin/dataops/extractions/trigger
Trigger an extraction for a source.
Runs asynchronously via background task.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | TriggerExtractionRequest |
| Source | dataops_admin.py:826 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
background_tasks | backgroundtasks | Yes | - | - |
GET /admin/dataops/extractions/{run_id}
Get full details of an extraction run including diffs.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | dataops_admin.py:469 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
run_id | int | Yes | - | - |
GET /admin/dataops/freshness
Get freshness summary by entity type and source.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | dataops_admin.py:620 |
GET /admin/dataops/freshness/queue
Get refresh queue status.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | Optional |
| Source | dataops_admin.py:690 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
status | optional | No | None | - |
limit | int | No | 50 | - |
POST /admin/dataops/freshness/queue
Queue an entity for refresh.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | QueueRefreshRequest |
| Source | dataops_admin.py:916 |
POST /admin/dataops/freshness/queue/process
Trigger processing of the refresh queue.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | BackgroundTasks |
| Source | dataops_admin.py:955 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
limit | int | No | 100 | - |
background_tasks | backgroundtasks | No | None | - |
GET /admin/dataops/freshness/stale
Get stale entities ordered by staleness.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | dataops_admin.py:653 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
limit | int | No | 100 | - |
GET /admin/dataops/health
Get overall system health status.
Calculated from: - Source freshness (all sources updated within threshold) - Quality alerts (critical/warning counts) - Stale entity percentage
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | HealthStatus |
| Source | dataops_admin.py:322 |
GET /admin/dataops/overrides
Get manual override records.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | Optional |
| Source | dataops_admin.py:722 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
active_only | bool | No | True | - |
override_type | optional | No | None | - |
POST /admin/dataops/overrides
Create a manual data override.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | CreateOverrideRequest |
| Source | dataops_admin.py:982 |
DELETE /admin/dataops/overrides/{override_id}
Soft-delete a manual override.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | dataops_admin.py:1028 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
override_id | int | Yes | - | - |
GET /admin/dataops/quality
Get current data quality metrics.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | dataops_admin.py:518 |
GET /admin/dataops/quality/alerts
Get data quality alerts.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | dataops_admin.py:555 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
unresolved_only | bool | No | True | - |
POST /admin/dataops/quality/alerts/{alert_id}/acknowledge
Acknowledge a quality alert.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | AcknowledgeAlertRequest |
| Source | dataops_admin.py:859 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
alert_id | int | Yes | - | - |
POST /admin/dataops/quality/alerts/{alert_id}/resolve
Resolve a quality alert.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | ResolveAlertRequest |
| Source | dataops_admin.py:887 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
alert_id | int | Yes | - | - |
GET /admin/dataops/quality/trends
Get quality metric trends over time.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | dataops_admin.py:586 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
days | int | No | 7 | - |
GET /admin/dataops/sources
Get status of all data sources.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | dataops_admin.py:378 |
POST /admin/jobs/daily-digest
Send daily digest emails.
Triggered by Cloud Scheduler daily at 6 AM ET.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications.py:531 |
POST /admin/jobs/market-intel
Send weekly market intelligence to Premier users.
Triggered by Cloud Scheduler Monday at 8 AM ET.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications.py:542 |
POST /admin/jobs/payment-check
Check for payment failures and send dunning emails.
Triggered by Cloud Scheduler hourly.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications.py:553 |
POST /admin/jobs/process-queue
Process the notification queue.
Triggered by Cloud Scheduler every hour.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications.py:509 |
POST /admin/jobs/trial-check
Check for expiring trials and queue notifications.
Triggered by Cloud Scheduler daily at 6 AM ET.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications.py:520 |
GET /admin/notifications/
List all notification types in the registry.
Returns summary view of each notification.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | Optional |
| Source | notifications_admin.py:142 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
type | optional | No | None | Filter by type |
enabled | optional | No | None | Filter by enabled status |
POST /admin/notifications/
Create a new notification type.
The notification ID must be unique and follow snake_case naming.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | NotificationCreate |
| Response | NotificationDetail |
| Source | notifications_admin.py:289 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
create | notificationcreate | Yes | - | - |
GET /admin/notifications/analytics/overview
Get overview analytics for all notifications.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications_admin.py:475 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
days | int | No | 7 | Number of days to analyze |
GET /admin/notifications/export
Export the entire notification registry as JSON.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications_admin.py:542 |
POST /admin/notifications/import
Import notification definitions from JSON.
By default, replaces all notifications. Use merge=True to only add/update.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | dict |
| Source | notifications_admin.py:558 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
data | dict | Yes | - | - |
merge | bool | No | False | Merge with existing (vs replace) |
GET /admin/notifications/stats
Get aggregate notification statistics.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications.py:564 |
GET /admin/notifications/summary
Get summary statistics of the notification registry.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | RegistrySummary |
| Source | notifications_admin.py:185 |
GET /admin/notifications/table
Get formatted table view of all notifications (text/plain).
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications_admin.py:193 |
POST /admin/notifications/test
Send a test notification to a specific email.
Bypasses user preferences and rate limits (force=True).
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | SendTestRequest |
| Source | notifications_admin.py:362 |
DELETE /admin/notifications/{notification_id}
Delete a notification type.
WARNING: This removes the notification definition. Any scheduled sends will fail.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications_admin.py:336 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
notification_id | str | Yes | - | - |
GET /admin/notifications/{notification_id}
Get full details of a notification.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Response | NotificationDetail |
| Source | notifications_admin.py:202 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
notification_id | str | Yes | - | - |
PUT /admin/notifications/{notification_id}
Update a notification's settings.
Only provided fields are updated.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | NotificationUpdate |
| Response | NotificationDetail |
| Source | notifications_admin.py:222 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
notification_id | str | Yes | - | - |
update | notificationupdate | Yes | - | - |
POST /admin/notifications/{notification_id}/disable
Disable a notification.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications_admin.py:267 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
notification_id | str | Yes | - | - |
POST /admin/notifications/{notification_id}/enable
Enable a notification.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications_admin.py:249 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
notification_id | str | Yes | - | - |
GET /admin/notifications/{notification_id}/stats
Get analytics for a specific notification type.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Source | notifications_admin.py:411 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
notification_id | str | Yes | - | - |
days | int | No | 7 | Number of days to analyze |
Other
POST /hbs/survey
Submit monthly HBS feedback survey.
Required for continued free access. Surveys can only be submitted once per calendar month.
| Property | Value |
|---|---|
| Auth Required | Yes |
| Request Body | HBSSurveyRequest |
| Source | hbs.py:108 |
POST /hbs/verify
Verify HBS student email for free tier access.
Validates email matches @mbaYYYY.hbs.edu pattern where YYYY is current year or future (valid graduation year).
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | HBSVerifyRequest |
| Source | hbs.py:68 |
GET /track/click/{tracking_id}
Click tracking endpoint.
Called when user clicks a tracked link. Records the click and redirects to the original URL.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | notifications.py:337 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
tracking_id | str | Yes | - | - |
url | str | No | Ellipsis | Base64-encoded destination URL |
GET /track/open/{tracking_id}.png
Tracking pixel endpoint.
Called when email is opened (image loads). Records the open event and returns a 1x1 transparent PNG.
| Property | Value |
|---|---|
| Auth Required | No |
| Source | notifications.py:304 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
tracking_id | str | Yes | - | - |
GET /unsubscribe/{token}
One-click unsubscribe endpoint (GET for email client compatibility).
Returns a simple HTML page confirming the unsubscription.
| Property | Value |
|---|---|
| Auth Required | No |
| Request Body | Optional |
| Source | notifications.py:454 |
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
token | str | Yes | - | - |
category | optional | No | None | - |
Legal
GET /legal/entity-info
Get legal entity information.
Returns structured information about Harris Capital Management LLC, the legal entity operating Firmhound. Returns: json { "legal_name": "Harris Capital Management LLC", "entity_type": "Limited Liability Company", "state_of_formation": "Wyoming", "entity_id": "2025-001685419", "status": "Active", "contact": { "legal": "legal@firmhound.com", "privacy": "privacy@firmhound.com", "support": "support@firmhound.com" } }
| Property | Value |
|---|---|
| Auth Required | No |
| Source | legal.py:108 |
GET /legal/privacy
Get the Privacy Policy (when available).
Status: Not yet implemented Planned: Will return full Privacy Policy in Markdown format
| Property | Value |
|---|---|
| Auth Required | No |
| Source | legal.py:94 |
GET /legal/terms
Get the API Terms of Service.
Returns the full Terms of Service document in Markdown format. This is the same document available at docs/legal/api-terms-of-service.md Use this endpoint to: - Display ToS in your application - Verify current terms before accepting - Archive ToS versions for compliance Returns: Full ToS document (Markdown)
| Property | Value |
|---|---|
| Auth Required | No |
| Source | legal.py:35 |
GET /legal/terms/version
Get current ToS version metadata.
Returns structured version information without the full document. Useful for checking if terms have been updated. Returns: json { "version": "1.0", "effective_date": "2026-01-01", "last_updated": "2025-12-11" }
| Property | Value |
|---|---|
| Auth Required | No |
| Source | legal.py:53 |