Input Data
Input data sets, lists, groups, and variant generation for crowd task customization.
Input data lets you structure the information presented to crowd workers in a reusable, parameterised way. Rather than creating one crowd task per content item by hand, you define an input data set containing one or more lists of plain string values and let Crowdee generate task variants automatically by substituting ###listName### placeholders in a survey template at task-claim time.
Data Hierarchy
Input data is organised in three tiers.
Input data set — The top-level container. Has a name, an optional description, a scope ("project" or "organization" — organization-scoped sets can be reused across projects), and a language. It groups together all the lists and groups that belong to a single campaign.
List — A flat, ordered array of plain strings, e.g. ["Summarize this article.", "Translate this sentence."]. Lists are not JSON records with multiple fields — each value is a single string. Every list within a data set needs a unique name; that name is what a template's ###name### placeholder resolves against.
Group — Pairs two or more same-length lists so their values move together, index-by-index, as a single task variant axis instead of being cross-multiplied against each other. For example, a headline list and a url list of the same length, grouped together, produce one variant per (headline, url) pair at the same row — not the full cross-product of every headline with every url.
Creating an Input Data Set
Lists (and optional groups) are created together with the data set in a single call — there's no separate "add a list" endpoint. language is required.
POST /v2/projects/:projectId/input-data{
"name": "News Article Review Campaign — Q3 2025",
"description": "Articles selected for systematic manipulation analysis",
"scope": "project",
"language": "en",
"lists": [
{ "name": "headline", "values": ["Central bank raises rates", "Election results disputed"] },
{ "name": "url", "values": ["https://example.com/article-1", "https://example.com/article-2"] }
],
"groups": [
{ "name": "articles", "listNames": ["headline", "url"] }
]
}A group's member lists must all have exactly the same number of values (headline and url above both have 2) — index i of one list is paired with index i of every other list in the group. Groups need at least two member lists.
The response is the created data set with its lists and groups nested inline (each list carries its own id/name/values).
Adding a Group Later
Groups can be added to an existing data set after the fact — lists cannot (see CSV Import for the only way to add more lists):
POST /v2/input-data/:dataSetId/groups{ "name": "articles", "listNames": ["headline", "url"] }Variant Generation
A data set's total variant count is the product of every slot — each ungrouped list is its own slot, and each group is a single slot (sized to its member lists' shared length, since they move together):
- One ungrouped list of 5 values → 5 variants.
- One ungrouped list of 5 values and a separate ungrouped list of 4 values → 5 × 4 = 20 variants.
- A group of two 5-value lists (instead of two separate ungrouped lists) → 5 variants, not 25 — the whole point of grouping is to avoid the cross-product.
GET /v2/input-data/:dataSetId/variants{
"count": 5,
"variants": [
{
"index": 0,
"slots": [
{ "type": "group", "id": "grp_abc", "name": "articles", "valueIndex": 0, "values": { "headline": "Central bank raises rates", "url": "https://example.com/article-1" } }
]
}
]
}Variant counts are capped at 10,000 per data set — both POST /v2/projects/:projectId/input-data and POST /v2/input-data/:dataSetId/groups reject a request that would push the total over that limit.
When a job references a data set (inputDataSetId on job creation), one variant is assigned per task at claim time, and every list name in that variant's merged values (e.g. {"headline": "...", "url": "..."}) is available to substitute into the job's survey template as ###headline###, ###url###, etc.
CSV Import
For large data sets, import a CSV directly — each column becomes its own list (named after its header), and if there's more than one column they're automatically grouped together (so a row's cells stay associated with each other, rather than being cross-multiplied):
curl -X POST https://api.crowdee.ai/v2/projects/{projectId}/input-data/from-csv \
-H "X-API-Key: crw_YOUR_API_KEY" \
-F "language=en" \
-F "scope=project" \
-F "file=@articles.csv"The data set's name is derived from the file name (there's no separate name field for this endpoint). The CSV's header row becomes list names, and every other row becomes that list's values — so a two-column CSV (headline,url) becomes two lists automatically grouped as one variant axis, exactly like the manual example above.
Managing Data Sets
GET /v2/projects/:projectId/input-data— list a project's data sets.GET /v2/input-data/:dataSetId— get one, with its lists and groups.PUT /v2/input-data/:dataSetId— updatename/description/scope/languageonly (not lists — data sets are otherwise append-only for lists).DELETE /v2/input-data/:dataSetId— rejected if the data set is referenced by a paid crowdsourcing job.
How is this guide?