REST API

Every endpoint is versioned under /api/v1 and returns snake_case JSON. Send an API key as X-API-Key: rsc_...; a key sent as a Bearer token is not recognised. A signed-in browser sends its session cookie, and the session token from /auth/verify can be sent as Authorization: Bearer <token>. Browse the interactive reference at /swagger or download the raw OpenAPI 3.1 spec. Need a key? Grab one from your Integrations tab.

Access

public
No credentials needed. What comes back can still depend on who is asking: see each endpoint.
signed-in
Any session or API key.
session
A signed-in user. API keys are refused, because a key has no user of its own.
provider-admin
A session whose organisation role is admin, a platform administrator, or an API key of the provider's organisation created with the admin scope, which only an organisation admin can grant. Other members, and keys without that scope, are refused.
org-admin
A session whose organisation role is admin. API keys and other members are refused.
platform-admin
Platform administrators only.
ingest
Any session, or an API key created with the ingest scope.

Buy-Side

13 endpoints

Cross-library research, watchlists, content access, and analytics for buy-side users.

Open in Swagger ›

Research & Search

GET/api/v1/searchaccess: signed-in

Full-text search across every provider's research. Results from providers the caller is not entitled to keep their descriptive metadata, with the rating and price target withheld. Filters: q, sectors, tickers, provider_ids, rating, note_types, analysts, published_since. Anonymous callers are admitted only on a public branded portal, scoped to its provider.

GET/api/v1/feedaccess: signed-in

Paginated feed of the latest notes from entitled providers. Filters: sectors, analysts, tickers, provider_id, note_type, since, rating_changes, language. Anonymous callers are admitted only on a public branded portal, scoped to its provider.

GET/api/v1/notes/{id}/contentaccess: signed-in

Entitlement-checked access to a note: returns its content URL and format, and records the read.

GET/api/v1/notes/{id}/content/streamaccess: signed-in

Streams a note's content. Hosted PDFs are watermarked for the reader; notes hosted by the provider redirect (302) to its URL.

Watchlists

GET/api/v1/watchlistaccess: session

List every watchlist for the signed-in user with the tickers each contains.

POST/api/v1/watchlistaccess: session

Create a new named watchlist.

POST/api/v1/watchlist/{name}/tickersaccess: session

Add a ticker to a watchlist.

DELETE/api/v1/watchlist/{name}/tickers/{ticker}access: session

Remove a ticker from a watchlist.

Coverage & Analysts

GET/api/v1/coverageaccess: public

Coverage map across the caller's entitled providers, ranked by note count. Anonymous callers get an empty list, except on a public branded portal, where they see its provider's coverage.

GET/api/v1/analystsaccess: public

Analyst discovery across the caller's entitled providers, ranked by published-note count. Anonymous callers get an empty list, except on a public branded portal, where they see its provider's analysts.

Analytics

GET/api/v1/buy-side/analytics/myaccess: session

The signed-in user's own research activity over the last 30 days (days sets the window, from 1 to 365): counts of searches, feed pages, note requests and note streams, a per-day series, and the notes most recently opened. An API key is refused, because a key has no user of its own.

GET/api/v1/buy-side/analytics/teamaccess: org-admin

Per-member usage across the caller's organisation over the last 30 days; days sets the window, from 1 to 365.

Portal

GET/api/v1/portal/configaccess: public

Branded portal configuration for the requesting hostname (Cloudflare-routed subdomain).

Sell-Side

39 endpoints

Provider self-service: profile, entitlements, templates, billing, and rate limits. Reads are open to anyone signed in to the provider's organisation; changes need a provider admin.

Open in Swagger ›

Provider Profile

GET/api/v1/providersaccess: signed-in

Provider directory with display name, health status, metadata mode, note count, and latest note.

GET/api/v1/providers/meaccess: signed-in

The caller's own provider profile.

PATCH/api/v1/providers/meaccess: provider-admin

Update the provider's display name and metadata mode.

GET/api/v1/providers/me/portalaccess: signed-in

Provider portal configuration: branding, slug, primary colour, custom config.

PATCH/api/v1/providers/me/portalaccess: provider-admin

Update branded portal configuration.

Research Ingestion

POST/api/v1/ingestaccess: ingest

Push research note metadata to the hub (sell-side ingestion). A batch is written only to the caller's own provider.

Entitlements & Access

GET/api/v1/providers/me/entitlementsaccess: signed-in

List clients entitled to this provider's research, joined to org name.

POST/api/v1/providers/me/entitlements/grantaccess: provider-admin

Grant a client organisation access to this provider (buy_side_org_id, optional access_type, expires_at and template_id). Re-granting updates the one entitlement, re-activating a revoked one. An organisation that owns another research provider is refused (422), an unknown one is 404.

POST/api/v1/providers/me/entitlements/{id}/revokeaccess: provider-admin

Revoke an entitlement (sets access type to blocked).

PATCH/api/v1/providers/me/entitlements/{id}/scope-modeaccess: provider-admin

Toggle user-level scoping on an entitlement.

POST/api/v1/providers/me/entitlements/{id}/user-access/bulkaccess: provider-admin

Bulk-set per-user allow/deny/clear on a user-scoped entitlement.

POST/api/v1/providers/me/entitlements/{id}/apply-templateaccess: provider-admin

Bind a template to an entitlement, copying its rules.

Clients & Contacts

POST/api/v1/providers/me/orgsaccess: provider-admin

Create a client organisation (name, optional domain, org_type, institution_type, regions, asset_classes), or attach to the existing one its email domain identifies when that organisation is already yours. A domain registered to an organisation outside your reach is refused (409) without naming it.

POST/api/v1/providers/me/contacts:bulk-upsertaccess: provider-admin

Add people to your client organisations, or update their names: up to 500 rows of buy_side_org_id, email, display_name and role, with one outcome per row (created, updated, or skipped with the reason). No email is sent. preview: true reports the outcomes and writes nothing.

POST/api/v1/providers/me/contacts/{userId}:archiveaccess: provider-admin

Remove a person who has left a client firm: archives the account, drops their per-user grants, cancels unused sign-in links, ends their sessions and revokes API keys they created. Refused with 409 org_shared_with_other_providers when other providers also serve the firm (deny them per user on your own entitlement instead), 403 for a peer broker's staff, 409 for a firm's last admin.

POST/api/v1/providers/me/contacts/{userId}:unarchiveaccess: provider-admin

Restore a removed contact, under the same rules. Access rights are not restored; re-grant what they should read.

POST/api/v1/providers/me/contacts:bulk-archiveaccess: provider-admin

Remove many contacts at once: user_ids, up to 500 per call. Each person goes through the single removal's rules, so one refusal never fails the batch: the answer counts succeeded, unchanged, refused and failed, then gives one row per id with its outcome (removed, already_removed, refused or failed) and, when refused, the same code and detail the single route returns.

POST/api/v1/providers/me/contacts:bulk-unarchiveaccess: provider-admin

Restore many removed contacts at once, under the same rules and with the same per-id answer (restored, not_archived, refused or failed). Access rights are not restored.

POST/api/v1/providers/me/contacts:bulk-categoriseaccess: provider-admin

Move client contacts between your Institutional and Corporate lists: user_ids (up to 500), categories (institutional and/or corporate) and mode (add keeps any other list the person is on, remove takes one away, set makes the list exactly what you name). One row per id: changed, unchanged, or refused with contact_not_found, not_a_client_contact (a portal registrant or your own staff) or last_category (a contact always keeps one).

Templates

GET/api/v1/providers/me/templatesaccess: signed-in

List access templates owned by this provider with rules + client counts.

POST/api/v1/providers/me/templatesaccess: provider-admin

Create a new access template.

POST/api/v1/providers/me/templates/{id}/rulesaccess: provider-admin

Add a rule to a template (sector, analyst, ticker, region, etc.).

POST/api/v1/providers/me/templates/{id}/syncaccess: provider-admin

Re-apply the template's current rules to every linked entitlement.

Team & Delegation

GET/api/v1/providers/me/teamaccess: provider-admin

Every active user in the provider's organisation, with a summary of the coverage and template-editor rights each holds.

GET/api/v1/providers/me/team/{userId}/coverageaccess: provider-admin

The (exchange, ticker) pairs one analyst covers. A member may also read their own. A userId outside the caller's organisation is 404, not 403.

POST/api/v1/providers/me/team/{userId}/coverageaccess: org-admin

Give an analyst coverage of one (exchange, ticker), so their forecast ingests for it pass without provider-admin escalation. The grant is attributed to the caller, so an API key is refused: it has no user to record.

DELETE/api/v1/providers/me/team/{userId}/coverage/{coverageId}access: provider-admin

Withdraw one coverage grant.

GET/api/v1/providers/me/team/{userId}/template-grantsaccess: provider-admin

The forecast templates one analyst may edit the structure of. A member may also read their own.

POST/api/v1/providers/me/team/{userId}/template-grantsaccess: org-admin

Let an analyst edit one forecast template, which must belong to the caller's provider. Attributed like the coverage grant, so an API key is refused.

DELETE/api/v1/providers/me/team/{userId}/template-grants/{grantId}access: provider-admin

Withdraw one template-editor grant. Open to a key, unlike the grant: withdrawing records no attribution.

Analytics & Payouts

GET/api/v1/providers/me/analyticsaccess: signed-in

Aggregate provider analytics: client counts, note counts, content access, templates.

GET/api/v1/providers/me/analytics/usageaccess: signed-in

Usage dashboard with active client count, note count, and 30-day publication count.

GET/api/v1/providers/me/analytics/clientsaccess: signed-in

Per-client metrics with org name and access status.

GET/api/v1/providers/me/analytics/trendsaccess: signed-in

Monthly publication trend data for the dashboard chart.

GET/api/v1/providers/me/analytics/payoutsaccess: signed-in

Provider payout summary from completed purchases, totalled per currency (by_currency); never summed across currencies.

Pricing & Rate Limits

GET/api/v1/providers/me/pricingaccess: signed-in

List pricing tiers for this provider.

POST/api/v1/providers/me/pricingaccess: provider-admin

Create a new pricing tier (per-note or bundle pricing).

GET/api/v1/providers/me/rate-limitsaccess: signed-in

List rate-limit rules configured for this provider.

POST/api/v1/providers/me/rate-limitsaccess: provider-admin

Create a new rate-limit rule (per-org, per-user, or global).

Admin & Protocol

10 endpoints

Platform administration, and protocol-wide analytics any signed-in caller can read. Routes under /api/v1/admin and /api/v1/entitlements/platform are also reachable only from allow-listed IP addresses.

Open in Swagger ›

Admin Operations

POST/api/v1/admin/providersaccess: platform-admin

Create a new provider record (admin onboarding).

GET/api/v1/admin/entitlementsaccess: platform-admin

Paged list of every entitlement with org names.

POST/api/v1/admin/entitlements/grantaccess: platform-admin

Protocol-level entitlement grant (any org to any provider).

POST/api/v1/entitlements/platform/revokeaccess: platform-admin

Protocol-level entitlement revoke for any organisation and provider.

GET/api/v1/admin/monitoringaccess: platform-admin

Live system health: PostgreSQL, Redis, per-provider health and counts.

GET/api/v1/audit-logsaccess: platform-admin

Immutable audit log: every API request with caller, status, duration, and error detail.

Protocol Analytics

GET/api/v1/analytics/networkaccess: signed-in

Protocol-wide totals: providers, organisations, notes, transactions.

GET/api/v1/analytics/coverageaccess: signed-in

Protocol-wide coverage map ranked by distinct note count.

GET/api/v1/analytics/velocityaccess: signed-in

Protocol-wide research velocity over the last 30 days.

GET/api/v1/analytics/analystsaccess: signed-in

Protocol-wide analyst league table by published-note count.

Auth & Identity

10 endpoints

Magic-link login, session lifecycle, API key management, and CSRF protection.

Open in Swagger ›

Authentication

POST/api/v1/auth/magic-linkaccess: public

Issue a magic-link email to start a session.

POST/api/v1/auth/verifyaccess: public

Exchange a magic-link token for a session cookie + Bearer token.

POST/api/v1/auth/logoutaccess: public

Sign out: revokes every session the signed-in user holds, not only this one, and clears the session cookie. Safe to call when already signed out.

GET/api/v1/auth/csrfaccess: public

Issue an anti-forgery token for cookie-authenticated state changes.

API Keys

GET/api/v1/api-keysaccess: session

List API keys for the caller's organisation (metadata only).

POST/api/v1/api-keysaccess: session

Create a new API key. Raw key returned once. A key cannot hold the ingest or admin scope unless the session creating it does.

DELETE/api/v1/api-keys/{id}access: session

Revoke an API key. An org admin may revoke any of the organisation's keys; any other member only a key they created.

Health & Billing

GET/api/v1/healthaccess: public

Readiness probe: overall status plus a per-check status for the database, Redis and schema parity.

POST/api/v1/billing/purchaseaccess: signed-in

Starts a per-note purchase: records a pending purchase priced from the note's pricing tier, with the hub fee and provider payout.

POST/api/v1/webhooks/stripeaccess: public

Stripe webhook receiver, signature-verified. A completed checkout confirms the purchase and grants access; a refund or dispute revokes it.