DocsDevelopers

TaskerData API

Place campaigns, collect workers' submissions and review them from your own code, or connect an external qualification test. Every request is authenticated with your API key.

Overview

The Campaign API lets your code do what you do in the requester dashboard: create campaigns, follow their progress, download submissions with their proof and approve or reject them. The external qualification endpoints let a test on your own website tell TaskerData whether each worker passed.

All requests go to https://taskerdata.com over HTTPS. Send and receive JSON.

Campaigns created through the API cost the same and follow the same rules as in the dashboard. TaskerData reviews them before they go live (trusted requesters go live straight away), and money is reserved and paid out the same way.

Authentication

Open the requester dashboard and go to API. You will find two keys there:

  • API key: for real requests. The Campaign API reads it from the Authorization header. The qualification endpoint takes it as api_token.
  • Test API key: only for the qualification test endpoint, so you can try that integration without touching real workers.

Generating a new key replaces the old one straight away, so update your backend when you do. You can generate up to 3 new keys per hour.

Important: Keep your API key secret. Use it only on your server, never in a web page or app that visitors can open.

Send your API key with every Campaign API request:

Authorization: Bearer YOUR_API_KEY

You can make up to 120 Campaign API requests per minute. The X-RateLimit-Remaining header shows how many are left. After that you get status 429, and the Retry-After header says how many seconds to wait.

Campaign API

Create campaigns and handle the work they bring in, from your own code.

List campaigns

GET/api/v1/campaigns

Your campaigns, newest first. total is how many campaigns match, so you can page through them with limit and offset.

Query parameters

ParameterDescription
status Only campaigns with this status: pending, in review, active, paused, completed, terminated or rejected
limit How many to return, 1 to 100 (default 20)
offset How many to skip, for paging (default 0)
curl "https://taskerdata.com/api/v1/campaigns?status=active&limit=20" \
  -H "Authorization: Bearer $TASKERDATA_API_KEY"

Response · 200

{
  "success": true,
  "campaigns": [
    {
      "id": "Ab12…-Cd34…-Ef56…",
      "title": "Test our sign-up page",
      "status": "active",
      "category": "Website Testing",
      "type": "instructions",
      "url": "https://example.com/signup",
      "payment": 0.5,
      "positions": 50,
      "filled_positions": 12,
      "time_to_complete": 10,
      "time_to_rate": 3,
      "cost": 34.06,
      "proof": {
        "text": "What went wrong?",
        "images": [
          "Screenshot after signing up"
        ],
        "video": null
      },
      "qualification_id": null,
      "created_at": "2026-10-16T09:30:00.000Z"
    }
  ],
  "total": 1,
  "limit": 20,
  "offset": 0
}

Error example

// status 401
{
  "success": false,
  "error": {
    "code": "invalid_api_key",
    "message": "Invalid API key."
  }
}

Get a campaign

GET/api/v1/campaigns/{id}

One campaign with its settings and how many submissions are waiting for review, waiting for a revision, approved and rejected. Use it to follow a campaign's progress.

In the address

ParameterDescription
id requiredThe campaign ID (id in the campaign list)
curl "https://taskerdata.com/api/v1/campaigns/CAMPAIGN_ID" \
  -H "Authorization: Bearer $TASKERDATA_API_KEY"

Response · 200

{
  "success": true,
  "campaign": {
    "id": "Ab12…-Cd34…-Ef56…",
    "title": "Test our sign-up page",
    "status": "active",
    "category": "Website Testing",
    "type": "instructions",
    "url": "https://example.com/signup",
    "payment": 0.5,
    "positions": 50,
    "filled_positions": 12,
    "time_to_complete": 10,
    "time_to_rate": 3,
    "cost": 34.06,
    "proof": {
      "text": "What went wrong?",
      "images": [
        "Screenshot after signing up"
      ],
      "video": null
    },
    "qualification_id": null,
    "created_at": "2026-10-16T09:30:00.000Z",
    "submissions": {
      "total": 14,
      "to_review": 3,
      "revision_requested": 1,
      "approved": 9,
      "rejected": 1
    }
  }
}

Error example

// status 404
{
  "success": false,
  "error": {
    "code": "not_found",
    "message": "Campaign not found."
  }
}

Create a campaign

POST/api/v1/campaigns

Places a new campaign and reserves its full cost from your available balance, exactly like the dashboard. The answer includes the campaign's id, its cost and its status: pending while TaskerData reviews it, or active straight away if you are a trusted requester.

JSON body

ParameterDescription
title requiredCampaign title, up to 100 characters
category requiredA category from GET /api/v1/options. Leave it out when you use a template
instructions requiredWhat workers should do, up to 5,000 characters
url The link workers open. Required for categories where needs_url is true
payment requiredPayment per task in USD, at least 0.12
positions requiredHow many workers, at least 10. With a template data file it is worked out from the rows
time_to_complete requiredMinutes a worker has to finish, 1 to 120
time_to_rate requiredDays you have to review each submission, 1 to 30. After that it is approved automatically
proof.text Ask for a text answer: tell the worker what to write
proof.images Ask for screenshots or photos: one description per image
proof.video Ask for a video or a recording: what it should show
targeting.region international (default), usa, west-europe, east-europe, latin-america or asia-africa
targeting.exclude_countries Country names to leave out of the region
targeting.min_success_rate Minimum worker success rate: 75 (default), 80, 85, 90, 95 or 100
targeting.type, targeting.group_id Set type to "group" and group_id to one of your worker groups to send the task only to that group
qualification_id Only workers who passed this qualification test can take the task
template Use one of your templates instead of instructions: id, plus data with columns and rows that fill its placeholders, one row per task. answers_per_row (1 to 5) and rows_per_task (1 to 50) are optional
drip_feed Release workers in batches: min_workers and max_workers (1 to 50) and interval_minutes (15, 30, 60, 120, 180, 360, 720 or 1440)
location For Local Field Tasks and Mystery Shopping: lat, lng, radius_m (50 to 50,000) and an optional address

For now, categories that need files you upload (such as Audio Transcription or Image Tagging), video tasks and example images can only be created in the dashboard. The Costs and fees guide explains how the price is calculated.

curl -X POST "https://taskerdata.com/api/v1/campaigns" \
  -H "Authorization: Bearer $TASKERDATA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Test our sign-up page",
    "category": "Website Testing",
    "url": "https://example.com/signup",
    "instructions": "Open the page, create an account and tell us anything that went wrong.",
    "payment": 0.5,
    "positions": 50,
    "time_to_complete": 10,
    "time_to_rate": 3,
    "proof": {
      "text": "What went wrong?",
      "images": [
        "Screenshot after signing up"
      ]
    },
    "targeting": {
      "region": "international",
      "min_success_rate": 90
    }
  }'

Response · 201

{
  "success": true,
  "campaign": {
    "id": "Ab12…-Cd34…-Ef56…",
    "title": "Test our sign-up page",
    "status": "pending",
    "category": "Website Testing",
    "type": "instructions",
    "url": "https://example.com/signup",
    "payment": 0.5,
    "positions": 50,
    "filled_positions": 0,
    "time_to_complete": 10,
    "time_to_rate": 3,
    "cost": 34.06,
    "proof": {
      "text": "What went wrong?",
      "images": [
        "Screenshot after signing up"
      ],
      "video": null
    },
    "qualification_id": null,
    "created_at": "2026-10-16T09:30:00.000Z"
  },
  "balance": {
    "available": 65.94,
    "reserved": 34.06
  }
}

Error example

// status 402
{
  "success": false,
  "error": {
    "code": "insufficient_balance",
    "message": "Insufficient balance"
  }
}

Get submissions

GET/api/v1/campaigns/{id}/submissions

The work workers sent for one campaign, oldest first, with their proof: the text answer, links to images and video, template answers (answers), the data row they worked on and, for field tasks, their location.

In the address

ParameterDescription
id requiredThe campaign ID (id in the campaign list)

Query parameters

ParameterDescription
status to_review (pending and resubmitted), pending, resubmitted, revision_requested, approved or rejected
since Only submissions sent at or after this time, for example 2026-10-01T00:00:00Z
after_id For paging: only submissions with a higher id. Use next_after_id from the previous page
limit How many to return, 1 to 100 (default 50)

To collect new work regularly, keep the last id you received and send it as after_id next time. raw holds everything the worker sent, in case you need something that isn't listed.

curl "https://taskerdata.com/api/v1/campaigns/CAMPAIGN_ID/submissions?status=to_review&after_id=0" \
  -H "Authorization: Bearer $TASKERDATA_API_KEY"

Response · 200

{
  "success": true,
  "submissions": [
    {
      "id": 1842,
      "campaign_id": "Ab12…-Cd34…-Ef56…",
      "worker_id": "wK3…",
      "status": "pending",
      "started_at": "2026-10-16 10:02:11",
      "submitted_at": "2026-10-16 10:09:45",
      "revision_count": 0,
      "revision_note": null,
      "rejection_reason": null,
      "payment": 0.5,
      "proof": {
        "text": "The confirm button did nothing on mobile.",
        "image_urls": [
          "https://storage.taskerdata.com/…/proof_0.png"
        ],
        "video_url": null
      },
      "answers": null,
      "data_row": null,
      "data_row_number": null,
      "items": null,
      "location": null,
      "raw": {
        "textProof": "…"
      }
    }
  ],
  "has_more": false,
  "next_after_id": null
}

Error example

// status 400
{
  "success": false,
  "error": {
    "code": "invalid_status",
    "message": "status must be one of: to_review, pending, resubmitted, revision_requested, approved, rejected."
  }
}

Review a submission

POST/api/v1/submissions/{id}/review

Approve, reject or ask for a revision, the same as the buttons in the dashboard. Approving pays the worker from the reserved money. Rejecting returns the payment and its fee to your balance and frees the position for another worker.

In the address

ParameterDescription
id requiredThe submission ID

JSON body

ParameterDescription
action requiredapprove, reject or revision
reason With reject: the reason the worker sees
note With revision (required): what the worker should fix

You can review a submission only while it is waiting for review (pending or resubmitted). Revisions are limited by the campaign's revision limit; after that you can only approve or reject.

curl -X POST "https://taskerdata.com/api/v1/submissions/1842/review" \
  -H "Authorization: Bearer $TASKERDATA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "action": "revision",
    "note": "Please add a screenshot of the error message."
  }'

Response · 200

{
  "success": true,
  "submission": {
    "id": 1842,
    "status": "revision_requested"
  },
  "balance": {
    "available": 65.94,
    "reserved": 34.06
  }
}

Error example

// status 409
{
  "success": false,
  "error": {
    "code": "already_reviewed",
    "message": "Submission already reviewed"
  }
}

Check your balance

GET/api/v1/balance

available is what you can spend on new campaigns, reserved is held for live campaigns, and spent is what you have paid workers so far.

curl "https://taskerdata.com/api/v1/balance" \
  -H "Authorization: Bearer $TASKERDATA_API_KEY"

Response · 200

{
  "success": true,
  "balance": {
    "available": 65.94,
    "reserved": 34.06,
    "spent": 212.4
  }
}

Options and IDs

GET/api/v1/options

Lists the categories you can use through the API (needs_url and needs_location show which ones need a link or a location), the allowed targeting and drip feed values, and the IDs of your templates, worker groups and qualification tests.

curl "https://taskerdata.com/api/v1/options" \
  -H "Authorization: Bearer $TASKERDATA_API_KEY"

Response · 200

{
  "success": true,
  "categories": [
    {
      "name": "Website Testing",
      "needs_url": true,
      "needs_location": false
    },
    "…"
  ],
  "regions": [
    "international",
    "usa",
    "west-europe",
    "east-europe",
    "latin-america",
    "asia-africa"
  ],
  "min_success_rates": [
    75,
    80,
    85,
    90,
    95,
    100
  ],
  "drip_feed_intervals": [
    15,
    30,
    60,
    120,
    180,
    360,
    720,
    1440
  ],
  "templates": [
    {
      "id": 12,
      "title": "Sentiment check"
    }
  ],
  "worker_groups": [
    {
      "id": 3,
      "name": "Trusted testers",
      "workers": 25
    }
  ],
  "qualifications": [
    {
      "id": "Qa1…",
      "title": "English test",
      "status": "active"
    }
  ]
}

Errors

The Campaign API uses HTTP status codes. When something goes wrong, success is false and error has a code to check in your code and a message to show or log. Campaign checks use the same messages as the dashboard.

Statuserror.codeWhat it means
400invalid_body, invalid_campaign, invalid_region, category_needs_files, invalid_status, invalid_since, invalid_action, note_requiredSomething in the request is missing or not allowed. message says what.
401missing_api_key, invalid_api_keyNo API key, or the key is wrong or was replaced by a newer one.
402insufficient_balanceYour available balance doesn't cover the campaign. Add funds and try again.
403test_key_not_allowed, account_suspendedUse your live API key. A suspended account can't use the API.
404not_foundThere is no campaign or submission with that ID in your account.
409already_reviewed, review_refusedThe submission was already reviewed, or the review isn't possible right now, for example because the revision limit was reached.
429rate_limitedMore than 120 requests in a minute. Wait the number of seconds in Retry-After.
500internal_errorA problem on our side. Try again, and contact support if it keeps happening.

External qualification tests

For qualification tests that run on your own website.

Report a test result Live

GET/api/worker/external_qualification/data

For qualification tests marked as external. The worker opens your test from the qualification and enters their worker token on your website. When they finish, call this endpoint with approve or reject.

ParameterDescription
qualification_id requiredThe ID of your qualification test
worker_token requiredThe worker token the worker entered on your website
api_token requiredYour API key (the test key for the test endpoint)
decision requiredapprove or reject

If the test pays a bonus for passing and your requester balance can't cover it, the submission is saved as pending instead, so you can top up and approve it in the dashboard.

A worker can be evaluated once per test. The test must be active and marked as external, and the API key must belong to the test's owner.

curl -G "https://taskerdata.com/api/worker/external_qualification/data" \
  --data-urlencode "qualification_id=QUAL_ID" \
  --data-urlencode "worker_token=WORKER_TOKEN" \
  --data-urlencode "api_token=YOUR_API_KEY" \
  --data-urlencode "decision=approve"

Response · 200

{
  "success": true
}

Error example

{
  "success": false,
  "error": "This worker has already been evaluated for this qualification"
}

Test your setup

POST/api/worker/external_qualification/data_test

Send the same fields as JSON to the test endpoint, with your test API key. Nothing is saved and no worker is affected: it only checks your request.

ParameterDescription
qualification_id requiredThe ID of your qualification test
worker_token requiredThe worker token the worker entered on your website
api_token requiredYour API key (the test key for the test endpoint)
decision requiredapprove or reject

A wrong test key returns status 401; missing fields or a wrong decision return status 400.

curl -X POST "https://taskerdata.com/api/worker/external_qualification/data_test" \
  -H "Content-Type: application/json" \
  -d '{
    "qualification_id": "QUAL_ID",
    "worker_token": "WORKER_TOKEN",
    "api_token": "YOUR_TEST_API_KEY",
    "decision": "approve"
  }'

Response · 200

{
  "success": true
}

Error example

// status 401
{
  "statusCode": 401,
  "statusMessage": "Invalid API test key"
}

Test result errors

The result endpoint always answers with status 200. Check success: when it is false, error says why:

errorWhat it means
Missing required parameters: qualification_id, worker_token, api_token, decisionOne of the four parameters is missing.
Decision must be 'approve' or 'reject'decision has another value.
Invalid API tokenThe API key is wrong or was replaced by a newer one.
Worker token not found for this qualificationThe token doesn't belong to this test. Ask the worker to check it.
API token does not belong to the qualification ownerUse the key of the account that created the test.
This qualification is not configured for external submissionsThe test isn't marked as external.
This qualification is no longer activeThe test is paused or finished.
This worker has already been evaluated for this qualificationEach worker gets one result per test.
Worker account is suspendedThe worker can't take tests right now.
No remaining positions for this qualificationAll places in the test are taken.