Skip to content

API Documentation

Everything you need to integrate InstantFocus into your application. RESTful JSON API with Bearer token authentication.

Quick start

terminal
# Run a concept test with 50 personas
curl -X POST https://api.instantfocus.dev/v1/evaluate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "study_type": "concept_test",
    "stimulus": "A meal kit delivery service that uses AI to learn your taste preferences.",
    "panel_size": 50,
    "audience": { "gender": "all", "region": "us_national" }
  }'

Bearer token

All authenticated endpoints require a Bearer token in the Authorization header. API keys are prefixed with if_ for easy identification.

headers
{
  "Authorization": "Bearer if_live_abc123...",
  "Content-Type": "application/json"
}
POST/v1/evaluate

Run a synthetic panel study. This is the primary endpoint.

Panels ≤ 100 personas return results synchronously (200). Panels > 100 return a job_id (202) — poll /v1/jobs/:id for results.

Request body

FieldTypeRequiredDescription
study_typestringYesOne of: concept_test, sentiment, nps, survey, ab_test
stimulusstringYes*Product description, copy, or concept (10–5000 chars). Not used for ab_test.
variant_astringab_testFirst variant for A/B comparison (10–5000 chars)
variant_bstringab_testSecond variant for A/B comparison (10–5000 chars)
questionsstring[]surveyArray of 1–10 open-ended questions (max 500 chars each)
panel_sizenumberNoNumber of personas (1–10,000). Overrides audience.size. Default: 100
audienceobjectNoPanel demographics and traits (see below)
contextstringNoAdditional context for the panel (max 2000 chars)
engine_modestringNo"standard" (default) or "anchor" (pre-calibrated personas)

Audience object (optional)

FieldTypeDefaultOptions
sizenumber10010–10,000
age_range[min, max][18, 80]Min 18, max 100
genderstring"all"all | male | female | nonbinary
regionstring"us_national"us_national | us_northeast | us_southeast | us_midwest | us_west | us_southwest | uk | eu | global
income_bracketstring"all"all | low | middle | upper_middle | high
educationstring"all"all | high_school | some_college | bachelors | graduate
tech_adoptionstring"all"all | innovator | early_adopter | early_majority | late_majority | laggard

Synchronous response (200) — panel ≤ 100

200 OK — inline result
{
  "ok": true,
  "data": {
    "study_type": "concept_test",
    "panel_size": 50,
    "mean_score": 5.8,
    "median_score": 6,
    "std_dev": 2.1,
    "score_distribution": { "1": 2, "2": 3, ... },
    "purchase_intent": {
      "definitely": 12, "probably": 24,
      "maybe": 30, "probably_not": 22,
      "definitely_not": 12
    },
    "top_concerns": ["Price sensitivity", "Feature gaps"],
    "top_appeals": ["Convenience", "Innovation"],
    "responses": [
      {
        "persona": { "id": "...", "age": 34, "gender": "female", ... },
        "score": 7,
        "sentiment": "positive",
        "reasoning": "This would save me so much time...",
        "purchase_intent": "probably"
      }
    ]
  },
  "meta": {
    "request_id": "a1b2c3d4-...",
    "credits_used": 50,
    "credits_remaining": 4950,
    "latency_ms": 3420,
    "engine": "standard",
    "mode": "inline",
    "panel": { "requested": 50, "delivered": 50 },
    "inference": {
      "strategy": "round_robin",
      "providers_used": ["gpt-4o-mini", "gemini-flash"],
      "total_cost_usd": 0.003421,
      "total_input_tokens": 12500,
      "total_output_tokens": 8200
    }
  }
}

Async response (202) — panel > 100

202 Accepted — poll for results
{
  "ok": true,
  "data": {
    "job_id": "f8a2e3c4-...",
    "status": "processing",
    "panel_size": 500,
    "total_batches": 100,
    "poll_url": "/v1/jobs/f8a2e3c4-...",
    "estimated_seconds": 10
  },
  "meta": {
    "request_id": "b2c3d4e5-...",
    "credits_used": 500,
    "credits_remaining": 4500,
    "latency_ms": 245,
    "engine": "standard",
    "mode": "async"
  }
}
GET/v1/jobs/:id

Poll for async job status and results. Use when /v1/evaluate returns a 202.

Job status values

StatusMeaning
pendingJob created, batches queuing
processingBatches being processed by LLM workers
finalizingAll batches complete, assembling results
completedResults ready — data.result contains the full study output
failedJob failed — check data.error

Polling example

javascript
async function pollJob(jobId, apiKey) {
  while (true) {
    const res = await fetch(
      `https://api.instantfocus.dev/v1/jobs/${jobId}`,
      { headers: { Authorization: `Bearer ${apiKey}` } }
    );
    const { data } = await res.json();

    if (data.status === 'completed') return data.result;
    if (data.status === 'failed') throw new Error(data.error);

    // Poll every 1-2 seconds
    await new Promise(r => setTimeout(r, 1000));
  }
}
GET/v1/usage

Check current credit balance and usage statistics. Requires Bearer token.

200 OK
{
  "ok": true,
  "data": {
    "tier": "pro",
    "credits_balance": 4500,
    "credits_used_this_month": 500,
    "request_count": 12,
    "last_request": "2026-04-13T04:30:00Z",
    "billing_period": "2026-04"
  }
}
GET/v1/health

Service health check. No authentication required.

200 OK
{
  "status": "ok",
  "service": "instantfocus",
  "version": "1.0.0",
  "providers": { "openai": true, "google": true, "groq": true, "anthropic": true }
}

Response schemas by type

concept_testRate a product or feature concept (1–10 scale) with purchase intent
Aggregate fields
  • mean_score
  • median_score
  • std_dev
  • score_distribution
  • purchase_intent
  • top_concerns
  • top_appeals
Per-persona fields
  • score (1–10)
  • sentiment
  • reasoning
  • purchase_intent
sentimentAnalyze sentiment toward a stimulus
Aggregate fields
  • positive_pct
  • negative_pct
  • neutral_pct
  • mixed_pct
  • confidence
  • key_themes
Per-persona fields
  • sentiment (positive/negative/neutral/mixed)
  • reasoning
  • key_theme
npsNet Promoter Score prediction (0–10 recommendation scale)
Aggregate fields
  • nps_score (-100 to 100)
  • promoters_pct
  • passives_pct
  • detractors_pct
  • mean_score
Per-persona fields
  • score (0–10)
  • reasoning
  • sentiment
surveyCustom open-ended questions to the panel
Aggregate fields
  • question_results (per-question summaries)
  • common_themes
Per-persona fields
  • answers (question → answer map)
  • reasoning
ab_testCompare two variants head-to-head
Aggregate fields
  • winner (a/b/tie)
  • variant_a_score
  • variant_b_score
  • variant_a_pct
  • variant_b_pct
  • no_preference_pct
  • key_differentiators
Per-persona fields
  • preference (a/b/none)
  • score_a (1–10)
  • score_b (1–10)
  • reasoning
  • sentiment

Envelope

All responses follow a consistent envelope. Error responses include ok: false and an error object with code and message.

Status codes

HTTPCodeMeaning
200Success (synchronous result or completed job)
202Accepted — async job created, poll /v1/jobs/:id for results
400VALIDATION_ERRORInvalid request body — check study_type and required fields
401UNAUTHORIZEDMissing or invalid API key
402INSUFFICIENT_CREDITSNot enough credits — purchase more at /pricing
403FORBIDDENAccess denied (wrong API key for this job)
404NOT_FOUNDEndpoint or job not found
500EVALUATION_ERRORLLM evaluation failed — retry with backoff
500JOB_CREATION_ERRORFailed to create async job

Credits

Each persona evaluation costs 1 credit. A study with panel_size: 500 costs 500 credits.

  • Free tier: 100 credits/month
  • Pay as you go pricing, with volume discounts
  • Pay only for what you use, no minimums, no required subscriptions
  • Buy credits at instantfocus.dev/pricing