Incr API

Counter as a Service

A straightforward API for managing numeric counters. Perfect for tracking page visits, monitoring button clicks, or counting any event in your application. Each counter lives within a namespace and is identified by a unique key—accessible only to those who know it.

Fastify TypeScript Upstash Redis Free to Use

Overview

What Can You Do?

Key Concepts

Namespaces

Namespaces prevent naming conflicts between different applications. We recommend using your domain name as the namespace (e.g., mysite.com). If you don't specify a namespace, counters are created in the default namespace.

Keys

Each counter is identified by a key within its namespace. Keys must be 3-64 characters long and can contain letters, numbers, underscores, hyphens, and dots. Pattern: ^[A-Za-z0-9_-.]{3,64}$

Reserved Keywords

Special keywords are automatically replaced server-side based on the request:

Note: Keywords shorter than 3 characters are left-padded with dots.

Expiration

Counters automatically expire after 6 months of inactivity. Each time you access a counter, its expiration is reset, so actively used counters never expire.

Quick Start

Step 1: Create a Counter

Create a counter with your namespace and a unique key:

GET /create/myapp/pageviews

Response:

{
  "key": "pageviews",
  "namespace": "myapp",
  "admin_key": "abc123def456...",
  "value": 0
}
Important: Save the admin_key! This is the only time you'll see it. You'll need it to delete, reset, or modify the counter later.

Step 2: Increment the Counter

Each request to the hit endpoint increases the counter by one:

GET /hit/myapp/pageviews

Response:

{
  "value": 1
}

Step 3: Retrieve the Value

Get the current value without incrementing:

GET /get/myapp/pageviews

Response:

{
  "value": 1
}

Usage Examples

Tracking Page Views

Display the number of times a page has been visited:

Using JSONP (Legacy Browser Support)

<div id="visits">...</div>

<script>
function displayVisits(response) {
    document.getElementById('visits').innerText = response.value;
}
</script>
<script async src="https://your-api.com/hit/mysite.com/visits?callback=displayVisits"></script>

Using Fetch API (Modern Browsers)

fetch('https://your-api.com/hit/mysite.com/visits')
    .then(res => res.json())
    .then(data => {
        document.getElementById('visits').innerText = data.value;
    });

Using XMLHttpRequest

var xhr = new XMLHttpRequest();
xhr.open("GET", "https://your-api.com/hit/mysite.com/visits");
xhr.responseType = "json";
xhr.onload = function() {
    document.getElementById('visits').innerText = this.response.value;
}
xhr.send();

Tracking Button Clicks

Count how many times a button has been clicked:

<button onclick="trackClick()">Click Me!</button>

<script>
function trackClick() {
    fetch('https://your-api.com/hit/mysite.com/button-clicks')
        .then(res => res.json())
        .then(data => {
            alert(`This button has been clicked ${data.value} times!`);
        });
}
</script>

Per-Page Counters

Track visits for individual pages using unique keys:

// Home page
GET /hit/mysite.com/page-home

// About page
GET /hit/mysite.com/page-about

// Product page
GET /hit/mysite.com/page-product-123

Or use reserved keywords for automatic page tracking:

// Automatically uses the current path
GET /hit/mysite.com/:PATH:

Python Example

import requests

# Create a counter
response = requests.get('https://your-api.com/create/myapp/downloads')
data = response.json()
admin_key = data['admin_key']

# Increment the counter
response = requests.get('https://your-api.com/hit/myapp/downloads')
print(f"Downloads: {response.json()['value']}")

# Reset using admin key
headers = {'Authorization': f'Bearer {admin_key}'}
requests.post('https://your-api.com/reset/myapp/downloads', headers=headers)

API Reference

Authentication & Rate Limits

Administrative endpoints (delete, set, reset, update) require an admin key passed as a Bearer token in the Authorization header. You receive this key when creating a counter.

Rate Limiting: 30 requests per 10 seconds per IP address. When exceeded, you'll receive a 429 status code. Check these headers to monitor your usage:

Public Endpoints

GET /healthcheck

Check API health and uptime.

Response: 200
{
  "status": "ok",
  "uptime": "1h23m45s"
}
GET /stats

Retrieve API statistics and usage information.

Response: 200
{
  "commands": {
    "create": 1234,
    "get": 5678,
    "hit": 9012,
    "total": 15924
  },
  "total_keys": 1000,
  "version": "1.0.0",
  "shard": "production",
  "uptime": "5h30m15s"
}
GET /create/:namespace/:key

Create a new counter with optional starting value. Returns an admin key for management.

Query Parameters: initializer (optional) - Starting value (default: 0)

Request:
GET /create/myapp/downloads?initializer=100

Response: 201
{
  "key": "downloads",
  "namespace": "myapp",
  "admin_key": "a1b2c3d4e5f6...",
  "value": 100
}

Error: 409 (if key exists)
{
  "error": "Key already exists, please use a different key."
}
GET /create

Create a counter with randomly generated namespace and key.

Response: 201
{
  "key": "x7k9m2",
  "namespace": "n4p8q1",
  "admin_key": "a1b2c3d4e5f6...",
  "value": 0
}
GET /get/:namespace/:key

Retrieve the current counter value without incrementing.

Query Parameters: callback (optional) - JSONP callback function

Request:
GET /get/myapp/visits

Response: 200
{
  "value": 42
}

Error: 404 (if key doesn't exist)
{
  "error": "Key not found"
}
GET /get/:key

Get counter value from the default namespace.

GET /hit/:namespace/:key

Increment the counter by 1 and return the new value. Creates the counter if it doesn't exist.

Query Parameters: callback (optional) - JSONP callback function

Request:
GET /hit/myapp/visits

Response: 200
{
  "value": 43
}
GET /hit/:key

Increment counter in the default namespace.

GET /info/:namespace/:key

Get detailed counter information including expiration data.

Response: 200
{
  "value": 42,
  "full_key": "K:myapp:visits",
  "is_genuine": true,
  "expires_in": 172800,
  "expires_str": "2d",
  "exists": true
}

Response: 404 (if key doesn't exist)
{
  "value": -1,
  "full_key": "default:nonexisting",
  "is_genuine": true,
  "expires_in": -2e-9,
  "expires_str": "-2ns",
  "exists": false
}
GET /info/:key

Get counter info from the default namespace.

Admin Endpoints

These endpoints require the Authorization: Bearer YOUR_ADMIN_KEY header.

POST /delete/:namespace/:key Auth Required

Permanently remove a counter.

Request:
POST /delete/myapp/visits
Authorization: Bearer abc123...

Response: 200
{
  "status": "ok",
  "message": "Deleted key: myapp:visits"
}
POST /set/:namespace/:key Auth Required

Set the counter to a specific value, overwriting the current value.

Query Parameters: value (required) - New value

Request:
POST /set/myapp/visits?value=1000
Authorization: Bearer abc123...

Response: 200
{
  "value": 1000
}

Error: 404 (if key doesn't exist)
{
  "error": "Key does not exist, please use a different key."
}
POST /reset/:namespace/:key Auth Required

Reset the counter to zero.

Request:
POST /reset/myapp/visits
Authorization: Bearer abc123...

Response: 200
{
  "value": 0
}

Error: 404 (if key doesn't exist)
{
  "error": "Key does not exist, please use a different key."
}
POST /update/:namespace/:key Auth Required

Adjust the counter by a specific amount (positive or negative).

Query Parameters: value (required) - Amount to add (negative to subtract)

Request:
POST /update/myapp/visits?value=10
Authorization: Bearer abc123...

Response: 200
{
  "value": 52
}

Decrement example:
POST /update/myapp/visits?value=-5
{
  "value": 47
}

Error: 404 (if key doesn't exist)
{
  "error": "Key does not exist, please first create it using /create."
}

Frequently Asked Questions

Yes, completely free. No registration or API keys required for basic usage.

The API allows 30 requests per 10 seconds per IP address. If you exceed this limit, you'll receive a 429 status code with a retry-after header. For higher limits, please contact the administrator.

Yes, if you created the counter using the /create endpoint and saved the admin key. Use the /delete endpoint with your admin key to remove it.

Counters expire after 6 months of inactivity. However, each time you access a counter (via get, hit, or info), its expiration is reset. Actively used counters never expire.

The admin key is shown only once when you create a counter. If you lose it, you won't be able to delete, reset, or modify that counter. However, you can still increment and read the counter value.

The API is built on Upstash Redis for high performance. If you're planning to make tens of thousands of requests, please reach out to discuss your use case.

Yes, all endpoints support Cross-Origin Resource Sharing (CORS), allowing you to make requests from any domain.