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 91.9% Pew parity. Free-tier sandbox keys available without a card.

REST + PYTHON SDK · 8B-PERSON POPULATION MODEL · 91.9% PEW PARITY · FREE SANDBOX KEYS

REFERENCE & SDKs

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 free at crowdos.ai — every account gets a sandbox API key (5 req/min, 50-agent cap, no card). Upgrade to Pro or Max for production rates and larger panels.

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.

Twenty-five country-level starter templates ship by default; the custom-audience builder accepts any country, age range, gender, income tier, education level, and political leaning. 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[]States / provinces — "CA", "NY", "ON", "BY"... (free-form)
citiesstring[]City names — "San Francisco", "Berlin", "Tokyo"... (free-form)
age_minintFloor age inclusive. Default 18.
age_maxintCeiling age inclusive. Default 65.
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_tierint0-20 scale where 10 ≈ US median household income.
income_max_tierint0-20 scale. Pair with min_tier for income brackets.

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": 8,
      "income_max_tier": 15
    }
  }'

# 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_min_tier": 10
    }
  }'

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

  • Reach < sample size. A narrow filter may leave fewer personas than you asked for. The platform tops up from related presets (5× scan cap) but won't fake matches. Check results.actual_population on the response.
  • Interests are case-sensitive. Use the exact strings from GET /audience/taxonomy — “Personal Finance” ≠ “personal-finance”.
  • Income tier is relative. Tier 10 means ~50th percentile household income for the country in your countries filter — not US dollars.
  • 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 (sandbox)Pro ($25/mo)Max (custom)
Max agents per sim507502,000
Rate limit5 req/min30 req/min120 req/min
API accessSandbox keyYesYes
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 free, mint a sandbox key, and run your first simulation in under a minute. No card required.

Get started