API Documentation

Shortify.pro

Enterprise-quality URL shortening with predictable, sub-100 ms performance

Introduction

Shortify.pro is a high-performance URL-shortening platform engineered for speed, reliability, and developer ergonomics. Endpoints consistently respond in under 100 ms, even under sustained load, making Shortify suitable for real-time workloads and latency-sensitive applications.

The service runs on Google Cloud Run, leveraging fully managed, horizontally scaling containers to deliver predictable performance without operational overhead. All persistence is backed by Google Firestore, providing low-latency reads, high write throughput, and strong consistency guarantees for mission-critical data.

When you create a short URL, Shortify generates a three-character shortcode and returns a JWT containing its metadata. This token serves as your ownership credential and may be safely stored or integrated into your automation pipelines.

Presenting this ownership JWT in subsequent requests authorises you to update, manage, or introspect your short URL at any time. The API follows modern backend patterns including strict rate-limiting, robust error semantics, and idempotent operations, ensuring smooth integration into microservice architectures and high-throughput internal systems.

Rate Limiting

Shortify’s API relies on FlowControl, a proactive flow-management service, to provide robust rate limiting while maintaining sub-100 ms performance under load.

FlowControl enforces a soft limit of six requests per minute per IP address. When a client exceeds this threshold, Shortify responds with an HTTP 429 (Too Many Requests) error, enabling callers to apply standard retry and backoff strategies without being penalised further.

FlowControl also applies a hard limit of twelve requests per minute. If this boundary is exceeded, FlowControl automatically uses the Cloudflare API to block the offending IP at the edge. The block is lifted later using an exponential-backoff schedule, ensuring resilience against both abusive and misconfigured traffic sources.

This two-tier approach ensures predictable behaviour for normal clients while providing strong, automated protection for the platform.

API Endpoints

Base URL
https://shortcode-api.shortify.pro

Click on the endpoints below to see request and response parameters

{
    "url": "https://example.org/my-page",
    "maxClicks": 0,
    "useWord": false
}
curl -X POST "https://shortcode-api.shortify.pro/create" \
  -H "Content-Type: application/json" \
  -d '{
        "url": "https://example.org/my-page",
        "maxClicks": 0,
        "useWord": false
    }'
package main

import (
    "encoding/base64"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "strings"
    "time"
)

// Request body sent to /create
type createRequest struct {
    URL       string `json:"url"`
    MaxClicks int    `json:"maxClicks"`
    UseWord   bool   `json:"useWord"`
}

// Shape of Shortify error response
type apiErrorBody struct {
    Error struct {
        Code    string `json:"code"`
        Message string `json:"message"`
        Status  int    `json:"status"`
    } `json:"error"`
}

// JWT claims expected from Shortify
type tokenClaims struct {
    ID  string `json:"id"`
    Iat int64  `json:"iat"`
    URL string `json:"url"`
}

func main() {
    // 1. Build request payload
    reqBody := createRequest{
        URL:       "https://example.org/my-url",
        MaxClicks: 0,
        UseWord:   false,
    }

    bodyBytes, err := json.Marshal(reqBody)
    if err != nil {
        panic(fmt.Errorf("failed to marshal request: %w", err))
    }

    // 2. Build HTTP request
    const endpoint = "https://shortcode-api.shortify.pro/create"

    req, err := http.NewRequest(http.MethodPost, endpoint, strings.NewReader(string(bodyBytes)))
    if err != nil {
        panic(fmt.Errorf("failed to build request: %w", err))
    }
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("User-Agent", "shortify-docs-example/1.0")

    client := &http.Client{Timeout: 5 * time.Second}

    // 3. Execute request
    resp, err := client.Do(req)
    if err != nil {
        panic(fmt.Errorf("request failed: %w", err))
    }
    defer resp.Body.Close()

    respBody, err := io.ReadAll(resp.Body)
    if err != nil {
        panic(fmt.Errorf("failed to read response body: %w", err))
    }

    // 4. Success must be exactly 201 Created or 200 OK
    if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
        // Try to parse structured error body
        var apiErr apiErrorBody
        if err := json.Unmarshal(respBody, &apiErr); err != nil {
            fmt.Printf("Unexpected non-201 status (%d) and body was not JSON: %s", resp.StatusCode, string(respBody))
            return
        }

        fmt.Println("Shortify returned an error:")
        fmt.Println("  Status:", apiErr.Error.Status)
        fmt.Println("  Code:  ", apiErr.Error.Code)
        fmt.Println("  Msg:   ", apiErr.Error.Message)
        return
    }

    // 5. Body is a raw JWT string
    jwt := strings.TrimSpace(string(respBody))
    if jwt == "" {
        fmt.Println("Empty JWT in response")
        return
    }

    parts := strings.Split(jwt, ".")
    if len(parts) != 3 {
        fmt.Println("Invalid JWT format:", jwt)
        return
    }

    // 6. Decode payload
    payloadSegment := parts[1]
    payloadBytes, err := base64.RawURLEncoding.DecodeString(payloadSegment)
    if err != nil {
        fmt.Println("Failed to decode JWT payload:", err)
        return
    }

    var claims tokenClaims
    if err := json.Unmarshal(payloadBytes, &claims); err != nil {
        fmt.Println("Failed to unmarshal JWT claims:", err)
        return
    }

    // 7. Output final short URL
    fmt.Println("Short URL created successfully!")
    fmt.Println("  ID:        ", claims.ID)
    fmt.Println("  Created at:", claims.Iat)
    fmt.Println("  Short URL: ", claims.URL)
}
VariableRequiredDefinition
urlYesThe long URL you want to shorten
maxClicksNoMaximum number of times the URL can be clicked before it expires
useWordNoGenerate a distinctive word instead of a random combination of characters
200 OK / 201 Created Success response

Shortify returns 201 Created when a long URL is shortened for the first time. In this case, the JWT includes an ownership claim identifying you as the creator of the short URL.

If the long URL has been shortened previously, the API returns 200 OK. The response still contains a valid JWT, but it does not include an ownership claim, as ownership is only granted to the creator of the original short URL.

In both cases, the response body contains a signed JWT representing the short URL:

Response body — JWT token
eyJhbGciOiJSUzI1NiIsI...zzUdsW1IyrKKuAy91-8D7EBvtw1CIOBWo4F5CRWEnZSja9Ti4SA
Token claims
Token claimDescription
idA UUID which uniquely references your short URL
iatA unix timestamp representing the time your short URL was created
urlYour new short URL. Must be accessed via https
is.creatorA boolean claim set to true when the token identifies the holder as creator of the short URL
Error responses

If the request cannot be processed, the API returns a non-200 status code with a short JSON error body.

HTTP Status CodeError CodeDefinition
429too_many_requestsRate limit has been exceeded
400invalid_create_requestYour request is not valid
503shortcode_exists_check_failedThere was a problem checking if your URL has already been shortened
503shortcode_generation_failedThere was a problem generating your short URL
503token_generation_failedThere was a problem generating a JWT token for your shortened URL
Example error body
{
    "error": {
        "code": "invalid_create_request",
        "message": "Invalid create request. Please check your parameters and try again.",
        "status": 400
    }
}

Changelog

2025-11-30
Introduced json errors

Replaced legacy custom error responses with properly structured json error responses comprising an HTTP status, a unique code and an accompanying string message.