DonutworkHelp Center
Donutwork documentation

Authentication

Secure your integration using API Key authentication.

Authentication and permissions

The Donutwork API uses API keys to authenticate requests. You can view and manage your API keys in the Donutwork Dashboard.

An API key identifies both the client and its company boundary. Keys can be restricted with resource scopes such as customers:read or customers:write; each endpoint displays the exact required scope.

Authorization Header

All API requests must include your API Key in the Authorization HTTP header as a Bearer token.

Authorization: Bearer <your_api_key>
Your API keys carry significant privileges. Keep them secure and never expose them in client-side code or public repositories.

Use one key per application and environment. Store keys in a managed secret store, restrict production access, rotate on personnel or vendor changes, and revoke immediately if a value may have leaked. Never send a key in a query string.

Permission failures

When a scoped key lacks access, the API responds with 403 and identifies both the missing permission and the grants currently attached to the key:

{
  "error": "insufficient_scope",
  "required_permission": "customers:write",
  "granted_permissions": ["customers:read"]
}

Read operations use resource:read; create, update, and delete operations use the documented resource:write permission. A valid key is not sufficient when its scope is narrower than the route.

Obtaining an API Key

Donutwork is currently in a controlled rollout phase. Access is granted to partners and early adopters through the following process:

Request Access

Submit a request to the Donutwork team outlining your integration use case.

Review & Provisioning

Our team will review your requirements and provision the necessary environments.

Environment Keys

Upon approval, you will be provided with distinct keys for:

  • Staging: For development, testing, and sandbox experimentation.
  • Production: For live, customer-facing traffic.

Connectivity and Health Checks

Use these endpoints to validate your authentication credentials and monitor API availability.

System Ping

Verify the operational status of the Donutwork API environment.

GET
/2026-02-01/ping.json
Required permissionping:read

Path, query, and header parameters

No path, query, or additional header parameters.

Responses

API is operational and responding.

{
  "status": "success",
  "env": "production",
  "RRT": "0.08 ms"
}

Invalid or revoked API key.

{
  "error": "Invalid token"
}

Request examples

curl --request GET 'https://api.hub.donutwork.com/2026-02-01/ping.json' \
  --header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.hub.donutwork.com/2026-02-01/ping.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/ping.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.

Connection Metadata

Retrieve detailed information about your current connection, including client IP and protocol negotiation.

GET
/2026-02-01/connection.json
Required permissionconnection:read

Path, query, and header parameters

No path, query, or additional header parameters.

Responses

Connection metadata retrieved successfully.

{
  "client": {
    "userAgent": "axios/1.6.0",
    "ips": {
      "ipv4": "192.168.1.1"
    }
  },
  "endpoint": {
    "apiVersion": "2026-02-01",
    "env": "production",
    "protocol": "HTTP3"
  }
}

Request examples

curl --request GET 'https://api.hub.donutwork.com/2026-02-01/connection.json' \
  --header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.hub.donutwork.com/2026-02-01/connection.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/connection.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.

On this page