Developers · REST API
Cited company diligence, over one REST API.
Search companies, run diligence as jobs, read every report section with its freshness, and search leads and trigger events — the same data, paywall and credits as the app, behind a scoped workspace API key.
49
operations
5
resource groups
7
API-key scopes
v1.0.0
OpenAPI 3.1.0
What you can do
Everything the dashboard does, as endpoints.
Every operation below is served by the same code paths as the app, so a report section or lead row reads the same over the API.
Companies & reports
Search companies, read the report
GET /v1/companies/search spans your workspace, the tracked corpus and public registries. Read the whole report or one section, its provenance, the memo, citations and structured evidence.Jobs
Diligence runs as jobs
POST …/diligence-runs answers 202 with a job at once; poll GET /v1/jobs/{job_id}. A second start while one is active returns the same job.Monitoring
Watchlist and alerts
POST /v1/alerts/{alert_id}/ack.Leads
Lead search and trigger feed
POST /v1/leads/search), the dated trigger-event feed, saved searches with alerts, and lists.Contacts · metered
Reveal contacts, export leads
POST /v1/leads/export/quote; already-revealed contacts and exported rows are free.Account
Credits and balances
GET /v1/credits returns remaining diligence assessments and lead-credit balances, so a client can check before it spends.Quickstart
From API key to report in three calls.
Create a key in Settings → API keys, add a company, start a diligence run and read the report.
- Base URL
https://marketprior-diligence.fly.dev - Adding a company is free and idempotent by name
- A run on a new company spends one assessment; re-runs are free
- The free screen is readable before any unlock
export MARKETPRIOR_API_KEY=mp_... # Settings → API keys
# 1. Add the company (free; idempotent by name) → company.id
curl -X POST "https://marketprior-diligence.fly.dev/v1/companies" \
-H "Authorization: Bearer $MARKETPRIOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Acme Payments", "domain": "acmepay.com"}'
# 2. Start a diligence run → 202 + a job; poll GET /v1/jobs/{job_id}
curl -X POST "https://marketprior-diligence.fly.dev/v1/companies/$COMPANY_ID/diligence-runs" \
-H "Authorization: Bearer $MARKETPRIOR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"
# 3. Read the report: every section's status + freshness
curl "https://marketprior-diligence.fly.dev/v1/companies/$COMPANY_ID/report" \
-H "Authorization: Bearer $MARKETPRIOR_API_KEY"import os, time, requests
BASE = "https://marketprior-diligence.fly.dev"
H = {"Authorization": f"Bearer {os.environ['MARKETPRIOR_API_KEY']}"}
company = requests.post(f"{BASE}/v1/companies", headers=H,
json={"name": "Acme Payments", "domain": "acmepay.com"}).json()["company"]
job = requests.post(f"{BASE}/v1/companies/{company['id']}/diligence-runs", headers=H).json()
while job["status"] in ("queued", "running"):
time.sleep(5)
job = requests.get(f"{BASE}/v1/jobs/{job['id']}", headers=H).json()
report = requests.get(f"{BASE}/v1/companies/{company['id']}/report", headers=H).json()Auth & scopes
One key, one workspace, least privilege.
Send the key as Authorization: Bearer mp_… or X-API-Key: mp_…. Keys are stored hashed, revocable, and run as their own workspace. Each operation names its x-required-scope; a missing scope is 403 insufficient_scope.
| Scope | Grants |
|---|---|
| reports:read | Read companies, report sections, memos, alerts, jobs and credit balances. |
| diligence:run | Add companies and start diligence runs (a new company spends one assessment). |
| monitor:write | Acknowledge monitoring alerts; add/remove watchlist subjects (uses plan monitor slots). |
| leads:read | Lead search, trigger feed, saved searches, alerts and masked contacts. |
| leads:write | Create/update/delete saved searches and lists, mark lead alerts read, add registry companies to the corpus, report lead outcomes (sent / bounced / replied …). |
| leads:reveal | Reveal a contact's details (metered: spends lead credits).metered |
| leads:export | Export leads as CSV (metered: spends lead credits).metered |
Operating model
Paywall, limits, retries, pages, freshness.
The rules every endpoint follows, so a client can be written once.
402 report_locked — the paywall
The free screen (fused_scorecard, risk_score, upside_score and their citations) is always readable. Other sections answer 402 with report_locked until the company’s report is unlocked — the same decision the dashboard makes. Never render a guess in its place.
const res = await fetch(`https://marketprior-diligence.fly.dev/v1/companies/${id}/sections/hiring`, {
headers: { Authorization: `Bearer ${process.env.MARKETPRIOR_API_KEY}` },
});
if (res.status === 402) {
// error.code === "report_locked" — unlock the report; never guess the content
} else {
const section = await res.json(); // payload + freshness
}Errors — one envelope
Every error, including validation and rate limiting, is {"error": {code, message, status, details}} with a stable machine-readable code: report_locked, lead_credits_required, upgrade_required, insufficient_scope, rate_limited, not_found…
HTTP/1.1 402 Payment Required
{
"error": {
"code": "report_locked",
"message": "This section is part of the paid company report. …",
"status": 402,
"details": { … }
}
}Rate limits
Per key, 120 requests/minute by default, shared by REST and MCP. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; over the limit you get 429 with Retry-After.
HTTP/1.1 200 OK
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: …
HTTP/1.1 429 Too Many Requests
Retry-After: …
{ "error": { "code": "rate_limited", "status": 429, … } }Idempotency keys
Send Idempotency-Key: <≤255 chars> on any POST /v1/…. A retry with the same key and body replays the first response (marked Idempotent-Replayed: true) and is never charged twice. The same key with a different body is 422 idempotency_key_reused; one still in flight is 409 idempotency_request_in_progress.
curl -X POST "https://marketprior-diligence.fly.dev/v1/companies/$COMPANY_ID/diligence-runs" \
-H "Authorization: Bearer $MARKETPRIOR_API_KEY" \
-H "Idempotency-Key: run-$COMPANY_ID-2026-09"Cursor pagination
List endpoints return {data, next_cursor, has_more}. Pass cursor=<next_cursor> back until has_more is false.
GET /v1/companies?limit=20
{ "data": [ … ], "next_cursor": "…", "has_more": true }
GET /v1/companies?limit=20&cursor=<next_cursor>Freshness on every section
Each section carries freshness — when it was computed, its age and status — and GET …/freshness lists them all. POST …/refresh re-fetches stale sections for free.
"freshness": {
"computed_at": "…",
"age_seconds": 5400,
"status": "…",
"as_of": "…"
}Reference
49 operations, generated from the spec.
This table is built from the live OpenAPI document (OpenAPI 3.1.0, API v1.0.0) with the scope each operation needs. Machine-readable: https://marketprior-diligence.fly.dev/v1/openapi.json
Companies & reports 15
| Method | Path | Summary | Scope |
|---|---|---|---|
| GET | /v1/companies | List your companies | reports:read |
| POST | /v1/companies | Add a company | diligence:run |
| GET | /v1/companies/search | Search companies | reports:read |
| GET | /v1/companies/{company_id} | Get a company | reports:read |
| GET | /v1/companies/{company_id}/report | Get the full report | reports:read |
| GET | /v1/companies/{company_id}/sections/{section} | Get one report section | reports:read |
| GET | /v1/companies/{company_id}/sections/{section}/provenance | Section provenance | reports:read |
| GET | /v1/companies/{company_id}/memo | Get the investment memo | reports:read |
| GET | /v1/companies/{company_id}/citations | Source-linked findings | reports:read |
| GET | /v1/companies/{company_id}/data | Structured evidence rows | reports:read |
| GET | /v1/companies/{company_id}/benchmark | Live cohort benchmark | reports:read |
| GET | /v1/companies/{company_id}/founder-screening | Founder screening candidates | reports:read |
| GET | /v1/companies/{company_id}/freshness | Section freshness | reports:read |
| POST | /v1/companies/{company_id}/refresh | Refresh stale sections | diligence:run |
| POST | /v1/companies/{company_id}/diligence-runs | Start a diligence run | diligence:run |
Jobs 2
| Method | Path | Summary | Scope |
|---|---|---|---|
| GET | /v1/jobs | List recent jobs | reports:read |
| GET | /v1/jobs/{job_id} | Get a job | reports:read |
Monitoring 5
| Method | Path | Summary | Scope |
|---|---|---|---|
| GET | /v1/alerts | List monitoring alerts | reports:read |
| POST | /v1/alerts/{alert_id}/ack | Acknowledge an alert | monitor:write |
| GET | /v1/watchlist | List the monitoring watchlist | reports:read |
| POST | /v1/watchlist | Add to the watchlist | monitor:write |
| DELETE | /v1/watchlist/{subject_id} | Remove from the watchlist | monitor:write |
Leads 26
| Method | Path | Summary | Scope |
|---|---|---|---|
| GET | /v1/contacts/companies/{company_id} | Get Company Contacts | leads:read |
| POST | /v1/contacts/companies/{company_id}/refresh | Request Refresh | leads:read |
| GET | /v1/leads/credits | Get Credits | leads:read |
| POST | /v1/leads/outcomes | Post Outcomes | leads:write |
| GET | /v1/leads/outcomes/stats | Outcome Stats | leads:read |
| GET | /v1/leads/events | List Events | leads:read |
| POST | /v1/leads/search | Search | leads:read |
| GET | /v1/leads/companies/suggest | Suggest Companies | leads:read |
| POST | /v1/leads/companies/add | Add Company | leads:write |
| GET | /v1/leads/jobs/{job_id} | Get Lead Job | leads:read |
| GET | /v1/leads/companies/{company_id}/enrichment | Get Company Enrichment | leads:read |
| GET | /v1/leads/saved-searches | List Saved Searches | leads:read |
| POST | /v1/leads/saved-searches | Create Saved Search | leads:write |
| PATCH | /v1/leads/saved-searches/{search_id} | Update Saved Search | leads:write |
| DELETE | /v1/leads/saved-searches/{search_id} | Delete Saved Search | leads:write |
| GET | /v1/leads/saved-searches/{search_id}/preview | Preview Saved Search | leads:read |
| GET | /v1/leads/alerts | List Alerts | leads:read |
| POST | /v1/leads/alerts/{alert_id}/read | Read Alert | leads:write |
| POST | /v1/leads/export/quote | Export Quote | leads:read |
| POST | /v1/leads/export | Export | leads:export |
| POST | /v1/leads/contacts/{contact_id}/reveal | Reveal Contact | leads:reveal |
| GET | /v1/leads/lists | Get Lists | leads:read |
| POST | /v1/leads/lists | Create List | leads:export |
| POST | /v1/leads/lists/{list_id}/companies | Add To List | leads:export |
| GET | /v1/leads/lists/{list_id} | Get List | leads:read |
| DELETE | /v1/leads/lists/{list_id} | Delete List | leads:write |
Account 1
| Method | Path | Summary | Scope |
|---|---|---|---|
| GET | /v1/credits | Credit balances | reports:read |
FAQ
API questions.
Prefer an agent? The same operations are tools on the MarketPrior MCP server. Credits and plans are on pricing; what feeds each section is on data sources.
How do I authenticate with the MarketPrior API?
What does a 402 report_locked response mean?
What costs credits?
Can a retried request charge me twice?
What are the rate limits?
Is there an OpenAPI spec?
Get an API key and make your first call.
Start free, create a key in Settings → API keys, and read a company’s free screen in one request.