Skip to content

Spark Suggestions ​

Spark produces one focused AI suggestion per request. It resolves context from your Chainies, Bits, personalization memory, and active sessions, then generates a concise suggestion without starting a full conversation session.

Use Spark for lightweight in-app moments: "what should I work on next?", "turn this comment into an action", "suggest a Bit for this Chainy".

Endpoint ​

MethodPathDescriptionAuthRate Limit
POST/ai/spark/suggestionsCreate a context-aware suggestionJWT + Spark entitlement30/min

POST /ai/spark/suggestions ​

Authentication: JWT Bearer token required.
Entitlement: Active Spark entitlement required. Available on Plus and above (not included in the Free plan).
Rate limit: 30 requests per minute.
Idempotency: Pass an idempotency-key header to deduplicate retries — identical keys return the cached result without re-invoking the LLM.


Request ​

Request Headers ​
HeaderRequiredDescription
AuthorizationYesBearer <token>
Content-TypeYesapplication/json
idempotency-keyNoUnique key to deduplicate the request

Request Body ​

All fields are optional. If no fields are provided the server uses the auto_suggest mode.

FieldTypeConstraintsDescription
modestringauto_suggest, prompt_suggest, next_bit, comment_resultExplicit mode. Omit to let the server resolve automatically.
promptstringmax 4000 charsPrimary instruction or question.
commentstringmax 4000 charsRaw comment to transform into a suggestion.
chainyIdsstring[]max 10, each a valid UUIDGround the suggestion in specific Chainies.
bitIdsstring[]max 25, each a valid UUIDGround the suggestion in specific Bits.
contextOptions.useMemoryboolean—Set false to suppress memory context for this request.
contextOptions.useLatestSessionsboolean—Set false to suppress recent-sessions context for this request.

Mode auto-resolution (when mode is omitted):

  1. comment provided → comment_result
  2. prompt provided → prompt_suggest
  3. chainyIds provided → next_bit
  4. Nothing → auto_suggest

Response ​

Response Example ​
json
{
  "data": {
    "suggestionId": "cm9spark01",
    "mode": "next_bit",
    "title": "Add a pronunciation practice session",
    "content": "Your Spanish Chainy has strong vocabulary coverage but no pronunciation Bits. Adding a 10-minute daily audio session would round out the practice cycle.",
    "structuredResult": {
      "type": "next_bit",
      "payload": {
        "suggestedTitle": "Pronunciation: 10-min daily audio",
        "suggestedPriority": "high"
      }
    },
    "contextUsed": ["chainies", "bits", "memory"],
    "blockedContext": [
      {
        "category": "sessions",
        "reason": "sessions_disabled_by_preference"
      }
    ],
    "chainyIdsUsed": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
    "bitIdsUsed": [
      "b2c3d4e5-f6a7-8901-bcde-f12345678901",
      "c3d4e5f6-a7b8-9012-cdef-123456789012"
    ],
    "personaUsed": "coach",
    "provider": "google",
    "model": "gemini-2.5-flash",
    "createdAt": "2026-05-22T09:30:00.000Z"
  }
}

Response Fields ​
FieldTypeDescription
suggestionIdstringPersisted suggestion ID
modestringResolved mode used: auto_suggest, prompt_suggest, next_bit, comment_result
titlestringShort suggestion headline (max 200 chars)
contentstringFull suggestion text (max 2000 chars)
structuredResultobject | nullOptional structured output (see below)
contextUsedstring[]Context categories that fed the suggestion
blockedContextobject[]Context categories that were suppressed and why
chainyIdsUsedstring[]Chainy IDs that grounded the suggestion
bitIdsUsedstring[]Bit IDs that grounded the suggestion
personaUsedstring | nullAI persona key if a persona was applied
providerstringAI provider used (e.g. google, anthropic)
modelstringModel identifier
createdAtstringISO 8601 timestamp

structuredResult object ​

Present when the LLM returns structured data in addition to the narrative text.

FieldTypeDescription
typestringnext_bit, idea, transformation, or generic
payloadobjectType-specific fields (e.g. suggestedTitle, suggestedPriority)

contextUsed values ​
ValueMeaning
promptUser's prompt field was used
commentUser's comment field was used
chainiesChainy data was retrieved
bitsBit data was retrieved
memoryPersonalization memory was used
sessionsRecent AI sessions were used
preferencesAI persona or language preference was applied

blockedContext object ​
FieldTypeDescription
categorystringThe contextUsed category that was blocked
reasonstringWhy it was blocked (see table below)
ReasonCause
memory_disabled_by_preferenceMemory disabled in your AI preferences
memory_disabled_by_clientRequest sent contextOptions.useMemory: false
sessions_disabled_by_preferenceSession context disabled in your AI preferences
sessions_disabled_by_clientRequest sent contextOptions.useLatestSessions: false
empty_inputNo prompt, comment, or Chainy IDs were provided
no_bits_availableThe requested Chainies exist but contain no Bits

Error Responses ​
StatusCodeWhen
400VALIDATION_FAILEDMode/input mismatch (e.g. next_bit without chainyIds)
403FORBIDDENchainyIds or bitIds do not belong to your account
429RATE_LIMIT_EXCEEDEDMore than 30 requests per minute
502BAD_GATEWAYAI provider returned an empty or failed response
503SERVICE_UNAVAILABLENo AI provider available

Code Examples ​

Use the id of one of your Chainies as $CHAINY_ID in the "next bit" examples below.

bash
curl -X POST "$BASE_URL/ai/spark/suggestions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
bash
curl -X POST "$BASE_URL/ai/spark/suggestions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "idempotency-key: req_abc123" \
  -d '{
    "mode": "prompt_suggest",
    "prompt": "What is the highest priority thing I should tackle today?"
  }'
bash
curl -X POST "$BASE_URL/ai/spark/suggestions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "next_bit",
    "chainyIds": ["'"$CHAINY_ID"'"]
  }'
bash
curl -X POST "$BASE_URL/ai/spark/suggestions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "comment_result",
    "comment": "I keep losing focus after lunch and end up skipping my language practice."
  }'
javascript
// Auto suggest
const autoResponse = await fetch(`${BASE_URL}/ai/spark/suggestions`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({}),
});
const { data: autoSuggestion } = await autoResponse.json();

// Prompt mode with idempotency
const promptResponse = await fetch(`${BASE_URL}/ai/spark/suggestions`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
    "idempotency-key": "req_abc123",
  },
  body: JSON.stringify({
    mode: "prompt_suggest",
    prompt: "What is the highest priority thing I should tackle today?",
  }),
});
const { data: promptSuggestion } = await promptResponse.json();

// Next bit for a Chainy
const chainyId = process.env.CHAINY_ID; // id of the Chainy to ground the suggestion in

const nextBitResponse = await fetch(`${BASE_URL}/ai/spark/suggestions`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    mode: "next_bit",
    chainyIds: [chainyId],
  }),
});
const { data: nextBitSuggestion } = await nextBitResponse.json();
python
import os
import requests

BASE_URL = "https://api.chainabit.com/api/v1"
headers = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}

# Auto suggest
res = requests.post(f"{BASE_URL}/ai/spark/suggestions", headers=headers, json={})
data = res.json()["data"]

# Prompt mode
res = requests.post(
    f"{BASE_URL}/ai/spark/suggestions",
    headers={**headers, "idempotency-key": "req_abc123"},
    json={
        "mode": "prompt_suggest",
        "prompt": "What is the highest priority thing I should tackle today?",
    },
)
data = res.json()["data"]

# Next bit
chainy_id = os.environ["CHAINY_ID"]  # id of the Chainy to ground the suggestion in

res = requests.post(
    f"{BASE_URL}/ai/spark/suggestions",
    headers=headers,
    json={
        "mode": "next_bit",
        "chainyIds": [chainy_id],
    },
)
data = res.json()["data"]

Plan availability ​

PlanSpark accessMonthly suggestion limit
FreeNo—
PlusYes150
ProYes500
Pro (higher capacity)YesUnlimited

Calling this endpoint on a plan without Spark access returns 403 FORBIDDEN.


Modes ​

auto_suggest ​

No inputs required. Spark reads your recent Bits, Chainies, memory, and sessions and generates an unprompted suggestion — useful for "surprise me" or "what's next?" moments.

prompt_suggest ​

Requires prompt. Generates a suggestion grounded in your explicit question or instruction combined with your available context.

next_bit ​

Requires at least one chainyId. Spark analyses the Chainy's existing Bits and suggests a concrete next Bit to create or action to take.

comment_result ​

Requires comment. Transforms a raw user comment (a note, thought, or observation) into an actionable suggestion.


Context controls ​

Grounding with specific IDs ​

Provide chainyIds and/or bitIds to pin the suggestion to specific content. Without IDs Spark pulls from your most recent Chainies and Bits automatically.

Suppressing context per request ​

Use contextOptions to override your account-level preferences for a single request:

json
{
  "contextOptions": {
    "useMemory": false,
    "useLatestSessions": false
  }
}

Account-level preferences ​

Memory and session context follow your AI preferences (ai_memory_enabled, use_latest_sessions). Manage these via the Preferences API.


Idempotency ​

Pass an idempotency-key header to make retries safe. If a suggestion was already created with the same key, the persisted result is returned immediately without calling the LLM again.

bash
curl -X POST "$BASE_URL/ai/spark/suggestions" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "idempotency-key: client-generated-unique-id" \
  -d '{ "prompt": "What should I focus on today?" }'

Keys are scoped to your account. Use a UUID or a hash of the request inputs as the key.

Built with purpose.