Account

Reference

API Documentation

Available on Practitioner, Pro Team, and Enterprise plans. Generate your API key from your account page.

Authentication

Pass your API key as a Bearer token in the Authorization header. Keys begin with cruc_ and are shown once at generation time.

Authorization: Bearer cruc_YOUR_KEY_HERE

Keep your key secret. Revoke and regenerate it from your account page if compromised. Each API call consumes one session from your monthly allocation.

Endpoint

POSThttps://thecrusible.systems/api/crucible

Runs your question through the multi-stage analysis pipeline and streams the result as Server-Sent Events (SSE).

Request Body

Content-Type: application/json

questionstring · requiredThe question to analyse. Min 10 chars, max 2000 chars.
supportingContextstring · optionalAdditional background text to inform the analysis. Max 50000 chars. Available on Practitioner and above, or any live-data-entitled account.
supportingUrlstring · optionalA URL to fetch and include as context. Must be a valid URL.
supportingUrl2string · optionalA second URL to fetch and include alongside supportingUrl.
supportingFilestring · optionalBase64-encoded file content (PDF, DOCX, XLSX, CSV, TXT). Requires supportingFileName.
supportingFileNamestring · optionalOriginal filename including extension. Used to detect file type for supportingFile.
liveDataboolean · optionalSet to false to force a sealed (source-only) run for this request — web search is disabled regardless of account entitlement. true or omitted defers to your account entitlement. Cannot grant live-data access beyond what your account allows.
parentRevelationIdstring · optionalUUID of a prior revelation. Used to run a follow-up depth analysis.
challengeTypestring · optionalDepth-analysis mode. One of: challenge · conditions · thread. Only meaningful when parentRevelationId is set.
depthContextstring · optionalAdditional context for a depth-analysis run. Max 2000 chars.
force_source_onlyboolean · optionalLegacy alias for liveData: false. Prefer liveData instead.

Response (SSE Stream)

The response is a text/event-stream. Each event is a JSON object on a data: line.

phase_starteventFired when each analysis phase begins.
phase_completeeventFired when a phase finishes.
session_completeeventFinal event. Contains revelationId, output (string), and liveDataUsed (boolean).
erroreventContains code and message fields. Stream ends after this.
data: {"type":"phase_start"}
data: {"type":"phase_complete"}
data: {"type":"phase_start"}
data: {"type":"phase_complete"}
data: {"type":"phase_start"}
data: {"type":"phase_complete"}
data: {"type":"phase_start"}
data: {"type":"phase_complete"}
data: {"type":"session_complete","revelationId":"uuid","output":"...","liveDataUsed":false}

Output Shape

The session_complete event has these fields:

{
  "type":          "session_complete",
  "revelationId":  "uuid — store this to retrieve the revelation later",
  "output":        "string — the full analysis as markdown text",
  "liveDataUsed":  "boolean — true if web search was used in this session"
}

output is a plain markdown string, not a structured object. If live web search was active and sources were used, the output ends with a ◈ Sources: line listing the domains consulted.

Example — curl

curl -X POST https://thecrusible.systems/api/crucible \
  -H "Authorization: Bearer cruc_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{"question": "Should I expand into a new market this year?"}' \
  --no-buffer

Example — JavaScript (SSE)

const response = await fetch('https://thecrusible.systems/api/crucible', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer cruc_YOUR_KEY_HERE',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    question: 'Should I expand into a new market this year?',
    supportingContext: 'We are a 12-person SaaS company, 3 years old, profitable.',
  }),
})

const reader = response.body.getReader()
const decoder = new TextDecoder()
let buffer = ''

while (true) {
  const { done, value } = await reader.read()
  if (!done) buffer += decoder.decode(value)

  const lines = buffer.split('\n')
  buffer = done ? '' : lines.pop()

  for (const line of lines) {
    if (!line.startsWith('data: ')) continue
    const event = JSON.parse(line.slice(6))

    if (event.type === 'session_complete') {
      console.log(event.output)        // full markdown string
      console.log(event.liveDataUsed)  // boolean
    }
  }

  if (done) break
}

Error Codes

401 unauthorizedHTTPMissing or invalid API key.
402 limit_reachedHTTPMonthly session limit reached. Resets on the 1st of next month.
422 validation_errorHTTPInvalid request body. Check the question field.
429 rate_limitedHTTPToo many requests — wait 30 seconds between sessions.
500 server_errorHTTPInternal error. Check Retry-After header and try again.

Questions or integration support

Contact Us