Workspace & developers / REST API

REST API Documentation

Complete REST API reference for UseClick.io integration

/api/v1Bearer API key

Quick Start

  1. 1. Generate API Key

    Sign in and visit Account, MCP & API Keys, Keys to create your first API key.

  2. 2. Authentication

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

    header
    Authorization: Bearer uc_live_YOUR_API_KEY_HERE
  3. 3. Base URL

    base url
    https://useclick.io/api/v1

Endpoints at a glance

Rate Limits

API rate limits vary by subscription plan:

  • Free100requests/minute
  • Starter300requests/minute
  • Growth600requests/minute
  • Pro1,200requests/minute
  • Business3,000requests/minute
How Rate Limiting Works: Rate limits are enforced per API key on a rolling 60-second window. If you exceed your limit, you'll receive a 429 Too Many Requests error. Every response also carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (a Unix timestamp in seconds), so you can pace requests before you hit the limit.

Code Examples

Here are complete examples in popular programming languages to help you get started:

// Using fetch API
const apiKey = 'uc_live_YOUR_API_KEY';

async function createLink(targetUrl, customSlug) {
  const response = await fetch('https://useclick.io/api/v1/links', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      target_url: targetUrl,
      slug: customSlug
    })
  });

  const data = await response.json();
  return data;
}

// Usage
createLink('https://example.com', 'my-link')
  .then(link => console.log('Created:', link))
  .catch(err => console.error('Error:', err));

Connect Your Tools

You do not need to write code to use the API. These automation platforms can call any UseClick endpoint with their built-in HTTP blocks, and the platform plugins below handle it for you.

No-code automation

Connect UseClick to thousands of apps without writing code.

Zapier

Native app coming, HTTP works today

Zapier: Webhooks by Zapier, Custom Request

A native UseClick Zapier app is on the way. Until it ships you can already do everything through the Webhooks by Zapier action, which can call any REST endpoint.

The Webhooks by Zapier action requires a paid Zapier plan. Everything on the UseClick side works on any plan, including Free.
  1. In your Zap, add an action step and choose "Webhooks by Zapier", then the event "Custom Request".
  2. Set Method to POST and URL to https://useclick.io/api/v1/links
  3. Set Data Pass-Through to "no" and paste the JSON below into the Data field, mapping your own trigger fields into it.
  4. Under Headers add Authorization with the value "Bearer uc_live_YOUR_API_KEY", and Content-Type with the value application/json
  5. Test the step. The new short link comes back as data__short_url, which you can map into later steps.
  6. To verify your key on its own, send a GET request to https://useclick.io/api/v1/auth/verify instead. It returns your plan and rate limit.
Zapier: Webhooks by Zapier, Custom Request
{
  "target_url": "https://example.com/summer-sale",
  "slug": "summer-sale",
  "title": "Summer Sale 2026"
}

Make.com

Native app coming, HTTP works today

Make: HTTP, Make a request

Native UseClick modules are planned. Today the built-in HTTP module covers every endpoint, and Make will parse the JSON response so you can map fields downstream.

  1. Add the "HTTP" module and choose "Make a request".
  2. Set URL to https://useclick.io/api/v1/links and Method to POST
  3. Add a header: Name "Authorization", Value "Bearer uc_live_YOUR_API_KEY"
  4. Set Body type to "Raw" and Content type to "JSON (application/json)", then paste the body below.
  5. Switch on "Parse response" so the short link is available as data.short_url in later modules.
Make: HTTP, Make a request
{
  "target_url": "https://example.com/summer-sale",
  "slug": "summer-sale",
  "title": "Summer Sale 2026"
}

n8n

Works today

n8n: HTTP Request node

n8n talks to the REST API through its standard HTTP Request node. Store the key once as a Header Auth credential and every UseClick node in the workflow can reuse it.

  1. Add an HTTP Request node to your workflow.
  2. Set Method to POST and URL to https://useclick.io/api/v1/links
  3. Set Authentication to "Generic Credential Type", then "Header Auth".
  4. Create the credential with Name "Authorization" and Value "Bearer uc_live_YOUR_API_KEY"
  5. Set Send Body on, Body Content Type to JSON, and use the body below.
  6. The short link is available downstream as {{ $json.data.short_url }}
  7. Building an AI workflow instead? Use the MCP Client Tool node with the UseClick MCP server and your agent gets all nine tools automatically.
n8n: HTTP Request node
{
  "target_url": "https://example.com/summer-sale",
  "slug": "summer-sale",
  "title": "Summer Sale 2026"
}

Your own code

Call the API directly from any language that can send an HTTP request.

cURL

Works today

Terminal

The quickest way to confirm a new key works. Every endpoint follows this same shape.

Terminal
curl -X POST https://useclick.io/api/v1/links \
  -H "Authorization: Bearer uc_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target_url": "https://example.com/summer-sale",
    "slug": "summer-sale"
  }'

JavaScript

Works today

JavaScript

Works in Node 18+ and in the browser. Never ship your key in client-side code: call the API from your own server.

JavaScript
const res = await fetch("https://useclick.io/api/v1/links", {
  method: "POST",
  headers: {
    Authorization: "Bearer uc_live_YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    target_url: "https://example.com/summer-sale",
    slug: "summer-sale"
  })
})

const { data, error } = await res.json()
if (!res.ok) throw new Error(error.message)
console.log(data.short_url)

Python

Works today

Python

Read the key from an environment variable rather than hard-coding it.

Python
import os, requests

res = requests.post(
    "https://useclick.io/api/v1/links",
    headers={
        "Authorization": f"Bearer {os.environ['USECLICK_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "target_url": "https://example.com/summer-sale",
        "slug": "summer-sale",
    },
)

body = res.json()
if not res.ok:
    raise RuntimeError(body["error"]["message"])
print(body["data"]["short_url"])

PHP

Works today

PHP

The same request using PHP's cURL extension.

PHP
<?php
$ch = curl_init("https://useclick.io/api/v1/links");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        "Authorization: Bearer " . getenv("USECLICK_API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "target_url" => "https://example.com/summer-sale",
        "slug"       => "summer-sale",
    ]),
]);

$body = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $body["data"]["short_url"];

Platforms & CMS

Purpose-built plugins for the platforms you already publish on.

WordPress

Native integration

The UseClick WordPress plugin creates and manages short links from your WP admin, including the UTM builder and campaigns. It authenticates with the same API key.

  1. Install the UseClick plugin in your WordPress admin.
  2. Open the UseClick settings screen.
  3. Paste an API key from this page and save. The plugin verifies it against the API and shows your plan.

Shopify

Native integration

Connect your Shopify store to create short links and track clicks for products and campaigns.

  1. Open the UseClick Shopify setup page.
  2. Paste an API key from this page (it starts with uc_live_) and connect.
  3. Short links and click tracking are then available for your products and campaigns.

Building an AI agent instead of a workflow? The MCP server exposes the same account to Claude, Cursor, Codex and other agents with no glue code.

Pagination & Filtering

Pagination Parameters

When listing links or clicks, use these query parameters to paginate results:

ParameterTypeDefaultDescription
pageinteger1Page number (starts at 1)
limitinteger50Results per page (max 100)
request
GET /api/v1/links?page=2&limit=25

Filtering Links

Filter your links list with these query parameters:

ParameterTypeDescription
searchstringSearch by slug or target URL
campaignstringFilter by campaign name
folderstringFilter by folder name
sortstringSort order: created_asc, created_desc, clicks_asc, clicks_desc
request
GET /api/v1/links?campaign=summer-sale&sort=clicks_desc

Response Metadata

Paginated responses include metadata to help you navigate results:

response.json
{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 50,
    "total": 237,
    "pages": 5,
    "has_next": true,
    "has_prev": false
  }
}

Best Practices

1. Secure Your API Keys

  • Never expose API keys in client-side code (JavaScript running in browsers)
  • Store keys in environment variables, not in your codebase
  • Use separate keys for development and production environments
  • Rotate keys periodically and immediately if compromised
  • Revoke unused keys on the Keys tab

2. Handle Rate Limits Gracefully

  • Implement exponential backoff when receiving 429 errors
  • Check the X-RateLimit-Reset header for when the window resets
  • Cache responses when possible to reduce API calls
  • Consider upgrading your plan if you consistently hit rate limits
javascript
// Example: Exponential backoff
async function makeRequestWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const reset = Number(response.headers.get('X-RateLimit-Reset'));
      const retryAfter = reset ? Math.max(1, reset - Math.ceil(Date.now() / 1000)) : Math.pow(2, i);
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      continue;
    }

    return response;
  }
  throw new Error('Max retries exceeded');
}

3. Validate Input Data

  • Ensure target URLs are valid and include the protocol (https:// or http://)
  • Slugs must be lowercase, alphanumeric, and use hyphens only (no spaces or special characters)
  • Check that campaign and folder names exist before referencing them
  • Validate country codes against ISO 3166-1 alpha-2 standard (US, GB, DE, etc.)

4. Use Pagination for Large Datasets

  • Don't fetch all links at once. Use pagination to retrieve data in chunks
  • Start with limit=50 and adjust based on your needs
  • Check has_next in the response to know if more pages exist
  • Implement cursor-based pagination for real-time data if available

5. Handle Errors Properly

  • Always check response status codes and handle errors appropriately
  • Parse error messages from the response body for user-friendly feedback
  • Log API errors for debugging and monitoring
  • Implement fallback behavior for non-critical API failures
javascript
// Example: Error handling
try {
  const response = await fetch(url, options);
  const data = await response.json();

  if (!response.ok) {
    throw new Error(`API Error: ${data.error.message}`);
  }

  return data;
} catch (error) {
  console.error('Failed to create link:', error);
  // Handle error appropriately
}

6. Monitor API Usage

  • Track your API request volume to stay within rate limits
  • Monitor error rates to detect integration issues early
  • Set up alerts for unusual API activity or failures
  • Review API logs regularly for optimization opportunities

Troubleshooting

401 Unauthorized Error

Symptom: All requests return "Unauthorized" error.

Causes:

  • Missing or invalid API key
  • API key not included in the Authorization header
  • Incorrect header format (should be Bearer uc_live_...)
  • API key has been revoked or expired

Solution: Verify your API key is correct, check the Authorization header format, and ensure the key hasn't been revoked on the Keys tab.

429 Rate Limit Exceeded

Symptom: Requests fail with "Too Many Requests" error.

Causes:

  • Exceeded your plan's request limit (100-3,000 req/min depending on plan)
  • Too many requests in a short time window
  • Multiple API clients using the same key

Solution: Implement exponential backoff, check the X-RateLimit-Reset header, reduce request frequency, or upgrade your plan for higher limits.

400 Validation Error - Duplicate Slug

Symptom: Creating a link fails with "Slug already exists" error.

Causes:

  • The custom slug you specified is already used by another link in your account
  • Slugs must be unique across your entire account

Solution: Choose a different slug or omit the slug field to auto-generate a unique random slug.

404 Not Found Error

Symptom: Request returns "Resource not found" error.

Causes:

  • The link slug you're requesting doesn't exist
  • The link belongs to a different user or organization
  • The link was deleted
  • Typo in the slug or endpoint URL

Solution: Verify the slug is correct, check that you own the link, and ensure the link hasn't been deleted.

403 Forbidden - Feature Not Available

Symptom: Request fails with "Feature not available on your plan" error.

Causes:

  • Trying to use a feature that requires a higher plan (e.g., geo-targeting on Free plan)
  • Link quota exceeded for your plan
  • Campaign or folder limits reached

Solution: Upgrade your plan to access the feature, or remove unused links/campaigns to free up quota.

CORS Errors (Browser Requests)

Symptom: API requests from browser JavaScript fail with CORS errors.

Causes:

  • API keys should never be used in client-side JavaScript
  • The UseClick API does not support CORS for security reasons

Solution: Make API requests from your backend server, not directly from the browser. Use a server-side proxy or serverless function to call the API.

500 Internal Server Error

Symptom: Request fails with "Internal Server Error."

Causes:

  • Temporary server issue
  • Unexpected error in the API

Solution: Retry the request after a short delay. If the problem persists, contact support at [email protected] with the request details.

Frequently Asked Questions

Is the API available on all plans?

Yes! All plans from Free to Business have API access. Rate limits vary by plan: Free (100 req/min), Starter (300 req/min), Growth (600 req/min), Pro (1,200 req/min), Business (3,000 req/min).

Can I create multiple API keys?

Yes, you can create multiple API keys for different applications or environments (development, staging, production). This allows you to revoke keys independently if one is compromised.

Do API-created links count towards my plan limit?

Yes. All links created via the API count towards your plan's total link limit (Free: 10, Starter: 300, Growth: 1,000, Pro: 5,000, Business: 25,000). You'll receive a 403 error if you attempt to exceed your limit.

Can I use the API to update link analytics?

No. Click analytics are automatically collected when users click your links. The API provides read-only access to analytics data via GET /api/v1/clicks.

Is there a webhook system for real-time events?

Not yet. Webhooks for click events, link creation, and other real-time notifications are planned for a future release. Currently, you need to poll the API to check for new clicks.

How do I test the API without affecting my production data?

Create a separate API key for testing and use it with test links. You can also use a different campaign or folder to organize test links separately from production links. There's no sandbox environment currently.

Can I bulk create links via the API?

Yes, but you need to make multiple POST /api/v1/links requests (one per link). Be mindful of rate limits. Use a delay between requests or implement batch processing with retries. For large bulk uploads (100+ links), consider using the CSV bulk upload feature in the dashboard instead.

What happens if I delete a link via the API?

Deleting a link via DELETE /api/v1/links/:slug permanently removes the link and all its associated click analytics data. This action cannot be undone, so use with caution.

Are there official API client libraries or SDKs?

Not officially at this time. However, the API follows REST conventions and works with any HTTP client library (fetch, axios, requests, curl, etc.). Community-contributed SDKs may be available. Check our GitHub or documentation updates.

Can I use the API to manage team members or billing?

No. The current API focuses on link management and analytics. Team member management, billing, and account settings are only available through the web dashboard.

What's the API version policy?

The current API is version 1 (/api/v1). We'll maintain backward compatibility and provide advance notice before deprecating endpoints. New features may be added without version changes if they don't break existing integrations.

How do I report API bugs or request features?

Email us at [email protected] with details about the bug or feature request. Include your API request/response examples, error messages, and expected behavior.

Advanced Link Features

UseClick supports several advanced features for your short links. Here's how to use them via the API:

Password Protection

Require users to enter a password before accessing the destination URL. Available on Starter+ plans.

Request Body

request.json
{
  "target_url": "https://example.com/secret-content",
  "slug": "protected-link",
  "password": "mySecurePassword123"
}

cURL Example

bash
curl -X POST https://useclick.io/api/v1/links \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "target_url": "https://example.com/secret-content",
    "slug": "protected-link",
    "password": "mySecurePassword123"
  }'
Note: Passwords are stored securely using bcrypt hashing. Users will see a password prompt page before being redirected to the target URL. To remove password protection, update the link with password: null.

Link Expiration

Set an expiration date/time after which the link stops working. Available on Starter+ plans.

Request Body

request.json
{
  "target_url": "https://example.com/limited-offer",
  "slug": "flash-sale",
  "expires_at": "2025-12-31T23:59:59Z"
}

Date Format

Use ISO 8601 format with timezone:

  • 2025-12-31T23:59:59Z - UTC timezone
  • 2025-12-31T23:59:59-05:00 - EST timezone
  • 2025-12-31T23:59:59+00:00 - UTC timezone (explicit)

Python Example

python
from datetime import datetime, timedelta
import requests

# Set expiration to 7 days from now
expires_at = (datetime.utcnow() + timedelta(days=7)).isoformat() + 'Z'

payload = {
    'target_url': 'https://example.com/limited-offer',
    'slug': 'flash-sale',
    'expires_at': expires_at
}

response = requests.post(
    'https://useclick.io/api/v1/links',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json=payload
)
Behavior: After expiration, users will see a "Link Expired" page. To remove expiration, update the link with expires_at: null. The link will automatically stop working at the specified date/time.

Click Limit

Limit the total number of clicks a link can receive. Available on Starter+ plans.

Request Body

request.json
{
  "target_url": "https://example.com/exclusive-content",
  "slug": "limited-access",
  "click_limit": 100
}

Use Cases

  • Limited Beta Access: Share a product beta with the first 50 people who click
  • Scarcity Marketing: Create urgency by limiting access to 100 customers
  • Budget Control: Cap affiliate link clicks to control commission costs
  • Event Registration: Limit registrations to venue capacity

JavaScript Example

javascript
// Create a link limited to 500 clicks
const response = await fetch('https://useclick.io/api/v1/links', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    target_url: 'https://example.com/exclusive-content',
    slug: 'limited-access',
    click_limit: 500
  })
});

const link = await response.json();
console.log(`Link will expire after ${link.data.click_limit} clicks`);
Behavior: Once the click limit is reached, users will see a "Link Limit Reached" page. The link stops working permanently. To remove the limit, update with click_limit: null. Track remaining clicks via the GET /api/v1/links/:slug endpoint.

Mature Content Warning

Display an age verification warning before users access the destination. Useful for adult content, gambling, or age-restricted products. Available on Starter+ plans.

Request Body

request.json
{
  "target_url": "https://example.com/adult-content",
  "slug": "age-restricted",
  "mature_warning": true
}

Warning Page Behavior

When enabled, users will see an interstitial page with:

  • Clear warning about mature/age-restricted content
  • "I am 18 or older" confirmation button
  • "Go Back" option
  • UseClick branding and disclaimer

PHP Example

php
<?php
$data = [
    'target_url' => 'https://example.com/adult-content',
    'slug' => 'age-restricted',
    'mature_warning' => true
];

$ch = curl_init('https://useclick.io/api/v1/links');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer YOUR_API_KEY',
    'Content-Type: application/json'
]);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
echo "Created link with mature content warning: " . $result['data']['slug'];
?>
Legal Note: The warning page is for informational purposes only. It does not verify age and should not be relied upon for legal compliance. Always ensure your content complies with local laws and platform policies. To disable the warning, update with mature_warning: false.

Combining Multiple Features

You can use multiple advanced features together on the same link:

Example: Limited-Time Password-Protected Link

request.json
{
  "target_url": "https://example.com/vip-content",
  "slug": "vip-access",
  "password": "VIP2025",
  "expires_at": "2025-12-31T23:59:59Z",
  "click_limit": 100,
  "mature_warning": false
}

Feature Priority Order

When multiple features are enabled, they execute in this order:

  1. Click Limit: Checked first - if reached, user sees limit page (no further checks)
  2. Expiration: Checked second - if expired, user sees expiration page
  3. Mature Warning: Shown third - user must confirm before proceeding
  4. Password: Checked last - user must enter password to access URL
Pro Tip: Combining expiration + click limit creates powerful scarcity campaigns. For example, "First 100 people OR before Dec 31, whichever comes first" motivates immediate action.

API Endpoints

GET/api/v1/clicks

Get click analytics for your links. Optional: add ?link_slug=your-slug to filter by specific link

Query Parameters

NameTypeDefaultDescription
link_slugstring-Filter by specific link slug (optional)

Example Request

bash
curl -X GET "https://useclick.io/api/v1/clicks?link_slug=my-slug" \
  -H "Authorization: Bearer YOUR_API_KEY"

GET/api/v1/auth/verify

Verify your API key is valid and get authentication status

Example Request

bash
curl -X GET https://useclick.io/api/v1/auth/verify \
  -H "Authorization: Bearer YOUR_API_KEY"

GET/api/v1/links/:slug/geo-targets

Get all geo-targeting rules for a specific link

Example Request

bash
curl -X GET https://useclick.io/api/v1/links/my-slug/geo-targets \
  -H "Authorization: Bearer YOUR_API_KEY"

POST/api/v1/links/:slug/geo-targets

Create a new geo-targeting rule for a link (redirect visitors from specific countries to different URLs)

Request Body

request.json
{
  "country_code": "US",
  "target_url": "https://us-specific-url.com"
}

Example Request

bash
curl -X POST https://useclick.io/api/v1/links/my-slug/geo-targets \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "country_code": "US",
    "target_url": "https://us-specific-url.com"
  }'

DELETE/api/v1/links/:slug/geo-targets

Delete a geo-targeting rule for a specific country

Query Parameters

NameTypeDefaultDescription
country_codestring-2-letter ISO country code (e.g., US, GB, DE)

Example Request

bash
curl -X DELETE "https://useclick.io/api/v1/links/my-slug/geo-targets?country_code=US" \
  -H "Authorization: Bearer YOUR_API_KEY"

Response Format

Success Response

200 OK
{
  "data": { ... }
}

Error Response

4xx / 5xx
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human readable error message"
  }
}

Common Error Codes

  • UNAUTHORIZED- Invalid or missing API key
  • RATE_LIMIT_EXCEEDED- Too many requests
  • NOT_FOUND- Resource not found
  • VALIDATION_ERROR- Invalid request data
  • INTERNAL_ERROR- Server error

Need Help?

If you have questions or need assistance with the API, please contact our support team at [email protected]

Note: Response times vary by plan. See our pricing page for details.