Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.manticscore.com/llms.txt

Use this file to discover all available pages before exploring further.

ManticScore exposes its full AI pipeline through a REST API at https://api.manticscore.com. This guide walks you through the complete flow: exchanging your Clerk JWT for a session token, loading your profile with a single bootstrap call, submitting a market research job, and streaming the results as they come in. By the end you’ll have a working script you can adapt for any product idea.
You need a ManticScore account and a Clerk JWT before starting. See Authentication for how to obtain your JWT from the Clerk dashboard or SDK.

Prerequisites

  • A ManticScore account
  • Your Clerk JWT (retrieved from the Clerk dashboard or your client SDK)

Complete walkthrough

1

Exchange your Clerk JWT for a session token

Every request to the ManticScore API uses a short-lived session token, not your raw Clerk JWT. Send your Clerk JWT to POST /auth/session to receive a token.
curl -X POST https://api.manticscore.com/auth/session \
  -H "Authorization: Bearer <your_clerk_jwt>"
Response:
{
  "token": "msc_a1b2c3d4e5f6...",
  "expires_in": 1800
}
Save the token value. You’ll pass it as a Bearer token on every subsequent request. The token is valid for 30 minutes — call POST /auth/session again with your Clerk JWT to refresh it.
POST /auth/session only accepts a Clerk JWT, not another session token. If your token expires mid-session, re-authenticate with your original Clerk JWT.
2

Load your profile with the bootstrap call

Before starting any work, call GET /auth/bootstrap. This single endpoint returns your profile, subscription details, and connected secrets in one shot — use it to confirm you’re authenticated and to check your available credits.
curl https://api.manticscore.com/auth/bootstrap \
  -H "Authorization: Bearer <session_token>"
Response:
{
  "profile": {
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "plan": "free",
    "credits_used": 3,
    "credits_total": 20,
    "project_count": 5
  },
  "subscription": {
    "plan": "free",
    "credits_used": 3,
    "credits_total": 20
  },
  "secrets": {
    "has_github_pat": true,
    "has_anthropic_key": false,
    "has_openai_key": false
  }
}
Check credits_used vs credits_total before submitting research jobs. Market research costs 3 credits. Free accounts receive 20 credits per day, automatically reset every 24 hours.
3

Submit a market research job

Send a POST /projects/research request with your product idea. The API queues the job immediately and returns a job_id you’ll use to stream progress.
curl -X POST https://api.manticscore.com/projects/research \
  -H "Authorization: Bearer <session_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "idea": "A Notion-like workspace for hardware engineers with built-in BOM management and supplier tracking",
    "mode": "market"
  }'
Request body:
FieldTypeRequiredDescription
ideastringYesYour product idea (max 5,000 characters)
descriptionstringNoOptional additional context (defaults to "")
modestringNomarket (default) or feature
Response 202 — queued:
{
  "project_id": "9a3f2c1e-...",
  "job_id": "b4e7d8a0-...",
  "status": "queued",
  "position": 0
}
If ManticScore has seen a similar idea before, it may return 200 with "cache_action": "clone" and "status": "completed" — meaning results are already available and no streaming is needed.
4

Stream progress events

Connect to GET /research/{job_id}/events to receive real-time progress over NDJSON. Each line is a JSON object describing a stage, progress update, or final result.
curl -N https://api.manticscore.com/research/<job_id>/events \
  -H "Authorization: Bearer <session_token>"
Sample stream output:
{"v": 1, "event": "stream_start", "data": {}}
{"v": 1, "event": "stage", "data": {"name": "interpret"}}
{"v": 1, "event": "stage", "data": {"name": "search"}}
{"v": 1, "event": "stage", "data": {"name": "judge"}}
{"v": 1, "event": "stage", "data": {"name": "analyze"}}
{"v": 1, "event": "stage", "data": {"name": "synthesize"}}
{"v": 1, "event": "stage", "data": {"name": "persist"}}
{"v": 1, "event": "result", "data": {"incumbents": [...], "emerging": [...], "features": [...], ...}}
{"v": 1, "event": "done", "data": {}}
Event types:
EventDescription
stream_startStream opened; pipeline is starting
stageA named pipeline stage has begun (interpret, search, judge, analyze, synthesize, persist)
progressIncremental progress update within a stage
resultFinal research output — parse this for results
errorA non-fatal error occurred in the pipeline
doneStream is complete; safe to disconnect
Parse on the event field and ignore any unknown event types — new event types may be added without breaking existing clients.

Complete Python example

Here is the full end-to-end script combining all four steps:
quickstart.py
import json
import httpx

BASE_URL = "https://api.manticscore.com"
CLERK_JWT = "<your_clerk_jwt>"


def main():
    # Step 1: Exchange Clerk JWT for session token
    resp = httpx.post(
        f"{BASE_URL}/auth/session",
        headers={"Authorization": f"Bearer {CLERK_JWT}"},
    )
    resp.raise_for_status()
    token = resp.json()["token"]
    headers = {"Authorization": f"Bearer {token}"}

    # Step 2: Bootstrap — load profile
    resp = httpx.get(f"{BASE_URL}/auth/bootstrap", headers=headers)
    resp.raise_for_status()
    profile = resp.json()["profile"]
    print(f"Logged in as {profile['name']} ({profile['plan']} plan)")
    print(f"Credits: {profile['credits_used']}/{profile['credits_total']}")

    # Step 3: Submit market research
    resp = httpx.post(
        f"{BASE_URL}/projects/research",
        headers={**headers, "Content-Type": "application/json"},
        json={
            "idea": "A Notion-like workspace for hardware engineers with BOM management",
            "mode": "market",
        },
    )
    resp.raise_for_status()
    job = resp.json()
    job_id = job["job_id"]

    # Handle cache hit
    if job.get("cache_action") == "clone":
        print(f"Cache hit — results already available for project {job['project_id']}")
        return

    print(f"Job queued: {job_id} (position {job['position']})")

    # Step 4: Stream events
    with httpx.stream(
        "GET",
        f"{BASE_URL}/research/{job_id}/events",
        headers=headers,
        timeout=None,
    ) as r:
        for line in r.iter_lines():
            if not line.strip():
                continue
            event = json.loads(line)
            etype = event.get("event")
            data = event.get("data", {})

            if etype == "stage":
                print(f"  → Stage: {data.get('name')}")
            elif etype == "result":
                print("\nResearch complete!")
                incumbents = data.get("incumbents", [])
                print(f"Found {len(incumbents)} incumbent competitors")
            elif etype == "done":
                break


if __name__ == "__main__":
    main()

Next steps

Authentication

Learn about session token TTLs, refreshing tokens, and error handling.

Market research

Explore the full research response schema and how to read results.

NDJSON streaming

Understand the streaming protocol and reconnection with cursors.

Credits

See how credits work and what each operation costs.