Files
routstr-core/docs/api/authentication.md
T
thefux 47807ae92e Remove child key feature and balance limits completely
Removes the child-key (shared parent balance) feature and the
balance-limit machinery from the entire stack:

Backend:
- Drop POST /v1/balance/child-key and /v1/balance/child-key/reset
- Remove parent-key billing indirection (get_billing_key); every key
  is charged directly
- Remove balance_limit/balance_limit_reset enforcement, reset
  policies, and the periodic limit-reset background task
- Remove child-key guards on refund/history endpoints
- Remove child_key_cost setting and /v1/info child_key_cost_msats
- Remove balance_limit fields from LightningInvoice model and
  invoice-creation API
- Admin balances API returns plain sums (no parent/child split)

Migration (e5a6b7c8d9f0):
- Nulls parent_key_hash on children (they become standalone keys;
  parents keep 100% of their balance, so no funds are lost)
- Drops parent_key_hash + balance_limit columns from api_keys and
  balance_limit columns from lightning_invoices
- Verified: upgrade, downgrade, and fund preservation round-trip

UI:
- Remove child-key creator, child key panels, balance-limit inputs
- Key options now offer validity date only
- Temporary balances table renders all keys uniformly

Tests: child-key suites removed; remaining suites converted to
single-key semantics (441 integration + 1313 unit tests pass).
Docs updated accordingly.
2026-09-03 11:33:39 +00:00

7.6 KiB

Authentication

Routstr uses API key authentication for all protected endpoints. This guide covers how to create, use, and manage API keys.

API Key Creation

From eCash Token

Create an API key by depositing an eCash token:

Note: The POST /v1/wallet/create endpoint is coming soon. Currently, you can use Cashu tokens directly as API credentials in the Authorization header. The token is hashed on the server, and the hash acts as an API key with the token's balance.

POST /v1/wallet/create
Content-Type: application/json

{
  "cashu_token": "cashuAeyJ0b2tlbiI6W3sibWludCI6Imh0dHBzOi8vbWlu..."
}

Request Parameters:

Field Type Required Description
cashu_token string Yes Base64-encoded Cashu token

Response:

{
  "api_key": "sk-1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p",
  "balance": 10000,
  "created_at": "2024-01-01T00:00:00Z",
  "key_id": "key_123456"
}

From Lightning Invoice (Coming Soon)

POST /v1/wallet/create/lightning
Content-Type: application/json

{
  "amount_sats": 10000,
  "name": "Lightning Key"
}

Response includes Lightning invoice for payment.

Using API Keys

Header Authentication

Include the API key in the Authorization header:

curl https://your-node.com/v1/chat/completions \
  -H "Authorization: Bearer sk-1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-3.5-turbo","messages":[{"role":"user","content":"Hello"}]}'

For tools that don't support headers:

GET /v1/models?api_key=sk-1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p

⚠️ Warning: Query parameters may be logged. Use headers when possible.

Key Management

Check Balance

Get current balance and usage statistics:

GET /v1/wallet/balance
Authorization: Bearer sk-...

Response:
{
  "balance": 8546,
  "total_deposited": 10000,
  "total_spent": 1454,
  "last_used": "2024-01-01T12:34:56Z",
  "created_at": "2024-01-01T00:00:00Z",
  "expires_at": null,
  "key_info": {
    "name": "Production Key",
    "key_id": "key_123456"
  }
}

Top Up Balance

Add funds to existing key:

POST /v1/wallet/topup
Authorization: Bearer sk-...
Content-Type: application/json

{
  "cashu_token": "cashuAeyJ0b2tlbiI6W3..."
}

Response:
{
  "old_balance": 8546,
  "added_amount": 5000,
  "new_balance": 13546,
  "transaction_id": "txn_789"
}

List Transactions

View transaction history:

GET /v1/wallet/transactions?limit=10
Authorization: Bearer sk-...

Response:
{
  "transactions": [
    {
      "id": "txn_123",
      "type": "usage",
      "amount": -154,
      "balance_after": 8546,
      "description": "gpt-3.5-turbo: 50 prompt + 150 completion tokens",
      "timestamp": "2024-01-01T12:34:56Z"
    },
    {
      "id": "txn_122",
      "type": "deposit",
      "amount": 10000,
      "balance_after": 10000,
      "description": "Initial deposit",
      "timestamp": "2024-01-01T00:00:00Z"
    }
  ],
  "has_more": false,
  "total": 2
}

Security Best Practices

API Key Storage

Do:

  • Store keys in environment variables
  • Use secret management systems
  • Encrypt keys at rest
  • Implement key rotation

Don't:

  • Commit keys to version control
  • Share keys between environments
  • Log keys in plain text
  • Expose keys in client-side code

Environment Variables

# .env file
ROUTSTR_API_KEY=sk-1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p
ROUTSTR_BASE_URL=https://your-node.com/v1

# Usage in code
import os
api_key = os.getenv("ROUTSTR_API_KEY")

Key Rotation

Regularly rotate API keys:

# 1. Create new key
new_key = create_api_key(balance=old_key_balance)

# 2. Update applications
update_environment_variable("ROUTSTR_API_KEY", new_key)

# 3. Test new key
test_api_connection(new_key)

# 4. Withdraw old key balance
withdraw_balance(old_key)

Authentication Errors

Invalid API Key

{
  "error": {
    "type": "authentication_failed",
    "message": "Invalid API key",
    "code": "invalid_api_key"
  }
}

Status Code: 401

Common Causes:

  • Typo in API key
  • Key doesn't exist
  • Key has been deleted

Expired API Key

{
  "error": {
    "type": "authentication_failed",
    "message": "API key has expired",
    "code": "key_expired",
    "details": {
      "expired_at": "2024-01-01T00:00:00Z"
    }
  }
}

Status Code: 401

Resolution:

  • Create a new API key
  • Contact admin if refund address was set

Insufficient Balance

{
  "error": {
    "type": "insufficient_balance",
    "message": "Insufficient balance for request",
    "code": "payment_required",
    "details": {
      "balance": 100,
      "required": 154,
      "shortfall": 54
    }
  }
}

Status Code: 402

Resolution:

  • Top up the API key balance
  • Use a more economical model
  • Optimize request parameters

Advanced Authentication

Per-Request Tokens (Coming Soon)

Pay per request without maintaining a balance:

curl https://your-node.com/v1/chat/completions \
  -H "X-Cashu: cashuAeyJ0b2tlbiI6W3..." \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-3.5-turbo","messages":[...]}'

Response includes change:

X-Cashu: cashuAeyJjaGFuZ2UiOlt7...

Multi-Key Authentication

Use multiple keys for different purposes:

# Production key for main app
PROD_KEY = os.getenv("ROUTSTR_PROD_KEY")

# Development key for testing
DEV_KEY = os.getenv("ROUTSTR_DEV_KEY")

# Analytics key with restricted permissions
ANALYTICS_KEY = os.getenv("ROUTSTR_ANALYTICS_KEY")

# Choose key based on environment
api_key = PROD_KEY if is_production() else DEV_KEY

Rate Limiting

Rate limits are applied per API key:

Default Limits

Metric Limit Window
Requests 1000 1 minute
Tokens 1,000,000 1 hour
Concurrent 10 -

Rate Limit Headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
X-RateLimit-Type: requests_per_minute

Handling Rate Limits

import time
from typing import Optional

def make_request_with_retry(
    client,
    max_retries: int = 3
) -> Optional[Response]:
    for attempt in range(max_retries):
        try:
            response = client.chat.completions.create(...)
            return response
        except RateLimitError as e:
            if attempt < max_retries - 1:
                # Extract retry-after from error
                retry_after = e.retry_after or 60
                print(f"Rate limited. Waiting {retry_after}s...")
                time.sleep(retry_after)
            else:
                raise

IP Whitelisting

Restrict API key usage by IP:

POST /v1/wallet/update
Authorization: Bearer sk-...
Content-Type: application/json

{
  "allowed_ips": [
    "192.168.1.100",
    "10.0.0.0/24"
  ]
}

Monitoring

Usage Alerts

Set up usage notifications:

POST /v1/wallet/alerts
Authorization: Bearer sk-...
Content-Type: application/json

{
  "low_balance_threshold": 1000,
  "daily_spend_limit": 5000,
  "webhook_url": "https://your-app.com/webhook"
}

Audit Logging

All API key usage is logged:

{
  "timestamp": "2024-01-01T12:34:56Z",
  "api_key_id": "key_123456",
  "endpoint": "/v1/chat/completions",
  "method": "POST",
  "ip_address": "192.168.1.100",
  "user_agent": "OpenAI-Python/1.0",
  "cost_sats": 154,
  "response_status": 200
}

Next Steps