POPULATION INTELLIGENCE · API

Query the crowd
from a single API call.

The same persistent, census-grounded crowd that powers Pulse, Screening Room, and Ads Labo — exposed as a REST API. Bearer-token auth, structured JSON, drawn from a calibrated 8-billion-person population model at 93.3% Pew parity. API access is included with Pro and Max subscriptions.

REST + PYTHON SDK·8B-PERSON POPULATION MODEL·93.3% PEW PARITY·INCLUDED WITH PRO + MAX

REFERENCE & SDKs

MCP SERVER (HOSTED + PIP) →COMPLETE REFERENCE (MD) →SWAGGER UI →REDOC →OPENAPI.JSON →PYTHON SDK →POSTMAN →MCP SERVER →

FOR AI AGENTS · MCP

Building with Claude Desktop, Cursor, or Cline?

pip install crowdos-mcp wires six tools — focus group, debate, cost preview, audience discovery — into your agent in one step.

MCP guide →

ON THIS PAGE

QuickstartAuthenticationEndpointsCode ExamplesDemographic PresetsCustom AudienceUse CasesRate Limits & Tiers

Quickstart

Three steps to field your first study:

1. Get an API key

Sign up at crowdos.ai and subscribe to Pro or Max — API keys mint from the account hub, and your plan's monthly wallet credit covers your first studies.

BASH
curl -X POST https://api.crowdos.ai/api/v1/developer/keys \
  -H "Content-Type: application/json" \
  -d '{"user_id": "YOUR_USER_ID", "name": "My App"}'

Save the key field from the response — the raw value is shown only once at creation.

2. Run a simulation

One API call creates, runs, and returns the full results payload:

BASH
curl -X POST https://api.crowdos.ai/api/v1/developer/simulations \
  -H "Authorization: Bearer crowd_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Should companies mandate return-to-office?",
    "mode": "voting",
    "demographic_preset": "us_general_population",
    "population_size": 50
  }'

3. Read the results

The response includes a resultsobject with the sentiment summary, diversity score, and every respondent’s individual response — persona, demographics, OCEAN profile, and cited reasoning.

Authentication

All endpoints (except key creation) require a Bearer token in the Authorization header:

HTTP
Authorization: Bearer crowd_aBcDeFgH1234...

Keys are prefixed with crowd_ and stored as SHA-256 hashes on our infrastructure. The raw key is returned only at creation.

Security notice: Treat API keys as credentials. Do not commit to version control or expose in client-side code. Resolve via environment variables.

Endpoints

KEY MANAGEMENT

POST
/developer/keys

Create a new API key (requires user_id on a Pro or Max plan)

GET
/developer/keys

List all your API keys

DELETE
/developer/keys/{id}

Revoke an API key

GET
/developer/usage

Monthly usage summary (simulations, tokens, cost)

SIMULATIONS

POST
/developer/simulations

Field a study synchronously and receive the full results payload

POST
/developer/simulations/async

Launch a study in the background (returns immediately with polling URLs)

GET
/developer/simulations/{id}

Retrieve a study and its findings

GET
/developer/simulations/{id}/status

Lightweight status poll (no payload)

GET
/developer/presets

Enumerate all demographic presets with OCEAN profiles

AUDIENCE (no auth required)

GET
/audience/taxonomy

IAB Tech Lab Audience Taxonomy 1.1 — every interest tag you can target

GET
/audience/presets

Demographic preset roster (same data as /developer/presets, unauthenticated)

POST
/audience/estimate-reach

Live preview of how many agents match a targeting spec — no LLM calls

Code Examples

PYTHON

PYTHON
import requests

API_KEY = "crowd_YOUR_API_KEY"
BASE = "https://api.crowdos.ai/api/v1/developer"
headers = {"Authorization": f"Bearer {API_KEY}"}

# Run a simulation
response = requests.post(f"{BASE}/simulations", headers=headers, json={
    "topic": "Is remote work better for productivity?",
    "mode": "voting",
    "demographic_preset": "tech_early_adopters",
    "population_size": 100,
    "stance_statement": "Remote work improves employee productivity",
})

result = response.json()
print(f"Status: {result['status']}")
print(f"Results: {result['results']['summary']}")

# List available presets
presets = requests.get(f"{BASE}/presets", headers=headers).json()
print(f"{presets['count']} presets available")

ASYNC (LARGE POPULATIONS)

BASH
# Launch in background (returns immediately)
curl -X POST https://api.crowdos.ai/api/v1/developer/simulations/async \
  -H "Authorization: Bearer crowd_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Should companies mandate return-to-office?",
    "mode": "voting",
    "demographic_preset": "us_general_population",
    "population_size": 500
  }'

# Response: { "id": "sim-abc", "status": "pending",
#   "poll_url": "/api/v1/developer/simulations/sim-abc/status",
#   "results_url": "/api/v1/developer/simulations/sim-abc" }

# Poll until complete
curl -H "Authorization: Bearer crowd_YOUR_API_KEY" \
  https://api.crowdos.ai/api/v1/developer/simulations/SIM_ID/status

# Fetch full results once status is "complete"
curl -H "Authorization: Bearer crowd_YOUR_API_KEY" \
  https://api.crowdos.ai/api/v1/developer/simulations/SIM_ID

JAVASCRIPT / TYPESCRIPT

JAVASCRIPT
const API_KEY = "crowd_YOUR_API_KEY";
const BASE = "https://api.crowdos.ai/api/v1/developer";

// Run a simulation
const response = await fetch(`${BASE}/simulations`, {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    topic: "What do consumers think about subscription fatigue?",
    mode: "voting",
    demographic_preset: "millennials",
    population_size: 200,
  }),
});

const { id, status, results } = await response.json();
console.log(`Simulation ${id}: ${status}`);
console.log("Summary:", results.summary);

// Each agent's response includes their persona + reasoning
for (const agent of results.agents.slice(0, 3)) {
  console.log(`${agent.name} (${agent.sentiment}): ${agent.reasoning}`);
}

Demographic Presets

Every study targets a demographic preset — a statistically grounded population model calibrated against published distributions (US ACS 2023, UK ONS 2021, AU ABS 2021) with OCEAN trait distributions from Rentfrow 2008 and Schmitt 2007.

23 country-level starter templates ship by default; the custom-audience filter narrows any of them by geography, age range, gender, interests, income — as affluence tiers or real amounts in local currency — and, on multi-ethnic markets, ethnicity and religion. Enumerate the templates via GET /developer/presets or reference this selection:

us_general_population

US General Pop

Census-weighted American adults

millennials

Millennials (28-43)

Digital-savvy, experience-focused

tech_early_adopters

Tech Adopters

Innovation-driven professionals

india_urban

India (Urban)

Delhi, Mumbai, Bangalore metros

germany

Germany

Manufacturing + engineering economy

au_melbourne

Melbourne, AU

Arts, coffee, university culture

japan

Japan

Aging population, consensus culture

brazil

Brazil

Services + commodities, coastal + interior

+ 34 more including US states, UK regions, Australian metros, South Korea, France, Canada, Mexico, and age cohorts.

Custom Audience

Demographic presets give you a population baseline. Custom audience narrows that panel by any combination of geography, age, gender, income tier, and IAB-taxonomy interest. The preset still seeds persona generation; the filter then keeps only personas matching your spec.

Pass custom_audience as a JSON object on any POST /developer/simulations or /simulations/asyncrequest. All fields are optional — omit anything you don't want to filter on.

SPEC

FieldTypeNotes
countriesstring[]ISO 3166-1 alpha-2 codes — "US", "GB", "DE", "JP"...
regionsstring[]Region tokens where the market supports them (US state codes like "CA"). GET /audience/presets lists each market's regions — empty means filter by cities instead.
citiesstring[]Each market's own city vocabulary — see GET /audience/presets. Case-insensitive.
age_minintFloor age inclusive. Default 18.
age_maxintCeiling age inclusive. Default 120 = no upper bound.
gendersstring"all" | "male" | "female" | "non_binary". Default "all".
interestsstring[]IAB taxonomy leaves — see GET /audience/taxonomy.
interest_exclusionsstring[]Drop personas matching any of these tags.
income_min_tierintAffluence ladder 0-7 (7 = top). Selects the equivalent standing within each market's own income distribution.
income_max_tierintSame 0-7 ladder. Pair with min_tier for income brackets.
income_currencystringISO code (USD, SGD, THB, VND...). Required with the amount fields; unknown codes are rejected, never guessed. Each market's currency: GET /audience/presets.
income_min_amountnumberMinimum annual household income in income_currency. Overrides income_min_tier.
income_max_amountnumberMaximum annual household income in income_currency. Overrides income_max_tier.
income_matchstring"position" (default): equivalent affluence standing in each market's own ladder. "absolute": actual earnings at indicative FX.
ethnicitiesstring[]Multi-ethnic presets only (singapore/malaysia/indonesia). OR-matched, e.g. ["Malay","Chinese"]. See GET /audience/presets.
religionsstring[]Multi-ethnic presets only. OR-matched, e.g. ["Islam","Buddhism"]. Combine with ethnicities for an AND (e.g. Malay AND Muslim).

DISCOVER INTEREST TAGS

BASH
# Browse the IAB Tech Lab Audience Taxonomy 1.1 (no auth required)
curl https://api.crowdos.ai/api/v1/audience/taxonomy

PREVIEW REACH (NO LLM CALLS, NO AUTH)

Use this to validate your targeting before committing to a study. Returns a match rate against a sampled persona pool — a 0.05 match rate against a 200-agent target means you should expect ~10 matching agents, not 200. Tighten the spec or pick a different demographic_preset baseline if reach is too narrow.

BASH
# Live-preview how many agents match a targeting spec.
# No LLM calls — pure-Python filter against a sampled persona pool.
curl -X POST https://api.crowdos.ai/api/v1/audience/estimate-reach \
  -H "Content-Type: application/json" \
  -d '{
    "preset_key": "us_general_population",
    "sample_size": 500,
    "targeting": {
      "countries": ["US"],
      "regions": ["CA", "NY", "TX"],
      "age_min": 25,
      "age_max": 44,
      "genders": "all",
      "interests": ["technology", "investing-and-stocks"],
      "interest_exclusions": ["gambling"],
      "income_min_tier": 5,
      "income_max_tier": 7
    }
  }'

# Response shape:
# {
#   "matched_count": 187,            # personas that passed the filter
#   "sample_total": 500,             # personas we tested
#   "match_rate": 0.374,              # matched_count / sample_total
#   "confidence": "medium",           # low | medium | high (sample-size)
#   "by_dimension": { ... }           # breakdown by country/age/etc.
# }

RUN A STUDY WITH CUSTOM AUDIENCE

BASH
# Field a sim against a narrowed audience.
# Adding custom_audience filters the panel beyond the preset baseline.
# Personas are still SEEDED by demographic_preset; the filter then
# keeps only those matching the spec.
curl -X POST https://api.crowdos.ai/api/v1/developer/simulations \
  -H "Authorization: Bearer crowd_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Would you switch banks for a 5% APY savings account?",
    "mode": "voting",
    "demographic_preset": "us_general_population",
    "population_size": 200,
    "custom_audience": {
      "countries": ["US"],
      "age_min": 30,
      "age_max": 55,
      "genders": "all",
      "interests": ["personal-finance", "investing-and-stocks"],
      "income_currency": "USD",
      "income_min_amount": 150000
    }
  }'

FULL FLOW (PYTHON)

PYTHON
import requests

API_KEY = "crowd_YOUR_API_KEY"
BASE = "https://api.crowdos.ai/api/v1/developer"
ROOT = "https://api.crowdos.ai"
headers = {"Authorization": f"Bearer {API_KEY}"}

# 1. Discover interest tags (unauthenticated)
taxonomy = requests.get(f"{ROOT}/api/v1/audience/taxonomy").json()
# taxonomy["categories"] = { "automotive": [...], "technology": [...], ... }

# 2. Preview reach before committing
preview = requests.post(f"{ROOT}/api/v1/audience/estimate-reach", json={
    "preset_key": "us_general_population",
    "sample_size": 500,
    "targeting": {
        "countries": ["US"],
        "age_min": 22,
        "age_max": 35,
        "interests": ["video-gaming", "technology"],
        "income_min_tier": 6,
    },
}).json()
print(f"~{preview['match_rate']*100:.1f}% match rate, confidence={preview['confidence']}")

# 3. Field the study with custom_audience
sim = requests.post(f"{BASE}/simulations", headers=headers, json={
    "topic": "Should game studios charge $70 for AAA titles?",
    "mode": "voting",
    "demographic_preset": "us_general_population",
    "population_size": 200,
    "custom_audience": {
        "countries": ["US"],
        "age_min": 22,
        "age_max": 35,
        "interests": ["video-gaming", "technology"],
        "income_min_tier": 6,
    },
}).json()
print(sim["results"]["summary"])

GOTCHAS

  • Preview reach before paying. A narrow filter may match few respondents; the panel is grown from your closest real matches rather than faked. POST /audience/estimate-reach is free and names the constraint that cuts hardest; the delivered count is results.agent_count.
  • Interests are exact tags. Use the slug strings from GET /audience/taxonomy — “personal-finance”, not “Personal Finance”. Matching is case-insensitive but the tag itself must exist.
  • Income tiers are relative; amounts are literal. Tiers pick the same affluence standing in every market's own income ladder. To target by real earnings instead, send income_currency + income_min_amount (and optionally income_match: "absolute").
  • JSONB cap: 16 KB. If you're passing hundreds of interests / regions / cities, group them by preset and field multiple smaller studies instead.

Application Domains

The API supplements traditional survey and qualitative panel research. Representative deployments:

Message-market fit

Field value-proposition research across multiple audience presets before go-to-market commitment. Re-field the identical instrument by preset to quantify resonance differentials.

millennials"Would you pay $15/month for AI-powered meal planning?"

Market entry research

Prior to geographic expansion, quantify local sentiment toward the product category. Country-specific presets carry localized demographics and culturally calibrated trait distributions.

germany"Would you switch from a local bank to a digital-only challenger bank?"

Message variant testing

Evaluate multiple copy variants against an identical respondent panel via the stance_statement parameter. Sentiment and cited reasoning attribute outperformance to specific factors.

tech_early_adopters"Our AI assistant saves you 10 hours per week"

Policy impact assessment

Quantify public reaction to proposed policy across demographic segments. Re-field by preset to isolate regional, generational, and cohort-level response differentials.

us_general_population"Should employers be required to disclose AI usage in hiring?"

Content strategy validation

Pre-field press releases, long-form content, and social campaigns against a representative respondent panel. Structured agree/disagree/undecided output with per-respondent reasoning.

small_business_owners"Small businesses should prioritize sustainability over short-term profit"

Competitive positioning research

Measure brand perception relative to competitors. Stance statements fix the comparison axis for clean sentiment measurement across customer segments.

us_california"Brand X offers better value than Brand Y for daily use"

Rate Limits & Tiers

Free (web only)Pro ($25/mo)Max ($100/mo)
Max agents per sim (API)7502,000
Rate limit30 req/min120 req/min
API accessNo — web app onlyYesYes
Async simulationsYesYesYes
Token budget per sim120k tokens3M tokens10M tokens
Export formatsJSONCSV, JSON, PDFAll
SupportCommunityEmailDedicated

Fielding duration:A 20-respondent Pulse study typically completes in 5–15 seconds. Panels at scale (200+ respondents) typically field in 30–120 seconds. For large populations, use POST /simulations/async which returns immediately, then poll GET /simulations/{id}/status until complete. Rate-limited requests receive a 429 with a Retry-After header.

Ready to ask the crowd?

Sign up, subscribe to Pro or Max, and run your first simulation from code in under a minute — monthly wallet credit included.

Get started