Skip to content

API Authentication

Secure by design. The Klinky API uses proven authentication methods to protect your link data and conversion tracking.

Get API access — Available on Growth and Scale plans


Authentication Methods

Klinky uses two authentication methods depending on the endpoint:

MethodUse ForHeader
API KeyPublic endpoints (links, analytics)X-API-Key
JWT TokenAPI key managementAuthorization: Bearer

API Key Authentication

Most endpoints require an API key passed in the X-API-Key header:

bash
curl -H "X-API-Key: klinky_live_your_api_key_here" \
  https://klinky-api.fly.dev/api/v1/public/links

API Key Format

Keys follow this pattern:

klinky_live_{32-character-random-string}

Example: klinky_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

Security Best Practices

Your API keys grant access to your link data. Protect them accordingly:

  • Environment variables — Never hardcode keys in source code
  • Separate environments — Use different keys for development and production
  • Regular rotation — Rotate keys quarterly or when team members leave
  • Immediate revocation — Delete compromised keys instantly
  • No client-side exposure — Never expose keys in browser JavaScript or mobile apps

Example: Environment-based configuration

python
import os

# Good: Key from environment variable
API_KEY = os.environ.get('KLINKY_API_KEY')

# Bad: Key in code
API_KEY = "klinky_live_abc123..."

Managing API Keys

API key management requires JWT authentication (your session token from the Klinky web app).

Create API Key

Create a new API key. The full key is returned only once and cannot be retrieved later.

Endpoint: POST /public/keys

Parameters:

NameTypeRequiredDescription
namestringYesDescriptive name for the key

Example:

bash
curl -X POST "https://klinky-api.fly.dev/api/v1/public/keys?name=Production%20API%20Key" \
  -H "Authorization: Bearer <your-jwt-token>"

Response (201 Created):

json
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Production API Key",
  "key": "klinky_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "key_prefix": "klinky_live_a1b2",
  "created_at": "2024-01-15T10:30:00Z",
  "rate_limit": 1000
}

Important: Save the key value immediately. You will not see it again.

List API Keys

List all active API keys for your account. Returns metadata without the actual key values.

Endpoint: GET /public/keys

Example:

bash
curl "https://klinky-api.fly.dev/api/v1/public/keys" \
  -H "Authorization: Bearer <your-jwt-token>"

Response (200 OK):

json
{
  "keys": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Production API Key",
      "key_prefix": "klinky_live_a1b2",
      "created_at": "2024-01-15T10:30:00Z",
      "last_used_at": "2024-01-15T14:22:00Z",
      "is_active": true
    },
    {
      "id": "660e8400-e29b-41d4-a716-446655440000",
      "name": "Development",
      "key_prefix": "klinky_live_x9y8",
      "created_at": "2024-01-10T09:15:00Z",
      "last_used_at": null,
      "is_active": true
    }
  ],
  "rate_limit_per_hour": 1000
}

Revoke API Key

Revoke an API key by ID. This immediately disables the key.

Endpoint: DELETE /public/keys/{key_id}

Parameters:

NameTypeRequiredDescription
key_idUUIDYesID of the key to revoke

Example:

bash
curl -X DELETE "https://klinky-api.fly.dev/api/v1/public/keys/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer <your-jwt-token>"

Response: 204 No Content

Get Rate Limit Status

Check your current rate limit status including remaining requests and reset time.

Endpoint: GET /public/keys/rate-limit

Example:

bash
curl "https://klinky-api.fly.dev/api/v1/public/keys/rate-limit" \
  -H "Authorization: Bearer <your-jwt-token>"

Response (200 OK):

json
{
  "limit": 1000,
  "remaining": 847,
  "reset_at": "2024-01-15T15:00:00Z"
}

JWT Authentication

JWT tokens are used for API key management and are obtained through the Klinky web application authentication flow. These tokens are short-lived and represent your user session.

To get a JWT token:

  1. Log in to app.klinky.io
  2. The token is stored in your browser's localStorage/sessionStorage
  3. Extract it for API calls (typically for scripting purposes)

For programmatic JWT authentication, use the Supabase auth endpoints directly:

bash
# Sign in to get JWT
curl -X POST "https://your-project.supabase.co/auth/v1/token?grant_type=password" \
  -H "apikey: your-anon-key" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "your-password"
  }'

Error Responses

Invalid API Key (401)

json
{
  "detail": "Invalid API key."
}

Resolution: Verify your API key is correct and active.

Missing API Key (401)

json
{
  "detail": "Missing API key. Include X-API-Key header."
}

Resolution: Include the X-API-Key header in your request.

Plan Without API Access (403)

json
{
  "detail": "Your plan (free) does not include API access. Upgrade to Growth or Scale."
}

Resolution: Upgrade to a Growth or Scale plan to enable API access.

See pricing — Compare plans and features


Code Examples

Python — Complete Key Management

python
import requests
import os

JWT_TOKEN = os.environ.get('KLINKY_JWT_TOKEN')
BASE_URL = "https://klinky-api.fly.dev/api/v1"

headers = {"Authorization": f"Bearer {JWT_TOKEN}"}

# Create a new API key
response = requests.post(
    f"{BASE_URL}/public/keys",
    headers=headers,
    params={"name": "Production API Key"}
)
new_key = response.json()
print(f"New API key: {new_key['key']}")  # Save this securely!

# List all keys
response = requests.get(f"{BASE_URL}/public/keys", headers=headers)
keys = response.json()["keys"]
for key in keys:
    print(f"{key['name']}: {key['key_prefix']}... (last used: {key['last_used_at']})")

# Check rate limit status
response = requests.get(f"{BASE_URL}/public/keys/rate-limit", headers=headers)
status = response.json()
print(f"Remaining: {status['remaining']}/{status['limit']}")

# Revoke a key
key_id = "550e8400-e29b-41d4-a716-446655440000"
response = requests.delete(f"{BASE_URL}/public/keys/{key_id}", headers=headers)
if response.status_code == 204:
    print("Key revoked successfully")

JavaScript — Key Management

javascript
const JWT_TOKEN = process.env.KLINKY_JWT_TOKEN;
const BASE_URL = 'https://klinky-api.fly.dev/api/v1';

const headers = {
  'Authorization': `Bearer ${JWT_TOKEN}`
};

// Create API key
const createKey = async (name) => {
  const response = await fetch(`${BASE_URL}/public/keys?name=${encodeURIComponent(name)}`, {
    method: 'POST',
    headers
  });
  const data = await response.json();
  console.log('Save this key securely:', data.key);
  return data;
};

// List keys
const listKeys = async () => {
  const response = await fetch(`${BASE_URL}/public/keys`, { headers });
  const data = await response.json();
  data.keys.forEach(key => {
    console.log(`${key.name}: ${key.key_prefix}...`);
  });
};

// Revoke key
const revokeKey = async (keyId) => {
  const response = await fetch(`${BASE_URL}/public/keys/${keyId}`, {
    method: 'DELETE',
    headers
  });
  return response.status === 204;
};

Plan Requirements

API key management requires a paid plan:

PlanAPI AccessRate LimitBest For
FreeNoDashboard only
StarterNoDashboard only
GrowthYes100/hourSmall teams, basic automation
ScaleYes1,000/hourLarge teams, heavy API usage

Upgrade for API access — Start building with the link shortener API today


Security Checklist

Before deploying to production:

  • [ ] API keys stored in environment variables
  • [ ] Separate keys for development/staging/production
  • [ ] Key rotation process documented
  • [ ] Revocation procedure tested
  • [ ] Rate limit monitoring in place
  • [ ] Error handling for 401/403 responses

Next Steps

Released under MIT License