Spoo.me Api Documentation


Welcome to the URL Shortener API documentation. This page provides information on how to use the API to shorten URLs and retrieve analytics.

Base URL: https://spoo.me


✂️ Shorten Long URLs


This endpoint is used to shorten a URL. The request payload must contain the URL to be shortened. The response contains the shortened URL.

Endpoint: POST /


Data

The following data parameters that the API understands:

Payload Data Type Description Required
url String The long URL to be shortened. Yes
alias String Custom alias for the shortened URL. No
password String Password to access the shortened URL. No
max-clicks Integer Maximum number of clicks allowed for the shortened URL. No

Note: password must be atleast 8 characters long, must contain atleast a letter and a number and a special character either '@' or '.' and cannot be consecutive.


Headers

The following headers are used in the API requests and responses:

Header Value
Accept* application/json
Content-Type* application/x-www-form-urlencoded

Note: Both of the above headers are compuslary


🧑🏻‍💻 Code Examples

import requests
import json

url = "https://spoo.me"

# Replace these with your actual values
payload = {
    "url": "https://example.com",
    "alias": "example",  # you can choose any other alias
    "max-clicks": 10,
    "password": "SuperStrongPassword@18322"
}

# Necessary to get a non-html response
headers = {
    "Accept": "application/json"
}

response = requests.post(url, data=payload, headers=headers)

if response.status_code == 200:
    # If the request was successful, print the shortened URL
    shortened_url = response.json()
else:
    # If the request failed, print the error message
    print(f"Error: {response.status_code}")
    print(response.text)

Response:

{"short_url": "https://spoo.me/example"}
const axios = require('axios');
const data = {
    url: 'https://example.com',
    alias: 'node-exampl',
    password: 'NodeIsCool@Example2',
    'max-clicks': '200'
};

axios.post('https://spoo.me/', data, {
    headers: {
        'content-type': 'application/x-www-form-urlencoded',
        Accept: 'application/json',
    },
})

.then(function (response) {
    console.log(response.data);
})

.catch(function (error) {
    console.error(error);
});

Response:

{"short_url": "https://spoo.me/node-exampl"}
using System.Net.Http;
using System.Net.Http.Headers;
using System.Collections.Generic;

var client = new HttpClient();
var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("https://spoo.me/"),
    Headers =
    {
        { "Accept", "application/json" },
    },
    Content = new FormUrlEncodedContent(new Dictionary<string, string>
    {
        { "url", "https://example.com" }, { "alias", "cSharpExa" }, { "password", "HelloC_sharp1@" }, { "max-clicks", "200" }
    }),
};
try
{
    using (var response = await client.SendAsync(request))
    {
        response.EnsureSuccessStatusCode();
        var body = await response.Content.ReadAsStringAsync();
        Console.WriteLine(body);
    }
}
catch (HttpRequestException ex)
{
    Console.WriteLine($"HTTP request error: {ex.Message}");
}

Response:

{"short_url": "https://spoo.me/cSharpExa"}
const url = 'https://spoo.me/';
const data = new URLSearchParams();
data.append('url', 'https://example.com');
data.append('alias', 'jsExample1');
data.append('password', 'jsIsAlsoCool@12');
data.append('max-clicks', '200');

const xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('Accept', 'application/json');

xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
        if (xhr.status == 200) {
            console.log(xhr.responseText);
        } else {
            console.error(`HTTP error! Status: ${xhr.status}`);
        }
    }
};

xhr.send(data);

Response:

{"short_url": "https://spoo.me/jsExample1"}
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class HttpRequestExample {

    public static void main(String[] args) {
        // Define the URL
        String url = "https://spoo.me/";

        // Define the Long URL
        String longUrl = "https://example.com";

        // Encode the Long URL
        String encodedLongUrl = URLEncoder.encode(longUrl, StandardCharsets.UTF_8);

        // Build the request body
        String requestBody = "url="+encodedLongUrl+"&alias=JavaIsHard&password=JavaHardNGL@1000&max-clicks=200";

        // Create and configure the HttpClient
        HttpClient httpClient = HttpClient.newHttpClient();

        // Build the HttpRequest
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .header("Accept", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        try {
            // Send the request and receive the response
            HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

            // Print the response status code and body
            System.out.println("Response Code: " + response.statusCode());
            System.out.println("Response Body: " + response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Response:

{"short_url": "https://spoo.me/JavaIsHard"}
package main

import (
    "context"
    "fmt"
    "io"
    "net"
    "net/http"
    "net/url"
    "strings"
    "time"
)

func main() {
    // Set DNS resolver to use Google's public DNS server
    net.DefaultResolver = &net.Resolver{
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            d := net.Dialer{Timeout: 500 * time.Millisecond}
            return d.DialContext(ctx, "udp", "8.8.8.8:53")
        },
    }

    apiUrl := "https://spoo.me/"

    longUrl := "https://example.com"
    encodedLongUrl := url.QueryEscape(longUrl)
    payload := strings.NewReader("url="+encodedLongUrl+"&alias=GoExample&max-clicks=200&password=GoIsNew@Yes5")

    req, err := http.NewRequest("POST", apiUrl, payload)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }

    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    req.Header.Add("Accept", "application/json")

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("Error making request:", err)
        return
    }

    defer res.Body.Close()
    body, err := io.ReadAll(res.Body)
    if err != nil {
        fmt.Println("Error reading response:", err)
        return
    }

    fmt.Println(res)
    fmt.Println(string(body))
}

Response:

{"short_url": "https://spoo.me/GoExample"}
require 'uri'
require 'net/http'

url = URI("https://spoo.me")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

longUrl = "https://example.com"
encodedLongUrl = URI.encode_www_form_component(longUrl)

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request["Accept"] = 'application/json'
request.body = "url=#{encodedLongUrl}&alias=RubyIsRuby&password=FHVygyg@132o&max-clicks=200"

response = http.request(request)
puts response.read_body

Response:

{"short_url": "https://spoo.me/RubyIsRuby"}

For More code samples you can try the /get-code command of our official discord-bot, spooBot 🤖

🪲 Errors

This section provides information about the various errors that could occur while making requests through this endpoint.

Error Name Code Description
UrlError 400 The request does not contain the long URL or contains an invalid url. The url must contain a valid protocol like https, http and must follow rfc-1034 & rfc-2727
AliasError 400 The User requested Alias is invalid or already taken. The alias must be alphanumeric & must be under 15 chars, anything beyond 15 chars would be stripped by the API
PasswordError 400 The user entered password must be atleast 8 characters long, must contain atleast a letter and a number and a special character either '@' or '.' and cannot be consecutive.
MaxClicksError 400 The user entered max-clicks is not a positive integer.



😉 Emoji URLs


Spoo.me also provides the ability to shorten URLs with custom emojis.

Endpoint: POST /emoji


Data

The following data parameters that the API understands:

Payload Data Type Description Required
url String The long URL to be shortened. Yes
emojies String Custom emojies sequence for the shortened URL. Must contain only emojies, no other character is allowed. No
password String Password to access the shortened URL. No
max-clicks Integer Maximum number of clicks allowed for the shortened URL. No

Note: password must be atleast 8 characters long, must contain atleast a letter and a number and a special character either '@' or '.' and cannot be consecutive.


Headers

The following headers are used in the API requests and responses:

Header Value
Accept* application/json
Content-Type* application/x-www-form-urlencoded

Note: Both of the above headers are compuslary


🧑🏻‍💻 Code Examples

import requests

url = "https://spoo.me/emoji/"

payload = {
    "url": "https://example.com",
    "alias": "🐍🐍",
    "password": 1000,
    "max-clicks": "Python.Snake63"
}
headers = {
    "Accept": "application/json",
}

response = requests.post(url, data=payload, headers=headers)

if response.status_code == 200:
    print(response.json())
else:
    print(response.text)

Response:

{"short_url": "https://spoo.me/🐍🐍"}
const axios = require('axios');
const data = {
    url: 'https://example.com/emoji/',
    alias: '🚀🚀',
    password: 'Node.emojiIsCool1',
    'max-clicks': '200'
};

axios.post('https://spoo.me/', data, {
    headers: {
        'content-type': 'application/x-www-form-urlencoded',
        Accept: 'application/json',
    },
})

.then(function (response) {
    console.log(response.data);
})

.catch(function (error) {
    console.error(error);
});

Response:

{"short_url": "https://spoo.me/🚀🚀"}
using System.Net.Http;
using System.Net.Http.Headers;
using System.Collections.Generic;

var client = new HttpClient();
var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("https://spoo.me/emoji/"),
    Headers =
    {
        { "Accept", "application/json" },
    },
    Content = new FormUrlEncodedContent(new Dictionary<string, string>
    {
        { "url", "https://example.com" }, { "alias", "🌊#️⃣" }, { "password", "Emoji@C_sharp1" }, { "max-clicks", "200" }
    }),
};
try
{
    using (var response = await client.SendAsync(request))
    {
        response.EnsureSuccessStatusCode();
        var body = await response.Content.ReadAsStringAsync();
        Console.WriteLine(body);
    }
}
catch (HttpRequestException ex)
{
    Console.WriteLine($"HTTP request error: {ex.Message}");
}

Response:

{"short_url": "https://spoo.me/🌊#️⃣"}
const url = 'https://spoo.me/emoji/';
const data = new URLSearchParams();
data.append('url', 'https://example.com');
data.append('alias', '☕📜');
data.append('password', 'jsIsAlsoCool@12');
data.append('max-clicks', '200');

const xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.setRequestHeader('Accept', 'application/json');

xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
        if (xhr.status == 200) {
            console.log(xhr.responseText);
        } else {
            console.error(`HTTP error! Status: ${xhr.status}`);
        }
    }
};

xhr.send(data);

Response:

{"short_url": "https://spoo.me/☕📜"}
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class HttpRequestExample {

    public static void main(String[] args) {
        // Define the URL
        String url = "https://spoo.me/emoji/";

        // Define the Long URL
        String longUrl = "https://example.com";

        // Encode the Long URL
        String encodedLongUrl = URLEncoder.encode(longUrl, StandardCharsets.UTF_8);

        // Build the request body
        String requestBody = "url="+encodedLongUrl+"&alias=☕&password=JavaHardNGL@1000&max-clicks=200";

        // Create and configure the HttpClient
        HttpClient httpClient = HttpClient.newHttpClient();

        // Build the HttpRequest
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .header("Accept", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        try {
            // Send the request and receive the response
            HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

            // Print the response status code and body
            System.out.println("Response Code: " + response.statusCode());
            System.out.println("Response Body: " + response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Response:

{"short_url": "https://spoo.me/☕"}
package main

import (
    "context"
    "fmt"
    "io"
    "net"
    "net/http"
    "net/url"
    "strings"
    "time"
)

func main() {
    // Set DNS resolver to use Google's public DNS server
    net.DefaultResolver = &net.Resolver{
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            d := net.Dialer{Timeout: 500 * time.Millisecond}
            return d.DialContext(ctx, "udp", "8.8.8.8:53")
        },
    }

    apiUrl := "https://spoo.me/emoji/"

    longUrl := "https://example.com"
    encodedLongUrl := url.QueryEscape(longUrl)
    payload := strings.NewReader("url="+encodedLongUrl+"&alias=💨👋🏻&max-clicks=200&password=GoIsNew@Yes5")

    req, err := http.NewRequest("POST", apiUrl, payload)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }

    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    req.Header.Add("Accept", "application/json")

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("Error making request:", err)
        return
    }

    defer res.Body.Close()
    body, err := io.ReadAll(res.Body)
    if err != nil {
        fmt.Println("Error reading response:", err)
        return
    }

    fmt.Println(res)
    fmt.Println(string(body))
}

Response:

{"short_url": "https://spoo.me/👋🏻💨"}
require 'uri'
require 'net/http'

url = URI("https://spoo.me/emoji/")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

longUrl = "https://example.com"
encodedLongUrl = URI.encode_www_form_component(longUrl)

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request["Accept"] = 'application/json'
request.body = "url=#{encodedLongUrl}&alias=💎&password=FHVygyg@132o&max-clicks=200"

response = http.request(request)
puts response.read_body

Response:

{"short_url": "https://spoo.me/💎"}

🪲 Errors

This section provides information about the various errors that could occur while making requests through this endpoint.

Error Name Code Description
UrlError 400 The request does not contain the long URL or contains an invalid url. The url must contain a valid protocol like https, http and must follow rfc-1034 & rfc-2727
EmojiError 400 The User requested Emoji sequence is invalid or already taken. The emoji sequence must contain only emojies, no other character is allowed.
PasswordError 400 The user entered password must be atleast 8 characters long, must contain atleast a letter and a number and a special character either '@' or '.' and cannot be consecutive.
MaxClicksError 400 The user entered max-clicks is not a positive integer.



📊 URL Statistics


This endpoint is used to retrieve statistics about a shortened URL. The request must contain the short code of the URL. The response contains the statistics.

Endpoint: POST /stats/{shortCode}

shortCode can also represent the short code of an emoji URL.


Data

The following data parameters that the API understands:

Payload Description Required
password Password of the shortened url if any. Yes, if and only if the short url is password protected.

Headers

The following headers are used in the API requests and responses:

Header Value
Content-Type* application/x-www-form-urlencoded

🧑🏻‍💻 Code Examples

import requests
import json

# Replace these with your actual values
short_code = "exa"
base_url = "https://spoo.me"

payload = {                      # not required if your short url is not password protected
    "password": "Example@12"
}

# Make the request
response = requests.post(
    f"{base_url}/stats/{short_code}",
    data = payload
)

# Check the response
if response.status_code == 200:
    # If the request was successful, print the URL statistics
    url_stats = response.json()
    print(json.dumps(url_stats, indent=4))
else:
    # If the request failed, print the error message
    print(f"Error: {response.status_code}")
    print(response.text)
const axios = require('axios');

const short_code = 'exa';

const data = {                 // not required if your short url is not password protected
    password: 'Example@12',
};

axios.post('https://spoo.me/stats/${short_code}', data, {
    headers: {
        'content-type': 'application/x-www-form-urlencoded',
    },
})

.then(function (response) {
    console.log(response.data);
})

.catch(function (error) {
    console.error(error);
});
using System.Net.Http;
using System.Net.Http.Headers;
using System.Collections.Generic;

var client = new HttpClient();
var request = new HttpRequestMessage
{
    Method = HttpMethod.Post,
    RequestUri = new Uri("https://spoo.me/stats/exa"),
    Headers =
    {
        { "Content-Type", "application/x-www-form-urlencoded" },
    },
    Content = new FormUrlEncodedContent(new Dictionary<string, string>   // not required if your short url is not password protected
    {
        { "password", "Example@12" }
    }),
};
try
{
    using (var response = await client.SendAsync(request))
    {
        response.EnsureSuccessStatusCode();
        var body = await response.Content.ReadAsStringAsync();
        Console.WriteLine(body);
    }
}
catch (HttpRequestException ex)
{
    Console.WriteLine($"HTTP request error: {ex.Message}");
}
// define the short_code & url

const url = 'https://spoo.me/stats/exa';
const data = new URLSearchParams();
data.append('password', 'Example@12');   // not required if your short url is not password protected

const xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');

xhr.onreadystatechange = function () {
    if (xhr.readyState == 4) {
        if (xhr.status == 200) {
            console.log(xhr.responseText);
        } else {
            console.error(`HTTP error! Status: ${xhr.status}`);
        }
    }
};

xhr.send(data);
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpRequestExample {

    public static void main(String[] args) {

        // Define the short_code
        String short_code = "exa";

        // Define the URL
        String url = "https://spoo.me/stats/"+short_code;

        // Build the request body
        String requestBody = "password=Example@12";    // not required if your short url is not password protected

        // Create and configure the HttpClient
        HttpClient httpClient = HttpClient.newHttpClient();

        // Build the HttpRequest
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

        try {
            // Send the request and receive the response
            HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

            // Print the response status code and body
            System.out.println("Response Code: " + response.statusCode());
            System.out.println("Response Body: " + response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
package main

import (
    "context"
    "fmt"
    "io"
    "net"
    "net/http"
    "strings"
    "time"
)

func main() {
    // Set DNS resolver to use Google's public DNS server
    net.DefaultResolver = &net.Resolver{
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            d := net.Dialer{Timeout: 500 * time.Millisecond}
            return d.DialContext(ctx, "udp", "8.8.8.8:53")
        },
    }

    short_code := "exa"
    url := "https://spoo.me/stats/" + short_code
    payload := strings.NewReader("password=Example@12")    // not required if your short url is not password protected

    req, err := http.NewRequest("POST", url, payload)
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }

    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

    res, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("Error making request:", err)
        return
    }

    defer res.Body.Close()
    body, err := io.ReadAll(res.Body)
    if err != nil {
        fmt.Println("Error reading response:", err)
        return
    }

    fmt.Println(res)
    fmt.Println(string(body))
}
require 'net/http'

short_code = "exa"
url = URI("https://spoo.me/stats/#{short_code}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "password=Example@12"   # not required if your short url is not password protected

response = http.request(request)
puts response.read_body

Response:

{
    "_id": "exa",
    "average_daily_clicks": 1.0,
    "average_monthly_clicks": 0.03,
    "average_weekly_clicks": 0.14,
    "bots": {
        "Googlebot": 1
    },
    "browser": {
        "Edge": 1
    },
    "counter": {
        "2023-12-18": 1
    },
    "country": {
        "France": 1
    },
    "creation-date": "2023-12-18",
    "expired": null,
    "last-click": "2023-12-18 22:06:02.298005+00:00",
    "last-click-browser": "Edge",
    "last-click-os": "Windows",
    "max-clicks": null,
    "os_name": {
        "Windows": 1
    },
    "password": "Example@12",
    "referrer": {
        "spoo.me": 1
    },
    "short_code": "exa",
    "total-clicks": 1,
    "total_unique_clicks": 1,
    "unique_browser": {
        "Edge": 1
    },
    "unique_counter": {
        "2023-12-18": 1
    },
    "unique_country": {
        "France": 1
    },
    "unique_os_name": {
        "Windows": 1
    },
    "unique_referrer": {
        "spoo.me": 1
    },
    "url": "https://example.com"
}

📑 Response Analysis

The response contains the following data:

Key Data Type Description
_id Str The Short Code of the Short Link.
average_daily_clicks Float Average Clicks per day since the link was created.
average_monthly_clicks Float Average Clicks per month since the link was created.
average_weekly_clicks Float Average Clicks per week since the link was created.
bots Dict Data about the Bots in which the short link was accessed.
browser Dict Data about the Browsers in which the short link was accessed.
creation-date Str Date when the short link was created.
counter Dict Data about the clicks per day since the link was created.
country Dict Data about the Countries in which the short link was accessed.
expired* Bool Tells whether the link has expired or not.
last-click Str Last Time when the short link was accessed.
last-click-browser Str Last Browser in which the short link was accessed.
last-click-os Str Last Os name in which the short link was accessed.
max-clicks* Str Information about the Max Clicks set my the User on the Short Link.
os_name Dict Data about the Os names in which the short link was accessed.
password* Str The password set by the User on the Short Link.
short_code Str The Short Code of the Short Link.
total-clicks Int Count of the total clicks made since the short link was created.
total_unique_clicks Int Count of the total unique clicks made since the short link was created.
unique_browser Dict Data about the Unique Browsers in which the short link was accessed.
unique_counter Dict Data about the Unique clicks per day since the link was created.
unique_country Dict Data about the Unique Countries in which the short link was accessed.
unique_os_name Dict Data about the Unique Os names in which the short link was accessed.
unique_referrer Dict Data about the Unique Referrers in which the short link was accessed.
url Str Original Long Url which the short link redirects to.

* Null if the Short link didnt have max-clicks set or was not password protected.


🪲 Errors

This section provides information about the various errors that could occur while making requests through the API.

Error Name Code Description
UrlError 404 The user requested Url never existed.
PasswordError 400 The user entered password is invalid.



📤 Exporting Data


This endpoint is used to export the data of your shortened URL. The request must contain the short code of the URL along with the format in which you want to recieve your data. The response contains the data of the shortened URL.


Endpoint: POST /export/{shortCode}/{exportFormat}

shortCode can also represent the short code of an emoji URL.


Available Export Formats

The following export formats are available:

Format Description
json Export the data in JSON format.
csv Export the data in CSV format. The API will return the data divided in many files zipped together.
xlsx Export the data in XLSX (Excel file) format.
xml Export the data in XML format.

You can choose anyone of these formats and pass it in the request parameter

Important Note: The API returns raw data in the specified format, which you may need to store in a file.


Data

The following data parameters that the API understands:

Payload Description Required
password Password of the shortened url if any. Yes, if and only if the short url is password protected.

Headers

The following headers are used in the API requests and responses:

Header Value
Content-Type* application/x-www-form-urlencoded

🧑🏻‍💻 Code Examples

import requests
import json

# Replace these with your actual values
short_code = "exa"
base_url = "https://spoo.me"
export_format = "xlsx"    # You can choose from ["json", "csv", "xlsx", "xml"]

payload = {                      # not required if your short url is not password protected
    "password": "Example@12"
}

# Make the request

response = requests.post(
    f"{base_url}/export/{short_code}/{export_format}",
    data = payload
)

# Check the response
if response.status_code == 200:
    # If the request was successful, store the data in a file
    with open(f"{short_code}.{export_format}", "wb") as file:    # Note if the export format is csv, the file will be a zip file
        file.write(response.content)
else:
    # If the request failed, print the error message
    print(f"Error: {response.status_code}")
    print(response.text)
const axios = require("axios");
const fs = require("fs");
const querystring = require("querystring");

// Replace these with your actual values
const short_code = "exa";
const base_url = "https://spoo.me";
const export_format = "xlsx"; // You can choose from ["json", "csv", "xlsx", "xml"]

const payload = {
    // not required if your short url is not password protected
    password: "Example@12",
};

// Make the request
axios
    .post(
        `${base_url}/export/${short_code}/${export_format}`,
        querystring.stringify(payload), // Convert the object to a URL-encoded string
        {
            responseType: "arraybuffer",
            headers: {
                "content-type": "application/x-www-form-urlencoded", // Specify the content type
            },
        }
    )
    .then((response) => {
        // If the request was successful, store the data in a file
        fs.writeFile(`${short_code}.${export_format}`, response.data, (err) => {     // Note if the export format is csv, the file will be a zip file
            if (err) {
                console.error(err);
            } else {
                console.log("File saved successfully");
            }
        });
    })
    .catch((error) => {
        // If the request failed, print the error message
        console.error(`Error: ${error.response.status}`);
        console.error(error.response.data.toString());
    });
// Import HttpClient module
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

// Replace these with your actual values
const string short_code = "exa";
const string base_url = "https://spoo.me";
const string export_format = "xlsx"; // You can choose from ["json", "csv", "xlsx", "xml"]

// Create an instance of HttpClient
var client = new HttpClient();

// Set the content
var content = new FormUrlEncodedContent(new Dictionary   // not required if your short url is not password protected
{
    { "password", "Example@12" }
});

// Make the request
var response = await client.PostAsync($"{base_url}/export/{short_code}/{export_format}", content);    // Note if the export format is csv, the file will be a zip file

// Check the response
if (response.IsSuccessStatusCode)
{
    // If the request was successful, store the data in a file
    var data = await response.Content.ReadAsByteArrayAsync();
    File.WriteAllBytes($"{short_code}.{export_format}", data);
    Console.WriteLine("File saved successfully");
}
else
{
    // If the request failed, print the error message
    Console.WriteLine($"Error: {response.StatusCode}");
    Console.WriteLine(await response.Content.ReadAsStringAsync());
}
// Create a new XMLHttpRequest object
var xhr = new XMLHttpRequest();

// Replace these with your actual values
var short_code = "exa";
var base_url = "https://spoo.me";
var export_format = "xlsx"; // You can choose from ["json", "csv", "xlsx", "xml"]

var payload = new FormData(); // not required if your short url is not password protected
payload.append("password", "Example@12");

// Open a connection by specifying the request type and endpoint
xhr.open("POST", `${base_url}/export/${short_code}/${export_format}`, true);

// Set the response type to blob or arraybuffer
xhr.responseType = "blob"; // or "arraybuffer"

// Send the request
xhr.send(payload);

// Listen to xhr events for response
xhr.onload = function () {
    // If the request was successful, store the data in a file
    if (xhr.status == 200) {
        var data = xhr.response;
        var blob = new Blob([data], { type: "application/octet-stream" });
        var url = window.URL.createObjectURL(blob);
        var a = document.createElement("a");
        a.href = url;
        a.download = `${short_code}.${export_format}`;    // Note if the export format is csv, the file will be a zip file
        a.click();
        window.URL.revokeObjectURL(url);
        console.log("File saved successfully");
    } else {
        // If the request failed, print the error message
        console.error(`Error: ${xhr.status}`);
        console.error(xhr.responseText);
    }
};
// Import java.net.http package
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;

public class ExportExample {

    public static void main(String[] args) {
        // Define the URL
        String short_code = "exa";
        String base_url = "https://spoo.me";
        String export_format = "csv"; // You can choose from ["json", "csv", "xlsx", "xml"]

        // Create a map for form data
        Map data = Map.of("password", "Example@12");

        // Convert map to form data string
        String formData = data.entrySet().stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining("&"));

        // Create a HttpClient object
        HttpClient client = HttpClient.newHttpClient();

        // Create a HttpRequest object
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(base_url + "/export/" + short_code + "/" + export_format))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(formData))
                .build();

        try {
            // Send the request and get the response
            HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());

            // Check the response status code
            if (response.statusCode() == 200) {
                // If the request was successful, store the data in a file
                byte[] responseData = response.body();
                FileOutputStream file = new FileOutputStream(short_code + "." + export_format);    // Note if the export format is csv, the file will be a zip file
                file.write(responseData);
                file.close();
                System.out.println("File saved successfully");
            } else {
                // If the request failed, print the error message
                System.out.println("Error: " + response.statusCode());
                System.out.println(new String(response.body(), StandardCharsets.UTF_8));
            }
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package main

import (
    "context"
    "fmt"
    "io"
    "net"
    "net/http"
    "strings"
    "time"
    "os"
    "net/url"
)

func main() {
    // Set DNS resolver to use Google's public DNS server
    net.DefaultResolver = &net.Resolver{
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            d := net.Dialer{Timeout: 500 * time.Millisecond}
            return d.DialContext(ctx, "udp", "8.8.8.8:53")
        },
    }

    base_url := "https://spoo.me"
    short_code := "exa"
    export_format := "xlsx" // You can choose from ["json", "csv", "xlsx", "xml"]

    // Create a form data with the password (not required if your short url is not password protected)
    formData := url.Values{}
    formData.Set("password", "Example@12")

    // Convert the form data to a URL-encoded string
    payload := formData.Encode()

    req, err := http.NewRequest("POST", base_url+"/export/"+short_code+"/"+export_format, strings.NewReader(payload))
    if err != nil {
        fmt.Println("Error creating request:", err)
        return
    }

    req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

    res, err := http.DefaultClient.Do(req)

    if err != nil {
        fmt.Println("Error making request:", err)
        return
    }

    defer res.Body.Close()

    if res.StatusCode == 200 {
        // If the request was successful, store the data in a file
        file, err := os.Create(short_code + "." + export_format)    // Note if the export format is csv, the file will be a zip file
        if err != nil {
            fmt.Println("Error creating file:", err)
            return
        }
        defer file.Close()

        _, err = io.Copy(file, res.Body)
        if err != nil {
            fmt.Println("Error copying data to file:", err)
            return
        }

        fmt.Println("File saved successfully")
    } else {
        // If the request failed, print the error message
        fmt.Println("Error:", res.StatusCode)
        body, err := io.ReadAll(res.Body)
        if err != nil {
            fmt.Println("Error reading response:", err)
            return
        }
        fmt.Println(string(body))
    }
}
require 'net/http'

short_code = "exa"
base_url = "https://spoo.me"
export_format = "xlsx" # You can choose from ["json", "csv", "xlsx", "xml"]

url = URI("#{base_url}/export/#{short_code}/#{export_format}")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "password=Example@12"   # not required if your short url is not password protected

response = http.request(request)

File.open("#{short_code}.#{export_format}", "w") do |file|    # Note if the export format is csv, the file will be a zip file
    file.write(response.read_body)

    puts "File saved successfully"

end

Response:

The API returns raw data in the specified format, which you may need to store in a file.

Download Sample JSON File Download Sample CSV File Download Sample XLSX File Download Sample XML File

🪲 Errors

This section provides information about the various errors that could occur while making requests through the API.

Error Name Code Description
UrlError 404 The user requested Url (short_code) never existed.
PasswordError 400 The user entered password is invalid.
FormatError 400 The user entered an invalid export format. The Exportformat must either xml, xlsx, json or csv

Note: If you're exporting your data in CSV format, ensure you save the file with a .zip extension, not .csv. Failure to do so may result in logical errors in your code. You need to save it in a zip file because the API returns the data divided in many files zipped together.




📜 API Rate Limits


Spoo.me API has a rate limit of 5 requests per minute, 50 requests per hour and 500 requests per day for the POST /, POST /emoji endpoints. If you exceed this limit, you will receive a 429 status code in response to your requests.




📦 Spoo.me Python Library


Spoo.me has a Python library that makes it easy to use the Spoo.me API. You can install it using pip:

pip install py_spoo_url

Once installed, you can use the library to shorten URLs, get the stats of a shortened URL, and export the data of a shortened URL.

Here's a quick example of how to shorten a URL:


from py_spoo_url import Shorten, Statistics

shortener = Shortener()
long_url = "https://www.example.com"
short_url = shortener.shorten(long_url, password="SuperSecretPassword@444", max_clicks=100)
# for custom alias, put `alias=<your_choice>`

print(f"Shortened URL: {short_url}")
        

Complete documentation for the library can be found here.




🤖 SpooBot


SpooBot is a Discord bot that uses the Spoo.me API. It provides the following features:

SpooBot is available on the Discord Bot List. You can add it to your server by clicking here.

SpooBot is also open source. You can find the source code on GitHub.




📚 Conclusion


Spoo.me API is a powerful tool that allows you to shorten URLs, get the stats of a shortened URL, and export the data of a shortened URL. It's easy to use and provides a lot of flexibility. We hope this guide has helped you understand how to use the API and how to integrate it into your applications.

If you have any questions or need further assistance, feel free to reach out to us at support@spoo.me or you can join our official Discord Server. We're always happy to help!