Skip to main content

LinkScale API (1.0.0)

Download OpenAPI specification:Download

LinkScale Support: contact@linkscale.to URL: https://linkscale.to/support License: MIT

Powerful link management API for creating, managing, and tracking shortened links.

Authentication

All API requests require authentication using an API key. Include your API key in the Authorization header:

Authorization: Bearer your_api_key_here

File Upload System

LinkScale uses a secure, three-step upload process with Uploadcare CDN for optimal performance and security.

Quick Start Guide

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

Why This Approach?

  • Security: Time-limited signatures prevent unauthorized uploads
  • Performance: Direct CDN upload, no server bottleneck
  • Scalability: Files never transit through your server
  • Reliability: Automatic validation and metadata extraction
  • Flexibility: Support for images, videos, documents, and more

Supported File Types

  • Images: PNG, JPEG, GIF, WebP, SVG (with dimensions, format, DPI)
  • Videos: MP4, WebM, MOV (with duration, bitrate, codecs)
  • Audio: MP3, WAV, OGG, M4A (with duration, bitrate)
  • Documents: PDF, JSON, XML, TXT, CSV

Complete Implementation

See the detailed documentation in the Assets endpoints for complete code examples in JavaScript/Node.js.

Dynamic Features

LinkScale provides powerful dynamic features that allow you to reuse templates and configurations while customizing specific elements per link.

Dynamic Informations

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:

  • Override template name with custom display name
  • Override template profile picture with custom image
  • Granular control over profile picture styling (size, borders, etc.)
  • Master toggles to enable/disable overrides
  • Only works when cs_template is specified

Example:

{
  "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.

Demos & Examples

Looking for practical examples and ready-to-use scripts? Visit our GitHub organization for concrete implementations:

🔗 LinkScale GitHub - Code Examples

You'll find:

  • Complete upload workflows with Node.js implementations
  • Link management scripts for batch operations
  • Integration examples for common use cases
  • Real-world scenarios and best practices

These repositories provide production-ready code you can use as a foundation for your own implementations.

Get link details

Retrieve detailed information about a specific link

Authorizations:
BearerAuth
path Parameters
id
required
string

The unique identifier of the link

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Templates

Create a new template

Create a new template for the authenticated project with customization options

Authorizations:
BearerAuth
Request Body schema: application/json
required
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)

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{
  • "success": true,
  • "message": "Template created successfully",
  • "data": {
    }
}

Get all templates

Retrieve all templates for the authenticated project

Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ]
}

Get template by ID

Retrieve a specific template by ID from the authenticated project

Authorizations:
BearerAuth
path Parameters
template_id
required
string
Example: 507f1f77bcf86cd799439011

The unique identifier of the template

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Update template

Update a specific template from the authenticated project. Only provided fields will be updated.

Authorizations:
BearerAuth
path Parameters
template_id
required
string
Example: 507f1f77bcf86cd799439011

The unique identifier of the template

Request Body schema: application/json
required
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

Responses

Request samples

Content type
application/json
Example
{
  • "t_name": "New Template Name"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "message": "Template updated successfully",
  • "data": {
    }
}

Delete template

Permanently delete a template from the authenticated project. This action cannot be undone.

Authorizations:
BearerAuth
path Parameters
template_id
required
string
Example: 507f1f77bcf86cd799439011

The unique identifier of the template

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "message": "Template deleted successfully",
  • "data": {
    }
}

Assets

Generate upload signature

Generate a secure signature for uploading files directly to Uploadcare CDN.

Complete Upload Workflow

Step 1: Request Upload Signature

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();

Step 2: Upload File to Uploadcare

Use the signature to upload your file directly to Uploadcare using multipart/form-data.

Required FormData Fields:

  • UPLOADCARE_PUB_KEY: Public key from upload_config
  • UPLOADCARE_STORE: Set to 'auto' for automatic storage
  • signature: Secure signature from upload_config
  • expire: Unix timestamp from upload_config
  • file: Your file as Blob/File object
  • metadata[project_id]: Project ID from upload_config.metadata
  • metadata[api_key_id]: API key ID from upload_config.metadata

Supported File Types:

  • Images: PNG, JPEG, GIF, WebP, SVG
  • Videos: MP4, WebM, MOV, AVI
  • Audio: MP3, WAV, OGG, M4A
  • Documents: PDF, ZIP, JSON, XML
  • Text: TXT, CSV, HTML, CSS

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();

Step 3: Poll for Validation

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);

Step 4: Use Your Asset

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/"

Security Features

  • Time-limited signatures: Signatures expire after specified time (1-60 minutes)
  • MIME type restrictions: Optionally restrict allowed file types
  • File size limits: Optionally set maximum file size in bytes
  • Metadata tracking: Automatically tagged with project_id and api_key_id
  • Direct upload: Files never transit through your server
  • Automatic validation: Webhook validates files asynchronously
  • Invalid files deleted: Files failing validation are automatically removed

Common MIME Types

Images:

  • image/png - PNG images
  • image/jpeg - JPEG images
  • image/gif - GIF images
  • image/webp - WebP images
  • image/svg+xml - SVG images

Videos:

  • video/mp4 - MP4 videos
  • video/webm - WebM videos

Documents:

  • application/pdf - PDF documents
  • application/json - JSON files

Text:

  • text/plain - Text files
  • text/csv - CSV files

Expected Timing

  • Signature generation: < 100ms
  • Upload to Uploadcare: Depends on file size and connection
  • Validation (webhook): 1-3 seconds (normal)
  • Recommended polling: Every 2 seconds for max 30 seconds

Error Handling

Signature Request Errors:

  • 400: Invalid expiration_minutes (must be 1-60)
  • 401: Missing or invalid API key

Upload Errors:

  • Check Uploadcare response for upload failures
  • Common: signature expired, file too large, invalid MIME type

Validation Errors:

  • 404: File not yet validated (keep polling)
  • Timeout after 30 seconds: File may still be processing or failed validation
Authorizations:
BearerAuth
Request Body schema: application/json
optional
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:

  • Images: image/png, image/jpeg, image/gif, image/webp, image/svg+xml
  • Videos: video/mp4, video/webm, video/mov
  • Audio: audio/mpeg, audio/wav, audio/ogg
  • Documents: application/pdf, application/json, text/plain
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:

  • Profile pictures: 5 MB (5242880 bytes)
  • Images: 10 MB (10485760 bytes)
  • Videos: 50-100 MB (52428800-104857600 bytes)
  • Documents: 10 MB (10485760 bytes)

Responses

Request samples

Content type
application/json
Example
{
  • "expiration_minutes": 10
}

Response samples

Content type
application/json
Example
{
  • "upload_config": {
    },
  • "project": {
    }
}

List assets

Retrieve a paginated list of all validated assets for your project with optional search and filtering.

Features:

  • Search by filename or MIME type
  • Filter by file category (image, video, audio, document, text)
  • Pagination with limit and offset
  • Returns rich metadata (file size, dimensions, duration, etc.)

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:

  • Display asset galleries
  • File managers
  • Search functionality
  • Asset selection interfaces
Authorizations:
BearerAuth
query Parameters
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

Responses

Response samples

Content type
application/json
Example
{
  • "assets": [
    ],
  • "total": 42,
  • "limit": 50,
  • "offset": 0,
  • "project": {
    }
}

Get asset details & validation polling

Retrieve information about a specific asset by its Uploadcare file ID.

Primary Use: Validation Polling

After uploading a file to Uploadcare, you MUST poll this endpoint to verify the file has been validated by the webhook.

Why Polling is Required

The upload process is asynchronous:

  1. You upload → File goes to Uploadcare CDN
  2. Uploadcare → Sends webhook notification to LinkScale
  3. LinkScale webhook → Validates file, extracts metadata (dimensions, duration, etc.)
  4. Database → Asset saved with all metadata
  5. You poll → Get confirmation that asset is ready

Processing includes:

  • File metadata extraction (size, MIME type, filename)
  • Image analysis (dimensions, format, color mode, DPI)
  • Video analysis (duration, bitrate, codecs)
  • Audio analysis (duration, bitrate, codec)
  • Validation checks
  • Automatic deletion of invalid files

Validation Flow

Upload to Uploadcare → Get file_id → Poll this endpoint → 200 OK → Use asset
                                        ↓
                                      404 = Still processing (wait 2s, retry)

Expected Timing

  • Normal validation: 1-3 seconds
  • Large files: Up to 5-10 seconds
  • Recommended polling: Every 2 seconds
  • Maximum attempts: 10-30 attempts (20-60 seconds total)
  • Give up after: 30 seconds (file likely failed validation)

Complete Polling Implementation

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');
};

Response Data

Once validated (200 OK), the response includes:

  • File metadata: ID, name, MIME type, size
  • CDN URL: provider_file_url for accessing the file
  • Upload info: Original upload timestamp
  • Image metadata (if image): width, height, format, color mode, DPI
  • Video metadata (if video): duration, bitrate, codecs
  • Project info: Which project owns this asset

Error Handling

404 Response: File not yet validated

  • Action: Wait 2 seconds and retry
  • Normal: This is expected during polling
  • Maximum retries: 10-30 attempts recommended

401 Response: Unauthorized

  • Cause: Invalid or missing API key
  • Action: Check your Authorization header

Other errors: Validation failed

  • Action: File may be invalid or corrupted

Complete Upload + Polling Example

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;
};
Authorizations:
BearerAuth
path Parameters
file_id
required
string
Example: 17be4678-dab7-4bc7-8753-28914a22960a

Uploadcare UUID of the file (received after uploading to Uploadcare)

Responses

Response samples

Content type
application/json
Example
{
  • "asset": {
    },
  • "project": {
    }
}

Folders

Get all folders

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:

  • Fast performance (no analytics computation)
  • Returns basic folder information with links count
  • Sorted by creation date (newest first)
  • Requires folders.read permission

Use this endpoint when you need to:

  • Display a folder selector/dropdown
  • List available folders without analytics
  • Get folder metadata quickly

Use /api/v1/folders/stats when you need:

  • Traffic analytics and statistics
  • Date-range based metrics
  • Detailed performance data
Authorizations:
BearerAuth

Responses

Response samples

Content type
application/json
Example
{
  • "project_id": "7c78db83-6bdd-4bb4-8545-c7cfdfc1e480",
  • "project": {
    },
  • "folders": [
    ]
}

Statistics

Get project statistics

Get comprehensive statistics for your entire project. Supports optional timezone and lazy-loading of traffic data via traffic_data_type.

Authorizations:
BearerAuth
query Parameters
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_referer=["https://t.co/","https://twitter.com"]

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: ?exclude_useragent=["Googlebot","TelegramBot"]

Responses

Response samples

Content type
application/json
{
  • "summary": {
    },
  • "dailyTraffic": [
    ],
  • "topReferrers": [
    ],
  • "socialTraffic": [
    ],
  • "trafficByCountries": [
    ],
  • "trafficByUrls": [
    ],
  • "trafficByLinks": [
    ],
  • "clicks": {
    }
}

Get statistics for all folders

Get statistics for all folders in your project.

Authorizations:
BearerAuth
query Parameters
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_referer=["https://t.co/","https://twitter.com"]

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: ?exclude_useragent=["Googlebot","TelegramBot"]

Responses

Response samples

Content type
application/json
{
  • "project_id": "project123",
  • "date_range": {
    },
  • "project": {
    },
  • "stats": {
    }
}

Get statistics for a specific folder

Get detailed statistics for a specific folder. Supports optional timezone and lazy-loading of traffic data via traffic_data_type.

Authorizations:
BearerAuth
path Parameters
folder_id
required
string
Example: folder1

The ID of the folder

query Parameters
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_referer=["https://t.co/","https://twitter.com"]

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: ?exclude_useragent=["Googlebot","TelegramBot"]

Responses

Response samples

Content type
application/json
{
  • "folder_id": "folder1",
  • "folder_name": "Marketing Links",
  • "date_range": {
    },
  • "analytics": {
    },
  • "trafficByUrls": [
    ],
  • "trafficByLinks": [
    ]
}

Get link statistics

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.

Authorizations:
BearerAuth
path Parameters
link_id
required
string
Example: 68b5c1a88568a81cc8355a64

The unique identifier of the link

query Parameters
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_referer=["https://t.co/","https://twitter.com"]

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: ?exclude_useragent=["Googlebot","TelegramBot"]

Responses

Response samples

Content type
application/json
{
  • "link_id": "68b5c1a88568a81cc8355a64",
  • "date_range": {
    },
  • "project": {
    },
  • "analytics": {
    }
}