Overview
The Simulation API generates a complete synthetic respondent-level dataset. You define who the respondents are (quota groups — target-group cells with explicit counts) and what they answer (a full survey), and the Oracle generates a row per respondent with their demographics and their individual answer to every question. The answer data is returned to you directly — there are no redirect links or external survey tools to reconcile.
Because a run can involve thousands of respondents across up to 30 questions, simulation is an asynchronous job. The lifecycle is:
- Create — submit the survey and quota groups; receive a job
id. - Track — poll the job, or receive a webhook when it finishes.
- Retrieve — pull the respondent-level results.
Base URL: https://app.simsurveys.com/api/v1
Authentication
All requests are authenticated with a Bearer token. Create and manage API keys from the API Dashboard.
Authorization: Bearer sk_live_abc123...
- Keys are 72 characters long and begin with
sk_live_. - Keys are shown once at creation and cannot be retrieved again.
- The key must carry the
oracle:simulatescope — select it when creating the key in the dashboard (or contact us to enable Oracle access). A missing, invalid, or expired key returns401; a key that lacks the scope returns403. - Keep keys server-side. An
sk_live_key is a sensitive credential — never embed it in browser or mobile-client code. The API is called server-to-server and does not support cross-origin (CORS) browser requests. - There is no sandbox or test mode — every simulation is billable. Validate integrations against small jobs.
Rate Limiting
Each API key has a configurable rate limit (default 60 requests per minute, range 1–1,000). Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers (X-RateLimit-Reset is a Unix epoch-seconds timestamp). Creating a simulation counts as a single request, regardless of respondent count.
When the limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header (in seconds) and the standard typed error envelope:
{ "error": { "type": "rate_limit_error", "message": "Rate limit exceeded. Try again later." } }
Job Lifecycle
A simulation job moves through the following statuses:
| Status | Meaning |
|---|---|
queued | Accepted and waiting to start |
processing | Respondents are being generated |
completed | Finished — results are available |
failed | The job could not complete; see the error object |
Jobs run to completion — there is no cancel operation once a job is created. Simulation is atomic: if any quota group fails to generate, the entire job transitions to failed and no partial results are returned. Once completed, a job's results are retained indefinitely and remain retrievable.
Create a Simulation
Creates a simulation job and returns immediately with a job id and status: "queued".
Idempotency: because a job is billable, pass an Idempotency-Key header (any unique string) to make retries safe. A replay with the same key returns 200 with the original job at its current status, not a duplicate. Reusing a key with a different request body returns 409 with a conflict_error. A key is bound only once a job is created (2xx) — a request that fails validation does not consume it, so you can retry with a corrected body. Keys are honored for 24 hours.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
model_type |
string | Yes | One of: consumer, hcp, social, patient |
quota_groups |
array | Yes | One or more demographic cells, each with an explicit respondent count. Total sample size N = the sum of all counts (up to 5,000) |
survey |
object | Yes | The survey instrument. Contains questions (1–30 items) |
context |
string | No | Study context applied to the whole run. Consumer and patient models only. |
webhook_url |
string | No | HTTPS URL notified when the job reaches completed or failed. See Webhooks. If omitted, poll for status instead. |
Quota Group Object (quota_groups[])
| Field | Type | Required | Description |
|---|---|---|---|
count |
integer | Yes | Number of respondents to generate for this cell (≥ 1) |
demographics |
object | Yes* | The demographic profile for this cell (free-form key-value pairs; see the Demographics reference). Consumer, social, and patient models. |
medical_specialty |
string | Yes* | The cell's specialty — one of the 20 supported specialties. HCP model only (replaces demographics). |
targeting_criteria |
array | No | Question–answer pairs that condition this cut on prior responses (see Targeting criteria). All models. |
* Each group carries the targeting fields appropriate to the chosen model_type — demographics for consumer/social/patient, medical_specialty for HCP.
Targeting criteria
Beyond demographics, you can constrain a quota group by prior answers. Each entry in targeting_criteria is a { question, answer } pair, and the respondents generated for that cut are people who gave those answers. Multiple pairs are combined with AND — the cell is the intersection of its demographics (or specialty) and every criterion. These are conditioning inputs, separate from survey.questions, and do not count against the 30-question survey limit. They are not part of the codebook and not coded — the question and answer are label text, echoed verbatim on each respondent row.
// quota group with targeting criteria { "count": 150, "demographics": { "age": "35-44", "gender": "Female" }, "targeting_criteria": [ { "question": "Do you own a car?", "answer": "Yes" }, { "question": "How often do you shop online?", "answer": "Weekly" } ] }
Each respondent generated for a cut echoes its criteria in a targeting_criteria field on the row, alongside demographics and responses:
{ "respondent_id": "resp_00001", "demographics": { "age": "35-44", "gender": "Female" }, "targeting_criteria": [ { "question": "Do you own a car?", "answer": "Yes" }, { "question": "How often do you shop online?", "answer": "Weekly" } ], "responses": { "q1": 1 } }
Patient model — conditioning on a diagnosis: for the patient model, a convenience shortcut lets you condition on a condition without writing a full criterion — include a demographics key named exactly "Patient Condition" (title case, with a space) whose value is one of the supported conditions, e.g. { "count": 100, "demographics": { "age": "55-64", "Patient Condition": "Type 2 Diabetes" } }. It is equivalent to a single targeting criterion. The key is case- and spelling-sensitive (a mistyped key like patient_condition is silently treated as an ordinary demographic label), and on the patient model the value is enforced — an unsupported condition returns a validation_error.
Question Object (survey.questions[])
| Field | Type | Required | Applies to | Description |
|---|---|---|---|---|
id | string | Yes | all | Client-defined identifier, unique within the survey; used as the key for this question's answer in each respondent's responses. Duplicate ids are rejected with a validation_error. |
type | string | Yes | all | One of: single_select, multi_select, grid, numeric, ranking, text |
text | string | Yes | all | The question wording (max 5,000 characters) |
options | object[] | Yes | single_select, multi_select, ranking, numeric | 2–20 answer options, each { "label": string, "code": string|number }. For numeric, each label is a value or range (e.g. "0", "1-2", "24"). |
rows | object[] | Yes | grid | The row items being rated, each { "label", "code" } (2–20) |
columns | object[] | Yes | grid | The scale/columns each row is rated against, each { "label", "code" } (2–20) |
max_selections | integer | No | multi_select | Maximum options a respondent may select. Defaults to the number of options (no cap). Respondents always select at least one. |
Labels & codes. Every question, option, grid row, and grid column carries a client-supplied code (its data value) alongside its human-readable label. The question id is the variable code and text is the variable label; each option/row/column's label is what the respondent sees and its code is what the data stores. Respondent answers are returned as codes, and the submitted survey is echoed on the completed job as the codebook, so the dataset is self-describing.
code is required on every option/row/column (omitting one returns a validation_error) and may be an integer or a string — e.g. 1, "01", or "97" for a DK/refused convention. A code must be unique within its own list — among a question's options, among a grid's rows, and among its columns (a row and a column may share a code, and codes may be reused across questions). Grid rows codes in particular must be unique among rows, since they become the keys of the grid answer object. Duplicate codes within a list are rejected with a validation_error. The codebook echoes each code exactly as submitted (types are preserved), so lookups round-trip — e.g. an option { "label": "Don't know", "code": "97" } comes back in a respondent's answer as the string "97", not the number 97. One caveat: a grid answer uses the row code as a JSON object key, so it is serialized as a string — coerce it when matching against the numeric codebook code, or use string row codes.
Example Request
curl -X POST https://app.simsurveys.com/api/v1/oracle/simulate \ -H "Authorization: Bearer sk_live_your_key_here" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: 7f3a9c1e-2b4d-4a10-9c8e-1f2a3b4c5d6e" \ -d '{ "model_type": "consumer", "quota_groups": [ { "count": 150, "demographics": { "age": "25-34", "gender": "Female" } }, { "count": 150, "demographics": { "age": "35-44", "gender": "Male" } } ], "survey": { "questions": [ { "id": "q1", "type": "single_select", "text": "Which brand do you prefer?", "options": [ {"label": "Nike", "code": 1}, {"label": "Adidas", "code": 2}, {"label": "New Balance", "code": 3}, {"label": "Puma", "code": 4} ] }, { "id": "q2", "type": "multi_select", "text": "What matters when buying?", "max_selections": 2, "options": [ {"label": "Price", "code": 1}, {"label": "Comfort", "code": 2}, {"label": "Style", "code": 3}, {"label": "Brand", "code": 4} ] }, { "id": "q3", "type": "grid", "text": "Rate each factor.", "rows": [ {"label": "Durability", "code": 1}, {"label": "Style", "code": 2} ], "columns": [ {"label": "Not important", "code": 1}, {"label": "Somewhat", "code": 2}, {"label": "Very important", "code": 3} ] }, { "id": "q4", "type": "numeric", "text": "Pairs bought last year?", "options": [ {"label": "0", "code": 1}, {"label": "1-2", "code": 2}, {"label": "3-5", "code": 3}, {"label": "6+", "code": 4} ] }, { "id": "q5", "type": "ranking", "text": "Rank these brands.", "options": [ {"label": "Nike", "code": 1}, {"label": "Adidas", "code": 2}, {"label": "New Balance", "code": 3}, {"label": "Puma", "code": 4} ] }, { "id": "q6", "type": "text", "text": "Describe your last purchase." } ] } }'
Response (202 Accepted)
{ "id": "sim_a1b2c3d4e5f6a1b2c3d4e5f6", "object": "oracle.simulation", "status": "queued", "model": "consumer", "respondent_count": 300, "created": 1770940800 }
Retrieve a Simulation
Returns the job's current status. Poll this endpoint until status is completed or failed; on completed, read respondents. Large datasets are paginated.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 100 | Respondents per page (1–1,000) |
offset | integer | 0 | Number of respondents to skip |
Response (while queued or processing)
Before the job finishes, the response carries status metadata only. The survey codebook, respondents, and pagination fields are omitted until status is completed (and then appear on every page of the result set):
{ "id": "sim_a1b2c3d4e5f6a1b2c3d4e5f6", "object": "oracle.simulation", "status": "processing", "model": "consumer", "respondent_count": 300, "created": 1770940800 }
Response (completed)
The completed job echoes the submitted survey (the codebook — labels and codes) and returns each respondent's answers as codes. The survey is included on every page.
{ "id": "sim_a1b2c3d4e5f6a1b2c3d4e5f6", "object": "oracle.simulation", "status": "completed", "model": "consumer", "respondent_count": 300, "created": 1770940800, "completed": 1770940815, "survey": { "questions": [ { "id": "q1", "type": "single_select", "text": "Which brand do you prefer?", "options": [ {"label": "Nike", "code": 1}, {"label": "Adidas", "code": 2}, {"label": "New Balance", "code": 3}, {"label": "Puma", "code": 4} ] }, { "id": "q2", "type": "multi_select", "text": "What matters when buying?", "max_selections": 2, "options": [ {"label": "Price", "code": 1}, {"label": "Comfort", "code": 2}, {"label": "Style", "code": 3}, {"label": "Brand", "code": 4} ] }, { "id": "q3", "type": "grid", "text": "Rate each factor.", "rows": [ {"label": "Durability", "code": 1}, {"label": "Style", "code": 2} ], "columns": [ {"label": "Not important", "code": 1}, {"label": "Somewhat", "code": 2}, {"label": "Very important", "code": 3} ] }, { "id": "q4", "type": "numeric", "text": "Pairs bought last year?", "options": [ {"label": "0", "code": 1}, {"label": "1-2", "code": 2}, {"label": "3-5", "code": 3}, {"label": "6+", "code": 4} ] }, { "id": "q5", "type": "ranking", "text": "Rank these brands.", "options": [ {"label": "Nike", "code": 1}, {"label": "Adidas", "code": 2}, {"label": "New Balance", "code": 3}, {"label": "Puma", "code": 4} ] }, { "id": "q6", "type": "text", "text": "Describe your last purchase." } ] }, "respondents": [ { "respondent_id": "resp_00001", "demographics": { "age": "25-34", "gender": "Female" }, "responses": { "q1": 1, "q2": [2, 1], "q3": { "1": 3, "2": 2 }, "q4": 2, "q5": [1, 3, 2, 4], "q6": "I bought running shoes online during a sale." } } ], "pagination": { "limit": 100, "offset": 0, "total": 300 } }
- The example shows one respondent for brevity; a page returns up to
limitrows. respondentsandpaginationare present only whenstatusiscompleted.respondent_countis the requested sample size (the sum of quota-group counts). Because generation is atomic, on a completed job it always equalspagination.total. Page againstpagination.total; whenoffset ≥ total,respondentsis an empty array.- Each response is keyed by the question
idand its value is the code of the chosen option(s) — decode via thesurveycodebook.textanswers are returned verbatim (uncoded). Themodelfield echoes the request'smodel_type. - The
surveycodebook (with labels and codes) is echoed on every page so each page is self-describing. - If a group defined
targeting_criteria, each of its respondent rows also carries atargeting_criteriafield echoing them. createdandcompletedare Unix timestamps in seconds.- Completed results are retained indefinitely and can be re-fetched at any time.
Response for HCP and patient jobs
For the hcp model, each respondent row carries medical_specialty in place of demographics. The consumer, social, and patient models all use demographics (the consumer example above); for patient, the input demographic keys are echoed back on each row, including the special "Patient Condition" key when supplied.
{ "respondent_id": "resp_00001", "medical_specialty": "Cardiology & Cardiovascular", "responses": { "q1": 1 } }
List Simulations
Lists your simulation jobs, most recent first. Because results are retained indefinitely and there is no other lookup, this is how you recover a job id that wasn't persisted. Paginated; optionally filter by status.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
status | string | — | Filter by status: queued, processing, completed, or failed |
limit | integer | 20 | Jobs per page (1–100) |
offset | integer | 0 | Number of jobs to skip |
Response
{ "object": "list", "data": [ { "id": "sim_a1b2c3d4e5f6a1b2c3d4e5f6", "object": "oracle.simulation", "status": "completed", "model": "consumer", "respondent_count": 300, "created": 1770940800 } ], "pagination": { "limit": 20, "offset": 0, "total": 42 } }
List items are job summaries (no respondents); fetch full results from the retrieve endpoint. When offset ≥ total, data is an empty array. Every request — create, retrieve, and list — counts against your key's rate limit.
Webhooks
If you supply an HTTPS webhook_url when creating a job, the Oracle sends a POST to that URL when the job reaches a terminal status — so you don't have to poll. The payload identifies the job and its outcome; always fetch the data itself from the retrieve endpoint.
POST // to your webhook_url { "id": "evt_9f8e7d6c5b4a3210", "object": "oracle.simulation.event", "type": "simulation.completed", "simulation_id": "sim_a1b2c3d4e5f6a1b2c3d4e5f6", "status": "completed", "respondent_count": 300, "occurred_at": 1770940815 }
The type is simulation.completed or simulation.failed, matching the job status. occurred_at is the Unix-seconds time the event was emitted (distinct from the job's own created).
Verifying signatures
Every delivery is signed so you can confirm it genuinely came from Simsurveys. Two headers are sent:
| Header | Value |
|---|---|
X-Simsurveys-Timestamp | Unix seconds when the request was sent |
X-Simsurveys-Signature | Hex HMAC-SHA256 of {timestamp}.{raw_body}, keyed with your webhook signing secret |
The signing secret is a single account-level secret, found in your dashboard (distinct from your sk_live_ API key). To verify: recompute the lowercase-hex HMAC over timestamp + "." + raw_request_body using that secret, and compare with a constant-time equality against the (lowercase) header value. Reject the request if it doesn't match, or if the timestamp is outside a 5-minute window (replay protection).
import hmac, hashlib, time def verify(raw_body, timestamp, signature, secret): if abs(time.time() - int(timestamp)) > 300: return False expected = hmac.new(secret.encode(), f"{timestamp}.{raw_body}".encode(), hashlib.sha256).hexdigest() return hmac.compare_digest(expected, signature.lower())
Treat the webhook as a hint, not the source of truth. After verifying, re-GET the job to read the authoritative status and results.
A simulation.failed event carries the same fields with status: "failed":
{ "id": "evt_1a2b3c4d5e6f7890", "object": "oracle.simulation.event", "type": "simulation.failed", "simulation_id": "sim_a1b2c3d4e5f6a1b2c3d4e5f6", "status": "failed", "respondent_count": 300, "occurred_at": 1770940815 }
Delivery & retries
- Respond with any
2xxto acknowledge. Non-2xxor timeout (>10s) triggers retries with exponential backoff for up to 24 hours. - Delivery is best-effort: after 24 hours of failed retries the event is dropped. Always keep polling available as the source of truth.
- Delivery is at-least-once — the same event may arrive more than once. Deduplicate on the event
id. - Event payloads follow the same versioning contract as API responses — ignore unrecognized fields.
Answer Encoding by Question Type
Each respondent's responses object maps a question id to its answer. Answers are returned as codes (from the survey codebook), not labels. The value's shape depends on the question type:
| Type | Value shape | Example |
|---|---|---|
single_select | the code of the chosen option | 1 |
multi_select | array of the chosen option codes | [2, 1] |
grid | object — { rowCode: columnCode } per row | { "1": 3, "2": 2 } |
numeric | the code of the selected value/range | 2 |
ranking | array of option codes, best → worst | [1, 3, 2, 4] |
text | string — open-ended response (uncoded) | "I shop online during sales." |
single_selectreturns the code of exactly one of the question'soptions.multi_selectreturns between 1 andmax_selectionsoption codes (never empty); order is not significant.rankingis exhaustive — it returns all of the question's option codes, in ranked order.numericreturns thecodeof the selected bucket — not the numeric value or range it labels. Codes need not equal the values (e.g. bucket"1-2"has code2here), so always decode via the codebook.gridreturns every row'scodeas a key, each mapped to exactly one columncode. Row codes are emitted as JSON string keys even when numeric — coerce when matching them against the codebook.textreturns a free-form string and is the only uncoded type.
Code Examples
A full run: create the job, poll until it completes, then page through the respondent-level results.
Python
import requests, time API_KEY = "sk_live_your_key_here" BASE_URL = "https://app.simsurveys.com/api/v1" HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"} # 1. Create the simulation job = requests.post( f"{BASE_URL}/oracle/simulate", headers=HEADERS, json={ "model_type": "consumer", "quota_groups": [ {"count": 150, "demographics": {"age": "25-34", "gender": "Female"}}, {"count": 150, "demographics": {"age": "35-44", "gender": "Male"}}, ], "survey": {"questions": [ {"id": "q1", "type": "single_select", "text": "Which brand do you prefer?", "options": [{"label": "Nike", "code": 1}, {"label": "Adidas", "code": 2}]}, ]}, }, ).json() sim_id = job["id"] # 2. Poll until complete while job["status"] in ("queued", "processing"): time.sleep(2) job = requests.get(f"{BASE_URL}/oracle/simulate/{sim_id}", headers=HEADERS).json() if job["status"] == "failed": raise RuntimeError(job["error"]["message"]) # 3. Page through respondent-level results (pagination.total is authoritative) respondents, offset = [], 0 while True: page = requests.get( f"{BASE_URL}/oracle/simulate/{sim_id}", headers=HEADERS, params={"limit": 1000, "offset": offset}, ).json() respondents += page["respondents"] offset += len(page["respondents"]) if offset >= page["pagination"]["total"]: break print(f"Retrieved {len(respondents)} respondents")
JavaScript / Node.js
const API_KEY = "sk_live_your_key_here"; const BASE_URL = "https://app.simsurveys.com/api/v1"; const HEADERS = { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" }; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); // 1. Create the simulation let job = await (await fetch(`${BASE_URL}/oracle/simulate`, { method: "POST", headers: HEADERS, body: JSON.stringify({ model_type: "consumer", quota_groups: [ { count: 150, demographics: { age: "25-34", gender: "Female" } }, { count: 150, demographics: { age: "35-44", gender: "Male" } }, ], survey: { questions: [ { id: "q1", type: "single_select", text: "Which brand do you prefer?", options: [{ label: "Nike", code: 1 }, { label: "Adidas", code: 2 }] }, ] }, }), })).json(); const simId = job.id; // 2. Poll until complete while (["queued", "processing"].includes(job.status)) { await sleep(2000); job = await (await fetch(`${BASE_URL}/oracle/simulate/${simId}`, { headers: HEADERS })).json(); } if (job.status === "failed") throw new Error(job.error.message); // 3. Page through respondent-level results (pagination.total is authoritative) const respondents = []; let offset = 0, total = Infinity; while (offset < total) { const page = await (await fetch( `${BASE_URL}/oracle/simulate/${simId}?limit=1000&offset=${offset}`, { headers: HEADERS }, )).json(); respondents.push(...page.respondents); offset += page.respondents.length; total = page.pagination.total; } console.log(`Retrieved ${respondents.length} respondents`);
Errors
Every error response — at any status code — uses the same typed error envelope. Request-time errors (bad body, invalid quotas, too many questions) are returned synchronously from the POST:
{ "error": { "type": "validation_error", "message": "survey.questions must contain between 1 and 30 items." } }
| Type | HTTP Status | Description |
|---|---|---|
validation_error | 400 | Invalid request body, quota groups, or survey |
authentication_error | 401 | Missing, invalid, or expired API key |
permission_error | 403 | Key lacks the oracle:simulate scope |
not_found_error | 404 | Unknown simulation id |
conflict_error | 409 | Idempotency-Key reused with a different request body |
rate_limit_error | 429 | Rate limit exceeded |
internal_error | 500 | Unexpected server error |
A job that fails after being accepted returns status: "failed" with an error object on the GET response. This is a job-level error: the HTTP status is still 200 (the request succeeded; the job did not). It carries the standard job fields plus error, and the error.type is a job-level value (currently generation_error) — a separate, open set from the transport error types above, so handle it independently of HTTP status. respondent_count stays the requested count on a failed job (no rows are produced).
{ "id": "sim_a1b2c3d4e5f6a1b2c3d4e5f6", "object": "oracle.simulation", "status": "failed", "model": "consumer", "respondent_count": 300, "created": 1770940800, "error": { "type": "generation_error", "message": "A quota group failed to generate; the job was aborted." } }
HTTP Status Codes
| Status | Meaning |
|---|---|
202 | Accepted — simulation job created |
200 | Success — job status/results returned |
400 | Bad request — invalid body, quotas, or survey |
401 | Unauthorized — missing, invalid, or expired API key |
403 | Forbidden — key lacks the oracle:simulate scope |
404 | Not found — unknown simulation id |
409 | Conflict — Idempotency-Key reused with a different request body |
429 | Too many requests — rate limit exceeded |
500 | Internal server error |
Limits & Constraints
| Constraint | Value |
|---|---|
| Questions per survey | 1–30 |
| Answer options per question | 2–20 |
| Max question length | 5,000 characters |
| Respondents per job | Up to 5,000 (sum of all quota-group counts) |
| Quota groups per job | At least 1; each count ≥ 1; combined total ≤ 5,000 |
| Grid rows / columns | 2–20 each |
| Results pagination | 100 per page (max 1,000) |
| Max request body size | 1 MB |
| Result retention | Indefinite — completed results never expire |
| Idempotency-Key window | 24 hours |
| Rate limit | Job creation counts as one request against your key's limit |
Exceeding any of these limits returns a 400 validation_error describing the violated constraint.
Demographics Reference
A quota group's demographics object (consumer, social, and patient models) is free-form: each key-value pair is passed through to the model verbatim. The API validates only that keys and values are strings — it does not enforce a fixed set. The table below is the recommended vocabulary the models were tuned on; using these keys and values gives the most reliable results.
| Key | Recommended values |
|---|---|
gender | Male, Female |
age | 18-24, 25-34, 35-44, 45-54, 55-64, 65-74, 75+ |
income | Under $10k, $10k-15k, $15k-20k, $20k-25k, $25k-30k, $30k-35k, $35k-40k, $40k-45k, $45k-50k, $50k-60k, $60k-75k, $75k-100k, $100k-125k, $125k-150k, $150k-200k, $200k+ |
location | Urban, Suburban, Rural |
race_ethnicity | White, Black/African American, American Indian/Alaska Native, Asian, Native Hawaiian/Pacific Islander, Other, Multiracial, Hispanic/Latino |
education | Some High School or Less, High School Graduate, Some College, College Graduate, Post-Graduate Degree |
employment | Not in Labor Force, Employed, Unemployed |
children | No, Yes |
political | Democrat, Republican, Libertarian, Green Party, Other |
marital_status | Married, Not Married |
For the patient model only, the special key "Patient Condition" conditions the cell on a diagnosis; its value must be one of the supported Patient Conditions (see Create).
Supported Specialties
For the hcp model, a quota group's medical_specialty must exactly match one of these 20 values:
Allied Health & Other Medical Professionals | Neurology & Neurosurgery |
Anesthesiology & Pain Management | Nursing & Advanced Practice Providers |
Cardiology & Cardiovascular | Oncology & Hematology |
Dermatology & Skin Conditions | Pathology & Laboratory Medicine |
Emergency & Critical Care | Pediatrics & Child Health |
Endocrinology & Diabetes | Primary Care & General Practice |
Eye & Vision Care | Pulmonology & Respiratory Medicine |
Gastroenterology & Digestive Health | Radiology & Medical Imaging |
Internal Medicine Subspecialties | Surgical Specialties |
Mental Health & Psychiatry | Women's Health & Reproductive Medicine |
Patient Conditions
For the patient model, the "Patient Condition" value (see Targeting criteria) must exactly match one of these 25 values; an unsupported value returns a validation_error:
Type 2 Diabetes | Migraine |
Obesity / Weight Management | Alzheimer's Disease / Dementia |
Breast Cancer | Major Depressive Disorder |
Lung Cancer | Anxiety Disorders |
Colorectal Cancer | Schizophrenia / Bipolar Disorder |
Prostate Cancer | Asthma |
Blood Cancers (Leukemia/Lymphoma/Myeloma) | COPD |
Rheumatoid Arthritis | Atopic Dermatitis / Eczema |
Psoriasis / Psoriatic Arthritis | Chronic Pain / Neuropathic Pain |
Inflammatory Bowel Disease (Crohn's/UC) | Osteoarthritis |
Heart Failure | Rare Disease |
Hypertension / Hyperlipidemia | Other |
Multiple Sclerosis |
Versioning
The current API version is v1, reflected in the URL path (/api/v1). Backwards-incompatible changes ship under a new version prefix; additive changes (new optional request fields, new response fields) may appear within v1, so clients should ignore unrecognized response fields. Unrecognized request fields — and fields that are recognized but not applicable to the chosen model_type (e.g. context or demographics sent to the hcp model, or medical_specialty sent to a non-HCP model) — are rejected with a validation_error.