Learn how to properly authenticate with the Crave.js API, manage API keys, and implement security best practices for your restaurant ordering system.

API Key Management

Location API Keys

Each restaurant location has its own API key for accessing the public API endpoints. These keys are provided when your location is set up through the Crave merchant dashboard. Your location credentials will be provided in this format:
{
  "id": "65f1a2b3c4d5e6f7a8b9c0d1",
  "name": "Downtown Bistro",
  "slug": "downtown-bistro",
  "apiKey": "crave_live_sk_1234567890abcdef",
  "status": "active"
}

API Access Tiers

The Crave API has different access levels:
API TypeSubscription RequiredFeatures Included
Storefront APIsAny paid Crave subscriptionMenu browsing, cart management, payment processing, basic customer data
Admin APIsEnterprise tier onlyOrder management, menu editing, analytics, webhooks
Contact hello@craveup.com for location setup and API key provisioning.

Authentication Methods

1. API Key Header

The most common method for public API access:
curl -X GET https://api.cravejs.com/api/v1/locations/downtown-bistro/menu \
  -H "X-API-Key: crave_live_sk_1234567890abcdef"

2. JavaScript/React Integration

const API_BASE = 'https://api.cravejs.com/api/v1';
const API_KEY = 'your_api_key_here';

const apiClient = {
  async request(endpoint, options = {}) {
    const response = await fetch(`${API_BASE}${endpoint}`, {
      ...options,
      headers: {
        'X-API-Key': API_KEY,
        'Content-Type': 'application/json',
        ...options.headers
      }
    });
    
    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }
    
    return response.json();
  }
};

// Usage
const menu = await apiClient.request('/locations/downtown-bistro/menu');
const cart = await apiClient.request('/locations/downtown-bistro/carts', {
  method: 'POST',
  body: JSON.stringify({ marketplaceId: 'stripe' })
});

3. Environment Variables

Store API keys securely using environment variables:
# .env.local
CRAVE_API_KEY=crave_live_sk_1234567890abcdef
CRAVE_API_BASE_URL=https://api.cravejs.com
// Next.js example
const createCart = async () => {
  const response = await fetch(`${process.env.CRAVE_API_BASE_URL}/api/v1/locations/downtown-bistro/carts`, {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.CRAVE_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ marketplaceId: 'stripe' })
  });
  
  return response.json();
};

Rate Limiting

The Crave.js API implements rate limiting to ensure fair usage and system stability:

Default Limits

  • Limit: 200 requests per 10 minutes per IP address
  • Headers:
    • X-RateLimit-Remaining: Requests remaining in current window
    • X-RateLimit-Reset: When the rate limit resets (Unix timestamp)
  • Exceeded: Returns 429 status with retry information

Rate Limit Headers

Every API response includes rate limit information:
HTTP/1.1 200 OK
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 187
X-RateLimit-Reset: 1640995200
X-RateLimit-Retry-After: 60

Handling Rate Limits

async function apiRequestWithRetry(endpoint, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(endpoint, options);
      
      if (response.status === 429) {
        const retryAfter = response.headers.get('X-RateLimit-Retry-After');
        if (attempt < maxRetries) {
          await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
          continue;
        }
      }
      
      return response;
    } catch (error) {
      if (attempt === maxRetries) throw error;
    }
  }
}

Security Best Practices

1. API Key Security

Do’s:
  • Store API keys in environment variables
  • Use different keys for development/staging/production
  • Rotate keys regularly
  • Monitor API key usage
Don’ts:
  • Never commit API keys to version control
  • Don’t expose API keys in client-side code
  • Avoid hardcoding keys in your application
  • Don’t share keys across different environments

2. CORS Configuration

Configure CORS properly for frontend integration:
// Example CORS configuration
const corsOptions = {
  origin: ['https://yourrestaurant.com', 'http://localhost:3000'],
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'X-API-Key']
};

3. HTTPS in Production

Always use HTTPS in production:
# Production API base
CRAVE_API_BASE=https://api.yourrestaurant.com/api/v1

4. Input Validation

Validate all inputs on both client and server:
const addToCart = async (cartId, productId, quantity) => {
  // Validate inputs
  if (!cartId || !productId || quantity < 1) {
    throw new Error('Invalid input parameters');
  }
  
  // Sanitize quantity
  const sanitizedQuantity = Math.max(1, Math.min(99, parseInt(quantity)));
  
  return apiClient.request(`/locations/downtown-bistro/carts/${cartId}/cart-item`, {
    method: 'POST',
    body: JSON.stringify({ 
      id: productId, 
      quantity: sanitizedQuantity 
    })
  });
};

Error Handling

Common Error Codes

CodeDescriptionAction
401Invalid API keyCheck API key validity
403Insufficient permissionsVerify endpoint access
429Rate limit exceededImplement retry logic
500Server errorCheck API status

Error Response Format

{
  "error": {
    "code": "INVALID_API_KEY",
    "message": "The provided API key is invalid or expired",
    "details": {
      "timestamp": "2024-01-15T10:30:00Z",
      "requestId": "req_1234567890"
    }
  }
}

Comprehensive Error Handling

class CraveAPIError extends Error {
  constructor(response, data) {
    super(data.error?.message || 'API request failed');
    this.status = response.status;
    this.code = data.error?.code;
    this.requestId = data.error?.details?.requestId;
  }
}

const apiClient = {
  async request(endpoint, options = {}) {
    try {
      const response = await fetch(`${API_BASE}${endpoint}`, {
        ...options,
        headers: {
          'X-API-Key': API_KEY,
          'Content-Type': 'application/json',
          ...options.headers
        }
      });
      
      const data = await response.json();
      
      if (!response.ok) {
        throw new CraveAPIError(response, data);
      }
      
      return data;
    } catch (error) {
      if (error instanceof CraveAPIError) {
        throw error;
      }
      throw new Error(`Network error: ${error.message}`);
    }
  }
};

Next Steps