REST API Documentation
Complete REST API reference for UseClick.io integration
Quick Start
1. Generate API Key
Sign in and visit API Keys Settings to create your first API key.
2. Authentication
All API requests require authentication using an API key in the Authorization header:
Authorization: Bearer uc_live_YOUR_API_KEY_HERE3. Base URL
https://useclick.io/api/v1Rate Limits
API rate limits vary by subscription plan:
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 with a Retry-After header indicating when you can retry.
Code Examples
Here are complete examples in popular programming languages to help you get started:
JavaScript
// 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));Python
import requests
API_KEY = 'uc_live_YOUR_API_KEY'
BASE_URL = 'https://useclick.io/api/v1'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
# Create a new link
def create_link(target_url, custom_slug=None):
payload = {'target_url': target_url}
if custom_slug:
payload['slug'] = custom_slug
response = requests.post(
f'{BASE_URL}/links',
headers=headers,
json=payload
)
return response.json()
# List all links
def list_links():
response = requests.get(
f'{BASE_URL}/links',
headers=headers
)
return response.json()
# Usage
link = create_link('https://example.com', 'my-link')
print('Created:', link)PHP
<?php
$apiKey = 'uc_live_YOUR_API_KEY';
$baseUrl = 'https://useclick.io/api/v1';
function createLink($targetUrl, $customSlug = null) {
global $apiKey, $baseUrl;
$data = ['target_url' => $targetUrl];
if ($customSlug) {
$data['slug'] = $customSlug;
}
$ch = curl_init("$baseUrl/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 $apiKey",
'Content-Type: application/json'
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// Usage
$link = createLink('https://example.com', 'my-link');
print_r($link);
?>Ruby
require 'net/http'
require 'json'
API_KEY = 'uc_live_YOUR_API_KEY'
BASE_URL = 'https://useclick.io/api/v1'
def create_link(target_url, custom_slug = nil)
uri = URI("#{BASE_URL}/links")
payload = { target_url: target_url }
payload[:slug] = custom_slug if custom_slug
request = Net::HTTP::Post.new(uri)
request['Authorization'] = "Bearer #{API_KEY}"
request['Content-Type'] = 'application/json'
request.body = payload.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)
end
# Usage
link = create_link('https://example.com', 'my-link')
puts "Created: #{link}"Pagination & Filtering
Pagination Parameters
When listing links or clicks, use these query parameters to paginate results:
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 | Page number (starts at 1) |
| limit | integer | 50 | Results per page (max 100) |
GET /api/v1/links?page=2&limit=25Filtering Links
Filter your links list with these query parameters:
| Parameter | Type | Description |
|---|---|---|
| search | string | Search by slug or target URL |
| campaign | string | Filter by campaign name |
| folder | string | Filter by folder name |
| sort | string | Sort order: created_asc, created_desc, clicks_asc, clicks_desc |
GET /api/v1/links?campaign=summer-sale&sort=clicks_descResponse Metadata
Paginated responses include metadata to help you navigate results:
{
"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 from the API Keys Settings page
2. Handle Rate Limits Gracefully
- Implement exponential backoff when receiving 429 errors
- Check the
Retry-Afterheader for recommended wait time - Cache responses when possible to reduce API calls
- Consider upgrading your plan if you consistently hit rate limits
// 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 retryAfter = response.headers.get('Retry-After') || 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=50and adjust based on your needs - Check
has_nextin 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
// 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 in your API Keys Settings.
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 Retry-After 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
{
"target_url": "https://example.com/secret-content",
"slug": "protected-link",
"password": "mySecurePassword123"
}cURL Example
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
{
"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 timezone2025-12-31T23:59:59-05:00- EST timezone2025-12-31T23:59:59+00:00- UTC timezone (explicit)
Python Example
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
{
"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
// 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
{
"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
$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
{
"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:
- Click Limit: Checked first - if reached, user sees limit page (no further checks)
- Expiration: Checked second - if expired, user sees expiration page
- Mature Warning: Shown third - user must confirm before proceeding
- 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
/api/v1/linksCreate a new short link. Optional: slug (auto-generated if not provided), branded_domain (your custom domain like 'go.yourdomain.com'), group_id (campaign UUID)
Request Body
{
"target_url": "https://example.com",
"slug": "optional-custom-slug",
"branded_domain": "go.yourdomain.com",
"group_id": "optional-campaign-uuid"
}Example Request
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",
"slug": "my-link",
"branded_domain": "go.yourdomain.com"
}'/api/v1/linksList all your links
Example Request
curl -X GET https://useclick.io/api/v1/links \
-H "Authorization: Bearer YOUR_API_KEY"/api/v1/links/:slugGet details of a specific link by slug
Example Request
curl -X GET https://useclick.io/api/v1/links/my-slug \
-H "Authorization: Bearer YOUR_API_KEY"/api/v1/links/:slugUpdate an existing link. All fields optional. Use branded_domain (your custom domain) or group_id (campaign UUID)
Request Body
{
"target_url": "https://new-url.com",
"branded_domain": "go.yourdomain.com",
"group_id": "optional-campaign-uuid"
}Example Request
curl -X PUT https://useclick.io/api/v1/links/my-slug \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"target_url": "https://new-url.com",
"branded_domain": "go.yourdomain.com"
}'/api/v1/links/:slugDelete a link (this also deletes all associated clicks)
Example Request
curl -X DELETE https://useclick.io/api/v1/links/my-slug \
-H "Authorization: Bearer YOUR_API_KEY"/api/v1/clicksGet click analytics for your links. Optional: add ?link_slug=your-slug to filter by specific link
Query Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| link_slug | string | - | Filter by specific link slug (optional) |
Example Request
curl -X GET "https://useclick.io/api/v1/clicks?link_slug=my-slug" \
-H "Authorization: Bearer YOUR_API_KEY"/api/v1/auth/verifyVerify your API key is valid and get authentication status
Example Request
curl -X GET https://useclick.io/api/v1/auth/verify \
-H "Authorization: Bearer YOUR_API_KEY"/api/v1/links/:slug/geo-targetsGet all geo-targeting rules for a specific link
Example Request
curl -X GET https://useclick.io/api/v1/links/my-slug/geo-targets \
-H "Authorization: Bearer YOUR_API_KEY"/api/v1/links/:slug/geo-targetsCreate a new geo-targeting rule for a link (redirect visitors from specific countries to different URLs)
Request Body
{
"country_code": "US",
"target_url": "https://us-specific-url.com"
}Example Request
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"
}'/api/v1/links/:slug/geo-targetsDelete a geo-targeting rule for a specific country
Query Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| country_code | string | - | 2-letter ISO country code (e.g., US, GB, DE) |
Example Request
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
{
"data": { ... }
}Error Response
{
"error": {
"code": "ERROR_CODE",
"message": "Human readable error message"
}
}Common Error Codes
UNAUTHORIZED- Invalid or missing API keyRATE_LIMIT_EXCEEDED- Too many requestsNOT_FOUND- Resource not foundVALIDATION_ERROR- Invalid request dataINTERNAL_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.