Download OpenAPI specification:Download
Powerful link management API for creating, managing, and tracking shortened links.
All API requests require authentication using an API key. Include your API key in the Authorization header:
Authorization: Bearer your_api_key_here
LinkScale uses a secure, three-step upload process with Uploadcare CDN for optimal performance and security.
Step 1: Get Upload Signature
PUT /api/v1/assets
Body: { "expiration_minutes": 10 }
→ Returns: upload_config with signature
Step 2: Upload to Uploadcare
POST upload_config.upload_url
FormData with: file, signature, public_key, metadata
→ Returns: { "file": "uuid-file-id" }
Step 3: Poll for Validation
GET /api/v1/assets/{file_id}
Poll every 2 seconds until 200 OK (usually 2-3 seconds)
→ Returns: Complete asset with CDN URL
See the detailed documentation in the Assets endpoints for complete code examples in JavaScript/Node.js.
LinkScale provides powerful dynamic features that allow you to reuse templates and configurations while customizing specific elements per link.
Override specific template properties (name and profile picture) while maintaining the template's design. This is particularly useful when using the same template (cs_template) for multiple links but with different profile information.
Use Case: You have a company template with standard branding, but want to create personalized links for different team members with their own names and profile pictures.
Key Features:
cs_template is specifiedExample:
{
"cs_template": "507f1f77bcf86cd799439011",
"dynamic_informations": {
"enabled": true,
"pp_enabled": true,
"n": "John Doe",
"pp": {
"url": "https://cdn.example.com/john.jpg",
"enabled": true,
"size": 150,
"border": {
"color": "#4A90E2",
"style": "solid",
"width": 3
}
}
}
}
Dynamically manage and customize link arrays within your landing pages for flexible content management.
Looking for practical examples and ready-to-use scripts? Visit our GitHub organization for concrete implementations:
🔗 LinkScale GitHub - Code Examples
You'll find:
These repositories provide production-ready code you can use as a foundation for your own implementations.
Create a new shortened link with optional customization options
| type required | string Enum: "l_p" "d_l" Link type - 'l_p' for landing page or 'd_l' for direct link. IMPORTANT: This field is required and determines the link behavior:
|
| u required | string Username or unique identifier (can be empty string) |
| domain required | string Domain for the link |
| url | string <uri> Target URL to redirect to. REQUIRED when type is 'd_l' (direct link). Optional when type is 'l_p' (landing page). |
| n | string Display name (optional, can be empty) |
| bio | string Bio or description text (optional, can be empty) |
Array of objects Array of link objects for the landing page | |
object | |
object | |
object | |
object | |
object | |
object | |
| template | string Template identifier |
| cs_template | string Contact sheet template ID (ObjectId format). Optional for landing pages (type 'l_p'). This field is used to customize the appearance of landing pages. |
object | |
object | |
object Social media settings | |
object | |
object | |
| shield | boolean Enable shield protection |
| folders | Array of strings Array of folder IDs (ObjectId format) |
| enabled | boolean Whether the link is active |
| note | string Internal note (can be empty) |
object Dynamic informations allow overriding specific template properties (name and profile picture) while maintaining the template's design. Only works when cs_template is specified. |
{- "type": "l_p",
- "u": "johndoe",
- "domain": "link.dm",
- "n": "John Doe",
- "bio": "Software Developer"
}{- "success": true,
- "data": {
- "id": "abc123def456",
- "type": "l_p",
- "created_at": "2024-01-15T10:30:00Z"
}
}Retrieve a paginated list of your links with optional filtering
| page | integer >= 1 Default: 1 Page number for pagination |
| limit | integer [ 1 .. 100 ] Default: 20 Number of links per page |
| tag | string Filter by tag |
| search | string Search in title and description |
{- "success": true,
- "data": [
- {
- "id": "abc123def456",
- "title": "Example Website",
- "description": "A demonstration website for testing",
- "tags": [
- "demo",
- "testing"
], - "clicks": 42,
- "dynamic_informations": {
- "enabled": true,
- "pp_enabled": true,
- "n": "Custom Name",
- "pp": { }
}, - "created_at": "2024-01-15T10:30:00Z",
- "updated_at": "2024-01-15T10:30:00Z",
- "expires_at": "2024-12-31T23:59:59Z",
- "is_active": true
}
], - "pagination": {
- "page": 1,
- "limit": 20,
- "total": 150,
- "pages": 8
}
}Retrieve detailed information about a specific link
| id required | string The unique identifier of the link |
{- "success": true,
- "data": {
- "id": "abc123def456",
- "title": "Example Website",
- "description": "A demonstration website for testing",
- "tags": [
- "demo",
- "testing"
], - "clicks": 42,
- "dynamic_informations": {
- "enabled": true,
- "pp_enabled": true,
- "n": "Custom Name",
- "pp": { }
}, - "created_at": "2024-01-15T10:30:00Z",
- "updated_at": "2024-01-15T10:30:00Z",
- "expires_at": "2024-12-31T23:59:59Z",
- "is_active": true
}
}Update an existing link (partial update). Only provided fields will be updated.
| id required | string The unique identifier of the link |
| url | string <uri> Target URL to redirect to (for direct links) |
| u | string Username or unique identifier |
| n | string Display name |
| bio | string Bio or description text |
Array of objects Array of link objects for the landing page | |
object | |
object | |
object | |
| template | string Template identifier |
| shield | boolean Enable shield protection |
| enabled | boolean Whether the link is active |
| note | string Internal note |
object Dynamic informations allow overriding specific template properties (name and profile picture) while maintaining the template's design. Only works when cs_template is specified. |
{
}{- "success": true,
- "message": "Link updated successfully",
- "data": {
- "id": "abc123def456",
- "type": "l_p",
- "updated_at": "2025-10-08T10:30:00.000Z"
}, - "timestamp": "2025-10-08T10:30:00.000Z"
}Permanently delete a link. This action cannot be undone.
| id required | string The unique identifier of the link |
{- "success": true,
- "message": "Link deleted successfully",
- "data": {
- "id": "abc123def456",
- "deleted_at": "2025-10-08T10:30:00.000Z"
}, - "timestamp": "2025-10-08T10:30:00.000Z"
}Create a new template for the authenticated project with customization options
| t_name | string Template name (optional) |
| type | string Enum: "l_p" "d_l" Link type - 'l_p' for landing page or 'd_l' for direct link |
| url | string <uri> Target URL to redirect to (required when type is 'd_l') |
| n | string Display name (optional, can be empty) |
| bio | string Bio or description text (optional, can be empty) |
Array of objects Array of link objects for the landing page | |
object | |
object | |
object | |
| template | string Template identifier |
object Social media settings | |
| shield | boolean Enable shield protection |
| enabled | boolean Whether the template is active |
| note | string Internal note (can be empty) |
{- "t_name": "My Custom Template",
- "type": "l_p",
- "n": "John Doe",
- "bio": "Professional developer and designer",
- "template": "default",
- "s": { },
- "shield": false,
- "enabled": true,
- "note": ""
}{- "success": true,
- "message": "Template created successfully",
- "data": {
- "template_id": "507f1f77bcf86cd799439011",
- "t_name": "My Custom Template",
- "created_at": "2024-01-15T10:30:00Z"
}
}Retrieve all templates for the authenticated project
{- "success": true,
- "data": [
- {
- "_id": "507f1f77bcf86cd799439011",
- "t_name": "My Custom Template",
- "type": "l_p",
- "project_id": "7c78db83-6bdd-4bb4-8545-c7cfdfc1e480",
- "enabled": true,
- "created_at": "2024-01-15T10:30:00Z"
}
]
}Retrieve a specific template by ID from the authenticated project
| template_id required | string Example: 507f1f77bcf86cd799439011 The unique identifier of the template |
{- "success": true,
- "data": {
- "_id": "507f1f77bcf86cd799439011",
- "t_name": "My Custom Template",
- "type": "l_p",
- "project_id": "7c78db83-6bdd-4bb4-8545-c7cfdfc1e480",
- "enabled": true,
- "n": "John Doe",
- "bio": "Professional developer",
- "pp": { },
- "cover": { },
- "background": { },
- "links": [ ],
- "created_at": "2024-01-15T10:30:00Z"
}
}Update a specific template from the authenticated project. Only provided fields will be updated.
| template_id required | string Example: 507f1f77bcf86cd799439011 The unique identifier of the template |
| t_name | string Template name |
| type | string Enum: "l_p" "d_l" Link type |
| url | string <uri> Target URL to redirect to |
| n | string Display name |
| bio | string Bio or description text |
Array of objects Array of link objects | |
object | |
object | |
object | |
| template | string Template identifier |
| shield | boolean Enable shield protection |
| enabled | boolean Whether the template is active |
| note | string Internal note |
{- "t_name": "New Template Name"
}{- "success": true,
- "message": "Template updated successfully",
- "data": {
- "template_id": "507f1f77bcf86cd799439011",
- "updated_at": "2024-01-15T10:30:00Z"
}
}Permanently delete a template from the authenticated project. This action cannot be undone.
| template_id required | string Example: 507f1f77bcf86cd799439011 The unique identifier of the template |
{- "success": true,
- "message": "Template deleted successfully",
- "data": {
- "template_id": "507f1f77bcf86cd799439011",
- "deleted_at": "2024-01-15T10:30:00Z"
}
}Generate a secure signature for uploading files directly to Uploadcare CDN.
Call this endpoint to get a secure upload signature that expires after your specified time (default: 10 minutes).
const response = await fetch('https://dashboard.linkscale.to/api/v1/assets', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
expiration_minutes: 10
})
});
const { upload_config, project } = await response.json();
Use the signature to upload your file directly to Uploadcare using multipart/form-data.
Required FormData Fields:
UPLOADCARE_PUB_KEY: Public key from upload_configUPLOADCARE_STORE: Set to 'auto' for automatic storagesignature: Secure signature from upload_configexpire: Unix timestamp from upload_configfile: Your file as Blob/File objectmetadata[project_id]: Project ID from upload_config.metadatametadata[api_key_id]: API key ID from upload_config.metadataSupported File Types:
Complete Upload Example (Browser):
const formData = new FormData();
formData.append('UPLOADCARE_PUB_KEY', upload_config.public_key);
formData.append('UPLOADCARE_STORE', 'auto');
formData.append('signature', upload_config.signature);
formData.append('expire', upload_config.expire.toString());
formData.append('file', fileInput.files[0]); // Browser File object
formData.append('metadata[project_id]', upload_config.metadata.project_id);
formData.append('metadata[api_key_id]', upload_config.metadata.api_key_id);
const uploadResponse = await fetch(upload_config.upload_url, {
method: 'POST',
body: formData
});
const { file: fileId } = await uploadResponse.json();
console.log('File ID:', fileId); // e.g., "17be4678-dab7-4bc7-8753-28914a22960a"
Complete Upload Example (Node.js):
const fs = require('fs');
const path = require('path');
// Read file and create Blob
const fileBuffer = fs.readFileSync('./image.jpg');
const fileName = path.basename('./image.jpg');
// Detect MIME type from extension
const mimeTypes = {
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.webp': 'image/webp',
'.svg': 'image/svg+xml',
'.mp4': 'video/mp4',
'.webm': 'video/webm',
'.pdf': 'application/pdf',
'.json': 'application/json',
'.txt': 'text/plain'
};
const fileExtension = path.extname('./image.jpg').toLowerCase();
const mimeType = mimeTypes[fileExtension] || 'application/octet-stream';
const fileBlob = new Blob([fileBuffer], { type: mimeType });
// Create FormData with all required fields
const formData = new FormData();
formData.append('UPLOADCARE_PUB_KEY', upload_config.public_key);
formData.append('UPLOADCARE_STORE', 'auto');
formData.append('signature', upload_config.signature);
formData.append('expire', upload_config.expire.toString());
formData.append('file', fileBlob, fileName);
formData.append('metadata[project_id]', upload_config.metadata.project_id);
formData.append('metadata[api_key_id]', upload_config.metadata.api_key_id);
const uploadResponse = await fetch(upload_config.upload_url, {
method: 'POST',
body: formData
});
const { file: fileId } = await uploadResponse.json();
After uploading, poll GET /api/v1/assets/{file_id} until the file is validated (usually 2-3 seconds).
const pollValidation = async (fileId, maxAttempts = 10, delayMs = 2000) => {
for (let i = 0; i < maxAttempts; i++) {
const response = await fetch(`https://dashboard.linkscale.to/api/v1/assets/${fileId}`, {
headers: { 'Authorization': 'Bearer YOUR_API_KEY' }
});
if (response.ok) {
const data = await response.json();
console.log('✅ File validated!');
return data; // Asset ready to use
}
if (response.status === 404) {
console.log(`⏳ Still processing... (${i + 1}/${maxAttempts})`);
await new Promise(resolve => setTimeout(resolve, delayMs));
continue;
}
throw new Error('Validation failed');
}
throw new Error('Timeout - file may still be processing');
};
const asset = await pollValidation(fileId);
console.log('CDN URL:', asset.asset.provider_file_url);
Once validated, use the provider_file_url from the asset object to access your file via CDN.
// Use in your application
const cdnUrl = asset.asset.provider_file_url;
// Example: "https://ucarecdn.com/17be4678-dab7-4bc7-8753-28914a22960a/"
Images:
image/png - PNG imagesimage/jpeg - JPEG imagesimage/gif - GIF imagesimage/webp - WebP imagesimage/svg+xml - SVG imagesVideos:
video/mp4 - MP4 videosvideo/webm - WebM videosDocuments:
application/pdf - PDF documentsapplication/json - JSON filesText:
text/plain - Text filestext/csv - CSV filesSignature Request Errors:
Upload Errors:
Validation Errors:
| expiration_minutes | integer [ 1 .. 60 ] Default: 10 Signature expiration time in minutes (1-60). After this time, the signature becomes invalid and cannot be used for uploads. Recommended: 10 minutes for standard uploads, 30 minutes for large files. |
| allowed_mime_types | Array of strings or null Optional array of allowed MIME types to restrict uploads. If specified, only files matching these MIME types can be uploaded. If null/omitted, all file types are allowed. Common MIME types:
|
| max_file_size | integer or null Optional maximum file size in bytes. If specified, files larger than this size will be rejected. If null/omitted, no size limit is enforced. Recommended limits:
|
{- "expiration_minutes": 10
}{- "upload_config": {
- "public_key": "demopublickey",
- "expire": 1728481200,
- "signature": "a8b7c6d5e4f3g2h1i0j9k8l7m6n5o4p3",
- "metadata": {
- "project_id": "proj_abc123def456",
- "api_key_id": "lk_xyz789abc123"
}
}, - "project": {
- "project_id": "proj_abc123def456",
- "project_name": "My Project"
}
}Retrieve a paginated list of all validated assets for your project with optional search and filtering.
Features:
File Type Categories:
image: PNG, JPEG, GIF, WebP, SVG, etc.video: MP4, WebM, MOV, AVI, etc.audio: MP3, WAV, OGG, M4A, etc.application: PDF, ZIP, JSON, XML, etc.text: TXT, CSV, HTML, CSS, etc.Use Cases:
| search | string <= 100 characters Example: search=logo Search in filename and MIME type (partial match, case-insensitive, max 100 chars) |
| file_type | string Enum: "image" "video" "audio" "application" "text" Example: file_type=image Filter by file category |
| limit | integer [ 1 .. 100 ] Default: 50 Example: limit=50 Number of results per page (1-100) |
| offset | integer >= 0 Default: 0 Number of items to skip for pagination |
{- "assets": [
- {
- "_id": "67890xyz",
- "project_id": "proj_abc123",
- "file_id": "17be4678-dab7-4bc7-8753-28914a22960a",
- "provider_file_name": "logo.png",
- "file_mime_type": "image/png",
- "provider_date_time_uploaded": "2025-10-09T10:30:00.000Z",
- "file_size": 123456,
- "image_info": {
- "width": 1920,
- "height": 1080,
- "format": "PNG"
}, - "created_at": "2025-10-09T10:30:05.000Z"
}, - {
- "_id": "67891abc",
- "project_id": "proj_abc123",
- "file_id": "28cf5789-ebc8-5cd8-9864-39a25b33a71b",
- "provider_file_name": "video.mp4",
- "file_mime_type": "video/mp4",
- "provider_date_time_uploaded": "2025-10-09T11:15:00.000Z",
- "file_size": 5242880,
- "video_info": {
- "duration": 30000,
- "bitrate": 1400000
}, - "created_at": "2025-10-09T11:15:03.000Z"
}
], - "total": 42,
- "limit": 50,
- "offset": 0,
- "project": {
- "project_id": "proj_abc123",
- "project_name": "My Project"
}
}Retrieve information about a specific asset by its Uploadcare file ID.
After uploading a file to Uploadcare, you MUST poll this endpoint to verify the file has been validated by the webhook.
The upload process is asynchronous:
Processing includes:
Upload to Uploadcare → Get file_id → Poll this endpoint → 200 OK → Use asset
↓
404 = Still processing (wait 2s, retry)
Basic Polling (Recommended):
const pollValidation = async (fileId, maxAttempts = 10, delayMs = 2000) => {
console.log('⏳ Polling for validation...');
for (let i = 0; i < maxAttempts; i++) {
try {
const response = await fetch(
`https://dashboard.linkscale.to/api/v1/assets/${fileId}`,
{
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
}
);
if (response.ok) {
const data = await response.json();
console.log('✅ File validated and ready!');
console.log('CDN URL:', data.asset.provider_file_url);
return data;
}
if (response.status === 404) {
console.log(`Attempt ${i + 1}/${maxAttempts}: Still processing...`);
await new Promise(resolve => setTimeout(resolve, delayMs));
continue;
}
// Other error
const errorText = await response.text();
throw new Error(`Validation check failed: ${response.status} - ${errorText}`);
} catch (error) {
console.warn(`Attempt ${i + 1}/${maxAttempts} error:`, error.message);
await new Promise(resolve => setTimeout(resolve, delayMs));
}
}
throw new Error('Validation timeout - file may still be processing or failed');
};
// Usage
try {
const asset = await pollValidation(fileId);
// Asset is ready! Use the CDN URL
const cdnUrl = asset.asset.provider_file_url;
console.log('Use this URL:', cdnUrl);
} catch (error) {
console.error('Upload failed:', error.message);
}
Advanced Polling with Exponential Backoff:
const pollValidationWithBackoff = async (fileId) => {
const delays = [1000, 2000, 2000, 3000, 5000]; // Progressive delays
for (let i = 0; i < delays.length; i++) {
const response = await fetch(
`https://dashboard.linkscale.to/api/v1/assets/${fileId}`,
{ headers: { 'Authorization': 'Bearer YOUR_API_KEY' } }
);
if (response.ok) {
return await response.json(); // ✅ Success!
}
if (response.status === 404 && i < delays.length - 1) {
console.log(`⏳ Waiting ${delays[i]}ms...`);
await new Promise(r => setTimeout(r, delays[i]));
continue;
}
if (response.status !== 404) {
throw new Error(`Validation failed: ${response.status}`);
}
}
throw new Error('Timeout after multiple attempts');
};
Once validated (200 OK), the response includes:
provider_file_url for accessing the file404 Response: File not yet validated
401 Response: Unauthorized
Other errors: Validation failed
const uploadFile = async (file) => {
// Step 1: Get signature
const sigResponse = await fetch('https://dashboard.linkscale.to/api/v1/assets', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({ expiration_minutes: 10 })
});
const { upload_config } = await sigResponse.json();
// Step 2: Upload to Uploadcare
const formData = new FormData();
formData.append('UPLOADCARE_PUB_KEY', upload_config.public_key);
formData.append('UPLOADCARE_STORE', 'auto');
formData.append('signature', upload_config.signature);
formData.append('expire', upload_config.expire.toString());
formData.append('file', file);
formData.append('metadata[project_id]', upload_config.metadata.project_id);
formData.append('metadata[api_key_id]', upload_config.metadata.api_key_id);
const uploadResponse = await fetch(upload_config.upload_url, {
method: 'POST',
body: formData
});
const { file: fileId } = await uploadResponse.json();
console.log('📤 File uploaded, ID:', fileId);
// Step 3: Poll for validation (THIS ENDPOINT)
const asset = await pollValidation(fileId);
console.log('✅ Upload complete!');
console.log('CDN URL:', asset.asset.provider_file_url);
return asset;
};
| file_id required | string Example: 17be4678-dab7-4bc7-8753-28914a22960a Uploadcare UUID of the file (received after uploading to Uploadcare) |
{- "asset": {
- "_id": "67890xyz",
- "project_id": "proj_abc123",
- "file_id": "17be4678-dab7-4bc7-8753-28914a22960a",
- "provider_file_name": "logo.png",
- "file_mime_type": "image/png",
- "provider_date_time_uploaded": "2025-10-09T10:30:00.000Z",
- "file_size": 123456,
- "image_info": {
- "width": 1920,
- "height": 1080,
- "format": "PNG",
- "color_mode": "RGB",
- "dpi": [
- 72,
- 72
]
}, - "created_at": "2025-10-09T10:30:05.000Z"
}, - "project": {
- "project_id": "proj_abc123",
- "project_name": "My Project"
}
}Retrieve a simple list of all folders in your project without statistics or analytics.
This is a lightweight endpoint designed for quick folder listing. For detailed analytics and statistics, use /api/v1/folders/stats instead.
Key Features:
folders.read permissionUse this endpoint when you need to:
Use /api/v1/folders/stats when you need:
{- "project_id": "7c78db83-6bdd-4bb4-8545-c7cfdfc1e480",
- "project": {
- "project_id": "7c78db83-6bdd-4bb4-8545-c7cfdfc1e480",
- "project_name": "My Project"
}, - "folders": [
- {
- "_id": "folder_abc123",
- "name": "Marketing Campaign",
- "project_id": "7c78db83-6bdd-4bb4-8545-c7cfdfc1e480",
- "links_count": 15,
- "created_at": "2025-10-19T10:30:00.000Z",
- "updated_at": "2025-10-19T15:45:00.000Z"
}, - {
- "_id": "folder_def456",
- "name": "Social Media",
- "project_id": "7c78db83-6bdd-4bb4-8545-c7cfdfc1e480",
- "links_count": 23,
- "created_at": "2025-10-18T08:15:00.000Z",
- "updated_at": "2025-10-19T12:30:00.000Z"
}, - {
- "_id": "folder_ghi789",
- "name": "Product Launch",
- "project_id": "7c78db83-6bdd-4bb4-8545-c7cfdfc1e480",
- "links_count": 8,
- "created_at": "2025-10-15T14:20:00.000Z",
- "updated_at": "2025-10-16T09:00:00.000Z"
}
]
}Get comprehensive statistics for your entire project. Supports optional timezone and lazy-loading of traffic data via traffic_data_type.
| from | string <date-time> Start date (ISO 8601) |
| to | string <date-time> End date (ISO 8601) |
| timezone | string Example: timezone=Europe/Paris Timezone for data aggregation (IANA tz). Default is UTC. |
| traffic_data_type | string Default: "urls" Enum: "urls" "links" "both" "none" Type of traffic data to include |
| include_clicks | boolean Default: false Include detailed clicks data |
| exclude_referer | string Example: exclude_referer=["https://t.co/","https://twitter.com"] Array of referers to exclude from statistics (JSON-encoded array in query string). Each referer string must not exceed 500 characters. Example: |
| exclude_useragent | string Example: exclude_useragent=["Googlebot","TelegramBot"] Array of user agents to exclude from statistics (JSON-encoded array in query string). Each user agent string must not exceed 500 characters. Example: |
{- "summary": {
- "totalViews": 45230,
- "normalTraffic": 42100,
- "botTraffic": 3130,
- "totalCountries": 87,
- "totalReferrers": 234
}, - "dailyTraffic": [
- {
- "date": "2024-01-01T00:00:00.000Z",
- "totalViews": 1250,
- "normalTraffic": 1180,
- "botTraffic": 70
}
], - "topReferrers": [
- {
- "referrer": "google.com",
- "views": 15000
}
], - "socialTraffic": [
- {
- "platform": "Facebook",
- "views": 8500
}
], - "trafficByCountries": [
- {
- "date": "2024-01-01T00:00:00.000Z",
- "countries": [
- {
- "country": "US",
- "views": 450
}
]
}
], - "trafficByUrls": [
- {
- "date": "2025-10-10T00:00:00.000Z",
- "host": "emilycutie.me",
- "u": "92",
- "id": "688fe9a45202a5dd8e25d639",
- "project_id": "dfc5abb5-d7e3-49a5-9535-36f43ea6d4d8",
- "url": "emilycutie.me/92",
- "clicks": 2949,
- "bots": 25,
- "human_proxy": 6,
- "human_vpn": 0,
- "human_proxy_vpn": 229,
- "note": "ismaud75",
- "currentNote": "Campaign Q4 2024",
- "countries": [
- {
- "country": "US",
- "visits": 305
}
]
}
], - "trafficByLinks": [
- {
- "link_id": "abc123",
- "link_name": "Campaign A",
- "folder_id": "folder1",
- "views": 1200,
- "clicks": 350,
- "note": "Previous note",
- "currentNote": "Updated campaign note"
}
], - "clicks": {
- "totalClicks": 11700,
- "clicksByLink": [
- {
- "link_id": "abc123",
- "clicks": 350
}
]
}
}Get statistics for all folders in your project.
| from | string <date-time> Start date (ISO 8601) |
| to | string <date-time> End date (ISO 8601) |
| timezone | string Example: timezone=UTC Timezone for data aggregation (IANA tz). Default is UTC. |
| exclude_referer | string Example: exclude_referer=["https://t.co/","https://twitter.com"] Array of referers to exclude from statistics (JSON-encoded array in query string). Each referer string must not exceed 500 characters. Example: |
| exclude_useragent | string Example: exclude_useragent=["Googlebot","TelegramBot"] Array of user agents to exclude from statistics (JSON-encoded array in query string). Each user agent string must not exceed 500 characters. Example: |
{- "project_id": "project123",
- "date_range": {
- "from": "2024-01-01T00:00:00Z",
- "to": "2024-01-31T23:59:59Z",
- "timezone": "UTC"
}, - "project": {
- "project_id": "project123",
- "project_name": "My Project"
}, - "stats": {
- "folders": [
- {
- "folder_id": "folder1",
- "folder_name": "Marketing Links",
- "totalClicks": 450,
- "totalViews": 1200,
- "uniqueVisitors": 890,
- "links": [
- {
- "link_id": "link1",
- "link_name": "Campaign A",
- "clicks": 200,
- "views": 500
}
]
}
], - "summary": {
- "totalFolders": 12,
- "totalLinks": 127,
- "totalClicks": 11700,
- "totalViews": 45200
}
}
}Get detailed statistics for a specific folder. Supports optional timezone and lazy-loading of traffic data via traffic_data_type.
| folder_id required | string Example: folder1 The ID of the folder |
| from | string <date-time> Start date (ISO 8601) |
| to | string <date-time> End date (ISO 8601) |
| timezone | string Example: timezone=UTC Timezone for data aggregation (IANA tz). Default is UTC. |
| traffic_data_type | string Default: "urls" Enum: "urls" "links" "both" "none" Type of traffic data to include in the response. Controls lazy-loading of trafficByUrls and trafficByLinks data. "urls" includes only traffic by URL (default), "links" includes only traffic by links, "both" includes both types, "none" excludes detailed traffic data. |
| exclude_referer | string Example: exclude_referer=["https://t.co/","https://twitter.com"] Array of referers to exclude from statistics (JSON-encoded array in query string). Each referer string must not exceed 500 characters. Example: |
| exclude_useragent | string Example: exclude_useragent=["Googlebot","TelegramBot"] Array of user agents to exclude from statistics (JSON-encoded array in query string). Each user agent string must not exceed 500 characters. Example: |
{- "folder_id": "folder1",
- "folder_name": "Marketing Links",
- "date_range": {
- "from": "2024-01-01T00:00:00Z",
- "to": "2024-01-31T23:59:59Z",
- "timezone": "UTC"
}, - "analytics": {
- "visits": 1200,
- "bots": 85,
- "total": 1285,
- "countries": 45,
- "topCountries": [
- {
- "country": "US",
- "visits": 450
}
], - "topReferrers": [
- {
- "referrer": "google.com",
- "visits": 380
}
], - "topLinks": [
- {
- "link_id": "link1",
- "link_name": "Campaign A",
- "visits": 500,
- "clicks": 200
}
]
}, - "trafficByUrls": [
- {
- "date": "2025-10-10T00:00:00.000Z",
- "host": "emilycutie.me",
- "u": "92",
- "id": "688fe9a45202a5dd8e25d639",
- "project_id": "dfc5abb5-d7e3-49a5-9535-36f43ea6d4d8",
- "url": "emilycutie.me/92",
- "clicks": 2949,
- "bots": 25,
- "human_proxy": 6,
- "human_vpn": 0,
- "human_proxy_vpn": 229,
- "note": "ismaud75",
- "currentNote": "Campaign Q4 2024",
- "countries": [
- {
- "country": "US",
- "visits": 305
}
]
}
], - "trafficByLinks": [
- {
- "link_id": "abc123",
- "link_name": "Campaign A",
- "folder_id": "folder1",
- "views": 1200,
- "clicks": 350,
- "note": "Previous note",
- "currentNote": "Updated campaign note"
}
]
}Retrieve analytics data for a specific link within a date range. Includes click aggregates from ClickHouse.
Authorization: Bearer API key
Required permission: statistics.read_link
Backward compatible: Existing fields unchanged; new field analytics.clicks added.
| link_id required | string Example: 68b5c1a88568a81cc8355a64 The unique identifier of the link |
| from required | string <date-time> Example: from=2025-10-26T00:00:00Z Start date for the analytics period (ISO 8601 format) |
| to required | string <date-time> Example: to=2025-10-27T00:00:00Z End date for the analytics period (ISO 8601 format) |
| timezone | string Example: timezone=UTC Timezone for data aggregation (IANA tz string). Defaults to project timezone or UTC. |
| exclude_referer | string Example: exclude_referer=["https://t.co/","https://twitter.com"] Array of referers to exclude from statistics (JSON-encoded array in query string). Each referer string must not exceed 500 characters. Example: |
| exclude_useragent | string Example: exclude_useragent=["Googlebot","TelegramBot"] Array of user agents to exclude from statistics (JSON-encoded array in query string). Each user agent string must not exceed 500 characters. Example: |
{- "link_id": "68b5c1a88568a81cc8355a64",
- "date_range": {
- "from": "2025-10-26T00:00:00Z",
- "to": "2025-10-27T00:00:00Z",
- "timezone": "UTC"
}, - "project": {
- "project_id": "proj_123",
- "project_name": "My Project"
}, - "analytics": {
- "visits": 1243,
- "bots": 91,
- "total": 1334,
- "countries": 27,
- "topCountries": [
- {
- "country": "United States",
- "visits": 410
}, - {
- "country": "FR",
- "visits": 205
}, - {
- "country": "CA",
- "visits": 128
}
], - "topReferrers": [
- {
- "referrer": "direct",
- "visits": 512
},
], - "clicks": [
- {
- "btn_id": "cta_primary",
- "clicks": 97,
- "lastClick": "2025-10-26T23:59:12.123Z",
- "position": 1,
- "btn_v": "A"
}, - {
- "btn_id": "cta_secondary",
- "clicks": 54,
- "lastClick": "2025-10-26T22:15:30.456Z",
- "position": 2,
- "btn_v": 1
}, - {
- "btn_id": null,
- "clicks": 23,
- "lastClick": "2025-10-26T20:45:18.789Z",
- "position": null,
- "btn_v": null
}
]
}
}