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.

Clips are the public share surface for ManticScore. Briefs become clip pages at manticscore.com/clip/brief-..., research shares become manticscore.com/clip/research-..., and voice-agent sessions become manticscore.com/clip/session-.... The endpoints below back those pages — they read the clip content from the CMS, resolve audio storage keys to short-lived signed URLs, and let an authenticated user text a clip link to their own phone over iMessage. To create a clip, see POST /briefs/{brief_id}/publish-clip and POST /research/{job_id}/share. The endpoints on this page are for reading and distributing clips that already exist.

Read a clip page (public)

Returns the structured content backing a public clip page. No authentication required. Content-negotiated: returns a rendered HTML landing page by default (with Open Graph meta tags for iMessage, Slack, and Twitter previews), or the structured JSON payload when you pass Accept: application/json. iOS App Clips request JSON; browsers and link previewers get HTML. Rate limit: 30 requests per minute per IP.
slug
string
required
Clip slug — for example brief-e3f8a1d2, research-abc123xyz, or session-....
curl "https://api.manticscore.com/clip/brief-e3f8a1d2" \
  -H "Accept: application/json"
200 response
{
  "id": "5a7f2c93-...",
  "title": "AI expense tracker for freelancers",
  "slug": "brief-e3f8a1d2",
  "description": "A market brief covering incumbents, emerging players, and white space.",
  "og_image_url": "https://manticscore.com/og/brief-e3f8a1d2.jpg",
  "blocks": [
    { "blockType": "hero", "heading": "...", "subheading": "..." },
    { "blockType": "stats", "items": [{ "value": "12", "label": "incumbents" }] }
  ],
  "published": true,
  "sort_order": 0,
  "research": null
}
id
string
required
Clip page identifier from the CMS.
title
string
required
Display title of the clip.
slug
string
required
URL-safe identifier. Equal to the path parameter.
description
string
Short summary suitable for Open Graph descriptions and link previews.
og_image_url
string
Absolute URL of the Open Graph preview image. May be null if no custom image was generated.
blocks
array
Ordered list of content blocks. Each block has a blockType field — hero, stats, richText, featureList, callToAction, divider, or sessionReplay. Block schemas are CMS-driven; clients should ignore unknown block types.
published
boolean
required
true if the clip is publicly visible. Unpublished clips return 404.
sort_order
number
Display ordering hint for grouped clip listings. Defaults to 0.
research
object
For brief clips, an embedded read-only snapshot of the underlying research at publish time (incumbents, emerging players, features, signals, white spaces, sources). null for non-brief clips.
Responses are cached at the edge for 5 minutes (Cache-Control: public, max-age=300). Returns 404 if the slug doesn’t exist or the page is unpublished, and 502 if the upstream CMS is unavailable.

Resolve a session-replay clip to playable audio

Session-replay clips embed opaque audio storage keys rather than direct URLs so that links don’t rot. This endpoint reads the clip, finds every sessionReplay block, and resolves each storage key to a short-lived signed URL that the iOS App Clip can play directly. The master recording and every advisor recording in a session are signed in parallel — a typical 6-call advisor roundtable resolves in roughly the same wall-clock time as a single round-trip. Public, no authentication required. Rate limit: 30 requests per minute per IP.
slug
string
required
Session-replay clip slug, typically prefixed session-.
curl "https://api.manticscore.com/clip/session-abc123/playable"
200 response
{
  "slug": "session-abc123",
  "title": "Should I build an AI expense tracker?",
  "description": "Voice session with the advisor roundtable.",
  "sessions": [
    {
      "audio_url": "https://<project>.supabase.co/storage/v1/object/sign/sessions/session-abc123/master.m4a?token=...",
      "transcript_segments": [
        { "speaker": "user", "text": "...", "t": 0.0 }
      ],
      "advisors": [
        {
          "persona": "skeptical_vc",
          "text": "...",
          "audio_url": "https://<project>.supabase.co/storage/v1/object/sign/sessions/session-abc123/advisor-1.m4a?token=...",
          "voice_id": "..."
        }
      ],
      "research_summary": "Brief summary of the underlying research.",
      "referrer_device_id": null,
      "cta": {
        "label": "Open in ManticScore",
        "url": "https://testflight.apple.com/join/4Ym7X41D"
      }
    }
  ],
  "signed_urls_wired": true
}
slug
string
required
The clip slug. Equal to the path parameter.
title
string
Clip title from the CMS.
description
string
Clip description from the CMS.
sessions
array
required
One entry per sessionReplay block on the clip. Most clips have a single session; the response is an array to accommodate multi-session compilations.
signed_urls_wired
boolean
required
true when the server is configured to mint Supabase Storage signed URLs (the default in production). When false, audio_url values may be raw storage keys rather than playable HTTPS URLs and clients should retry rather than cache the response.
When signed_urls_wired is true, responses include Cache-Control: public, max-age=300 — matching the signed-URL TTL. When false, responses are returned with Cache-Control: no-cache so clients refetch freely. Returns 404 if the slug doesn’t exist or the clip has no sessionReplay block (i.e. it isn’t a session replay), and 502 if the upstream CMS is unavailable.
Signed URLs expire 5 minutes after they are minted. Re-fetch this endpoint to get fresh URLs rather than persisting them on the client.

Send a clip to yourself over iMessage

Texts the authenticated user a link to their own clip over iMessage. Self-delivery only — there is no recipient parameter, and no arbitrary text payload. Every iMessage ManticScore sends is exactly one App Clip URL. Requires a verified phone number on the user’s profile. Link your phone via PATCH /profile/phone before calling this endpoint. Rate limit: 10 requests per hour per user.
slug
string
required
Clip slug to send.
curl -X POST "https://api.manticscore.com/clips/brief-e3f8a1d2/send-to-me" \
  -H "Authorization: Bearer <token>"
200 response
{
  "ok": true,
  "slug": "brief-e3f8a1d2",
  "to": "+15551234567"
}
ok
boolean
required
Always true on success. Failures return non-2xx status codes.
slug
string
required
The clip slug that was sent.
to
string
required
E.164 phone number the message was delivered to — the verified phone on the authenticated user’s profile.
Returns:
  • 400 — no phone number is linked to the user’s profile.
  • 404 — the clip slug does not exist.
  • 502 — the upstream CMS is unavailable, or iMessage delivery failed.

Vote on a clip’s idea

Records a recipient’s vote on the project behind a vote clip (App Clip variant). Accepts both authenticated users and anonymous principals — recipients won’t sign in just to vote, so anonymous is the dominant write path. Votes are idempotent on (project_id, voter_principal_id): re-voting updates the prior vote rather than duplicating it. The first vote a project receives also fires a votes.received event on the project channel; subsequent re-votes are silent. Rate limit: 30 requests per hour per principal (per anonymous device or authenticated user).
slug
string
required
Vote-clip slug. The clip must contain a voteClip block — otherwise this returns 404.
vote
number
required
1 for upvote, -1 for downvote, 0 to retract a prior vote.
comment
string
Optional free-text comment, up to 200 characters.
curl -X POST "https://api.manticscore.com/clip/brief-e3f8a1d2/vote" \
  -H "Content-Type: application/json" \
  -d '{"vote": 1, "comment": "Love it"}'
200 response
{
  "ok": true,
  "total_up": 17,
  "total_down": 3,
  "ack_message": "Your vote was added — thanks for shaping AI expense tracker for freelancers."
}
ok
boolean
required
Always true on success.
total_up
number
required
Total upvotes on this project after the request.
total_down
number
required
Total downvotes on this project after the request.
ack_message
string
required
Short acknowledgment string suitable for display in the App Clip after the vote lands.
Returns 404 if the slug doesn’t exist or the clip is not a vote clip, and 502 if the upstream CMS is unavailable.

Submit a roast on a clip’s idea

Records a recipient’s voice critique (~60s) on the project behind a roast clip. Anonymous-friendly — recipients won’t sign in just to leave a roast. Audio is uploaded as multipart/form-data. The server enforces a hard size cap on raw audio bytes (≈2 MB) — the iOS App Clip limits recordings to 60 seconds in the UI, but the server does not trust the client. Each accepted roast persists as a clip_kind='roast' row in the voice clips table with parent_project_id pointing back to the originator and emits a roast.received event on the project channel. Rate limit: 5 requests per hour per principal.
slug
string
required
Roast-clip slug. The clip must contain a roast_clip block — otherwise this returns 404.
audio
file
required
Raw audio file (recommended audio/m4a). Maximum ~2 MB.
transcript
string
Optional plain-text transcript captured by the client.
curl -X POST "https://api.manticscore.com/clip/brief-e3f8a1d2/roast" \
  -F "audio=@roast.m4a" \
  -F "transcript=Honestly, the pricing tiers don't make sense."
200 response
{
  "ok": true,
  "roast_id": "f1b2c3d4-...",
  "ack_message": "Roast received — they'll hear it later."
}
ok
boolean
required
Always true on success.
roast_id
string
required
UUID of the persisted roast row.
ack_message
string
required
Short acknowledgment string for display in the App Clip after the roast is accepted.
Returns:
  • 404 — the slug doesn’t exist or the clip is not a roast clip.
  • 413 — the uploaded audio exceeds the server-side size cap.
  • 502 — the upstream CMS is unavailable.

Swipe through a project’s research gaps

Records a recipient’s swipe session on a project’s gap cards (App Clip variant of “swipe-the-gaps”). One request can submit up to 50 swipes; gaps are addressed by a deterministic 16-character gap_id derived from the project ID + normalized gap text — the same gap text always hashes to the same id, so multiple recipients converge on the same buckets. Swipes are idempotent on (gap_id, voter_principal_id): re-swiping a card overrides the prior decision rather than duplicating it. Each call emits a single gaps.swiped event on the project channel carrying the truncated voter id and the top-3 yes-swiped gaps. Rate limit: 60 requests per hour per principal (~6 full 10-card sessions).
slug
string
required
Swipe-clip slug. The clip must contain a swipe_clip block — otherwise this returns 404.
swipes
object[]
required
Array of 1–50 swipes.
curl -X POST "https://api.manticscore.com/clip/brief-e3f8a1d2/swipe" \
  -H "Content-Type: application/json" \
  -d '{
    "swipes": [
      {"gap_text": "No native Android client", "direction": 1},
      {"gap_text": "Lacks bulk receipt import", "direction": -1}
    ]
  }'
200 response
{
  "ok": true,
  "recorded": 2,
  "ack_message": "Got it — you helped shape 2 gaps for AI expense tracker for freelancers."
}
ok
boolean
required
Always true on success.
recorded
number
required
Number of swipes persisted from this request.
ack_message
string
required
Short acknowledgment string for the App Clip.
Returns 404 if the slug doesn’t exist or the clip is not a swipe clip, and 502 if the upstream CMS is unavailable.