Skip to main content

URL Lifecycle

Short URLs in the system go through the following states:
1

Created

URL is created via /create endpoint and becomes immediately active for redirection.
2

Active (url_state: true)

URL is live and redirecting traffic. Hit counter increments with each access.
3

Paused (url_state: false)

URL redirection is temporarily disabled. Returns 423 (Locked) status when accessed.
4

Deleted

URL and all associated statistics are permanently removed from the database.
Only password-protected URLs can be paused, resumed, or deleted. URLs without passwords are permanent.

Creating URLs

Basic URL Creation

POST /create
Content-Type: application/json

{
  "url_code": "mylink",
  "url": "https://example.com",
  "url_pass": ""
}

With Password Protection

POST /create
Content-Type: application/json

{
  "url_code": "mylink",
  "url": "https://example.com",
  "url_pass": "securepass123"
}

Response

{
  "message": "URL created",
  "short_url": "https://short.url/mylink"
}

URL Code Validation

URL codes must meet specific validation criteria enforced by the validCode function:
helper.py:2-7
def validCode(url_code: str) -> bool:
    key_words=['docs','redoc','create','login','delete','pause','resume','details','refresh_token','change_password','reset_hits','change_url','validate_token','health']
    if url_code.lower() in key_words:
        return False
    pattern = r'^[A-Za-z0-9_-]{3,20}$'
    return bool(re.match(pattern, url_code))

Validation Rules

  • Minimum: 3 characters
  • Maximum: 20 characters
helper.py:6
pattern = r'^[A-Za-z0-9_-]{3,20}$'
URL codes can only contain:
  • Uppercase letters (A-Z)
  • Lowercase letters (a-z)
  • Numbers (0-9)
  • Hyphens (-)
  • Underscores (_)
Valid Examples: my-link, URL_123, short2024Invalid Examples: my link (space), url@code (special char), my.url (period)
The following keywords are reserved and cannot be used as URL codes:
  • docs
  • redoc
  • create
  • login
  • delete
  • pause
  • resume
  • details
  • refresh_token
  • change_password
  • reset_hits
  • change_url
  • validate_token
  • health
Reserved keywords are checked case-insensitively. Both LOGIN and login are rejected.

Validation Error

{
  "detail": "Invalid URL code"
}

Password Protection

Passwords are optional but enable full management capabilities when provided.

Password Validation

Passwords must meet the following criteria:
helper.py:19-21
def validPass(url_pass:str):
    len_url_pass=len(url_pass)
    return len_url_pass==0 or (len_url_pass<=20 and len_url_pass>=3)
Requirements:
  • Minimum: 3 characters
  • Maximum: 20 characters
Enables:
  • Full management control
  • Pause/resume functionality
  • URL deletion
  • Destination URL changes
  • Statistics access

Password Hashing

Passwords are hashed using PBKDF2-SHA256 before storage:
main.py:85
entry.url_pass=hash_password(entry.url_pass)
Passwords are never stored in plain text. The system cannot recover forgotten passwords - only reset them.

Password Validation Error

{
  "detail": "Password length must be 3..20"
}

URL State Management

Password-protected URLs can be paused and resumed without deletion.

Pausing a URL

Temporarily disable redirection while keeping the URL reserved:
PATCH /pause
Authorization: Bearer <your_access_token>
Implementation:
main.py:139-147
@app.patch("/pause")
async def pause(credentials:HTTPAuthorizationCredentials=Depends(security)):
    url_code=await authenticate(credentials)
    entry = await app.URLStats.find_one({"url_code": url_code})
    if entry:
        await app.URLStats.update_one({"url_code": url_code},{"$set": {"url_state": False}})
        return {"message": f"{url_code} successfully paused"}
    else:
        raise HTTPException(status_code=404, detail="URL not found")
Response:
{
  "message": "mylink successfully paused"
}
When paused, accessing the short URL returns a 423 (Locked) error: “Redirect temporarily paused”

Resuming a URL

Re-enable redirection for a paused URL:
PATCH /resume
Authorization: Bearer <your_access_token>
Response:
{
  "message": "mylink successfully resumed"
}

Paused URL Behavior

When a URL is paused, the redirect endpoint checks the state:
main.py:233-239
if len(entry["url_pass"])>0:
    stats = await app.URLStats.find_one({"url_code": url_code})
    if not stats["url_state"]:
        raise HTTPException(status_code=423, detail="Redirect temporarily paused")
    else:
       background_tasks.add_task(update_hits_sync, url_code)
Use pause/resume for temporary URL control without losing statistics or the URL code.

Hit Counter Tracking

The system automatically tracks how many times each URL is accessed.

Automatic Tracking

Hit counters increment asynchronously in the background:
main.py:49-51
def update_hits_sync(url_code: str):
    anyio.from_thread.run(app.URLStats.update_one, {"url_code": url_code}, {"$inc": {"url_hits": 1}})
Hit tracking only occurs for password-protected URLs. Public URLs without passwords do not track hits.

Resetting Hit Counter

Reset the hit counter to zero without affecting other statistics:
PATCH /reset_hits
Authorization: Bearer <your_access_token>
Implementation:
main.py:159-167
@app.patch("/reset_hits")
async def reset_hits(credentials:HTTPAuthorizationCredentials=Depends(security)):
    url_code=await authenticate(credentials)
    entry = await app.URLStats.find_one({"url_code": url_code})
    if entry:
        await app.URLStats.update_one({"url_code": url_code},{"$set": {"url_hits": 0}})
        return {"message": f"{url_code} hits reset successfully"}
    else:
        raise HTTPException(status_code=404, detail="URL not found")
Response:
{
  "message": "mylink hits reset successfully"
}

Viewing Hit Statistics

Retrieve hit count and other statistics via the /details endpoint:
GET /details
Authorization: Bearer <your_access_token>
Response:
{
  "message": "Details fetched successfully",
  "data": {
    "url_code": "mylink",
    "url_hits": 42,
    "url_created_at": "2026-03-04T10:30:00",
    "url_state": true,
    "url": "https://example.com"
  }
}

Changing Destination URLs

Update where a short URL redirects without changing the URL code:
PATCH /change_url?url=https://newdestination.com
Authorization: Bearer <your_access_token>

Implementation

main.py:169-179
@app.patch("/change_url")
async def change_url(url:str,credentials:HTTPAuthorizationCredentials=Depends(security)):
    url_code=await authenticate(credentials)
    entry = await app.URLMap.find_one({"url_code": url_code})
    if entry:
        if helper.blackURL(url,URL_BLACKLIST):
            raise HTTPException(status_code=400, detail="URL Blacklisted")
        await app.URLMap.update_one({"url_code": url_code},{"$set": {"url": helper.formatURL(url)}})
        return {"message": f"{url_code} redirect url changed successfully"}
    else:
        raise HTTPException(status_code=404, detail="URL not found")
Response:
{
  "message": "mylink redirect url changed successfully"
}

URL Formatting

The system automatically formats URLs by adding https:// if missing:
helper.py:9-13
def formatURL(url: str):
    url=url.strip()
    if not url.startswith(("http://", "https://")):
        url="https://"+url
    return url
Examples:
  • Input: example.com → Output: https://example.com
  • Input: http://example.com → Output: http://example.com
  • Input: https://example.com → Output: https://example.com
Hit counters and creation timestamps are preserved when changing the destination URL.

URL Blacklisting

The system supports blacklisting specific URLs to prevent malicious or unwanted destinations.

Configuration

Blacklist is configured via the URL_BLACKLIST environment variable:
main.py:17
URL_BLACKLIST=helper.listENV(os.getenv("URL_BLACKLIST"))
Format: Comma-separated list of blocked domains or keywords
URL_BLACKLIST=malicious.com,spam.site,phishing.net

Blacklist Checking

helper.py:23-27
def blackURL(url:str,black_list: list):
    for black_list_url in black_list:
        if black_list_url in url:
            return True
    return False

Where Blacklisting Applies

Blacklisted URLs are rejected during creation:
main.py:78-79
if helper.blackURL(entry.url,URL_BLACKLIST):
    raise HTTPException(status_code=400, detail="URL Blacklisted")
Error Response:
{
  "detail": "URL Blacklisted"
}
Blacklist is also enforced when changing destination URLs:
main.py:174-175
if helper.blackURL(url,URL_BLACKLIST):
    raise HTTPException(status_code=400, detail="URL Blacklisted")
Blacklist checking uses substring matching. Adding malicious.com to the blacklist blocks all URLs containing that string, including https://malicious.com/page and https://example.com/malicious.com/redirect.

Deleting URLs

Permanently remove a short URL and all associated statistics:
DELETE /delete
Authorization: Bearer <your_access_token>

Implementation

main.py:127-137
@app.delete("/delete")
async def delete(credentials:HTTPAuthorizationCredentials=Depends(security)):
    url_code=await authenticate(credentials)

    result_map = await app.URLMap.delete_one({"url_code": url_code})
    result_stats = await app.URLStats.delete_one({"url_code": url_code})

    if result_map.deleted_count == 0:
        raise HTTPException(status_code=404, detail="URL not found")
    else:
        return {"message": f"{url_code} successfully deleted"}
Response:
{
  "message": "mylink successfully deleted"
}
Deletion is permanent and cannot be undone. Both the URL mapping and statistics are removed.

Data Model

URLEntry (URLMap Collection)

models.py:3-6
class URLEntry(BaseModel):
    url_code: str
    url_pass: str=""
    url: str

URLStats Collection

models.py:8-12
class URLStats(BaseModel):
    url_code: str
    url_hits: int
    url_created_at: datetime
    url_state: bool

Database Structure

Stores the core URL mapping:
FieldTypeDescription
_idObjectIdUnique MongoDB identifier
url_codestringShort URL code (unique index)
url_passstringHashed password (empty for public URLs)
urlstringDestination URL
URLStats entries are only created for non-empty URLs. The system checks if len(entry.url)>0 before creating statistics.

Common Errors

Status CodeErrorCause
400Invalid URL codeURL code violates validation rules
400Password length must be 3..20Password outside allowed length
400URL BlacklistedDestination URL matches blacklist
404URL not foundURL code doesn’t exist
409URL code already existsDuplicate URL code
423Redirect temporarily pausedURL is in paused state

Best Practices

  • Use descriptive codes: product-launch-2026 instead of abc123
  • Keep them short but memorable
  • Avoid easily confused characters if sharing verbally
  • Always use passwords for URLs you might need to update
  • Public URLs without passwords cannot be modified
  • Keep passwords secure - they cannot be recovered
  • Use /details to track URL performance
  • Reset counters when repurposing URLs for new campaigns
  • Pause URLs instead of deleting if you might reuse them
  • Return user-friendly messages for 423 errors
  • Use pause for maintenance windows
  • Resume URLs as soon as maintenance completes

Build docs developers (and LLMs) love