Developers
REST API v1
Create and manage short links from your own code. Every endpoint speaks JSON and returns the same link shape you see in the dashboard.
Base URL
https://urlbot.cc/api/v1
API access requires a Business plan or higher
Keys on a lower plan receive 403 upgrade_required. Read /api/v1/plans for the live capability list.
Authentication
Create a key in API keys. The full key is shown only once. Send it with either header:
Authorization: Bearer <your-api-key> X-API-Key: <your-api-key>
A missing key returns 401 missing_api_key; an unknown or revoked key returns 401 invalid_api_key. Session cookies and CSRF tokens are never required.
Rate limits
Each key gets its own budget, 120 requests per 60 seconds by default. Every response reports the current state via X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Exceeding it returns 429 rate_limited with Retry-After.
Endpoints
| Method & path | Purpose |
|---|---|
| GET /me | Account, plan and quota usage |
| GET /plans | Capability list for every plan |
| GET /links | List links (cursor or offset paging) |
| POST /links | Create one link |
| POST /links/bulk | Create many links in one call |
| GET /links/:code | Fetch one link |
| PATCH /links/:code | Update destination, status or tags |
| DELETE /links/:code | Delete a link |
| GET /links/:code/stats | Click stats within your retention window |
Create a link
curl -X POST https://urlbot.cc/api/v1/links \
-H "Authorization: Bearer $URLBOT_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/spring-campaign",
"alias": "spring26",
"tags": "campaign, email",
"expires_at": "2026-12-31T23:59:00Z"
}'
All fields except url are optional. Omitting alias generates a short code. Tags are lower-cased, de-duplicated and hyphenated: "Spring Sale, spring sale" becomes spring-sale, up to 8 per link.
Link shape
{
"data": {
"id": 412,
"short_code": "spring26",
"short_url": "https://urlbot.cc/spring26",
"original_url": "https://example.com/spring-campaign",
"is_active": true,
"available": true,
"has_password": false,
"click_count": 0,
"expires_at": "2026-12-31T23:59:00Z",
"tags": ["campaign", "email"],
"created_at": "2026-08-01T09:12:44Z"
}
}
Update tags
Send tags to replace the whole list. Send an empty string to clear it. Omit the field entirely and existing tags are left untouched.
curl -X PATCH https://urlbot.cc/api/v1/links/spring26 \
-H "Authorization: Bearer $URLBOT_KEY" \
-H "Content-Type: application/json" \
-d '{"tags": "campaign, q3", "is_active": false}'
List and filter
curl https://urlbot.cc/api/v1/links?limit=50 \ -H "Authorization: Bearer $URLBOT_KEY"
Responses include a next_cursor when more rows exist. Pass it back as ?cursor= to page forward; cursor paging stays stable when links share a timestamp.
Errors
Errors return a JSON body with a stable error code, and often a human hint or message. Match on the code, not the prose.
| Status | Code |
|---|---|
| 400 | invalid_body, invalid_url, invalid_alias, invalid_expires_at |
| 401 | missing_api_key, invalid_api_key |
| 403 | upgrade_required |
| 404 | link_not_found |
| 409 | alias_taken |
| 429 | rate_limited |