Jobs
A job is a batch of tasks posted to the Effect AI worker network. Workers complete tasks and submit answers; you poll for results.
Credits are debited upfront at job creation (reward × taskCount). If a
job fails to create after the debit, credits are automatically refunded.
Job types
| Type | How it works | Best for |
|---|---|---|
csv | One task per CSV row, each row seen by one worker | Labelling, classification, transcription |
constant | Same data sent to up to maxTasks different workers | Surveys, repeated annotation, consensus tasks |
Estimate cost
POST /v1/jobs/estimate
Validates a job and returns the cost without charging your account.
CSV estimate
curl -s -X POST "https://api.effect.ai/v1/jobs/estimate" \
-H "Authorization: Bearer eff_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "csv",
"templateId": "TEMPLATE_ID",
"reward": "0.5",
"csv": "product,question\nWidget A,Is this good?\nGadget B,Is this good?"
}'Constant estimate
curl -s -X POST "https://api.effect.ai/v1/jobs/estimate" \
-H "Authorization: Bearer eff_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "constant",
"templateId": "TEMPLATE_ID",
"reward": "0.2",
"maxTasks": 50,
"data": {"product": "Widget A", "question": "Is this good?"}
}'200
{
"type": "csv",
"taskCount": 2,
"rewardPerTask": "0.5",
"cost": "1",
"currency": "EFFECT",
"balance": "25",
"sufficient": true
}Create a job
POST /v1/jobs
Creates a job, debits your credits, and immediately begins posting tasks to workers.
CSV job
curl -s -X POST "https://api.effect.ai/v1/jobs" \
-H "Authorization: Bearer eff_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "csv",
"name": "Sentiment Labelling",
"templateId": "TEMPLATE_ID",
"reward": "0.5",
"csv": "product,question\nWidget A,Is this good?\nGadget B,Is this good?",
"uniqueWorker": false,
"timeLimitSeconds": 600
}'| Field | Required | Description |
|---|---|---|
type | Yes | "csv" |
name | No | Display name for the job (defaults to "Untitled job") |
templateId | Yes | ID of the template to use |
reward | Yes | EFFECT reward per completed task (0.001-100) |
csv | Yes | CSV string where the first row is the header, max 10,000 rows |
uniqueWorker | No | true prevents the same worker completing multiple tasks |
timeLimitSeconds | No | Seconds a worker has to complete a task before re-queue (default 600) |
capability | No | Filter to workers with a specific capability tag |
Constant job
curl -s -X POST "https://api.effect.ai/v1/jobs" \
-H "Authorization: Bearer eff_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "constant",
"name": "Widget Survey",
"templateId": "TEMPLATE_ID",
"reward": "0.2",
"maxTasks": 25,
"data": {"product": "Widget A", "question": "Is this good?"},
"uniqueWorker": true
}'| Field | Required | Description |
|---|---|---|
type | Yes | "constant" |
name | No | Display name (defaults to "Untitled job") |
templateId | Yes | Template ID |
reward | Yes | EFFECT reward per completed task |
maxTasks | Yes | How many workers should answer (cost = reward × maxTasks, max 10,000) |
data | Yes | Object with a key for each template field |
uniqueWorker | No | true ensures each worker answers only once (recommended for surveys) |
timeLimitSeconds | No | Seconds per task before re-queue (default 600) |
capability | No | Capability filter |
Response 201 (same shape for both types)
{
"id": "01JQKX3Z8VFNWRB2TGHM4Y5P6B",
"name": "Sentiment Labelling",
"type": "csv",
"status": "active",
"templateId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"reward": "0.5",
"taskCount": 2,
"uniqueWorker": false,
"createdAt": 1750000100000,
"tasks": {
"queued": 2,
"active": 0,
"completed": 0,
"failed": 0
},
"credits": {
"currency": "EFFECT",
"reserved": "1",
"consumed": "0",
"refunded": "0",
"remaining": "1"
}
}Bulk survey
POST /v1/jobs/bulk
Creates one constant job per CSV row: the bulk equivalent of the
constant job above. Takes the same body, except csv
replaces data: every row becomes its own job of maxTasks tasks. Use it
when you have many things to survey and want each one answered by several
workers.
curl -s -X POST "https://api.effect.ai/v1/jobs/bulk" \
-H "Authorization: Bearer eff_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Clickability",
"templateId": "TEMPLATE_ID",
"reward": "0.05",
"maxTasks": 15,
"uniqueWorker": true,
"csv": "imageUrl,purpose\nexample.com/a.png,Social post\nexample.com/b.png,Flyer"
}'| Field | Required | Description |
|---|---|---|
name | No | Display name applied to every row's job |
templateId | Yes | Template ID |
reward | Yes | EFFECT reward per completed task |
maxTasks | Yes | Workers per row (cost = reward × rows × maxTasks) |
csv | Yes | CSV string, first row is the header; each row becomes its own job |
uniqueWorker | No | true limits each worker to one answer per row (recommended) |
timeLimitSeconds | No | Seconds per task before re-queue (default 600) |
capability | No | Capability filter |
201
{
"created": 2,
"jobs": [
{ "id": "01JQKX3Z8VFNWRB2TGHM4Y5P6B", "type": "constant", "taskCount": 15, "..." : "..." },
{ "id": "01JQKX3Z8VFNWRB2TGHM4Y5P6C", "type": "constant", "taskCount": 15, "..." : "..." }
]
}Each entry in jobs has the same shape as a single job creation response.
Partial runs. Rows are created one at a time, and the run stops at the first failure (a row missing a template field, or credits running out mid-run). The response then carries the failing status plus whatever was already created: those jobs are real and already charged. Nothing is charged for rows that were never reached:
{
"created": 12,
"jobs": ["..."],
"failedRow": 12,
"error": { "code": "insufficient_credits", "message": "..." }
}Estimate the run first (POST /v1/jobs/estimate with type: "csv" and the
same CSV gives you the row count) to avoid running out partway.
List jobs
GET /v1/jobs
Returns all your jobs, newest first. Supports limit / offset pagination.
curl -s "https://api.effect.ai/v1/jobs?limit=10&offset=0" \
-H "Authorization: Bearer eff_live_YOUR_KEY"200
{
"jobs": [
{
"id": "01JQKX3Z8VFNWRB2TGHM4Y5P6B",
"name": "Sentiment Labelling",
"type": "csv",
"status": "active",
"templateId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"reward": "0.5",
"taskCount": 2,
"uniqueWorker": false,
"createdAt": 1750000100000,
"tasks": { "queued": 0, "active": 1, "completed": 1, "failed": 0 },
"credits": {
"currency": "EFFECT",
"reserved": "1",
"consumed": "0.5",
"refunded": "0",
"remaining": "0.5"
}
}
],
"total": 1,
"limit": 10,
"offset": 0
}Get job status
GET /v1/jobs/:id
Returns live task counts and credit breakdown. Poll this to monitor progress.
A job is fully complete when tasks.queued + tasks.active === 0.
curl -s "https://api.effect.ai/v1/jobs/JOB_ID" \
-H "Authorization: Bearer eff_live_YOUR_KEY"200
{
"id": "01JQKX3Z8VFNWRB2TGHM4Y5P6B",
"name": "Sentiment Labelling",
"type": "csv",
"status": "active",
"templateId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"reward": "0.5",
"taskCount": 2,
"uniqueWorker": false,
"createdAt": 1750000100000,
"tasks": {
"queued": 0,
"active": 1,
"completed": 1,
"failed": 0
},
"credits": {
"currency": "EFFECT",
"reserved": "1",
"consumed": "0.5",
"refunded": "0",
"remaining": "0.5"
}
}Get results
GET /v1/jobs/:id/results
Returns completed task results, newest first. Available as JSON (default) or CSV download.
JSON results
curl -s "https://api.effect.ai/v1/jobs/JOB_ID/results?limit=10&offset=0" \
-H "Authorization: Bearer eff_live_YOUR_KEY"200
{
"jobId": "01JQKX3Z8VFNWRB2TGHM4Y5P6B",
"count": 2,
"total": 2,
"limit": 100,
"offset": 0,
"results": [
{
"taskId": "01JQKX3Z8VFNWRB2TGHM4Y5P6D",
"submittedAt": 1750000300000,
"worker": "12D3KooWHYeaXgA4Rv8sqFGrLnh6sLNAS2jxaw1KhaSsYGT3PQab",
"input": {
"product": "Gadget B",
"question": "Is this good?"
},
"result": "{\"answer\":\"yes\",\"confidence\":0.9}"
},
{
"taskId": "01JQKX3Z8VFNWRB2TGHM4Y5P6C",
"submittedAt": 1750000200000,
"worker": "12D3KooWRv8sqFGrHYeaXgA4Lnh6sLNAS2jxaw1KhaSsYGT3PQcd",
"input": {
"product": "Widget A",
"question": "Is this good?"
},
"result": "{\"answer\":\"no\",\"confidence\":0.7}"
}
]
}| Field | Description |
|---|---|
worker | Worker's peer ID on the network |
input | The CSV row data shown to the worker |
result | JSON string containing the values the worker submitted via postMessage |
CSV download
curl -s "https://api.effect.ai/v1/jobs/JOB_ID/results?format=csv" \
-H "Authorization: Bearer eff_live_YOUR_KEY" \
-o results.csvCSV columns: taskId, submittedAt, worker, input, result
Cancel a job
POST /v1/jobs/:id/cancel
Stops the job immediately: no further tasks are posted to workers, and tasks currently in progress are not collected. Credits are refunded for every task without a completed submission at the moment of cancellation, both queued and in-progress. You only pay for tasks that were already completed.
This is idempotent, so cancelling an already-cancelled job returns 200.
curl -s -X POST "https://api.effect.ai/v1/jobs/JOB_ID/cancel" \
-H "Authorization: Bearer eff_live_YOUR_KEY"200
{
"id": "01JQKX3Z8VFNWRB2TGHM4Y5P6B",
"name": "Sentiment Labelling",
"type": "csv",
"status": "cancelled",
"templateId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
"reward": "0.5",
"taskCount": 2,
"uniqueWorker": false,
"createdAt": 1750000100000,
"tasks": {
"queued": 0,
"active": 0,
"completed": 1,
"failed": 0
},
"credits": {
"currency": "EFFECT",
"reserved": "1",
"consumed": "0.5",
"refunded": "0.5",
"remaining": "0"
}
}1 task completed (0.5 EFFECT consumed), 1 task unfinished at cancellation
(0.5 EFFECT refunded). remaining reaches zero, so the account is fully
settled.