> ## Documentation Index
> Fetch the complete documentation index at: https://docs.satsuma.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Secure API authentication using API keys

## Overview

The Satsuma API uses API key authentication for secure access to all endpoints. This guide covers how to obtain, configure, and use your API keys properly.

## API Key Management

### Getting Your API Key

<Steps>
  <Step title="Create Account">
    Sign up at [dashboard.satsuma.ai](https://dashboard.satsuma.ai) for your developer account
  </Step>

  <Step title="Generate API Key">
    Navigate to the API Keys section and click "Generate New Key"
  </Step>

  <Step title="Configure Key">
    Configure your API key settings as needed
  </Step>

  <Step title="Copy and Store">
    Copy your API key and store it securely - it won't be shown again
  </Step>
</Steps>

<Warning>
  API keys provide access to your account and should be treated like passwords. Never commit them to version control or expose them in client-side code.
</Warning>

## Authentication Methods

### Header-based Authentication

Include your API key in the `Authorization` header for all requests:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET 'https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194' \
    -H 'Authorization: sk_live_abcd1234567890'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194', {
    headers: {
      'Authorization': 'sk_live_abcd1234567890'
    }
  });
  ```

  ```python Python theme={null}
  import requests

  headers = {
      'Authorization': 'sk_live_abcd1234567890'
  }

  response = requests.get(
      'https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194',
      headers=headers
  )
  ```

  ```java Java theme={null}
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.net.URI;

  HttpClient client = HttpClient.newHttpClient();
  HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194"))
      .header("Authorization", "sk_live_abcd1234567890")
      .GET()
      .build();

  HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
  ```
</CodeGroup>

## Environment Configuration

### Development vs Production

Use different API keys for development and production environments:

<CodeGroup>
  ```javascript .env theme={null}
  # Development
  SATSUMA_API_KEY=sk_test_1234567890abcdef
  SATSUMA_BASE_URL=https://api-staging.satsuma.ai

  # Production  
  SATSUMA_API_KEY=sk_live_abcd1234567890
  SATSUMA_BASE_URL=https://api.satsuma.ai
  ```

  ```python config.py theme={null}
  import os

  class Config:
      SATSUMA_API_KEY = os.environ.get('SATSUMA_API_KEY')
      SATSUMA_BASE_URL = os.environ.get('SATSUMA_BASE_URL', 'https://api.satsuma.ai')
      
      @property
      def is_production(self):
          return self.SATSUMA_API_KEY.startswith('sk_live_')
  ```

  ```java Config.java theme={null}
  import java.util.Optional;

  public class Config {
      private final String apiKey;
      private final String baseUrl;
      
      public Config() {
          this.apiKey = System.getenv("SATSUMA_API_KEY");
          this.baseUrl = getEnv("SATSUMA_BASE_URL", "https://api.satsuma.ai");
      }
      
      public String getApiKey() {
          return apiKey;
      }
      
      public String getBaseUrl() {
          return baseUrl;
      }
      
      public boolean isProduction() {
          return apiKey != null && apiKey.startsWith("sk_live_");
      }
      
      private String getEnv(String key, String fallback) {
          return Optional.ofNullable(System.getenv(key))
                        .filter(value -> !value.isEmpty())
                        .orElse(fallback);
      }
  }
  ```
</CodeGroup>

## SDK Authentication

### JavaScript/Node.js SDK

```javascript theme={null}
import { SatsumaClient } from '@satsuma/sdk';

const client = new SatsumaClient({
  apiKey: process.env.SATSUMA_API_KEY,
  environment: 'production' // or 'staging'
});

// SDK handles authentication automatically
const products = await client.products.search({
  query: 'coffee',
  latitude: 37.7749,
  longitude: -122.4194,
  distance: '10mi'
});
```

### Python SDK

```python theme={null}
from satsuma import Client

client = Client(
    api_key=os.environ['SATSUMA_API_KEY'],
    environment='production'  # or 'staging'
)

# SDK handles authentication automatically
products = client.products.search(
    query='coffee',
    latitude=37.7749,
    longitude=-122.4194,
    distance='10mi'
)
```

## Security Best Practices

### API Key Storage

<AccordionGroup>
  <Accordion title="Environment Variables">
    Store API keys in environment variables, never in code:

    ```bash theme={null}
    export SATSUMA_API_KEY=sk_live_abcd1234567890
    ```
  </Accordion>

  <Accordion title="Secret Management Services">
    Use services like AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault:

    ```javascript theme={null}
    const AWS = require('aws-sdk');
    const secretsManager = new AWS.SecretsManager();

    const secret = await secretsManager.getSecretValue({
      SecretId: 'satsuma-api-key'
    }).promise();
    ```
  </Accordion>

  <Accordion title="Configuration Files">
    If using config files, ensure they're not committed to version control:

    ```gitignore theme={null}
    # .gitignore
    config/secrets.json
    .env
    *.key
    ```
  </Accordion>
</AccordionGroup>

### Network Security

* Always use HTTPS endpoints (http\:// requests will be rejected)
* Implement proper certificate validation
* Use connection timeouts and retry logic
* Consider IP allowlisting for production environments

### Key Rotation

<Steps>
  <Step title="Generate New Key">
    Create a new API key with the same settings as your current key
  </Step>

  <Step title="Update Applications">
    Deploy the new key to all applications and services
  </Step>

  <Step title="Verify Operation">
    Confirm all services are working with the new key
  </Step>

  <Step title="Revoke Old Key">
    Delete the old API key from your dashboard
  </Step>
</Steps>

## Error Handling

### Authentication Errors

Handle authentication failures gracefully:

<CodeGroup>
  ```javascript JavaScript theme={null}
  try {
    const response = await fetch('https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194', {
      headers: { 'Authentication': apiKey }
    });

    if (response.status === 401) {
      throw new Error('Invalid or expired API key');
    }
    
    if (response.status === 403) {
      throw new Error('Insufficient permissions for this operation');
    }

  } catch (error) {
    console.error('Authentication failed:', error.message);
  }
  ```

  ```python Python theme={null}
  import requests
  from requests.exceptions import HTTPError

  try:
      response = requests.get(
          'https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194',
          headers={'Authorization': api_key}
      )
      response.raise_for_status()

  except HTTPError as e:
      if response.status_code == 401:
          print("Invalid or expired API key")
      elif response.status_code == 403:
          print("Insufficient permissions for this operation")
      else:
          print(f"Authentication error: {e}")
  ```

  ```java Java theme={null}
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;
  import java.net.URI;

  try {
      HttpClient client = HttpClient.newHttpClient();
      HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create("https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194"))
          .header("Authorization", apiKey)
          .GET()
          .build();

      HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
      
      if (response.statusCode() == 401) {
          throw new RuntimeException("Invalid or expired API key");
      }
      
      if (response.statusCode() == 403) {
          throw new RuntimeException("Insufficient permissions for this operation");
      }

  } catch (Exception e) {
      System.err.println("Authentication failed: " + e.getMessage());
  }
  ```
</CodeGroup>

### Rate Limiting

Implement proper backoff when hitting rate limits:

```javascript theme={null}
async function makeRequestWithBackoff(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);
    
    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      continue;
    }
    
    return response;
  }
  
  throw new Error('Max retries exceeded');
}
```

## Testing Authentication

### API Key Validation

Test your API key setup with a simple request:

```bash theme={null}
curl -X GET 'https://api.satsuma.ai/product?latitude=37.7749&longitude=-122.4194' \
  -H 'Authorization: your-api-key-here' \
  -w "Status: %{http_code}\n"
```

### Endpoint Testing

Verify your API key works with different endpoints:

```javascript theme={null}
const testEndpoints = async (apiKey) => {
  const tests = [
    { endpoint: '/product?latitude=37.7749&longitude=-122.4194', description: 'Product search' },
    { endpoint: '/cart', method: 'POST', description: 'Cart management' },
    { endpoint: '/order', method: 'POST', description: 'Order placement' }
  ];

  for (const test of tests) {
    try {
      const response = await fetch(`https://api.satsuma.ai${test.endpoint}`, {
        method: test.method || 'GET',
        headers: { 'Authorization': apiKey }
      });
      
      console.log(`${test.description}: ${response.status === 403 ? 'Access Denied' : 'OK'}`);
    } catch (error) {
      console.log(`${test.description}: ERROR - ${error.message}`);
    }
  }
};
```

## Need Help?

If you're having trouble with authentication:

* Check your API key format and ensure it's not truncated
* Verify you're using the correct environment (staging vs production)
* Confirm your key has the required permissions for your use case
* Review the [Error Handling](/integration/error-handling) guide for common issues
* Contact [support@satsuma.ai](mailto:support@satsuma.ai) for assistance
