ApikeeApikeeDocs
SDKs

Node.js SDK

Protect Node.js APIs with Apikee adapters for Express, Fastify, and Hono. Configure API key validation, scoped access, and OpenAPI integration.

npm

npm install apikee

Zero dependencies — the package uses only Node built-ins.

Configure

export APIKEE_SECRET=$(openssl rand -hex 32)

# Server mode (optional)
export APIKEE_BASE_URL=https://apikee.example.com/api/v1
export APIKEE_SERVER_KEY=sk_...
export APIKEE_PROJECT_ENV=payments-api-production

Express

import express from 'express'
import { apikeeMiddleware, requireScope, injectSwagger } from 'apikee/express'
import swaggerJsdoc from 'swagger-jsdoc'
import swaggerUi from 'swagger-ui-express'

const app = express()

const spec = swaggerJsdoc({
  definition: { openapi: '3.0.0', info: { title: 'My API', version: '1.0.0' } },
  apis: ['./routes.js'],
})
injectSwagger(spec)                                    // adds 🔒 to every route
app.use('/docs', swaggerUi.serve, swaggerUi.setup(spec))

app.use(apikeeMiddleware())                            // reads APIKEE_SECRET

app.get('/v1/users', (req, res) => res.json({ tenant: req.apikee!.tenant }))
app.delete('/v1/users/:id', requireScope('admin'), handler)

apikeeMiddleware skips /health, /ready and /metrics by default. Override with excludePaths:

app.use(apikeeMiddleware({ excludePaths: new Set(['/health', '/webhooks/stripe']) }))

Fastify

import Fastify from 'fastify'
import { apikeePlugin, injectFastifySwagger } from 'apikee/fastify'

const fastify = Fastify()
await fastify.register(apikeePlugin)
injectFastifySwagger(fastify)              // optional, for @fastify/swagger

fastify.get('/v1/users', async (req) => ({ tenant: req.apikee.tenant }))

Hono (edge-ready)

import { Hono } from 'hono'
import { apikeeMiddleware, requireScope } from 'apikee/hono'

const app = new Hono()
app.use('*', apikeeMiddleware())

app.get('/v1/users', (c) => c.json({ tenant: c.get('apikee').tenant }))
app.delete('/v1/users/:id', requireScope('admin'), handler)

Any other framework

protect() verifies a header value and throws on failure, so it drops into Koa, Next.js route handlers, raw http — anywhere you can reach the request.

import { Apikee, ApikeeError } from 'apikee'

const apikee = new Apikee()

try {
  const claims = apikee.protect(req.headers['x-api-key'])
  // claims.tenant, claims.scopes, claims.environment …
} catch (err) {
  if (err instanceof ApikeeError) {
    return res.status(401).json({ error: err.code, message: err.message })
  }
  throw err
}

Issuing keys

const key = apikee.create({
  tenant: 'acme',
  scopes: ['read:users', 'write:orders'],
  expiresIn: '90d',                 // or a Date, or milliseconds
  meta: { plan: 'partner' },
})
// apikee_… — returned once

Describing endpoints

apikee.describeEndpoint('GET', '/v1/users', {
  description: "List users in the caller's tenant.",
  scopes: ['read:users'],
  tags: ['users'],
})

No-op in local mode. See Endpoints.

Server client

For creating clients and keys against the platform directly:

import { ApikeeServer } from 'apikee'

const server = new ApikeeServer({
  baseUrl: process.env.APIKEE_BASE_URL!,
  serverKey: process.env.APIKEE_SERVER_KEY!,
  projectEnv: 'payments-api-production',
})

await server.createClientWithKey({
  name: 'Acme mobile app',
  clientType: 'company',
  expiresAt: new Date('2027-01-01'),
})

Options

new Apikee({
  secrets: [process.env.APIKEE_SECRET!],   // array enables rotation
  headerName: 'x-api-key',
  failOpen: true,
  baseUrl: process.env.APIKEE_BASE_URL,
  serverKey: process.env.APIKEE_SERVER_KEY,
  projectEnv: process.env.APIKEE_PROJECT_ENV,
  serverPublicKey: process.env.APIKEE_SERVER_PUBLIC_KEY,
})

Full table in the SDK overview.

On this page