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.
Link Lifecycle Management
Audit Shortlink Directory
Retrieve a paginated directory of all shortlinks associated with your organization. This inventory includes current operational status and destination metadata.
shortlinks:readPath, query, and header parameters
sizepageResponses
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.
Provision New Shortlink
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.
shortlinks:writePath, query, and header parameters
No path, query, or additional header parameters.
Request Body
{
"shortlink": {
"title": "Product Launch Announcement",
"original_url": "https://acme.com/products/new-gen-ai",
"fragment": "launch-2026",
"is_active": true
}
}shortlink.titleRequiredshortlink.original_urlRequiredshortlink.fragmentshortlink.is_activeResponses
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.
Retrieve Link Configuration
Fetch the detailed configuration and operational status for a specific shortlink.
shortlinks:readPath, query, and header parameters
shortlinkIdRequiredResponses
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
Update Link Parameters
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.
shortlinks:writePath, query, and header parameters
shortlinkIdRequiredRequest Body
{
"shortlink": {
"title": "Revised Spring Campaign",
"original_url": "https://marketing.acme.com/promo/spring-final",
"fragment": "spring-final",
"is_active": true
}
}shortlink.titleRequiredshortlink.original_urlRequiredshortlink.fragmentshortlink.is_activeResponses
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.
Revoke Shortlink
Permanently revoke a shortlink and decommission its redirection service.
shortlinks:writePath, query, and header parameters
shortlinkIdRequiredResponses
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.
shortlinks:readPath, query, and header parameters
shortlinkIdRequiredResponses
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.