This guide covers rate limiting functionality including namespace creation, override management, and rate limit checking.

Overview

Rate limiting endpoints manage request limits, overrides, and namespace-based rate limiting across your API infrastructure.

Key Changes in v2:

  • Response format: result{meta, data} wrapper
  • Rate limit structure: Single ratelimit object → ratelimits array with named limits
  • Override management: Enhanced override response format with additional metadata
  • Async handling: Improved autoApply parameter (formerly async)

Migration Impact:

  • Existing in v1: Full rate limiting and override management functionality
  • Enhanced in v2: Improved response format, better override metadata, and new listing capabilities
  • Maintained in v2: All core rate limiting functionality with backward-compatible request formats

Rate Limit Checking

POST /v1/ratelimits.limit → POST /v2/ratelimits.limit

Key Changes:
  • Response format: Direct response → {meta, data} envelope
  • Enhanced response with additional metadata
  • Better override handling
Rate Limit Request
{
  "namespace": "email_sending",
  "identifier": "user_123",
  "limit": 100,
  "duration": 3600000,
  "cost": 1
}

Rate Limit Overrides

POST /v1/ratelimits.setOverride → POST /v2/ratelimits.setOverride

Key Changes:
  • Response format: Direct response → {meta, data} envelope
  • Enhanced override targeting options
  • Better validation and error handling
Set Override Request
{
  "namespace": "api_requests",
  "identifier": "premium_user_456",
  "limit": 10000,
  "duration": 3600000,
  "async": false
}

GET /v1/ratelimits.getOverride → POST /v2/ratelimits.getOverride

Key Changes:
  • HTTP method: GET → POST
  • Request format: Query parameters → Request body
  • Response format: Direct response → {meta, data} envelope
Get Override Request
{
  "namespace": "api_requests",
  "identifier": "premium_user_456"
}
Get Override Response Diff
// v1 Response (direct response)
{
  "id": "over_123", 
  "identifier": "premium_user_456", 
  "limit": 10000, 
  "duration": 3600000, 
  "async": false
}

// v2 Response
{
  "meta": { 
    "requestId": "req_getoverride789"
  }, 
  "data": { 
    "overrideId": "override_abc123", 
    "namespace": "api_requests", 
    "identifier": "premium_user_456", 
    "limit": 10000, 
    "duration": 3600000, 
    "async": false, 
    "createdAt": "2024-01-15T10:30:00Z"
  } 
}

GET /v1/ratelimits.listOverrides → POST /v2/ratelimits.listOverrides

Purpose: Get paginated list of all overrides in a namespace. Key Changes:
  • HTTP method: GET → POST
  • Request format: Query parameters → Request body
  • Response format: Direct response → {meta, data} envelope
List Overrides Request
{
  "namespace": "api_requests",
  "limit": 100,
  "cursor": "optional_cursor"
}

POST /v1/ratelimits.deleteOverride → POST /v2/ratelimits.deleteOverride

Key Changes:
  • Response format: Direct response → {meta, data} envelope
Delete Override Request
{
  "namespace": "api_requests",
  "identifier": "premium_user_456"
}
Delete Override Response Diff
// v1 Response (direct empty response)
{} 

// v2 Response
{
  "meta": { 
    "requestId": "req_deleteoverride999"
  }, 
  "data": {} 
}

Key-Level Rate Limiting Changes

v1 Single Rate Limit → v2 Multiple Named Rate Limits

Key Rate Limit Structure Migration
// v1 Key Creation
{
  "apiId": "api_123",
  "ratelimit": { 
    "limit": 1000, 
    "duration": 3600000, 
    "async": true
  } 
}

// v2 Key Creation
{
  "apiId": "api_123",
  "ratelimits": [ 
    { 
      "name": "api_requests", 
      "limit": 1000, 
      "duration": 3600000, 
      "autoApply": true
    }, 
    { 
      "name": "heavy_operations", 
      "limit": 10, 
      "duration": 60000, 
      "autoApply": false
    } 
  ] 
}

Migration Patterns

Response Format Migration

v1 vs v2: Response Handling
// v1: Direct response access
const rateLimit = await fetch('/v1/ratelimits.limit', { 
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <root-key>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    namespace: 'api_calls',
    identifier: 'user_123',
    limit: 100,
    duration: 3600000
  })
});

const data = await rateLimit.json(); 
const success = data.success; // v1 direct format
const remaining = data.remaining; 

// v2: Access data through data field
const rateLimit = await fetch('/v2/ratelimits.limit', { 
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <root-key>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    namespace: 'api_calls',
    identifier: 'user_123',
    limit: 100,
    duration: 3600000
  })
});

const response = await rateLimit.json(); 
const success = response.data.success; // v2 format
const remaining = response.data.remaining; 
const requestId = response.meta.requestId; // for debugging

Key-Level Rate Limiting Migration

v1 vs v2: Key Rate Limit Structure
// v1: Single Rate Limit
{
  "apiId": "api_123",
  "ratelimit": { 
    "limit": 1000, 
    "duration": 3600000, 
    "async": true
  } 
}

// v2: Multiple Named Rate Limits
{
  "apiId": "api_123",
  "ratelimits": [ 
    { 
      "name": "general_requests", 
      "limit": 1000, 
      "duration": 3600000, 
      "autoApply": true
    }, 
    { 
      "name": "expensive_ops", 
      "limit": 10, 
      "duration": 60000, 
      "autoApply": false
    } 
  ] 
}

Override Management Patterns

Override CRUD Operations
// Set override (same in v1 & v2)
const override = await fetch('/v2/ratelimits.setOverride', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <root-key>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    namespace: 'api_requests',
    identifier: 'premium_user',
    limit: 10000,
    duration: 3600000
  })
});

// Get override (same in v1 & v2)
const existing = await fetch('/v2/ratelimits.getOverride', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <root-key>',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    namespace: 'api_requests',
    identifier: 'premium_user'
  })
});

const result = await existing.json();
const limit = result.data.limit; // v2: access via data

Advanced Features in v2

Multiple Rate Limits per Key

Complex rate limiting setup
{
  "apiId": "api_123",
  "ratelimits": [
    {
      "name": "requests_per_minute",
      "limit": 60,
      "duration": 60000,
      "autoApply": true
    },
    {
      "name": "requests_per_hour",
      "limit": 1000,
      "duration": 3600000,
      "autoApply": true
    },
    {
      "name": "expensive_operations",
      "limit": 5,
      "duration": 300000,
      "autoApply": false
    }
  ]
}

Named Rate Limit Targeting

Selective rate limit application
{
  "key": "sk_123",
  "ratelimits": [
    {
      "name": "expensive_operations",
      "cost": 1
    }
  ]
}
Only applies cost to the “expensive_operations” rate limit, leaving others unchanged.

Batch Override Management

Managing multiple overrides
// List all overrides in namespace
const overrides = await unkey.ratelimits.listOverrides({
  namespace: "api_requests"
});

// Process overrides in batches
for (const override of overrides.data?.overrides || []) {
  if (override.limit < 1000) {
    // Update low-limit overrides
    await unkey.ratelimits.setOverride({
      namespace: override.namespace,
      identifier: override.identifier,
      limit: 1000,
      duration: override.duration
    });
  }
}

Migration Checklist

Response Format Updates

  • Change direct response access to response.data in all rate limiting calls
  • Extract and log meta.requestId from responses for debugging
  • Update error handling for new envelope response structure
  • Handle enhanced metadata in override responses

Key-Level Rate Limiting Updates

  • Convert ratelimit object to ratelimits array in key creation
  • Add name field to all rate limit configurations
  • Change async parameter to autoApply
  • Plan for multiple rate limits per key (different operation types)
  • Update key verification to handle multiple rate limits

Override Management Updates

  • Update override response parsing from result to data
  • Utilize new listOverrides endpoint for enhanced management
  • Handle enhanced override metadata (overrideId, createdAt)
  • Implement cursor-based pagination for large override lists

Enhanced Features

  • Implement named rate limit targeting in key verification
  • Use multiple rate limits for different operation types
  • Set up batch override management processes using listOverrides
  • Plan for granular rate limit control and monitoring
  • Use request IDs for debugging and support

Advanced Rate Limiting Patterns

  • Implement selective rate limit application by name
  • Set up different costs for different rate limits
  • Use identity-level rate limiting combined with key-level limits
  • Build override management dashboards with enhanced data

Testing

  • Test rate limiting with new response format
  • Verify override creation, retrieval, and deletion
  • Test multiple rate limits on single keys
  • Validate named rate limit targeting in key verification
  • Confirm override listing and pagination works correctly
  • Test batch override management workflows