Security Bearer Auth TLS 1.3

API Authentication

Every LumiID request is authenticated with your Secret Key — a private bearer token passed in the Authorization header. One header is all it takes to access Nigeria's sovereign identity rails.

Key Rotation Required

Legacy keys from the v1 system will be deprecated on 30 June 2025. Rotate your credentials →

Start authenticating right now

Copy these two headers, swap in your key, and your first verified request is ready to send. That's the entire auth contract — no OAuth flows, no token exchange, no expiry timers.

Request Headers
Authorization:  LUMI_SANDBOX_SK_xxxxxxxxxxxxxxxx
Content-Type:   application/json

How authentication works

LumiID uses a single Secret Key passed as a bearer token in the Authorization header. This key both identifies your account and authorises access — keep it private, rotate it regularly, and never expose it in client-side code.

Header name

Authorization
Private

Your secret API key. Authenticates your account and authorises every request. Treat this like a password — never log it, never expose it client-side.

LUMI_SANDBOX_SK_b7e2c9d1f4a8e3b6…
  • Required on every request
  • Server-side only — never in browsers
  • Never commit to version control
  • Rotate immediately if compromised
  • Different values for Sandbox / Live

Full request examples

Here's a complete authenticated NIN verification call across every major language.

cURL
curl --request GET \
  'https://api.lumiid.com/v1/kyc/nin?nin=12345678901' \
  --header 'Authorization: LUMI_SANDBOX_SK_xxxxxxxxxxxx' \
  --header 'Content-Type: application/json'
Python
import requests, os

headers = {
    "Authorization": os.getenv("LUMIID_SECRET_KEY"),
    "Content-Type":  "application/json",
}

response = requests.get(
    "https://api.lumiid.com/v1/kyc/nin",
    headers=headers,
    params={"nin": "12345678901"},
)

print(response.json())
Node.js
const axios = require('axios');

const response = await axios.get(
  'https://api.lumiid.com/v1/kyc/nin',
  {
    params:  { nin: '12345678901' },
    headers: {
      'Authorization': process.env.LUMIID_SECRET_KEY,
      'Content-Type':  'application/json',
    },
  }
);

console.log(response.data);
PHP
<?php
$ch = curl_init('https://api.lumiid.com/v1/kyc/nin?nin=12345678901');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        "Authorization: ". getenv('LUMIID_SECRET_KEY'),
        "Content-Type: application/json",
    ],
]);
$data = json_decode(curl_exec($ch), true);
var_dump($data);
Go
package main

import (
    "fmt"
    "net/http"
    "os"
)

func main() {
    req, _ := http.NewRequest(
        "GET",
        "https://api.lumiid.com/v1/kyc/nin?nin=12345678901",
        nil,
    )
    req.Header.Set("Authorization", os.Getenv("LUMIID_SECRET_KEY"))
    req.Header.Set("Content-Type",  "application/json")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    fmt.Println(resp.Status)
}

Test your credentials live

Paste your Sandbox key below to run a live authentication check directly from this page. Nothing is stored — your key is used only for this single request.


        

Credentials entered here are sent directly to api.lumiid.com and are never stored or logged by this documentation page.

Authentication error reference

Every auth failure returns a machine-readable JSON error body alongside the HTTP status. Here's every code you'll encounter and exactly how to fix it.

Status Error What it means & how to fix it
401 Unauthorized

Missing, malformed, or incorrect Authorization key. Check that the header is present and exactly as copied from the dashboard.

Fix: re-copy your key from API Settings
401 wrong_env_key

You're using a Sandbox key against a Live endpoint (or vice versa). Key prefixes must match the environment.

Fix: use LUMI_SANDBOX_SK_* for sandbox; LUMI_LIVE_SK_* for production
403 Forbidden

Your credentials are valid, but your account doesn't have permission for this specific endpoint or service tier.

Fix: enable the service in Dashboard → Services
403 ip_not_whitelisted

IP Whitelisting is enabled on your account but the request originated from an unlisted IP address.

Fix: add your server IP in Settings → IP Whitelist
429 rate_limit_exceeded

You've exceeded the request limit for your plan. The Retry-After header tells you exactly how many seconds to wait.

Fix: wait Retry-After seconds, or upgrade your plan
401 Unauthorized — response body
{
  "error":       "Unauthorized",
  "message":     "Invalid or missing API credentials",
  "status_code": 401
}

Rate limits

Limits apply per API key per rolling 60-second window. The response headers tell you exactly where you stand after every call.

Sandbox

100 req/min

Free · simulated data

Starter

500 req/min

Live data · pay per call

Growth

2 000 req/min

Volume discounts

Enterprise

Custom

SLA + dedicated infra

Rate-limit headers on every response
X-RateLimit-Limit:     500        # your plan's limit per minute
X-RateLimit-Remaining: 487        # requests left this window
X-RateLimit-Reset:     1717200060 # Unix timestamp when window resets
Retry-After:           34         # seconds to wait (only on 429s)

Security guardrails

Follow these practices to keep your integration bulletproof in production.

Use environment variables

Store your key in .env files locally and your platform's secrets manager (AWS Secrets Manager, Vercel env vars, etc.) in production. Never hardcode.

Rotate keys every 90 days

Generate a new key in the dashboard, deploy it, then revoke the old one. Zero downtime if you stage the rollout.

Enable IP Whitelisting

Lock your Live key to your server's static IP addresses. Even a leaked key is useless without a matching IP.

Never call from browsers or mobile apps

Always proxy LumiID requests through your own backend. Your Secret Key must never appear in client-side code, network logs, or mobile bundles.

Monitor 401 spikes

A sudden spike in 401 responses can signal a misconfiguration or a credential leak. Alert on them internally.

Add .env to .gitignore

A single accidental commit can expose your key to your entire team and public repos. Add it before you write your first line of code.