DonutworkHelp Center
Api ReferenceDeveloper Tools
Donutwork documentation

Job Runner

Manage scheduled HTTP jobs and trigger them on demand.

Job Runner API

List Jobs

GET
/2026-02-01/job-runner.json
Required permissionjob_runner:read

Path, query, and header parameters

sizeinteger· query
Records per page (default 50, max 100).
pageinteger· query
Page number starting from 1.

Responses

Job runner list returned.

{
  "entities": "JobRunner",
  "count": 1,
  "per_page": 50,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "681f10...",
      "title": "Sync CRM Contacts",
      "method": "POST",
      "url": "https://api.partner.com/sync",
      "content_type": "application/json",
      "has_body": true,
      "schedulation": [
        "08:00",
        "14:30"
      ]
    }
  ]
}

Request examples

curl --request GET 'https://api.hub.donutwork.com/2026-02-01/job-runner.json' \
  --header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.hub.donutwork.com/2026-02-01/job-runner.json', {
  method: 'GET',
  headers: {
    Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
  },
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
  const error = await response.text();
  throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
  : contentType.includes('application/json') ? await response.json()
  : await response.text();
$request = curl_init('https://api.hub.donutwork.com/2026-02-01/job-runner.json');
curl_setopt_array($request, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
    ],
]);
$response = curl_exec($request);
if ($response === false) {
    $error = curl_error($request);
    curl_close($request);
    throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
    : (str_contains($contentType, 'application/json')
        ? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);

Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.

Create Job

POST
/2026-02-01/job-runner.json
Required permissionjob_runner:write

Path, query, and header parameters

No path, query, or additional header parameters.

Request Body

JSON
{
  "jobrunner": {
    "title": "Sync CRM Contacts",
    "method": "POST",
    "url": "https://api.partner.com/sync",
    "content_type": "application/json",
    "body": "{\"scope\":\"daily\"}",
    "schedulation": [
      "08:00",
      "14:30"
    ]
  }
}
jobrunnerobjectRequired
Job runner configuration payload.

Responses

Job runner created.

{
  "id": "681f10...",
  "created": true
}

Validation error on payload.

{
  "error": "Invalid schedulation time \"24:30\". Use HH:mm format"
}

Request examples

curl --request POST 'https://api.hub.donutwork.com/2026-02-01/job-runner.json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "jobrunner": {
    "title": "Sync CRM Contacts",
    "method": "POST",
    "url": "https://api.partner.com/sync",
    "content_type": "application/json",
    "body": "{\"scope\":\"daily\"}",
    "schedulation": [
      "08:00",
      "14:30"
    ]
  }
}'
const response = await fetch('https://api.hub.donutwork.com/2026-02-01/job-runner.json', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "jobrunner": {
      "title": "Sync CRM Contacts",
      "method": "POST",
      "url": "https://api.partner.com/sync",
      "content_type": "application/json",
      "body": "{\"scope\":\"daily\"}",
      "schedulation": [
        "08:00",
        "14:30"
      ]
    }
  }),
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
  const error = await response.text();
  throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
  : contentType.includes('application/json') ? await response.json()
  : await response.text();
$request = curl_init('https://api.hub.donutwork.com/2026-02-01/job-runner.json');
curl_setopt_array($request, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => '{
  "jobrunner": {
    "title": "Sync CRM Contacts",
    "method": "POST",
    "url": "https://api.partner.com/sync",
    "content_type": "application/json",
    "body": "{\\"scope\\":\\"daily\\"}",
    "schedulation": [
      "08:00",
      "14:30"
    ]
  }
}',
]);
$response = curl_exec($request);
if ($response === false) {
    $error = curl_error($request);
    curl_close($request);
    throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
    : (str_contains($contentType, 'application/json')
        ? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);

Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.

Run Job

POST
/2026-02-01/job-runner/{jobRunnerId}/run.json
Required permissionjob_runner:write

Path, query, and header parameters

jobRunnerIdstring· pathRequired
Job runner identifier.

Responses

Job execution completed.

{
  "job_runner_id": "681f10...",
  "status": "success",
  "headers": [
    "HTTP/1.1 200 OK"
  ],
  "response": "{\"ok\":true}",
  "ms": 122.45
}

Request examples

curl --request POST 'https://api.hub.donutwork.com/2026-02-01/job-runner/JOBRUNNERID/run.json' \
  --header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.hub.donutwork.com/2026-02-01/job-runner/JOBRUNNERID/run.json', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
  },
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
  const error = await response.text();
  throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
  : contentType.includes('application/json') ? await response.json()
  : await response.text();
$request = curl_init('https://api.hub.donutwork.com/2026-02-01/job-runner/JOBRUNNERID/run.json');
curl_setopt_array($request, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
    ],
]);
$response = curl_exec($request);
if ($response === false) {
    $error = curl_error($request);
    curl_close($request);
    throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
    : (str_contains($contentType, 'application/json')
        ? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);

Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.

Delete Job

DELETE
/2026-02-01/job-runner/{jobRunnerId}.json
Required permissionjob_runner:write

Path, query, and header parameters

jobRunnerIdstring· pathRequired
Job runner identifier.

Responses

Job runner deleted.

{
  "id": "681f10...",
  "deleted": true
}

Request examples

curl --request DELETE 'https://api.hub.donutwork.com/2026-02-01/job-runner/JOBRUNNERID.json' \
  --header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.hub.donutwork.com/2026-02-01/job-runner/JOBRUNNERID.json', {
  method: 'DELETE',
  headers: {
    Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
  },
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
  const error = await response.text();
  throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
  : contentType.includes('application/json') ? await response.json()
  : await response.text();
$request = curl_init('https://api.hub.donutwork.com/2026-02-01/job-runner/JOBRUNNERID.json');
curl_setopt_array($request, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
    ],
]);
$response = curl_exec($request);
if ($response === false) {
    $error = curl_error($request);
    curl_close($request);
    throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
    : (str_contains($contentType, 'application/json')
        ? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);

Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.

On this page