API Documentation
Everything you need to integrate InstantFocus into your application. RESTful JSON API with Bearer token authentication.
Quick start
# 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.
{
"Authorization": "Bearer if_live_abc123...",
"Content-Type": "application/json"
}/v1/evaluateRun 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
| Field | Type | Required | Description |
|---|---|---|---|
study_type | string | Yes | One of: concept_test, sentiment, nps, survey, ab_test |
stimulus | string | Yes* | Product description, copy, or concept (10–5000 chars). Not used for ab_test. |
variant_a | string | ab_test | First variant for A/B comparison (10–5000 chars) |
variant_b | string | ab_test | Second variant for A/B comparison (10–5000 chars) |
questions | string[] | survey | Array of 1–10 open-ended questions (max 500 chars each) |
panel_size | number | No | Number of personas (1–10,000). Overrides audience.size. Default: 100 |
audience | object | No | Panel demographics and traits (see below) |
context | string | No | Additional context for the panel (max 2000 chars) |
engine_mode | string | No | "standard" (default) or "anchor" (pre-calibrated personas) |
Audience object (optional)
| Field | Type | Default | Options |
|---|---|---|---|
size | number | 100 | 10–10,000 |
age_range | [min, max] | [18, 80] | Min 18, max 100 |
gender | string | "all" | all | male | female | nonbinary |
region | string | "us_national" | us_national | us_northeast | us_southeast | us_midwest | us_west | us_southwest | uk | eu | global |
income_bracket | string | "all" | all | low | middle | upper_middle | high |
education | string | "all" | all | high_school | some_college | bachelors | graduate |
tech_adoption | string | "all" | all | innovator | early_adopter | early_majority | late_majority | laggard |
Synchronous response (200) — panel ≤ 100
{
"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
{
"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"
}
}/v1/jobs/:id Poll for async job status and results. Use when /v1/evaluate returns a 202.
Job status values
| Status | Meaning |
|---|---|
pending | Job created, batches queuing |
processing | Batches being processed by LLM workers |
finalizing | All batches complete, assembling results |
completed | Results ready — data.result contains the full study output |
failed | Job failed — check data.error |
Polling example
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)); } }
/v1/usageCheck current credit balance and usage statistics. Requires Bearer token.
{
"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"
}
}/v1/healthService health check. No authentication required.
{
"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- mean_score
- median_score
- std_dev
- score_distribution
- purchase_intent
- top_concerns
- top_appeals
- score (1–10)
- sentiment
- reasoning
- purchase_intent
sentimentAnalyze sentiment toward a stimulus- positive_pct
- negative_pct
- neutral_pct
- mixed_pct
- confidence
- key_themes
- sentiment (positive/negative/neutral/mixed)
- reasoning
- key_theme
npsNet Promoter Score prediction (0–10 recommendation scale)- nps_score (-100 to 100)
- promoters_pct
- passives_pct
- detractors_pct
- mean_score
- score (0–10)
- reasoning
- sentiment
surveyCustom open-ended questions to the panel- question_results (per-question summaries)
- common_themes
- answers (question → answer map)
- reasoning
ab_testCompare two variants head-to-head- winner (a/b/tie)
- variant_a_score
- variant_b_score
- variant_a_pct
- variant_b_pct
- no_preference_pct
- key_differentiators
- 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
| HTTP | Code | Meaning |
|---|---|---|
| 200 | — | Success (synchronous result or completed job) |
| 202 | — | Accepted — async job created, poll /v1/jobs/:id for results |
| 400 | VALIDATION_ERROR | Invalid request body — check study_type and required fields |
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 402 | INSUFFICIENT_CREDITS | Not enough credits — purchase more at /pricing |
| 403 | FORBIDDEN | Access denied (wrong API key for this job) |
| 404 | NOT_FOUND | Endpoint or job not found |
| 500 | EVALUATION_ERROR | LLM evaluation failed — retry with backoff |
| 500 | JOB_CREATION_ERROR | Failed 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