Jobs – Effect AI
Skip to content

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

TypeHow it worksBest for
csvOne task per CSV row, each row seen by one workerLabelling, classification, transcription
constantSame data sent to up to maxTasks different workersSurveys, repeated annotation, consensus tasks

Estimate cost

POST /v1/jobs/estimate

Validates a job and returns the cost without charging your account.

CSV estimate

curl
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
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?"}
  }'
Response 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
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
  }'
CSV job fields
FieldRequiredDescription
typeYes"csv"
nameNoDisplay name for the job (defaults to "Untitled job")
templateIdYesID of the template to use
rewardYesEFFECT reward per completed task (0.001-100)
csvYesCSV string where the first row is the header, max 10,000 rows
uniqueWorkerNotrue prevents the same worker completing multiple tasks
timeLimitSecondsNoSeconds a worker has to complete a task before re-queue (default 600)
capabilityNoFilter to workers with a specific capability tag

Constant job

curl
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
  }'
Constant job fields
FieldRequiredDescription
typeYes"constant"
nameNoDisplay name (defaults to "Untitled job")
templateIdYesTemplate ID
rewardYesEFFECT reward per completed task
maxTasksYesHow many workers should answer (cost = reward × maxTasks, max 10,000)
dataYesObject with a key for each template field
uniqueWorkerNotrue ensures each worker answers only once (recommended for surveys)
timeLimitSecondsNoSeconds per task before re-queue (default 600)
capabilityNoCapability 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
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"
  }'
Bulk survey fields
FieldRequiredDescription
nameNoDisplay name applied to every row's job
templateIdYesTemplate ID
rewardYesEFFECT reward per completed task
maxTasksYesWorkers per row (cost = reward × rows × maxTasks)
csvYesCSV string, first row is the header; each row becomes its own job
uniqueWorkerNotrue limits each worker to one answer per row (recommended)
timeLimitSecondsNoSeconds per task before re-queue (default 600)
capabilityNoCapability filter
Response 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
curl -s "https://api.effect.ai/v1/jobs?limit=10&offset=0" \
  -H "Authorization: Bearer eff_live_YOUR_KEY"
Response 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
curl -s "https://api.effect.ai/v1/jobs/JOB_ID" \
  -H "Authorization: Bearer eff_live_YOUR_KEY"
Response 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
curl -s "https://api.effect.ai/v1/jobs/JOB_ID/results?limit=10&offset=0" \
  -H "Authorization: Bearer eff_live_YOUR_KEY"
Response 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}"
    }
  ]
}
FieldDescription
workerWorker's peer ID on the network
inputThe CSV row data shown to the worker
resultJSON string containing the values the worker submitted via postMessage

CSV download

curl
curl -s "https://api.effect.ai/v1/jobs/JOB_ID/results?format=csv" \
  -H "Authorization: Bearer eff_live_YOUR_KEY" \
  -o results.csv

CSV 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
curl -s -X POST "https://api.effect.ai/v1/jobs/JOB_ID/cancel" \
  -H "Authorization: Bearer eff_live_YOUR_KEY"
Response 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.