API Documentation
Programmatic access to Zi.Ink URL shortener
Authentication
All API requests require authentication.
API Key (Recommended for programmatic access)
Include your API key in the Authorization header:
Authorization: Bearer zi_ink_your_api_key_hereGet your API key from the API Keys page. API access requires a paid plan.
- Pro: 1 API key
- Enterprise: 10 API keys
- Free: No API access
Base URL
https://zi.ink🌐 Using Custom Domains
To use your custom domain with the API, you need to get your domain_id first:
Method 1: Get from /api/domains
curl https://zi.ink/api/domains \ -H "Authorization: Bearer zi_ink_your_key"{ "domains": [ { "id": "72fa7279-65ca-4fa6-9407-63f1d711fb68", "domain": "yourdomain.com", "status": "active", "subscription_status": "active" } ]
}Method 2: Get from /api/links
The /api/links response includes a customDomains array with your active domains.
⚠️ Important: Slugs and Domain Identification
The same slug can exist on multiple domains (e.g., zi.ink/abc123 and yourdomain.com/abc123 are different links). When using GET, DELETE, or PATCH on a slug, use the domain_id query parameter to specify which domain's link you're targeting. If omitted, the API defaults to zi.ink domain links.
💡 Tip: Copy the id value and use it as domain_id in your API requests.
/api/shortenCreate a new shortened link.
Request Body
{ "long_url": "https://example.com/very-long-url", "custom_slug": "optional-custom", "domain_id": "optional-domain-id"
}long_url- The URL to shorten (required)custom_slug- Custom short code (optional, 3-50 chars, alphanumeric + hyphen/underscore)domain_id- Your custom domain ID (optional, requires active custom domain subscription)
Response (201)
{ "success": true, "slug": "abc1234", "short_url": "https://zi.ink/abc1234", "domain": null
}Note: When using a custom domain, short_url will use your custom domain (e.g., https://yourdomain.com/abc1234).
Example - Default Domain
curl -X POST https://zi.ink/api/shorten -H "Authorization: Bearer zi_ink_your_key" -H "Content-Type: application/json" -d '{"long_url":"https://example.com/page"}'Example - With Custom Domain
# First, get your domain_id from /api/domains
# Then use it in the request:
curl -X POST https://zi.ink/api/shorten -H "Authorization: Bearer zi_ink_your_key" -H "Content-Type: application/json" -d '{"long_url":"https://example.com/page","domain_id":"72fa7279-65ca-4fa6-9407-63f1d711fb68"}' # Response will use your custom domain:
# {"success":true,"short_url":"https://yourdomain.com/abc123","slug":"abc123","domain":"yourdomain.com"}/api/links?page=1&limit=20Get paginated links for authenticated user. Use /api/analytics/:slug for click statistics.
Query Parameters
page(optional) - Page number (default: 1)limit(optional) - Items per page (default: 20, max: 100)Response (200)
{ "links": [ { "id": 1, "slug": "abc1234", "long_url": "https://example.com", "short_url": "https://zi.ink/abc1234", "user_id": 1, "domain_id": null, "domain_name": "zi.ink", "domain_expired": false, "password_protected": false, "created_at": "2026-01-27T10:00:00.000Z", "expires_at": null } ], "total": 150, "page": 1, "limit": 20, "totalPages": 8, "customDomains": [], "subscriptionExpired": null
}Note: Click statistics are not included in this endpoint for performance. Use /api/analytics/:slug to get detailed analytics for a specific link.
Example
curl "https://zi.ink/api/links?page=1&limit=20" -H "Authorization: Bearer zi_ink_your_key"/api/links/:slug?domain_id=xxxDelete a link by slug. If you have the same slug on multiple domains, use domain_id query parameter to specify which one.
Query Parameters
domain_id(optional) - Custom domain ID. Omit for zi.ink links.Response (200)
{ "success": true, "message": "Link deleted successfully"
}Example - Delete from zi.ink
curl -X DELETE https://zi.ink/api/links/abc1234 \ -H "Authorization: Bearer zi_ink_your_key"Example - Delete from Custom Domain
curl -X DELETE "https://zi.ink/api/links/abc123?domain_id=72fa7279-65ca-4fa6-9407-63f1d711fb68" \ -H "Authorization: Bearer zi_ink_your_key"/api/links/:slug?domain_id=xxxGet details for a specific link including click count. If you have the same slug on multiple domains, use domain_id query parameter.
Query Parameters
domain_id(optional) - Custom domain ID. Omit for zi.ink links.Response (200)
{ "link": { "id": 746, "slug": "abc1234", "long_url": "https://example.com", "user_id": 1, "created_at": "2026-01-27T10:00:00.000Z", "expires_at": null, "password_protected": false, "short_url": "https://zi.ink/abc1234", "clicks": 42 }
}Example - Get zi.ink Link
curl https://zi.ink/api/links/abc1234 \ -H "Authorization: Bearer zi_ink_your_key"Example - Get Custom Domain Link
curl "https://zi.ink/api/links/abc123?domain_id=72fa7279-65ca-4fa6-9407-63f1d711fb68" \ -H "Authorization: Bearer zi_ink_your_key"/api/links/:slug?domain_id=xxxEnterprise OnlyUpdate link settings including destination URL, expiration, and password protection. Enterprise plan required. If you have the same slug on multiple domains, use domain_id query parameter.
Query Parameters
domain_id(optional) - Custom domain ID. Omit for zi.ink links.Request Body
{ "long_url": "https://new-destination.com", "expires_at": "2026-12-31T23:59:59Z", "password_enabled": true, "password": "secretpass123"
}long_url- New destination URL (optional)expires_at- Expiration date in ISO 8601 format, or null to remove (optional)password_enabled- Enable/disable password protection (optional)password- Password for protection, required when enabling (optional)
Response (200)
{ "success": true, "message": "Link updated successfully", "link": { "slug": "abc1234", "long_url": "https://new-destination.com", "expires_at": "2026-12-31T23:59:59.000Z", "password_protected": true }
}Example
curl -X PATCH https://zi.ink/api/links/abc1234 \ -H "Authorization: Bearer zi_ink_your_key" \ -H "Content-Type: application/json" \ -d '{"expires_at":"2026-12-31T23:59:59Z","password_enabled":true,"password":"secret"}'/api/bulk-shortenPro & Enterprise OnlyBulk shorten up to 100 URLs in a single request. Requires Pro or Enterprise plan.
Request Body
{ "urls": [ "https://example.com/page1", "https://example.com/page2", "https://example.com/page3" ], "domain_id": "optional-domain-id"
}urls- Array of URLs to shorten (required, max 100)domain_id- Your custom domain ID (optional, applies to all URLs)
Response (201) - Completed Immediately
For small batches (≤10 URLs), processing is synchronous and results are returned immediately:
{ "success": true, "jobId": "bulk-1770004251559-ous1bln", "status": "completed", "total": 3, "processed": 3, "successful": 3, "failed": 0, "results": [ { "original_url": "https://example.com/page1", "short_url": "https://zi.ink/abc123", "slug": "abc123", "success": true } ], "message": "Bulk processing completed in sync mode"
}Response (201) - Processing Async
For larger batches (>10 URLs), processing is asynchronous:
{ "success": true, "jobId": "bulk-1769661366024-abc123"
}Use the jobId with /api/bulk-status/:jobId to check progress.
Example - Default Domain
curl -X POST https://zi.ink/api/bulk-shorten -H "Authorization: Bearer zi_ink_your_key" -H "Content-Type: application/json" -d '{"urls":["https://example.com/1","https://example.com/2"]}'Example - With Custom Domain
# First, get your domain_id from /api/domains
# Then use it in the request to apply custom domain to all URLs:
curl -X POST https://zi.ink/api/bulk-shorten -H "Authorization: Bearer zi_ink_your_key" -H "Content-Type: application/json" -d '{"urls":["https://example.com/1","https://example.com/2"],"domain_id":"72fa7279-65ca-4fa6-9407-63f1d711fb68"}' # Response will use your custom domain for all URLs:
# {"success":true,"status":"completed","results":[{"short_url":"https://yourdomain.com/abc123",...}]}/api/bulk-status/:jobIdPro & Enterprise OnlyCheck the status of a bulk shorten job.
Response (200) - Pending
{ "jobId": "bulk-1769661366024-abc123", "status": "pending", "progress": 50, "total": 100, "processed": 50
}Response (200) - Completed
{ "jobId": "bulk-1769661366024-abc123", "status": "completed", "total": 3, "successful": 3, "failed": 0, "results": [ { "original_url": "https://example.com/page1", "success": true, "short_url": "https://zi.ink/abc123", "slug": "abc123" } ]
}Example
curl https://zi.ink/api/bulk-status/bulk-1769661366024-abc123 -H "Authorization: Bearer zi_ink_your_key"/api/links/bulk-deletePro & Enterprise OnlyBulk delete multiple links. Supports both zi.ink and custom domain links. Requires Pro or Enterprise plan.
Request Body (Option 1 - Simple)
{ "slugs": ["abc1234", "xyz5678"], "domain_id": "optional-domain-id"
}Note: If domain_id is omitted, all slugs default to zi.ink domain. If provided, all slugs will be deleted from that custom domain.
Request Body (Option 2 - Per-Link Domain)
{ "links": [ {"slug": "abc123", "domain_id": null}, {"slug": "xyz789", "domain_id": "your-domain-id"} ]
}Note: Use this format when deleting links from multiple domains in one request. Set domain_id: null for zi.ink links.
Response (200)
{ "success": true, "deleted": 2, "failed": 0, "failedSlugs": []
}Example - Delete from zi.ink
curl -X POST https://zi.ink/api/links/bulk-delete -H "Authorization: Bearer zi_ink_your_key" -H "Content-Type: application/json" -d '{"slugs":["abc1234","xyz5678"]}'Example - Delete from Custom Domain
# Delete specific slugs from custom domain
curl -X POST https://zi.ink/api/links/bulk-delete -H "Authorization: Bearer zi_ink_your_key" -H "Content-Type: application/json" -d '{"slugs":["abc123","xyz789"],"domain_id":"72fa7279-65ca-4fa6-9407-63f1d711fb68"}'Example - Delete from Mixed Domains
# Delete links from both zi.ink and custom domains
curl -X POST https://zi.ink/api/links/bulk-delete -H "Authorization: Bearer zi_ink_your_key" -H "Content-Type: application/json" -d '{ "links": [ {"slug": "abc123", "domain_id": null}, {"slug": "custom1", "domain_id": "72fa7279-65ca-4fa6-9407-63f1d711fb68"} ]
}'/api/userGet current authenticated user information.
Response (200)
{ "user": { "email": "user@example.com", "name": "John Doe", "picture": "https://example.com/avatar.jpg", "plan_tier": "enterprise", "created_at": "2026-01-01T00:00:00.000Z" }
}Example
curl https://zi.ink/api/user -H "Authorization: Bearer zi_ink_your_key"/api/analytics/:slugGet analytics data for a specific link.
Query Parameters
days- Number of days to fetch (default: 7, max: 365)
Response (200)
{ "slug": "abc1234", "long_url": "https://example.com", "created_at": "2026-01-27T10:00:00.000Z", "total_clicks": 533, "by_country": [...], "by_referrer": [...], "by_browser": [...], "by_device": [...]
}Example
curl https://zi.ink/api/analytics/abc1234?days=30 -H "Authorization: Bearer zi_ink_your_key"Rate Limits
Plan-Based Limits (per hour, shared)
- • Free: 100 links/hour
- • Pro: 2,000 links/hour (20x free)
- • Enterprise: 20,000 links/hour (200x free)
📝 Note: Rate limits are shared between /api/shorten and /api/bulk-shorten endpoints. For example, if you create 50 links via single API and 50 via bulk, you've used 100 of your hourly limit.
Additional Limits
- • Global IP Limit: 10,000 requests per hour (all requests including browsing)
- • /api/shorten (Guest): 10 requests per minute (unauthenticated users)
- • Redirects: 100 requests per minute per IP
💡 Tip: Upgrade to Pro or Enterprise for higher rate limits and bulk processing capabilities.
Rate limit info is included in response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Plan
Error Codes
400Bad Request - Invalid parameters401Unauthorized - Invalid or missing API key404Not Found - Resource doesn't exist409Conflict - Slug already exists429Too Many Requests - Rate limit exceeded500Internal Server Error