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.
ON THIS PAGE
QuickstartAuthenticationEndpointsCode ExamplesDemographic PresetsCustom AudienceUse CasesRate Limits & TiersQuickstart
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.
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:
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:
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
/developer/keysCreate a new API key (requires user_id on a Pro or Max plan)
/developer/keysList all your API keys
/developer/keys/{id}Revoke an API key
/developer/usageMonthly usage summary (simulations, tokens, cost)
SIMULATIONS
/developer/simulationsField a study synchronously and receive the full results payload
/developer/simulations/asyncLaunch a study in the background (returns immediately with polling URLs)
/developer/simulations/{id}Retrieve a study and its findings
/developer/simulations/{id}/statusLightweight status poll (no payload)
/developer/presetsEnumerate all demographic presets with OCEAN profiles
AUDIENCE (no auth required)
/audience/taxonomyIAB Tech Lab Audience Taxonomy 1.1 — every interest tag you can target
/audience/presetsDemographic preset roster (same data as /developer/presets, unauthenticated)
/audience/estimate-reachLive preview of how many agents match a targeting spec — no LLM calls
Code Examples
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)
# 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_IDJAVASCRIPT / TYPESCRIPT
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
| Field | Type | Notes |
|---|---|---|
| countries | string[] | ISO 3166-1 alpha-2 codes — "US", "GB", "DE", "JP"... |
| regions | string[] | States / provinces — "CA", "NY", "ON", "BY"... (free-form) |
| cities | string[] | City names — "San Francisco", "Berlin", "Tokyo"... (free-form) |
| age_min | int | Floor age inclusive. Default 18. |
| age_max | int | Ceiling age inclusive. Default 65. |
| genders | string | "all" | "male" | "female" | "non_binary". Default "all". |
| interests | string[] | IAB taxonomy leaves — see GET /audience/taxonomy. |
| interest_exclusions | string[] | Drop personas matching any of these tags. |
| income_min_tier | int | 0-20 scale where 10 ≈ US median household income. |
| income_max_tier | int | 0-20 scale. Pair with min_tier for income brackets. |
DISCOVER INTEREST TAGS
# Browse the IAB Tech Lab Audience Taxonomy 1.1 (no auth required)
curl https://api.crowdos.ai/api/v1/audience/taxonomyPREVIEW 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.
# 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
# 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)
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_populationon 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
countriesfilter — 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.
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.
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.
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.
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.
Competitive positioning research
Measure brand perception relative to competitors. Stance statements fix the comparison axis for clean sentiment measurement across customer segments.
Rate Limits & Tiers
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