DonutworkHelp Center
Api ReferenceStrumenti di utilità
Documentazione Donutwork

Shortlinks

Manage short URL redirection, monitor traffic attribution, and control shortlink lifecycle.

Shortlinks API

The Shortlinks API enables organizations to transform complex destination URLs into concise links. Beyond simple redirection, the system provides integrated telemetry for traffic attribution, enabling teams to monitor engagement performance in real time across distribution channels.


Retrieve a paginated directory of all shortlinks associated with your organization. This inventory includes current operational status and destination metadata.

GET
/2026-02-01/shortlinks.json
Required permissionshortlinks:read

Path, query, and header parameters

sizeinteger· query
Maximum records per page (max 100).
pageinteger· query
Target page index.

Responses

Shortlink inventory successfully retrieved.

{
  "entities": "Shortlink",
  "count": 42,
  "per_page": 100,
  "pages": {
    "current": 1,
    "max": 1
  },
  "elements": [
    {
      "id": "675d9fea...",
      "title": "Spring 2026 Campaign",
      "original_url": "https://marketing.acme.com/promo/spring",
      "short_code": "k9x2m-spr26",
      "url": "https://d.dw2.it/r/k9x2m-spr26",
      "is_active": true
    }
  ]
}

Request examples

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

Generate a new shortlink for a target destination.
You can optionally provide a custom fragment (bitly-style suffix). The platform always prepends an auto-generated prefix to reduce collision risk.

POST
/2026-02-01/shortlinks.json
Required permissionshortlinks:write

Path, query, and header parameters

No path, query, or additional header parameters.

Request Body

JSON
{
  "shortlink": {
    "title": "Product Launch Announcement",
    "original_url": "https://acme.com/products/new-gen-ai",
    "fragment": "launch-2026",
    "is_active": true
  }
}
shortlink.titlestringRequired
Administrative label for the link.
shortlink.original_urlstringRequired
The full destination URL (must include protocol).
shortlink.fragmentstring
Custom shortlink suffix (3-48 chars, letters/numbers/hyphens). Alias: `shortlink.short_code`.
shortlink.is_activeboolean
Operational status of the link. Defaults to true.

Responses

Shortlink successfully provisioned.

{
  "shortlink": {
    "id": "6768440..."
  },
  "short_code": "k9x2m-launch-2026",
  "url": "https://d.dw2.it/r/k9x2m-launch-2026"
}

Requested custom fragment is already in use.

{
  "error": "This shortlink fragment is already in use"
}

Request examples

curl --request POST 'https://api.hub.donutwork.com/2026-02-01/shortlinks.json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "shortlink": {
    "title": "Product Launch Announcement",
    "original_url": "https://acme.com/products/new-gen-ai",
    "fragment": "launch-2026",
    "is_active": true
  }
}'
const response = await fetch('https://api.hub.donutwork.com/2026-02-01/shortlinks.json', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "shortlink": {
      "title": "Product Launch Announcement",
      "original_url": "https://acme.com/products/new-gen-ai",
      "fragment": "launch-2026",
      "is_active": true
    }
  }),
});
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/shortlinks.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 => '{
  "shortlink": {
    "title": "Product Launch Announcement",
    "original_url": "https://acme.com/products/new-gen-ai",
    "fragment": "launch-2026",
    "is_active": true
  }
}',
]);
$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.

Fetch the detailed configuration and operational status for a specific shortlink.

GET
/2026-02-01/shortlinks/{shortlinkId}.json
Required permissionshortlinks:read

Path, query, and header parameters

shortlinkIdstring· pathRequired
The unique identifier of the shortlink.

Responses

Shortlink configuration retrieved.

{
  "id": "675d9fea...",
  "title": "Spring 2026 Campaign",
  "original_url": "https://marketing.acme.com/promo/spring",
  "short_code": "k9x2m-spr26",
  "url": "https://d.dw2.it/r/k9x2m-spr26",
  "is_active": true
}

Request examples

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


Operational Controls

Modify the destination URL, custom fragment, or operational status of an existing shortlink. Link updates are propagated across the redirection edge in near real-time.
When updating fragment, the existing auto-generated prefix is preserved.

PUT
/2026-02-01/shortlinks/{shortlinkId}.json
Required permissionshortlinks:write

Path, query, and header parameters

shortlinkIdstring· pathRequired
The unique identifier to update.

Request Body

JSON
{
  "shortlink": {
    "title": "Revised Spring Campaign",
    "original_url": "https://marketing.acme.com/promo/spring-final",
    "fragment": "spring-final",
    "is_active": true
  }
}
shortlink.titlestringRequired
Updated shortlink title.
shortlink.original_urlstringRequired
Updated destination URL.
shortlink.fragmentstring
Updated custom suffix (3-48 chars, letters/numbers/hyphens). Alias: `shortlink.short_code`.
shortlink.is_activeboolean
Enable or disable link redirection.

Responses

Configuration updated successfully.

{
  "shortlink": {
    "id": "675d9fea..."
  },
  "short_code": "k9x2m-spring-final",
  "url": "https://d.dw2.it/r/k9x2m-spring-final"
}

Requested custom fragment is already in use.

{
  "error": "This shortlink fragment is already in use"
}

Request examples

curl --request PUT 'https://api.hub.donutwork.com/2026-02-01/shortlinks/SHORTLINKID.json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "shortlink": {
    "title": "Revised Spring Campaign",
    "original_url": "https://marketing.acme.com/promo/spring-final",
    "fragment": "spring-final",
    "is_active": true
  }
}'
const response = await fetch('https://api.hub.donutwork.com/2026-02-01/shortlinks/SHORTLINKID.json', {
  method: 'PUT',
  headers: {
    Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "shortlink": {
      "title": "Revised Spring Campaign",
      "original_url": "https://marketing.acme.com/promo/spring-final",
      "fragment": "spring-final",
      "is_active": true
    }
  }),
});
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/shortlinks/SHORTLINKID.json');
curl_setopt_array($request, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => '{
  "shortlink": {
    "title": "Revised Spring Campaign",
    "original_url": "https://marketing.acme.com/promo/spring-final",
    "fragment": "spring-final",
    "is_active": true
  }
}',
]);
$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.

Permanently revoke a shortlink and decommission its redirection service.

DELETE
/2026-02-01/shortlinks/{shortlinkId}.json
Required permissionshortlinks:write

Path, query, and header parameters

shortlinkIdstring· pathRequired
The identifier to decompose.

Responses

Shortlink successfully revoked.

{
  "id": "675d9fea...",
  "deleted": true
}

Request examples

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


Analytics & Telemetry

Retrieve Interaction Metrics

Access real-time engagement telemetry for a specific shortlink. This include visit counts, unique interactions, and longitudinal performance data.

GET
/2026-02-01/shortlinks/{shortlinkId}/stats.json
Required permissionshortlinks:read

Path, query, and header parameters

shortlinkIdstring· pathRequired
The shortlink identifier.

Responses

Engagement metrics successfully aggregated.

{
  "shortlink": {
    "id": "675d9fea...",
    "title": "Spring 2026 Campaign",
    "original_url": "https://marketing.acme.com/promo/spring",
    "short_code": "k9x2m-spr26",
    "is_active": true,
    "url": "https://d.dw2.it/r/k9x2m-spr26",
    "created_at": 1772536800
  },
  "metrics": {
    "summary": {
      "human": 1530,
      "bot": 12,
      "total": 1542
    },
    "view_density": [
      {
        "country": "IT",
        "count": 600
      },
      {
        "country": "US",
        "count": 420
      }
    ],
    "referrers": {
      "Direct": 900,
      "linkedin.com": 350,
      "newsletter.acme.com": 292
    },
    "bots": {
      "Google": 7,
      "Facebook": 5
    },
    "browsers": {
      "Chrome": 1100,
      "Safari": 320,
      "Firefox": 110
    },
    "os": {
      "Windows": 620,
      "macOS": 410,
      "iOS": 320,
      "Android": 180
    }
  }
}

Request examples

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