> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.prolific.com/llms.txt.
> For full documentation content, see https://docs.prolific.com/llms-full.txt.

# Get Started: Running AI Task Builder Batches via Prolific's API

# What you'll accomplish

* Upload raw datapoints (e.g., text, image URLs) into an **AI Task Builder Dataset**
* Create an **AI Task Builder Batch** and attach **Instructions**
* Convert your dataset into **tasks** and wait until the batch is **READY**
* Create and **publish a Prolific study** that references the batch
* Pull **annotated responses** from the batch

For detailed reference documentation, see:

* [Working with Batches](/api-reference/ai-task-builder/batches)
* [Working with Datasets](/api-reference/ai-task-builder/datasets)
* [Instructions](/api-reference/ai-task-builder/instructions)

# Prerequisites

* Your **workspace\_id**
* Your **API token** (`Authorization: Token ...`)
* Decide how many **tasks per participant** you want to show (via `tasks_per_group`)
* Decide your **study** settings (reward, sample size, timing, targeting)

# Step-by-step guide

<Steps>
  <Step>
    ## Create a Dataset

    Create a container that will hold the datapoints participants will annotate.

    ### Request

    POST [https://api.prolific.com/api/v1/data-collection/datasets](https://api.prolific.com/api/v1/data-collection/datasets)

    ```curl
    curl -X POST https://api.prolific.com/api/v1/data-collection/datasets \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json" \
         -d '{
      "name": "Customer Feedback Dataset",
      "workspace_id": "6278acb09062db3b35bcbeb0"
    }'
    ```

    ```python
    import requests

    url = "https://api.prolific.com/api/v1/data-collection/datasets"

    payload = {
        "name": "Customer Feedback Dataset",
        "workspace_id": "6278acb09062db3b35bcbeb0"
    }
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript
    const url = 'https://api.prolific.com/api/v1/data-collection/datasets';
    const options = {
      method: 'POST',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{"name":"Customer Feedback Dataset","workspace_id":"6278acb09062db3b35bcbeb0"}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/data-collection/datasets"

    	payload := strings.NewReader("{\n  \"name\": \"Customer Feedback Dataset\",\n  \"workspace_id\": \"6278acb09062db3b35bcbeb0\"\n}")

    	req, _ := http.NewRequest("POST", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/data-collection/datasets")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Post.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{\n  \"name\": \"Customer Feedback Dataset\",\n  \"workspace_id\": \"6278acb09062db3b35bcbeb0\"\n}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.post("https://api.prolific.com/api/v1/data-collection/datasets")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{\n  \"name\": \"Customer Feedback Dataset\",\n  \"workspace_id\": \"6278acb09062db3b35bcbeb0\"\n}")
      .asString();
    ```

    ```php
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('POST', 'https://api.prolific.com/api/v1/data-collection/datasets', [
      'body' => '{
      "name": "Customer Feedback Dataset",
      "workspace_id": "6278acb09062db3b35bcbeb0"
    }',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/data-collection/datasets");
    var request = new RestRequest(Method.POST);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{\n  \"name\": \"Customer Feedback Dataset\",\n  \"workspace_id\": \"6278acb09062db3b35bcbeb0\"\n}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = [
      "name": "Customer Feedback Dataset",
      "workspace_id": "6278acb09062db3b35bcbeb0"
    ] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/datasets")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    Response will include `id` (your `dataset_id`) and `status` (one of `UNINITIALISED|PROCESSING|READY|ERROR`).
  </Step>

  <Step>
    ## Request An Upload URL For Your Data

    Upload one or more files (CSV format) that contain the datapoints.

    ### Request

    GET [https://api.prolific.com/api/v1/data-collection/datasets/\{dataset\_id}/upload-url/\{filename}](https://api.prolific.com/api/v1/data-collection/datasets/\{dataset_id}/upload-url/\{filename})

    ```curl
    curl https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json"
    ```

    ```python
    import requests

    url = "https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename"

    payload = {}
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.get(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript
    const url = 'https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename';
    const options = {
      method: 'GET',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename"

    	payload := strings.NewReader("{}")

    	req, _ := http.NewRequest("GET", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Get.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.get("https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{}")
      .asString();
    ```

    ```php
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('GET', 'https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename', [
      'body' => '{}',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename");
    var request = new RestRequest(Method.GET);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = [] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/datasets/dataset_id/upload-url/filename")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "GET"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    **The response body will be structured as follows**

    ```json
    {
        "upload_url": "string",
        "expires_at": "string",  // ISO-8601 DateTime string
        "http_method": "string", // PUT in all instances
        "dataset_id": "string"
    }
    ```
  </Step>

  <Step>
    ## Upload Your Data (files → dataset)

    Upload the file containing your datapoints.

    ```bash
    curl -X PUT "UPLOAD_URL_FROM_PREVIOUS_STEP" --data-binary "@{path_to_file}"
    ```

    **Poll status** until the dataset is processed:

    <RunnableEndpoint endpoint="GET /api/v1/data-collection/datasets/{dataset_id}" readonly={["examples"]} />

    ```bash
    {"status": "READY"} # (wait for READY)
    ```

    For advanced dataset options including metadata columns and custom task grouping, see [Working with Datasets](/api-reference/ai-task-builder/datasets).
  </Step>

  <Step>
    ## Create a Batch

    Batches bind datasets + instructions into something you can attach to a Prolific study.

    You can also include task details here with introductions and steps.
    `task_introduction` and `task_steps` fields support basic HTML.

    ### Request

    POST [https://api.prolific.com/api/v1/data-collection/batches](https://api.prolific.com/api/v1/data-collection/batches)

    ```curl
    curl -X POST https://api.prolific.com/api/v1/data-collection/batches \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json" \
         -d '{
      "name": "Sentiment Analysis Batch",
      "workspace_id": "6278acb09062db3b35bcbeb0",
      "task_details": {
        "task_name": "Evaluate Product Reviews",
        "task_introduction": "<p>In this task, you will analyze product reviews and categorize their sentiment.</p>",
        "task_steps": "<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>"
      },
      "dataset_id": "1234acb09999db4b99bcded1"
    }'
    ```

    ```python
    import requests

    url = "https://api.prolific.com/api/v1/data-collection/batches"

    payload = {
        "name": "Sentiment Analysis Batch",
        "workspace_id": "6278acb09062db3b35bcbeb0",
        "task_details": {
            "task_name": "Evaluate Product Reviews",
            "task_introduction": "<p>In this task, you will analyze product reviews and categorize their sentiment.</p>",
            "task_steps": "<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>"
        },
        "dataset_id": "1234acb09999db4b99bcded1"
    }
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript
    const url = 'https://api.prolific.com/api/v1/data-collection/batches';
    const options = {
      method: 'POST',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{"name":"Sentiment Analysis Batch","workspace_id":"6278acb09062db3b35bcbeb0","task_details":{"task_name":"Evaluate Product Reviews","task_introduction":"<p>In this task, you will analyze product reviews and categorize their sentiment.</p>","task_steps":"<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>"},"dataset_id":"1234acb09999db4b99bcded1"}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/data-collection/batches"

    	payload := strings.NewReader("{\n  \"name\": \"Sentiment Analysis Batch\",\n  \"workspace_id\": \"6278acb09062db3b35bcbeb0\",\n  \"task_details\": {\n    \"task_name\": \"Evaluate Product Reviews\",\n    \"task_introduction\": \"<p>In this task, you will analyze product reviews and categorize their sentiment.</p>\",\n    \"task_steps\": \"<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>\"\n  },\n  \"dataset_id\": \"1234acb09999db4b99bcded1\"\n}")

    	req, _ := http.NewRequest("POST", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/data-collection/batches")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Post.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{\n  \"name\": \"Sentiment Analysis Batch\",\n  \"workspace_id\": \"6278acb09062db3b35bcbeb0\",\n  \"task_details\": {\n    \"task_name\": \"Evaluate Product Reviews\",\n    \"task_introduction\": \"<p>In this task, you will analyze product reviews and categorize their sentiment.</p>\",\n    \"task_steps\": \"<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>\"\n  },\n  \"dataset_id\": \"1234acb09999db4b99bcded1\"\n}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.post("https://api.prolific.com/api/v1/data-collection/batches")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{\n  \"name\": \"Sentiment Analysis Batch\",\n  \"workspace_id\": \"6278acb09062db3b35bcbeb0\",\n  \"task_details\": {\n    \"task_name\": \"Evaluate Product Reviews\",\n    \"task_introduction\": \"<p>In this task, you will analyze product reviews and categorize their sentiment.</p>\",\n    \"task_steps\": \"<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>\"\n  },\n  \"dataset_id\": \"1234acb09999db4b99bcded1\"\n}")
      .asString();
    ```

    ```php
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('POST', 'https://api.prolific.com/api/v1/data-collection/batches', [
      'body' => '{
      "name": "Sentiment Analysis Batch",
      "workspace_id": "6278acb09062db3b35bcbeb0",
      "task_details": {
        "task_name": "Evaluate Product Reviews",
        "task_introduction": "<p>In this task, you will analyze product reviews and categorize their sentiment.</p>",
        "task_steps": "<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>"
      },
      "dataset_id": "1234acb09999db4b99bcded1"
    }',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/data-collection/batches");
    var request = new RestRequest(Method.POST);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{\n  \"name\": \"Sentiment Analysis Batch\",\n  \"workspace_id\": \"6278acb09062db3b35bcbeb0\",\n  \"task_details\": {\n    \"task_name\": \"Evaluate Product Reviews\",\n    \"task_introduction\": \"<p>In this task, you will analyze product reviews and categorize their sentiment.</p>\",\n    \"task_steps\": \"<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>\"\n  },\n  \"dataset_id\": \"1234acb09999db4b99bcded1\"\n}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = [
      "name": "Sentiment Analysis Batch",
      "workspace_id": "6278acb09062db3b35bcbeb0",
      "task_details": [
        "task_name": "Evaluate Product Reviews",
        "task_introduction": "<p>In this task, you will analyze product reviews and categorize their sentiment.</p>",
        "task_steps": "<ol><li>Read each review carefully</li><li>Select the appropriate sentiment</li><li>Provide a brief explanation</li></ol>"
      ],
      "dataset_id": "1234acb09999db4b99bcded1"
    ] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/batches")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    (**Note:** `dataset_id` is optional at creation time and can be added later via update, but must be provided before setup.)

    Save the returned `id` as `BATCH_ID`.
  </Step>

  <Steps>
    <Step>
      ### Update a Batch (optional)

      You can update a batch's name, task details, or associated dataset after creation.

      ### Request

      PATCH [https://api.prolific.com/api/v1/data-collection/batches/\{batch\_id}](https://api.prolific.com/api/v1/data-collection/batches/\{batch_id})

      ```curl
      curl -X PATCH https://api.prolific.com/api/v1/data-collection/batches/batch_id \
           -H "Authorization: Token <token>" \
           -H "Content-Type: application/json" \
           -d '{}'
      ```

      ```python
      import requests

      url = "https://api.prolific.com/api/v1/data-collection/batches/batch_id"

      payload = {}
      headers = {
          "Authorization": "Token <token>",
          "Content-Type": "application/json"
      }

      response = requests.patch(url, json=payload, headers=headers)

      print(response.json())
      ```

      ```javascript
      const url = 'https://api.prolific.com/api/v1/data-collection/batches/batch_id';
      const options = {
        method: 'PATCH',
        headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
        body: '{}'
      };

      try {
        const response = await fetch(url, options);
        const data = await response.json();
        console.log(data);
      } catch (error) {
        console.error(error);
      }
      ```

      ```go
      package main

      import (
      	"fmt"
      	"strings"
      	"net/http"
      	"io"
      )

      func main() {

      	url := "https://api.prolific.com/api/v1/data-collection/batches/batch_id"

      	payload := strings.NewReader("{}")

      	req, _ := http.NewRequest("PATCH", url, payload)

      	req.Header.Add("Authorization", "Token <token>")
      	req.Header.Add("Content-Type", "application/json")

      	res, _ := http.DefaultClient.Do(req)

      	defer res.Body.Close()
      	body, _ := io.ReadAll(res.Body)

      	fmt.Println(res)
      	fmt.Println(string(body))

      }
      ```

      ```ruby
      require 'uri'
      require 'net/http'

      url = URI("https://api.prolific.com/api/v1/data-collection/batches/batch_id")

      http = Net::HTTP.new(url.host, url.port)
      http.use_ssl = true

      request = Net::HTTP::Patch.new(url)
      request["Authorization"] = 'Token <token>'
      request["Content-Type"] = 'application/json'
      request.body = "{}"

      response = http.request(request)
      puts response.read_body
      ```

      ```java
      import com.mashape.unirest.http.HttpResponse;
      import com.mashape.unirest.http.Unirest;

      HttpResponse<String> response = Unirest.patch("https://api.prolific.com/api/v1/data-collection/batches/batch_id")
        .header("Authorization", "Token <token>")
        .header("Content-Type", "application/json")
        .body("{}")
        .asString();
      ```

      ```php
      <?php
      require_once('vendor/autoload.php');

      $client = new \GuzzleHttp\Client();

      $response = $client->request('PATCH', 'https://api.prolific.com/api/v1/data-collection/batches/batch_id', [
        'body' => '{}',
        'headers' => [
          'Authorization' => 'Token <token>',
          'Content-Type' => 'application/json',
        ],
      ]);

      echo $response->getBody();
      ```

      ```csharp
      using RestSharp;

      var client = new RestClient("https://api.prolific.com/api/v1/data-collection/batches/batch_id");
      var request = new RestRequest(Method.PATCH);
      request.AddHeader("Authorization", "Token <token>");
      request.AddHeader("Content-Type", "application/json");
      request.AddParameter("application/json", "{}", ParameterType.RequestBody);
      IRestResponse response = client.Execute(request);
      ```

      ```swift
      import Foundation

      let headers = [
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
      ]
      let parameters = [] as [String : Any]

      let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

      let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/batches/batch_id")! as URL,
                                              cachePolicy: .useProtocolCachePolicy,
                                          timeoutInterval: 10.0)
      request.httpMethod = "PATCH"
      request.allHTTPHeaderFields = headers
      request.httpBody = postData as Data

      let session = URLSession.shared
      let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
        if (error != nil) {
          print(error as Any)
        } else {
          let httpResponse = response as? HTTPURLResponse
          print(httpResponse)
        }
      })

      dataTask.resume()
      ```

      All fields are optional - include only what you want to update.
    </Step>

    <Step>
      ### Duplicate a Batch (optional)

      You can create a copy of an existing batch, either with or without its dataset.

      #### Duplicate with the same dataset (dataset is shared, not copied)

      ```bash
      curl -X POST https://api.prolific.com/api/v1/data-collection/batches/BATCH_ID/duplicate \
        -H "Authorization: Token YOUR_API_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{
          "name": "Copy of My Batch"
        }'
      ```

      #### Duplicate without a dataset (requires new upload)

      ```bash
      curl -X POST https://api.prolific.com/api/v1/data-collection/batches/BATCH_ID/duplicate \
        -H "Authorization: Token YOUR_API_TOKEN" \
        -H "Content-Type: application/json" \
        -d '{
          "name": "Copy of My Batch",
          "upload_new_dataset": true
        }'
      ```

      If `name` is omitted, the duplicate will be named `[Original Batch Name] (Copy)`.

      **Note:** When duplicating with a dataset, both batches will reference the same dataset - it is not duplicated.
    </Step>
  </Steps>

  <Step>
    ## Add Instructions to the Batch

    You can create **multiple** instructions. Types supported:

    * `multiple_choice` — selection from options (use `answer_limit` for single or multi-select)
    * `free_text` — open-ended text input
    * `multiple_choice_with_free_text` — selection with associated free text fields
    * `file_upload` — file submission

    For full schema details, see [Instructions](/api-reference/ai-task-builder/instructions).

    ### Request

    POST [https://api.prolific.com/api/v1/data-collection/batches/\{batch\_id}/instructions](https://api.prolific.com/api/v1/data-collection/batches/\{batch_id}/instructions)

    ```curl AI Task Builder_CreateTaskBuilderInstructions_example
    curl -X POST https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json" \
         -d '{
      "instructions": [
        {
          "type": "multiple_choice",
          "description": "Choose the LLM response which is more accurate.",
          "answer_limit": 1,
          "options": [
            {
              "label": "Response 1",
              "value": "response1"
            },
            {
              "label": "Response 2",
              "value": "response2"
            }
          ]
        },
        {
          "type": "free_text",
          "description": "Please share the reasons for your choice.",
          "placeholder_text_input": "e.g. I chose this response because..."
        },
        {
          "type": "multiple_choice_with_free_text",
          "description": "Rate each aspect and explain your reasoning.",
          "answer_limit": -1,
          "options": [
            {
              "label": "Good",
              "value": "accuracy_good",
              "heading": "Accuracy"
            },
            {
              "label": "Needs improvement",
              "value": "accuracy_poor",
              "heading": "Accuracy"
            }
          ]
        },
        {
          "type": "free_text_with_unit",
          "description": "What is your height?",
          "unit_options": [
            {
              "label": "Centimeters",
              "value": "cm",
              "validation": {
                "type": "number",
                "min": 50,
                "max": 300
              }
            },
            {
              "label": "Feet",
              "value": "ft",
              "validation": {
                "type": "number",
                "min": 1,
                "max": 9
              }
            }
          ],
          "unit_position": "suffix"
        },
        {
          "type": "file_upload",
          "description": "Upload a photo of the item",
          "accepted_file_types": [
            ".jpg",
            ".jpeg",
            ".png"
          ],
          "max_file_size_mb": 10,
          "min_file_count": 1,
          "max_file_count": 3
        }
      ]
    }'
    ```

    ```python AI Task Builder_CreateTaskBuilderInstructions_example
    import requests

    url = "https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions"

    payload = { "instructions": [
            {
                "type": "multiple_choice",
                "description": "Choose the LLM response which is more accurate.",
                "answer_limit": 1,
                "options": [
                    {
                        "label": "Response 1",
                        "value": "response1"
                    },
                    {
                        "label": "Response 2",
                        "value": "response2"
                    }
                ]
            },
            {
                "type": "free_text",
                "description": "Please share the reasons for your choice.",
                "placeholder_text_input": "e.g. I chose this response because..."
            },
            {
                "type": "multiple_choice_with_free_text",
                "description": "Rate each aspect and explain your reasoning.",
                "answer_limit": -1,
                "options": [
                    {
                        "label": "Good",
                        "value": "accuracy_good",
                        "heading": "Accuracy"
                    },
                    {
                        "label": "Needs improvement",
                        "value": "accuracy_poor",
                        "heading": "Accuracy"
                    }
                ]
            },
            {
                "type": "free_text_with_unit",
                "description": "What is your height?",
                "unit_options": [
                    {
                        "label": "Centimeters",
                        "value": "cm",
                        "validation": {
                            "type": "number",
                            "min": 50,
                            "max": 300
                        }
                    },
                    {
                        "label": "Feet",
                        "value": "ft",
                        "validation": {
                            "type": "number",
                            "min": 1,
                            "max": 9
                        }
                    }
                ],
                "unit_position": "suffix"
            },
            {
                "type": "file_upload",
                "description": "Upload a photo of the item",
                "accepted_file_types": [".jpg", ".jpeg", ".png"],
                "max_file_size_mb": 10,
                "min_file_count": 1,
                "max_file_count": 3
            }
        ] }
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript AI Task Builder_CreateTaskBuilderInstructions_example
    const url = 'https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions';
    const options = {
      method: 'POST',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{"instructions":[{"type":"multiple_choice","description":"Choose the LLM response which is more accurate.","answer_limit":1,"options":[{"label":"Response 1","value":"response1"},{"label":"Response 2","value":"response2"}]},{"type":"free_text","description":"Please share the reasons for your choice.","placeholder_text_input":"e.g. I chose this response because..."},{"type":"multiple_choice_with_free_text","description":"Rate each aspect and explain your reasoning.","answer_limit":-1,"options":[{"label":"Good","value":"accuracy_good","heading":"Accuracy"},{"label":"Needs improvement","value":"accuracy_poor","heading":"Accuracy"}]},{"type":"free_text_with_unit","description":"What is your height?","unit_options":[{"label":"Centimeters","value":"cm","validation":{"type":"number","min":50,"max":300}},{"label":"Feet","value":"ft","validation":{"type":"number","min":1,"max":9}}],"unit_position":"suffix"},{"type":"file_upload","description":"Upload a photo of the item","accepted_file_types":[".jpg",".jpeg",".png"],"max_file_size_mb":10,"min_file_count":1,"max_file_count":3}]}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go AI Task Builder_CreateTaskBuilderInstructions_example
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions"

    	payload := strings.NewReader("{\n  \"instructions\": [\n    {\n      \"type\": \"multiple_choice\",\n      \"description\": \"Choose the LLM response which is more accurate.\",\n      \"answer_limit\": 1,\n      \"options\": [\n        {\n          \"label\": \"Response 1\",\n          \"value\": \"response1\"\n        },\n        {\n          \"label\": \"Response 2\",\n          \"value\": \"response2\"\n        }\n      ]\n    },\n    {\n      \"type\": \"free_text\",\n      \"description\": \"Please share the reasons for your choice.\",\n      \"placeholder_text_input\": \"e.g. I chose this response because...\"\n    },\n    {\n      \"type\": \"multiple_choice_with_free_text\",\n      \"description\": \"Rate each aspect and explain your reasoning.\",\n      \"answer_limit\": -1,\n      \"options\": [\n        {\n          \"label\": \"Good\",\n          \"value\": \"accuracy_good\",\n          \"heading\": \"Accuracy\"\n        },\n        {\n          \"label\": \"Needs improvement\",\n          \"value\": \"accuracy_poor\",\n          \"heading\": \"Accuracy\"\n        }\n      ]\n    },\n    {\n      \"type\": \"free_text_with_unit\",\n      \"description\": \"What is your height?\",\n      \"unit_options\": [\n        {\n          \"label\": \"Centimeters\",\n          \"value\": \"cm\",\n          \"validation\": {\n            \"type\": \"number\",\n            \"min\": 50,\n            \"max\": 300\n          }\n        },\n        {\n          \"label\": \"Feet\",\n          \"value\": \"ft\",\n          \"validation\": {\n            \"type\": \"number\",\n            \"min\": 1,\n            \"max\": 9\n          }\n        }\n      ],\n      \"unit_position\": \"suffix\"\n    },\n    {\n      \"type\": \"file_upload\",\n      \"description\": \"Upload a photo of the item\",\n      \"accepted_file_types\": [\n        \".jpg\",\n        \".jpeg\",\n        \".png\"\n      ],\n      \"max_file_size_mb\": 10,\n      \"min_file_count\": 1,\n      \"max_file_count\": 3\n    }\n  ]\n}")

    	req, _ := http.NewRequest("POST", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby AI Task Builder_CreateTaskBuilderInstructions_example
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Post.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{\n  \"instructions\": [\n    {\n      \"type\": \"multiple_choice\",\n      \"description\": \"Choose the LLM response which is more accurate.\",\n      \"answer_limit\": 1,\n      \"options\": [\n        {\n          \"label\": \"Response 1\",\n          \"value\": \"response1\"\n        },\n        {\n          \"label\": \"Response 2\",\n          \"value\": \"response2\"\n        }\n      ]\n    },\n    {\n      \"type\": \"free_text\",\n      \"description\": \"Please share the reasons for your choice.\",\n      \"placeholder_text_input\": \"e.g. I chose this response because...\"\n    },\n    {\n      \"type\": \"multiple_choice_with_free_text\",\n      \"description\": \"Rate each aspect and explain your reasoning.\",\n      \"answer_limit\": -1,\n      \"options\": [\n        {\n          \"label\": \"Good\",\n          \"value\": \"accuracy_good\",\n          \"heading\": \"Accuracy\"\n        },\n        {\n          \"label\": \"Needs improvement\",\n          \"value\": \"accuracy_poor\",\n          \"heading\": \"Accuracy\"\n        }\n      ]\n    },\n    {\n      \"type\": \"free_text_with_unit\",\n      \"description\": \"What is your height?\",\n      \"unit_options\": [\n        {\n          \"label\": \"Centimeters\",\n          \"value\": \"cm\",\n          \"validation\": {\n            \"type\": \"number\",\n            \"min\": 50,\n            \"max\": 300\n          }\n        },\n        {\n          \"label\": \"Feet\",\n          \"value\": \"ft\",\n          \"validation\": {\n            \"type\": \"number\",\n            \"min\": 1,\n            \"max\": 9\n          }\n        }\n      ],\n      \"unit_position\": \"suffix\"\n    },\n    {\n      \"type\": \"file_upload\",\n      \"description\": \"Upload a photo of the item\",\n      \"accepted_file_types\": [\n        \".jpg\",\n        \".jpeg\",\n        \".png\"\n      ],\n      \"max_file_size_mb\": 10,\n      \"min_file_count\": 1,\n      \"max_file_count\": 3\n    }\n  ]\n}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java AI Task Builder_CreateTaskBuilderInstructions_example
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.post("https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{\n  \"instructions\": [\n    {\n      \"type\": \"multiple_choice\",\n      \"description\": \"Choose the LLM response which is more accurate.\",\n      \"answer_limit\": 1,\n      \"options\": [\n        {\n          \"label\": \"Response 1\",\n          \"value\": \"response1\"\n        },\n        {\n          \"label\": \"Response 2\",\n          \"value\": \"response2\"\n        }\n      ]\n    },\n    {\n      \"type\": \"free_text\",\n      \"description\": \"Please share the reasons for your choice.\",\n      \"placeholder_text_input\": \"e.g. I chose this response because...\"\n    },\n    {\n      \"type\": \"multiple_choice_with_free_text\",\n      \"description\": \"Rate each aspect and explain your reasoning.\",\n      \"answer_limit\": -1,\n      \"options\": [\n        {\n          \"label\": \"Good\",\n          \"value\": \"accuracy_good\",\n          \"heading\": \"Accuracy\"\n        },\n        {\n          \"label\": \"Needs improvement\",\n          \"value\": \"accuracy_poor\",\n          \"heading\": \"Accuracy\"\n        }\n      ]\n    },\n    {\n      \"type\": \"free_text_with_unit\",\n      \"description\": \"What is your height?\",\n      \"unit_options\": [\n        {\n          \"label\": \"Centimeters\",\n          \"value\": \"cm\",\n          \"validation\": {\n            \"type\": \"number\",\n            \"min\": 50,\n            \"max\": 300\n          }\n        },\n        {\n          \"label\": \"Feet\",\n          \"value\": \"ft\",\n          \"validation\": {\n            \"type\": \"number\",\n            \"min\": 1,\n            \"max\": 9\n          }\n        }\n      ],\n      \"unit_position\": \"suffix\"\n    },\n    {\n      \"type\": \"file_upload\",\n      \"description\": \"Upload a photo of the item\",\n      \"accepted_file_types\": [\n        \".jpg\",\n        \".jpeg\",\n        \".png\"\n      ],\n      \"max_file_size_mb\": 10,\n      \"min_file_count\": 1,\n      \"max_file_count\": 3\n    }\n  ]\n}")
      .asString();
    ```

    ```php AI Task Builder_CreateTaskBuilderInstructions_example
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('POST', 'https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions', [
      'body' => '{
      "instructions": [
        {
          "type": "multiple_choice",
          "description": "Choose the LLM response which is more accurate.",
          "answer_limit": 1,
          "options": [
            {
              "label": "Response 1",
              "value": "response1"
            },
            {
              "label": "Response 2",
              "value": "response2"
            }
          ]
        },
        {
          "type": "free_text",
          "description": "Please share the reasons for your choice.",
          "placeholder_text_input": "e.g. I chose this response because..."
        },
        {
          "type": "multiple_choice_with_free_text",
          "description": "Rate each aspect and explain your reasoning.",
          "answer_limit": -1,
          "options": [
            {
              "label": "Good",
              "value": "accuracy_good",
              "heading": "Accuracy"
            },
            {
              "label": "Needs improvement",
              "value": "accuracy_poor",
              "heading": "Accuracy"
            }
          ]
        },
        {
          "type": "free_text_with_unit",
          "description": "What is your height?",
          "unit_options": [
            {
              "label": "Centimeters",
              "value": "cm",
              "validation": {
                "type": "number",
                "min": 50,
                "max": 300
              }
            },
            {
              "label": "Feet",
              "value": "ft",
              "validation": {
                "type": "number",
                "min": 1,
                "max": 9
              }
            }
          ],
          "unit_position": "suffix"
        },
        {
          "type": "file_upload",
          "description": "Upload a photo of the item",
          "accepted_file_types": [
            ".jpg",
            ".jpeg",
            ".png"
          ],
          "max_file_size_mb": 10,
          "min_file_count": 1,
          "max_file_count": 3
        }
      ]
    }',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp AI Task Builder_CreateTaskBuilderInstructions_example
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions");
    var request = new RestRequest(Method.POST);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{\n  \"instructions\": [\n    {\n      \"type\": \"multiple_choice\",\n      \"description\": \"Choose the LLM response which is more accurate.\",\n      \"answer_limit\": 1,\n      \"options\": [\n        {\n          \"label\": \"Response 1\",\n          \"value\": \"response1\"\n        },\n        {\n          \"label\": \"Response 2\",\n          \"value\": \"response2\"\n        }\n      ]\n    },\n    {\n      \"type\": \"free_text\",\n      \"description\": \"Please share the reasons for your choice.\",\n      \"placeholder_text_input\": \"e.g. I chose this response because...\"\n    },\n    {\n      \"type\": \"multiple_choice_with_free_text\",\n      \"description\": \"Rate each aspect and explain your reasoning.\",\n      \"answer_limit\": -1,\n      \"options\": [\n        {\n          \"label\": \"Good\",\n          \"value\": \"accuracy_good\",\n          \"heading\": \"Accuracy\"\n        },\n        {\n          \"label\": \"Needs improvement\",\n          \"value\": \"accuracy_poor\",\n          \"heading\": \"Accuracy\"\n        }\n      ]\n    },\n    {\n      \"type\": \"free_text_with_unit\",\n      \"description\": \"What is your height?\",\n      \"unit_options\": [\n        {\n          \"label\": \"Centimeters\",\n          \"value\": \"cm\",\n          \"validation\": {\n            \"type\": \"number\",\n            \"min\": 50,\n            \"max\": 300\n          }\n        },\n        {\n          \"label\": \"Feet\",\n          \"value\": \"ft\",\n          \"validation\": {\n            \"type\": \"number\",\n            \"min\": 1,\n            \"max\": 9\n          }\n        }\n      ],\n      \"unit_position\": \"suffix\"\n    },\n    {\n      \"type\": \"file_upload\",\n      \"description\": \"Upload a photo of the item\",\n      \"accepted_file_types\": [\n        \".jpg\",\n        \".jpeg\",\n        \".png\"\n      ],\n      \"max_file_size_mb\": 10,\n      \"min_file_count\": 1,\n      \"max_file_count\": 3\n    }\n  ]\n}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift AI Task Builder_CreateTaskBuilderInstructions_example
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = ["instructions": [
        [
          "type": "multiple_choice",
          "description": "Choose the LLM response which is more accurate.",
          "answer_limit": 1,
          "options": [
            [
              "label": "Response 1",
              "value": "response1"
            ],
            [
              "label": "Response 2",
              "value": "response2"
            ]
          ]
        ],
        [
          "type": "free_text",
          "description": "Please share the reasons for your choice.",
          "placeholder_text_input": "e.g. I chose this response because..."
        ],
        [
          "type": "multiple_choice_with_free_text",
          "description": "Rate each aspect and explain your reasoning.",
          "answer_limit": -1,
          "options": [
            [
              "label": "Good",
              "value": "accuracy_good",
              "heading": "Accuracy"
            ],
            [
              "label": "Needs improvement",
              "value": "accuracy_poor",
              "heading": "Accuracy"
            ]
          ]
        ],
        [
          "type": "free_text_with_unit",
          "description": "What is your height?",
          "unit_options": [
            [
              "label": "Centimeters",
              "value": "cm",
              "validation": [
                "type": "number",
                "min": 50,
                "max": 300
              ]
            ],
            [
              "label": "Feet",
              "value": "ft",
              "validation": [
                "type": "number",
                "min": 1,
                "max": 9
              ]
            ]
          ],
          "unit_position": "suffix"
        ],
        [
          "type": "file_upload",
          "description": "Upload a photo of the item",
          "accepted_file_types": [".jpg", ".jpeg", ".png"],
          "max_file_size_mb": 10,
          "min_file_count": 1,
          "max_file_count": 3
        ]
      ]] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/batches/5f7b5e9a-3f3c-4b3e-8f1a-1a2b3c4d5e6f/instructions")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    (You can later **PUT** the same endpoint to update instructions -
    please include the complete payload as it will replace all instructions on the batch, or **GET** it to read them back.)
  </Step>

  <Step>
    ## Set Up the Batch (build tasks, set tasks per participant)

    Configure how datapoints become tasks and how many tasks each participant gets.

    ### Request

    POST [https://api.prolific.com/api/v1/data-collection/batches/\{batch\_id}/setup](https://api.prolific.com/api/v1/data-collection/batches/\{batch_id}/setup)

    ```curl
    curl -X POST https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json" \
         -d '{}'
    ```

    ```python
    import requests

    url = "https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup"

    payload = {}
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript
    const url = 'https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup';
    const options = {
      method: 'POST',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup"

    	payload := strings.NewReader("{}")

    	req, _ := http.NewRequest("POST", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Post.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.post("https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{}")
      .asString();
    ```

    ```php
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('POST', 'https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup', [
      'body' => '{}',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup");
    var request = new RestRequest(Method.POST);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = [] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/batches/batch_id/setup")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    **Note:** The dataset must be in `READY` status before running the setup endpoint.

    Now **poll batch status** until it's **READY**:

    ### Request

    GET [https://api.prolific.com/api/v1/data-collection/batches/\{batch\_id}](https://api.prolific.com/api/v1/data-collection/batches/\{batch_id})

    ```curl
    curl https://api.prolific.com/api/v1/data-collection/batches/batch_id \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json"
    ```

    ```python
    import requests

    url = "https://api.prolific.com/api/v1/data-collection/batches/batch_id"

    payload = {}
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.get(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript
    const url = 'https://api.prolific.com/api/v1/data-collection/batches/batch_id';
    const options = {
      method: 'GET',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/data-collection/batches/batch_id"

    	payload := strings.NewReader("{}")

    	req, _ := http.NewRequest("GET", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/data-collection/batches/batch_id")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Get.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.get("https://api.prolific.com/api/v1/data-collection/batches/batch_id")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{}")
      .asString();
    ```

    ```php
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('GET', 'https://api.prolific.com/api/v1/data-collection/batches/batch_id', [
      'body' => '{}',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/data-collection/batches/batch_id");
    var request = new RestRequest(Method.GET);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = [] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/batches/batch_id")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "GET"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    ```bash
    {"status":"READY"} # (possible values: UNINITIALISED|PROCESSING|READY|ERROR)
    ```
  </Step>

  <Step>
    ## Create a Prolific Study that References the Batch

    When the batch is **READY**, create a standard study but include these two fields:

    * `"data_collection_method": "AI_TASK_BUILDER_BATCH"`
    * `"data_collection_id": "BATCH_ID"`

    ### Request

    POST [https://api.prolific.com/api/v1/studies/](https://api.prolific.com/api/v1/studies/)

    ```curl study_with_allow_list
    curl -X POST https://api.prolific.com/api/v1/studies/ \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json" \
         -d '{
      "name": "Study about API\'s for selected participants",
      "description": "This study aims to determine how to make a good public API",
      "external_study_url": "https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}",
      "prolific_id_option": "url_parameters",
      "total_available_places": 30,
      "estimated_completion_time": 5,
      "reward": 13,
      "internal_name": "WIT-2022 Study about API\'s version 2",
      "completion_codes": [
        {
          "code": "ABC123",
          "code_type": "COMPLETED",
          "actions": [
            {
              "action": "AUTOMATICALLY_APPROVE"
            }
          ]
        },
        {
          "code": "DEF234",
          "code_type": "FOLLOW_UP_STUDY",
          "actions": [
            {
              "action": "AUTOMATICALLY_APPROVE"
            },
            {
              "action": "ADD_TO_PARTICIPANT_GROUP",
              "participant_group": "619e049f7648a4e1f8f3645b"
            }
          ]
        }
      ],
      "device_compatibility": [
        "mobile",
        "desktop",
        "tablet"
      ],
      "peripheral_requirements": [],
      "filters": [
        {
          "filter_id": "custom_allowlist",
          "selected_values": [
            "619e049f7648a4e1f8f3645b"
          ]
        }
      ],
      "submissions_config": {
        "max_submissions_per_participant": 1
      },
      "completion_code": "ABC123"
    }'
    ```

    ```python study_with_allow_list
    import requests

    url = "https://api.prolific.com/api/v1/studies/"

    payload = {
        "name": "Study about API's for selected participants",
        "description": "This study aims to determine how to make a good public API",
        "external_study_url": "https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}",
        "prolific_id_option": "url_parameters",
        "total_available_places": 30,
        "estimated_completion_time": 5,
        "reward": 13,
        "internal_name": "WIT-2022 Study about API's version 2",
        "completion_codes": [
            {
                "code": "ABC123",
                "code_type": "COMPLETED",
                "actions": [{ "action": "AUTOMATICALLY_APPROVE" }]
            },
            {
                "code": "DEF234",
                "code_type": "FOLLOW_UP_STUDY",
                "actions": [
                    { "action": "AUTOMATICALLY_APPROVE" },
                    {
                        "action": "ADD_TO_PARTICIPANT_GROUP",
                        "participant_group": "619e049f7648a4e1f8f3645b"
                    }
                ]
            }
        ],
        "device_compatibility": ["mobile", "desktop", "tablet"],
        "peripheral_requirements": [],
        "filters": [
            {
                "filter_id": "custom_allowlist",
                "selected_values": ["619e049f7648a4e1f8f3645b"]
            }
        ],
        "submissions_config": { "max_submissions_per_participant": 1 },
        "completion_code": "ABC123"
    }
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript study_with_allow_list
    const url = 'https://api.prolific.com/api/v1/studies/';
    const options = {
      method: 'POST',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{"name":"Study about API\'s for selected participants","description":"This study aims to determine how to make a good public API","external_study_url":"https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}","prolific_id_option":"url_parameters","total_available_places":30,"estimated_completion_time":5,"reward":13,"internal_name":"WIT-2022 Study about API\'s version 2","completion_codes":[{"code":"ABC123","code_type":"COMPLETED","actions":[{"action":"AUTOMATICALLY_APPROVE"}]},{"code":"DEF234","code_type":"FOLLOW_UP_STUDY","actions":[{"action":"AUTOMATICALLY_APPROVE"},{"action":"ADD_TO_PARTICIPANT_GROUP","participant_group":"619e049f7648a4e1f8f3645b"}]}],"device_compatibility":["mobile","desktop","tablet"],"peripheral_requirements":[],"filters":[{"filter_id":"custom_allowlist","selected_values":["619e049f7648a4e1f8f3645b"]}],"submissions_config":{"max_submissions_per_participant":1},"completion_code":"ABC123"}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go study_with_allow_list
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/studies/"

    	payload := strings.NewReader("{\n  \"name\": \"Study about API's for selected participants\",\n  \"description\": \"This study aims to determine how to make a good public API\",\n  \"external_study_url\": \"https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}\",\n  \"prolific_id_option\": \"url_parameters\",\n  \"total_available_places\": 30,\n  \"estimated_completion_time\": 5,\n  \"reward\": 13,\n  \"internal_name\": \"WIT-2022 Study about API's version 2\",\n  \"completion_codes\": [\n    {\n      \"code\": \"ABC123\",\n      \"code_type\": \"COMPLETED\",\n      \"actions\": [\n        {\n          \"action\": \"AUTOMATICALLY_APPROVE\"\n        }\n      ]\n    },\n    {\n      \"code\": \"DEF234\",\n      \"code_type\": \"FOLLOW_UP_STUDY\",\n      \"actions\": [\n        {\n          \"action\": \"AUTOMATICALLY_APPROVE\"\n        },\n        {\n          \"action\": \"ADD_TO_PARTICIPANT_GROUP\",\n          \"participant_group\": \"619e049f7648a4e1f8f3645b\"\n        }\n      ]\n    }\n  ],\n  \"device_compatibility\": [\n    \"mobile\",\n    \"desktop\",\n    \"tablet\"\n  ],\n  \"peripheral_requirements\": [],\n  \"filters\": [\n    {\n      \"filter_id\": \"custom_allowlist\",\n      \"selected_values\": [\n        \"619e049f7648a4e1f8f3645b\"\n      ]\n    }\n  ],\n  \"submissions_config\": {\n    \"max_submissions_per_participant\": 1\n  },\n  \"completion_code\": \"ABC123\"\n}")

    	req, _ := http.NewRequest("POST", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby study_with_allow_list
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/studies/")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Post.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{\n  \"name\": \"Study about API's for selected participants\",\n  \"description\": \"This study aims to determine how to make a good public API\",\n  \"external_study_url\": \"https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}\",\n  \"prolific_id_option\": \"url_parameters\",\n  \"total_available_places\": 30,\n  \"estimated_completion_time\": 5,\n  \"reward\": 13,\n  \"internal_name\": \"WIT-2022 Study about API's version 2\",\n  \"completion_codes\": [\n    {\n      \"code\": \"ABC123\",\n      \"code_type\": \"COMPLETED\",\n      \"actions\": [\n        {\n          \"action\": \"AUTOMATICALLY_APPROVE\"\n        }\n      ]\n    },\n    {\n      \"code\": \"DEF234\",\n      \"code_type\": \"FOLLOW_UP_STUDY\",\n      \"actions\": [\n        {\n          \"action\": \"AUTOMATICALLY_APPROVE\"\n        },\n        {\n          \"action\": \"ADD_TO_PARTICIPANT_GROUP\",\n          \"participant_group\": \"619e049f7648a4e1f8f3645b\"\n        }\n      ]\n    }\n  ],\n  \"device_compatibility\": [\n    \"mobile\",\n    \"desktop\",\n    \"tablet\"\n  ],\n  \"peripheral_requirements\": [],\n  \"filters\": [\n    {\n      \"filter_id\": \"custom_allowlist\",\n      \"selected_values\": [\n        \"619e049f7648a4e1f8f3645b\"\n      ]\n    }\n  ],\n  \"submissions_config\": {\n    \"max_submissions_per_participant\": 1\n  },\n  \"completion_code\": \"ABC123\"\n}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java study_with_allow_list
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.post("https://api.prolific.com/api/v1/studies/")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{\n  \"name\": \"Study about API's for selected participants\",\n  \"description\": \"This study aims to determine how to make a good public API\",\n  \"external_study_url\": \"https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}\",\n  \"prolific_id_option\": \"url_parameters\",\n  \"total_available_places\": 30,\n  \"estimated_completion_time\": 5,\n  \"reward\": 13,\n  \"internal_name\": \"WIT-2022 Study about API's version 2\",\n  \"completion_codes\": [\n    {\n      \"code\": \"ABC123\",\n      \"code_type\": \"COMPLETED\",\n      \"actions\": [\n        {\n          \"action\": \"AUTOMATICALLY_APPROVE\"\n        }\n      ]\n    },\n    {\n      \"code\": \"DEF234\",\n      \"code_type\": \"FOLLOW_UP_STUDY\",\n      \"actions\": [\n        {\n          \"action\": \"AUTOMATICALLY_APPROVE\"\n        },\n        {\n          \"action\": \"ADD_TO_PARTICIPANT_GROUP\",\n          \"participant_group\": \"619e049f7648a4e1f8f3645b\"\n        }\n      ]\n    }\n  ],\n  \"device_compatibility\": [\n    \"mobile\",\n    \"desktop\",\n    \"tablet\"\n  ],\n  \"peripheral_requirements\": [],\n  \"filters\": [\n    {\n      \"filter_id\": \"custom_allowlist\",\n      \"selected_values\": [\n        \"619e049f7648a4e1f8f3645b\"\n      ]\n    }\n  ],\n  \"submissions_config\": {\n    \"max_submissions_per_participant\": 1\n  },\n  \"completion_code\": \"ABC123\"\n}")
      .asString();
    ```

    ```php study_with_allow_list
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('POST', 'https://api.prolific.com/api/v1/studies/', [
      'body' => '{
      "name": "Study about API\'s for selected participants",
      "description": "This study aims to determine how to make a good public API",
      "external_study_url": "https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}",
      "prolific_id_option": "url_parameters",
      "total_available_places": 30,
      "estimated_completion_time": 5,
      "reward": 13,
      "internal_name": "WIT-2022 Study about API\'s version 2",
      "completion_codes": [
        {
          "code": "ABC123",
          "code_type": "COMPLETED",
          "actions": [
            {
              "action": "AUTOMATICALLY_APPROVE"
            }
          ]
        },
        {
          "code": "DEF234",
          "code_type": "FOLLOW_UP_STUDY",
          "actions": [
            {
              "action": "AUTOMATICALLY_APPROVE"
            },
            {
              "action": "ADD_TO_PARTICIPANT_GROUP",
              "participant_group": "619e049f7648a4e1f8f3645b"
            }
          ]
        }
      ],
      "device_compatibility": [
        "mobile",
        "desktop",
        "tablet"
      ],
      "peripheral_requirements": [],
      "filters": [
        {
          "filter_id": "custom_allowlist",
          "selected_values": [
            "619e049f7648a4e1f8f3645b"
          ]
        }
      ],
      "submissions_config": {
        "max_submissions_per_participant": 1
      },
      "completion_code": "ABC123"
    }',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp study_with_allow_list
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/studies/");
    var request = new RestRequest(Method.POST);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{\n  \"name\": \"Study about API's for selected participants\",\n  \"description\": \"This study aims to determine how to make a good public API\",\n  \"external_study_url\": \"https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}\",\n  \"prolific_id_option\": \"url_parameters\",\n  \"total_available_places\": 30,\n  \"estimated_completion_time\": 5,\n  \"reward\": 13,\n  \"internal_name\": \"WIT-2022 Study about API's version 2\",\n  \"completion_codes\": [\n    {\n      \"code\": \"ABC123\",\n      \"code_type\": \"COMPLETED\",\n      \"actions\": [\n        {\n          \"action\": \"AUTOMATICALLY_APPROVE\"\n        }\n      ]\n    },\n    {\n      \"code\": \"DEF234\",\n      \"code_type\": \"FOLLOW_UP_STUDY\",\n      \"actions\": [\n        {\n          \"action\": \"AUTOMATICALLY_APPROVE\"\n        },\n        {\n          \"action\": \"ADD_TO_PARTICIPANT_GROUP\",\n          \"participant_group\": \"619e049f7648a4e1f8f3645b\"\n        }\n      ]\n    }\n  ],\n  \"device_compatibility\": [\n    \"mobile\",\n    \"desktop\",\n    \"tablet\"\n  ],\n  \"peripheral_requirements\": [],\n  \"filters\": [\n    {\n      \"filter_id\": \"custom_allowlist\",\n      \"selected_values\": [\n        \"619e049f7648a4e1f8f3645b\"\n      ]\n    }\n  ],\n  \"submissions_config\": {\n    \"max_submissions_per_participant\": 1\n  },\n  \"completion_code\": \"ABC123\"\n}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift study_with_allow_list
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = [
      "name": "Study about API's for selected participants",
      "description": "This study aims to determine how to make a good public API",
      "external_study_url": "https://eggs-experriment.com?participant={{%PROLIFIC_PID%}}",
      "prolific_id_option": "url_parameters",
      "total_available_places": 30,
      "estimated_completion_time": 5,
      "reward": 13,
      "internal_name": "WIT-2022 Study about API's version 2",
      "completion_codes": [
        [
          "code": "ABC123",
          "code_type": "COMPLETED",
          "actions": [["action": "AUTOMATICALLY_APPROVE"]]
        ],
        [
          "code": "DEF234",
          "code_type": "FOLLOW_UP_STUDY",
          "actions": [
            ["action": "AUTOMATICALLY_APPROVE"],
            [
              "action": "ADD_TO_PARTICIPANT_GROUP",
              "participant_group": "619e049f7648a4e1f8f3645b"
            ]
          ]
        ]
      ],
      "device_compatibility": ["mobile", "desktop", "tablet"],
      "peripheral_requirements": [],
      "filters": [
        [
          "filter_id": "custom_allowlist",
          "selected_values": ["619e049f7648a4e1f8f3645b"]
        ]
      ],
      "submissions_config": ["max_submissions_per_participant": 1],
      "completion_code": "ABC123"
    ] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/studies/")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```
  </Step>

  <Step>
    ## Publish the Study

    ### Request

    POST [https://api.prolific.com/api/v1/studies/\{id}/transition/](https://api.prolific.com/api/v1/studies/\{id}/transition/)

    ```curl Publish a draft study
    curl -X POST https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/ \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json" \
         -d '{
      "action": "PUBLISH"
    }'
    ```

    ```python Publish a draft study
    import requests

    url = "https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/"

    payload = { "action": "PUBLISH" }
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.post(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript Publish a draft study
    const url = 'https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/';
    const options = {
      method: 'POST',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{"action":"PUBLISH"}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go Publish a draft study
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/"

    	payload := strings.NewReader("{\n  \"action\": \"PUBLISH\"\n}")

    	req, _ := http.NewRequest("POST", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby Publish a draft study
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Post.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{\n  \"action\": \"PUBLISH\"\n}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java Publish a draft study
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.post("https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{\n  \"action\": \"PUBLISH\"\n}")
      .asString();
    ```

    ```php Publish a draft study
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('POST', 'https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/', [
      'body' => '{
      "action": "PUBLISH"
    }',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp Publish a draft study
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/");
    var request = new RestRequest(Method.POST);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{\n  \"action\": \"PUBLISH\"\n}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift Publish a draft study
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = ["action": "PUBLISH"] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/studies/60d9aadeb86739de712faee0/transition/")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "POST"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    (Other actions available include `PAUSE`, `START` (resume), and `STOP`.)
  </Step>

  <Step>
    ## Retrieve Annotated Responses

    There are two ways to retrieve responses once participants have completed their tasks.

    ### Option 1: JSON responses

    Get individual responses as JSON, useful for processing programmatically or streaming results as they come in.

    ### Request

    GET [https://api.prolific.com/api/v1/data-collection/batches/\{batch\_id}/responses](https://api.prolific.com/api/v1/data-collection/batches/\{batch_id}/responses)

    ```curl
    curl https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json"
    ```

    ```python
    import requests

    url = "https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses"

    payload = {}
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.get(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript
    const url = 'https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses';
    const options = {
      method: 'GET',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses"

    	payload := strings.NewReader("{}")

    	req, _ := http.NewRequest("GET", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Get.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.get("https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{}")
      .asString();
    ```

    ```php
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('GET', 'https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses', [
      'body' => '{}',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses");
    var request = new RestRequest(Method.GET);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = [] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/batches/batch_id/responses")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "GET"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    ```json
    {
      "results": [
        {
          "id": "01997d0c-34ab-748a-b6e3-104288f7a1bf",
          "batch_id": "01997d05-8689-72a8-b980-3f930729f28a",
          "participant_id": "6862a1a367ad476b8601fa2a",
          "submission_id": "68d43c57a56e9439d5d1e93e",
          "task_id": "84cc7c99-9097-5c0f-8052-65382273ace5",
          "response": {
            "instruction_id": "01997d05-8f20-734f-ad19-c82e279b5118",
            "type": "free_text",
            "answer": [
              { "value": "abc" }
            ]
          },
          "created_at": "2025-09-24T18:46:15.979Z"
        }
      ],
      "meta": {
        "count": 1
      }
    }
    ```

    ### Option 2: CSV report

    Download a CSV report containing your original data with response columns appended.

    ### Request

    GET [https://api.prolific.com/api/v1/data-collection/batches/\{batch\_id}/report/](https://api.prolific.com/api/v1/data-collection/batches/\{batch_id}/report/)

    ```curl
    curl https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/ \
         -H "Authorization: Token <token>" \
         -H "Content-Type: application/json"
    ```

    ```python
    import requests

    url = "https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/"

    payload = {}
    headers = {
        "Authorization": "Token <token>",
        "Content-Type": "application/json"
    }

    response = requests.get(url, json=payload, headers=headers)

    print(response.json())
    ```

    ```javascript
    const url = 'https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/';
    const options = {
      method: 'GET',
      headers: {Authorization: 'Token <token>', 'Content-Type': 'application/json'},
      body: '{}'
    };

    try {
      const response = await fetch(url, options);
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error(error);
    }
    ```

    ```go
    package main

    import (
    	"fmt"
    	"strings"
    	"net/http"
    	"io"
    )

    func main() {

    	url := "https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/"

    	payload := strings.NewReader("{}")

    	req, _ := http.NewRequest("GET", url, payload)

    	req.Header.Add("Authorization", "Token <token>")
    	req.Header.Add("Content-Type", "application/json")

    	res, _ := http.DefaultClient.Do(req)

    	defer res.Body.Close()
    	body, _ := io.ReadAll(res.Body)

    	fmt.Println(res)
    	fmt.Println(string(body))

    }
    ```

    ```ruby
    require 'uri'
    require 'net/http'

    url = URI("https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/")

    http = Net::HTTP.new(url.host, url.port)
    http.use_ssl = true

    request = Net::HTTP::Get.new(url)
    request["Authorization"] = 'Token <token>'
    request["Content-Type"] = 'application/json'
    request.body = "{}"

    response = http.request(request)
    puts response.read_body
    ```

    ```java
    import com.mashape.unirest.http.HttpResponse;
    import com.mashape.unirest.http.Unirest;

    HttpResponse<String> response = Unirest.get("https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/")
      .header("Authorization", "Token <token>")
      .header("Content-Type", "application/json")
      .body("{}")
      .asString();
    ```

    ```php
    <?php
    require_once('vendor/autoload.php');

    $client = new \GuzzleHttp\Client();

    $response = $client->request('GET', 'https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/', [
      'body' => '{}',
      'headers' => [
        'Authorization' => 'Token <token>',
        'Content-Type' => 'application/json',
      ],
    ]);

    echo $response->getBody();
    ```

    ```csharp
    using RestSharp;

    var client = new RestClient("https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/");
    var request = new RestRequest(Method.GET);
    request.AddHeader("Authorization", "Token <token>");
    request.AddHeader("Content-Type", "application/json");
    request.AddParameter("application/json", "{}", ParameterType.RequestBody);
    IRestResponse response = client.Execute(request);
    ```

    ```swift
    import Foundation

    let headers = [
      "Authorization": "Token <token>",
      "Content-Type": "application/json"
    ]
    let parameters = [] as [String : Any]

    let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

    let request = NSMutableURLRequest(url: NSURL(string: "https://api.prolific.com/api/v1/data-collection/batches/batch_id/report/")! as URL,
                                            cachePolicy: .useProtocolCachePolicy,
                                        timeoutInterval: 10.0)
    request.httpMethod = "GET"
    request.allHTTPHeaderFields = headers
    request.httpBody = postData as Data

    let session = URLSession.shared
    let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
      if (error != nil) {
        print(error as Any)
      } else {
        let httpResponse = response as? HTTPURLResponse
        print(httpResponse)
      }
    })

    dataTask.resume()
    ```

    This returns a presigned URL to download the CSV:

    ```json
    {
      "url": "https://...",
      "expires_at": "2025-01-20T10:17:34.949Z",
      "http_method": "GET"
    }
    ```

    Use the `url` to download your annotated dataset.
  </Step>
</Steps>

# Operational Notes & Tips

* **Statuses**: Datasets and Batches both progress through `UNINITIALISED → PROCESSING → READY` (or `ERROR`).
  Don't attach a batch to a study until it's `READY`.
* **Instructions**: You can mix multiple instruction types within the same batch
  (e.g., two `multiple_choice` plus one `free_text`).
* **`tasks_per_group`**: Controls how many tasks a single participant receives in one "sitting"
  (this is what will be classed as a single Submission on Prolific).
  Increase to reduce study overhead and per-task price dispersion; decrease if tasks are long.
* **Targeting & Reward**: As with any Prolific study, all participants share the same targeting and reward.
* Once a batch has been set up (step 6) you can no longer edit its instructions.
* **Dataset Requirements**: Datasets do not need to be in READY status when creating, updating, or duplicating batches.
  However, the dataset **must** be in READY status before running the setup endpoint.
* **Batch Duplication**: When duplicating a batch with a dataset, the dataset is shared between both batches, not duplicated.
  If you need separate datasets, use `upload_new_dataset: true`.