Docs · API reference

The Felarity API.

A small, predictable REST surface. Bearer-token auth with per-key scopes, per-key rate limits, and per-call audit rows.

The public API is intentionally narrow. It exposes what an integration actually needs — usage, workspace membership, reports — and nothing else. The forensic pipeline itself is driven from the web app and the in-meeting endpoints; the API exists so your downstream systems (BI tools, retention pipelines, compliance archives) can read the artifacts the pipeline produces.

1. Base URL

All endpoints live under a single, versioned host:

https://api.felarity.com/v1

A machine-readable OpenAPI 3.1 document is published at /api/openapi.json on the same host. It is the canonical schema; if this page and the spec disagree, the spec wins.

Browser-only endpoints. A handful of endpoints — meeting transcription, MFA setup, account deletion, Stripe checkout — require an active web-app session and are not callable with an API key. They are documented separately under Docs → Web app.

2. Authentication

Authenticate by sending a Bearer token in the Authorization header. Tokens are prefixed flrt_ and are minted in the web app at app.felarity.com/settings/ under API keys.

curl https://api.felarity.com/v1/usage \
  -H "Authorization: Bearer flrt_live_8a4f...e02c"

Each token has a name, a scope, an optional expiry, and a creation timestamp. The full secret is displayed exactly once at creation time — after that the dashboard shows only the prefix (flrt_live_8a4f…) and a SHA-256 fingerprint. If you lose a key, revoke it and mint a new one; there is no recovery path.

Key lifecycle endpoints are themselves web-session-only — you cannot mint or revoke keys with another key:

3. Rate limits

Each key has its own bucket. The default is 60 requests per minute, sliding window. Limits can be raised per key on Professional and Enterprise plans — ask hello@felarity.com.

When you exceed the bucket you get a 429 Too Many Requests with a structured body:

HTTP/1.1 429 Too Many Requests
Retry-After: 14
Content-Type: application/json

{
  "error": "rate_limited",
  "limit_per_min": 60,
  "retry_after_seconds": 14
}

The Retry-After header is authoritative. Back off by that many seconds; do not retry tighter.

4. Scopes

Every key carries exactly one scope string. There are two:

Scope

read

Default for new keys. Permits all GET endpoints and POST /v1/verify (which is also unauthenticated). Cannot mutate state.

Scope

read,write

Reserved for forthcoming write endpoints (workspace member invitations, report tagging, webhook subscriptions). Today it behaves identically to read. We are publishing the scope name now so you can mint keys with the right permission before the write surface ships.

Scopes are checked on every request. A read key calling a write endpoint receives 403 insufficient_scope.

5. Endpoints

The full v1 surface is five endpoints. Four are authenticated reads. One — verify — is public.

Method Path Auth Purpose
GET/v1/usageBearerCurrent period usage + plan limits
GET/v1/workspaceBearerWorkspace metadata and seat counts
GET/v1/reportsBearerList session reports (paginated)
GET/v1/reports/<id>BearerFull report JSON + attestation chain
POST/v1/verifyPublicVerify an Ed25519-signed report

GET /v1/usage

Returns the calling workspace's usage for the current Stripe billing period and the limits enforced by its plan.

curl https://api.felarity.com/v1/usage \
  -H "Authorization: Bearer flrt_live_..."
{
  "workspace_id": "wks_3kQ9...",
  "plan": "professional",
  "period_start": "2026-06-01T00:00:00Z",
  "period_end": "2026-07-01T00:00:00Z",
  "meeting_minutes_used": 482,
  "meeting_minutes_limit": 1500,
  "ask_calls_used": 217,
  "ask_calls_limit": 2000,
  "reports_generated": 31,
  "seats_active": 6,
  "seats_limit": 10
}

GET /v1/workspace

Returns workspace metadata: name, owner, plan, region, created-at, and the public Ed25519 verification key fingerprint that signs reports issued to this workspace.

curl https://api.felarity.com/v1/workspace \
  -H "Authorization: Bearer flrt_live_..."
{
  "workspace_id": "wks_3kQ9...",
  "name": "Northbridge Legal",
  "plan": "professional",
  "region": "us-east",
  "created_at": "2026-02-14T16:08:11Z",
  "owner_email": "katherine@northbridge.example",
  "seats_active": 6,
  "signing_key_fingerprint": "ed25519:3c8a:91f0:...:bb24"
}

GET /v1/reports

Lists post-session reports, newest first. Supports cursor pagination via ?after= and ?limit= (max 100). Reports appear in the list within roughly thirty seconds of the post-session pipeline completing.

curl "https://api.felarity.com/v1/reports?limit=20" \
  -H "Authorization: Bearer flrt_live_..."
{
  "data": [
    {
      "id": "rpt_8h4j2L...",
      "session_id": "sess_2k...",
      "industry": "legal",
      "title": "Settlement call — Northbridge v. Atlas",
      "duration_seconds": 2841,
      "contradiction_count": 4,
      "speaker_count": 3,
      "created_at": "2026-06-06T19:12:44Z",
      "attestation_root": "sha256:8e1c...90fa"
    }
  ],
  "next_cursor": "rpt_8h4j2L..."
}

GET /v1/reports/<id>

Returns the full structured report: speakers, transcript with diarization, contradictions with attribution, acoustic markers, topology graph, council synthesis, and the eight-node Merkle attestation chain with its Ed25519 signature.

curl https://api.felarity.com/v1/reports/rpt_8h4j2L... \
  -H "Authorization: Bearer flrt_live_..."

The response is large — a one-hour meeting typically produces a 200–600 KB JSON document. We strongly recommend streaming and incremental parsing. The attestation object at the root contains everything /v1/verify needs:

{
  "id": "rpt_8h4j2L...",
  "session_id": "sess_2k...",
  "industry": "legal",
  "speakers": [ ... ],
  "transcript": [ ... ],
  "contradictions": [ ... ],
  "acoustic": { ... },
  "topology": { ... },
  "council_synthesis": "...",
  "attestation": {
    "version": 1,
    "algorithm": "ed25519",
    "nodes": [
      { "name": "audio_capture",          "hash": "sha256:..." },
      { "name": "transcription",          "hash": "sha256:..." },
      { "name": "contradiction_pre",      "hash": "sha256:..." },
      { "name": "diarization",            "hash": "sha256:..." },
      { "name": "attribution_binding",    "hash": "sha256:..." },
      { "name": "acoustic_analysis",      "hash": "sha256:..." },
      { "name": "topology",               "hash": "sha256:..." },
      { "name": "final_report",           "hash": "sha256:..." }
    ],
    "merkle_root": "sha256:8e1c...90fa",
    "signed_at": "2026-06-06T19:12:51Z",
    "signature": "base64:MEUCIQ...",
    "signing_key_fingerprint": "ed25519:3c8a:91f0:...:bb24"
  }
}

POST /v1/verify

The verifier is public, unauthenticated, and idempotent. It accepts an attestation object and returns whether the Merkle root is internally consistent and whether the signature validates against the current Felarity public key.

This is the endpoint your counsel, your auditor, or opposing counsel will call. It does not require an account. The same logic runs offline against the public key published at /.well-known/felarity-signing-key.pem — you do not have to trust our verifier to verify a Felarity-signed report.

curl -X POST https://api.felarity.com/v1/verify \
  -H "Content-Type: application/json" \
  -d @attestation.json
{
  "ok": true,
  "merkle_root_recomputed": "sha256:8e1c...90fa",
  "signature_valid": true,
  "signing_key_fingerprint": "ed25519:3c8a:91f0:...:bb24",
  "signed_at": "2026-06-06T19:12:51Z",
  "node_count": 8
}

If the Merkle root does not match the supplied nodes, or the signature does not validate, ok is false and the response names which check failed. We never report "true" when either condition is in doubt.

6. Webhooks

Not in v1. The shape we are designing for v1.1 (Q4 2026):

Deliveries will be signed with the same Ed25519 key as reports, with HMAC-SHA256 over the body for transit verification. If you have a use case you would not want us to break, tell us before the spec freezes.

7. SDKs

Official Python and JavaScript SDKs are in development. Until they ship, both languages talk to the API perfectly well with their standard HTTP clients — the surface is too small to need a wrapper. Examples:

# Python
import requests

r = requests.get(
    "https://api.felarity.com/v1/reports",
    headers={"Authorization": f"Bearer {key}"},
    params={"limit": 50},
    timeout=15,
)
r.raise_for_status()
for report in r.json()["data"]:
    print(report["id"], report["title"])
// JavaScript (Node 20+ / modern browsers)
const r = await fetch("https://api.felarity.com/v1/reports?limit=50", {
  headers: { Authorization: `Bearer ${key}` },
});
if (!r.ok) throw new Error(`felarity: ${r.status}`);
const { data } = await r.json();
for (const report of data) {
  console.log(report.id, report.title);
}

8. Audit

Every authenticated call writes one row to the workspace audit log. The row captures key fingerprint, endpoint, HTTP status, response size, originating IP, user agent, and timestamp. It does not capture the request body or the response body — only metadata.

Workspace owners can export the audit log from app.felarity.com/settings/Audit log, as CSV or NDJSON. Retention follows your plan's data retention setting; Enterprise customers can lift retention or pipe a copy to their own SIEM on request.

9. Errors

Error responses share a single shape: a JSON object with at minimum an error string. Endpoint-specific responses may add fields (for example, limit_per_min on a 429).

{
  "error": "insufficient_scope",
  "required_scope": "read,write",
  "key_scope": "read"
}

Common status codes:

StatusMeaningWhat to do
400Malformed request — missing field, bad cursor, invalid JSONFix the request. Errors are descriptive; the error string names the field.
401Missing, malformed, or revoked Bearer tokenRe-issue the key. Revoked keys never come back.
403Key is valid but does not have scope or workspace accessCheck the key's scope and which workspace it belongs to.
404Resource does not exist or belongs to a different workspace404 is returned for both cases on purpose; we do not confirm the existence of resources you can't see.
429Rate limit exceededHonor Retry-After. Back off, do not hammer.
5xxOur problemRetry idempotent reads with exponential backoff. Check /trust/ for incident status.

10. Versioning

The current major version is v1. We do not change the meaning of an existing field in v1; we only add fields. Adding a new field is not a breaking change — write clients that ignore unknown fields.

Breaking changes ship as v2, served from /v2, alongside v1. When v2 ships we publish a deprecation calendar for v1 with a minimum of twelve months of overlap. The deprecation date is announced on this page, on the changelog, and by email to every workspace owner whose key has called v1 in the prior 30 days.

Stuck?

Talk to a human.

Integration questions, schema feedback, write-surface use cases — hello@felarity.com. For vulnerabilities, security@felarity.com or the disclosure page.