Unkey
ServicesApi

API

This document only covers v2 of the Unkey API. The v1 API on Cloudflare Workers is deprecated and will be removed in the future. It was too hard to selfhost anyways.

Our API runs on AWS containers, in multiple regions behind a global load balancer to ensure high availability and low latency.

The source code is available on GitHub.

Quickstart

To get started, you need go1.24+ installed on your machine.

Clone the repository:

git clone git@github.com:unkeyed/unkey.git
cd unkey/go

Build the binary:

go build -o unkey .

Run the binary:

unkey api --database-primary="mysql://unkey:password@tcp(localhost:3306)/unkey?parseTime=true"

You should now be able to access the API at

$ curl http://localhost:7070/v2/liveness
{"message":"we're cooking"}%

Configuration

You can configure the Unkey API using command-line flags or environment variables. For each flag shown below, there's an equivalent environment variable.

For example, --http-port=8080 can also be set using the environment variable UNKEY_HTTP_PORT=8080.

Basic Configuration

These options control the fundamental behavior of the API server.

--platformstring

Identifies the cloud platform where this node is running. This information is primarily used for logging, metrics, and debugging purposes.

Environment variable: UNKEY_PLATFORM

Examples:

  • --platform=aws - When running on Amazon Web Services
  • --platform=gcp - When running on Google Cloud Platform
  • --platform=hetzner - When running on Hetzner Cloud
  • --platform=docker - When running in Docker (e.g., local or Docker Compose)

--imagestring

Container image identifier for this node. This information is used for logging, metrics, and helps with tracking which version of the application is running.

Environment variable: UNKEY_IMAGE

Examples:

  • --image=ghcr.io/unkeyed/unkey:latest - Latest image from GitHub Container Registry
  • --image=ghcr.io/unkeyed/unkey:v1.2.3 - Specific version of the image

--http-port | UNKEY_HTTP_PORTint

HTTP port for the API server to listen on. This port must be accessible by all clients that will interact with the API. In containerized environments, ensure this port is properly exposed.

Examples:

  • --http-port=7070 - Default port

--test-mode | UNKEY_TEST_MODEboolean

Enable test mode. This option is designed for testing environments and should NOT be used in production. When enabled, the server may trust client inputs blindly, potentially bypassing security checks.

The server logs a warning when started with this flag enabled.

Examples:

  • --test-mode=true - Enable test mode for testing environments
  • --test-mode=false - Normal operation mode (default, suitable for production)

--region | UNKEY_REGIONstring

Geographic region identifier where this node is deployed. Used for logging, metrics categorization, and can affect routing decisions in multi-region setups.

Examples:

  • --region=us-east-1 - AWS US East (N. Virginia)
  • --region=eu-west-1 - AWS Europe (Ireland)
  • --region=us-central1 - GCP US Central
  • --region=dev-local - For local development environments

--instance-id | UNKEY_INSTANCE_IDstring

Unique identifier for this instance. This identifier is used in logs, metrics, and for identifying this specific instance of the API server. If not provided, a random ID with a unique prefix will be auto-generated.

For persistent instances, setting a consistent ID can help with log correlation and tracking instance-specific issues over time.

Examples:

  • --instance-id=api-prod-1 - First production API instance
  • --instance-id=api-us-east-001 - API instance in US East region

Database Configuration

The Unkey API requires a MySQL database for storing keys and configuration. For global deployments, a read replica endpoint can be configured to offload read operations.

--database-primary | UNKEY_DATABASE_PRIMARY_DSN
Required
string

Primary database connection string for read and write operations. This MySQL database stores all persistent data including API keys, workspaces, and configuration. It is required for all deployments.

For production use, ensure the database has proper backup procedures in place. Unkey is using PlanetScale

Examples:

  • --database-primary=mysql://root:password@localhost:3306/unkey?parseTime=true - Local MySQL for development
  • --database-primary=mysql://username:pscale_pw_...@aws.connect.psdb.cloud/unkey?sslmode=require - PlanetScale connection

--database-readonly-replica | UNKEY_DATABASE_READONLY_DSNstring

Optional read-replica database connection string for read operations. When provided, most read operations will be directed to this read replica, reducing load on the primary database and latency for users.

This is recommended for high-traffic deployments to improve performance and scalability. The read replica must be a valid MySQL read replica of the primary database.

Unkey is using PlanetScales global read replica endpoint.

Examples:

  • --database-readonly-replica=mysql://root:password@localhost:3306/unkey?parseTime=true - Local MySQL for development
  • --database-readonly-replica=mysql://username:pscale_pw_...@aws.connect.psdb.cloud/unkey?sslmode=require - PlanetScale connection

Analytics & Monitoring

These options configure analytics storage and observability for the Unkey API.

--clickhouse-url | UNKEY_CLICKHOUSE_URLstring

ClickHouse database connection string for analytics. ClickHouse is used for storing high-volume event data like API key validations, http request logs and historically aggregated analytics.

This is optional but highly recommended for production environments. If not provided, analytical capabilities will be omitted but core key validation will still function.

Examples:

  • --clickhouse-url=clickhouse://localhost:9000/unkey
  • --clickhouse-url=clickhouse://user:password@clickhouse.example.com:9000/unkey
  • --clickhouse-url=clickhouse://default:password@clickhouse.default.svc.cluster.local:9000/unkey?secure=true

--otel | UNKEY_OTELboolean

Enable OpenTelemetry. The Unkey API will collect and export telemetry data (metrics, traces, and logs) using the OpenTelemetry protocol.

When this flag is set to true, the following standard OpenTelemetry environment variables are used to configure the exporter:

  • OTEL_EXPORTER_OTLP_ENDPOINT: The URL of your OpenTelemetry collector
  • OTEL_EXPORTER_OTLP_PROTOCOL: The protocol to use (http/protobuf or grpc)
  • OTEL_EXPORTER_OTLP_HEADERS: Headers for authentication (e.g., "authorization=Bearer <token>")

Using these standard variables ensures compatibility with OpenTelemetry documentation and tools. For detailed configuration information, see the official OpenTelemetry documentation.

Examples:

# Enable OpenTelemetry
export UNKEY_OTEL=true
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp-gateway-prod-us-east-0.grafana.net/otlp"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_EXPORTER_OTLP_HEADERS="authorization=Basic ..."
 
# Or as command-line flags
unkey api --otel=true"

--otel-trace-sampling-rate | UNKEY_OTEL_TRACE_SAMPLING_RATEfloat64

Sets the sampling rate for OpenTelemetry traces as a decimal value between 0.0 and 1.0. This controls what percentage of traces will be collected and exported, helping to balance observability needs with performance and cost considerations.

  • 0.0 means no traces are sampled (0%)
  • 0.25 means 25% of traces are sampled (default)
  • 1.0 means all traces are sampled (100%)

Lower sampling rates reduce overhead and storage costs but provide less visibility. Higher rates give more comprehensive data but increase resource usage and costs.

This setting only takes effect when OpenTelemetry is enabled with --otel=true.

Examples:

  • --otel-trace-sampling-rate=0.1 - Sample 10% of traces
  • --otel-trace-sampling-rate=0.25 - Sample 25% of traces (default)
  • --otel-trace-sampling-rate=1.0 - Sample all traces

Environment variable: UNKEY_OTEL_TRACE_SAMPLING_RATE

--prometheus-port | UNKEY_PROMETHEUS_PORTnumber

Port for exposing Prometheus metrics. When set to a value greater than 0, the API server will expose a /metrics endpoint on the specified port for scraping by Prometheus. Setting this to 0 disables the Prometheus metrics endpoint.

This is useful for monitoring the API server's performance and health in production environments. The metrics include information about HTTP requests, database operations, cache performance, and more.

Examples:

  • --prometheus-port=0 - Disable Prometheus metrics endpoint (default)
  • --prometheus-port=9090 - Expose metrics on port 9090
  • --prometheus-port=9100 - Standard port used by node_exporter

Environment variable: UNKEY_PROMETHEUS_PORT

--color | UNKEY_COLORboolean

Enable ANSI color codes in log output. When enabled, log output will include ANSI color escape sequences to highlight different log levels, timestamps, and other components of the log messages.

This is useful for local development and debugging but may need to be disabled in production environments where logs are collected by systems that may not properly handle ANSI escape sequences.

Examples:

  • --color=true - Enable colored logs (default)
  • --color=false - Disable colored logs (for environments that don't handle ANSI colors well)

Redis Configuration

--redis-url | UNKEY_REDIS_URLstring

Redis connection string for rate-limiting and distributed counters. Redis is used to maintain counters for rate limiting and other features that require distributed state.

While not strictly required, Redis is recommended for production deployments, especially when running multiple instances of the API server, to ensure consistent rate limiting.

Examples:

  • --redis-url=redis://localhost:6379/0
  • --redis-url=redis://user:password@redis.example.com:6379/0
  • --redis-url=redis://user:password@redis-master.default.svc.cluster.local:6379/0?tls=true

Deployment Examples

Single-Node

unkey api \
  --database-primary="mysql://root:password@localhost:3306/unkey?parseTime=true" \
  --color=true \
  --http-port=8080 \
  --region=dev-local

Docker Compose Setup

services:
  api:
    deploy:
      replicas: 3
      endpoint_mode: vip
    command: ["api"]
    image: ghcr.io/unkeyed/unkey:latest
    depends_on:
      - mysql
      - redis
      - clickhouse
    environment:
      UNKEY_HTTP_PORT: 7070
      UNKEY_PLATFORM: "docker"
      UNKEY_IMAGE: "ghcr.io/unkeyed/unkey:latest"
      UNKEY_REDIS_URL: "redis://redis:6379"
      UNKEY_DATABASE_PRIMARY_DSN: "mysql://unkey:password@tcp(mysql:3900)/unkey?parseTime=true"
      UNKEY_CLICKHOUSE_URL: "clickhouse://default:password@clickhouse:9000"
      UNKEY_PROMETHEUS_PORT: 9090

AWS ECS Production Example

unkey api \
  --platform="aws" \
  --region="us-east-1" \
  --image="ghcr.io/unkeyed/unkey:latest" \
  --redis-url="redis://user:password@redis.example.com:6379" \
  --database-primary="mysql://user:password@primary.mysql.example.com:3306/unkey?parseTime=true" \
  --database-readonly-replica="mysql://readonly:password@replica.mysql.example.com:3306/unkey?parseTime=true" \
  --clickhouse-url="clickhouse://user:password@clickhouse.example.com:9000/unkey" \
  --otel=true \
  --prometheus-port=9090

Last updated on

On this page