Skip to main content
Projects are the top-level container in ManticScore. Each project holds research runs, build graphs, briefs, and feature deep research. You can create a bare project and attach research later, or use the atomic POST /projects/research endpoint to create a project and kick off a research pipeline in a single call. The list endpoint is optimized for speed and returns quickly even when you have many projects.

Create a project

string
required
Display name for the project. Used to generate the URL slug and the normalized clean_title.
string
Free-text description of what you’re building. Defaults to an empty string.
Idempotent by idea. Submitting the same idea twice from the same account does not create a duplicate. The server collapses both calls to the same project — the second request returns the existing project’s id with a refreshed updated_at, surfacing it at the top of your recent list. Two distinct ideas that happen to share a short_title remain separate projects.
201 response
Immediately after the project row is persisted, the server kicks off a background canonical-knowledge lookup that pre-populates the project with suggested competitors and features drawn from similar prior research. Suggestions are delivered as a project.seeded event on the project channel — not in this response. Subscribe to the channel using the project UUID as entity_id to receive them, or read them off the timeline returned by GET /projects/{id}/home.The event payload looks like:
This step is best-effort. If the canonical layer is empty, the embedding fails, or no similar prior research exists, no event is emitted (or the event arrives with empty competitors and features arrays). Project creation never blocks on or fails because of seeding.
string
required
UUID for the new project.
string
required
URL-safe identifier derived from title.
string
required
Always draft on creation. Transitions: draft → researching → ready → building, plus blocked and done as manual targets.
number
required
Starts at 0. Updated after each completed research run.
string
Normalized version of the title produced by the LLM normalization pass.
string
Single sentence summary generated during normalization.
string
Either complete or failed.

Create a project and start research atomically

Use this endpoint instead of calling POST /projects followed by POST /research. It creates the project row and enqueues the first research job in a single transaction.
Supply an Idempotency-Key header to safely retry the request on network failure. The server replays the original response without starting a duplicate pipeline.
string
required
The product idea to research. Maximum 5,000 characters.
string
Optional extended context. Defaults to an empty string.
string
default:"market"
Research mode. Either market (full market analysis) or feature (feature-focused analysis that auto-chains into feature deep research on completion).
The research job is queued. Stream progress from GET /research/{job_id}/events.
A 409 response means an identical request is already in progress. Wait for the existing job to complete before retrying.

List projects

Returns a paginated list of your projects, ordered by most recently updated. This is the fastest way to get an overview of your projects.
number
default:"5"
Maximum items to return. Upper bound: 100.
number
default:"0"
Number of items to skip for pagination.
200 response
object[]
required
boolean
required
true if additional pages exist. Use offset to paginate.

Get a project

Returns the project detail row along with counts and inline summaries of recent research and build graphs.
200 response
Returns 404 if the project does not exist or belongs to another user.

Get the full project (mobile-optimized)

Returns the project, its latest completed research, any in-progress research job, the latest build graph with full node tree, and similar projects — all in one call.
200 response
Use this endpoint in your mobile app to replace three separate calls (GET /projects/{id}, GET /projects/{id}/research, GET /projects/{id}/build-graph). Build graph nodes are returned under roots, not nodes.

Get the project home (single round-trip aggregator)

Returns everything the mobile project tab needs in a single call: the project, its short digest, recent research, build graphs, briefs, voice clips, agents, Forge runs, and the most recent timeline events. Pair this with a single WebSocket subscription on the project channel using the returned ws.last_event_seq as cursor to keep the screen live.
200 response
object
required
Compact project block. short_title and description come from the summary projection; status is the current state (draft, researching, ready, building, blocked, done).
string
One-line natural language summary of recent project activity. Empty string when nothing notable has happened.
object[]
Up to the 10 most recent research runs. Each entry carries id, status, version, completed_at, the overall quality.overall_score, and the first three competitor names from incumbents.
object[]
Up to the 5 most recent build graphs with node_count and expanded_count. Subscribe to the build channel for live updates.
object[]
Up to the 10 most recent briefs with audience (template name) and a share_url when a share token is set.
object[]
Voice clips threaded to this project. Each entry has slug, target_type, target_id, and created_at.
object[]
Up to 20 active spawned agents attached to this project. Each entry includes the natural-language goal, schedule_cron (cron, ISO interval, or on:event sentinel), and last/next run timestamps.
object[]
Up to 10 most recent Forge runs scoped to this project, with pr_url populated when the run created a GitHub pull request.
object[]
Up to 50 most recent fanned-in events from research, build, brief, Forge, chat, and agent runs. Each entry has ts, kind, a short summary (truncated to 200 chars), and an optional ref (entity UUID).
object
required
Subscription coordinates for the project channel. Pass last_event_seq as cursor in your subscribe frame to resume from the exact point the home payload was generated.
Use this endpoint as your single fetch on project-tab load. Render from the response, then open one WebSocket subscription on channel="project" with cursor = ws.last_event_seq to receive all subsequent activity across every domain.
Returns 404 if the project does not exist or belongs to another user.

Get the public preview

Returns a safe public subset of the project — no user information. Accessible without authentication. Use this for social sharing, App Clip previews, and OG tag generation.
200 response

Update a project

Accepts any subset of fields. Pass null to clear a field.
string
Updated project title.
string
Updated description.
string
Manually override the project state. Valid values: draft, researching, ready, building, blocked, done.
string
GitHub repository in owner/repo format. Used by Forge for code generation. Pass null to clear.
Returns the full updated project row on 200.

Delete a project

200 response

Get research data for a project

Returns the full payload of the latest completed research run attached to this project.
200 response

Get the build graph for a project

Returns the latest build graph with the full node tree assembled under roots.
This endpoint returns nodes under roots. The direct GET /build-graphs/{id} endpoint uses nodes instead.
200 response

List feature research jobs for a project

Returns the latest 10 feature deep research jobs associated with this project.
200 response

Get per-tab research data

Extracts a single column from the research table for a given display tab. Useful for populating individual UI tabs without fetching the entire research payload.
string
required
The tab to fetch. One of: incumbents, emerging, features, signals, white_spaces, interpretation, quality, sources, recommendations, existential_risks, build_readiness.
Returns an array of research rows, each containing id and the requested column. Returns 400 for an unrecognized tab name.
Search across your projects (and any public projects you have access to) using natural language. A query like “mobile payments for gig workers” surfaces semantically related projects, not just exact keyword matches.
string
required
Search query. Between 1 and 500 characters.
number
default:"10"
Number of results to return. Upper bound: 50.
200 response
number
required
Cosine similarity score between 0 and 1. Higher is more relevant.
boolean
required
true if the result belongs to the authenticated user.
Returns 503 if the semantic search service is temporarily unavailable. Retry after a moment.

Publish a project

Flips a project to public-by-opt-in and returns its shareable URL. Projects are private by default; publishing makes the project readable at GET /public/p/{slug} without authentication. The slug is derived from the kebab-cased title plus a 6-character salted hash so unpublished or unknown slugs cannot be brute-forced. Re-publishing an already-published project (or publishing an unpublished one that previously had a slug) returns the same URL — slugs are deterministic and durable. Requires a real (non-anonymous) account. Anonymous principals receive 401. Persists a project.published event on the project channel.
string
required
UUID of the project to publish.
object
Per-section visibility toggles. Omitted fields fall back to defaults.
200 response
boolean
required
Always true on success.
string
required
The deterministic public slug. Stable across re-publishes.
string
required
Absolute URL of the public project page.
Returns:
  • 400 — unknown key in options, wrong value type, or invalid show_handle_or_anon choice.
  • 401 — anonymous principal (publishing requires a real account).
  • 404 — project does not exist or belongs to another user.

Unpublish a project

Flips is_public back to false. The slug and published_at timestamp are preserved as an audit trail, so re-publishing later returns the same URL. Persists a project.unpublished event on the project channel.
200 response
Returns 404 if the project does not exist or belongs to another user.

Update public visibility options

Updates public_options without changing is_public or published_at. Use this to tweak what’s visible on an already-public page.
string
required
UUID of the project.
object
required
New public_options payload. Same fields as the publish endpoint. Unknown keys return 400.
200 response
Returns:
  • 400 — unknown key in options or invalid value type.
  • 404 — project does not exist or belongs to another user.