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

# Security

Implementing proper security practices is crucial when working with the Dakota Platform API. Follow these guidelines to keep your integration secure.

# API Key Management

## Store Keys Securely

**Never expose API keys in your code:**

```javascript Bad Example theme={null}
// ❌ Never do this
const apiKey = 'AHGlPZaxDSMz8Wf1l8VRH4ObdbHiKsWFWnmRyHtiwAc=';
```

**Use environment variables instead:**

```bash cURL theme={null}
# Use environment variable in shell scripts
curl -X GET https://api.platform.dakota.xyz/customers \
  -H "X-API-Key: $DAKOTA_API_KEY"
```

```javascript JavaScript theme={null}
// ✅ Use environment variables
const apiKey = process.env.DAKOTA_API_KEY;
```

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

api_key = os.getenv('DAKOTA_API_KEY')
```

```go Go theme={null}
package main

import "os"

func main() {
    apiKey := os.Getenv("DAKOTA_API_KEY")
}
```

```rust Rust theme={null}
use std::env;

fn main() {
    let api_key = env::var("DAKOTA_API_KEY")
        .expect("DAKOTA_API_KEY environment variable not set");
}
```

```java Java theme={null}
public class DakotaConfig {
    public static void main(String[] args) {
        String apiKey = System.getenv("DAKOTA_API_KEY");
        if (apiKey == null) {
            throw new IllegalStateException("DAKOTA_API_KEY environment variable not set");
        }
    }
}
```

## Environment Variables Setup

Set up your environment variables properly:

```bash .env file theme={null}
DAKOTA_API_KEY=AHGlPZaxDSMz8Wf1l8VRH4ObdbHiKsWFWnmRyHtiwAc=
```

```bash Shell theme={null}
export DAKOTA_API_KEY="AHGlPZaxDSMz8Wf1l8VRH4ObdbHiKsWFWnmRyHtiwAc="
```

## Key Rotation

* Rotate API keys regularly (recommended: every 90 days)
* Create new keys before deactivating old ones to avoid downtime
* Have a key rotation process documented and tested

## Access Control

* Limit API key access to only necessary team members
* Use separate keys for different services or applications
* Revoke unused or compromised keys immediately

# Request Security

## Always Use HTTPS

All API requests must use HTTPS. The Dakota Platform API will reject HTTP requests:

```javascript JavaScript theme={null}
// ✅ Correct - HTTPS
const response = await fetch('https://api.platform.dakota.xyz/customers', {
  headers: { 'X-API-Key': process.env.DAKOTA_API_KEY }
});

// ❌ Wrong - HTTP will be rejected
const response = await fetch('http://api.platform.dakota.xyz/customers', {
  headers: { 'X-API-Key': process.env.DAKOTA_API_KEY }
});
```

## Validate SSL Certificates

Ensure your HTTP client validates SSL certificates:

```bash cURL theme={null}
# ✅ Certificate validation enabled by default
curl -X GET https://api.platform.dakota.xyz/customers \
  -H "X-API-Key: $DAKOTA_API_KEY"

# ❌ Never disable certificate verification
# curl -k https://api.platform.dakota.xyz/customers  # DON'T DO THIS
```

```javascript Node.js theme={null}
// ✅ Certificate validation enabled by default
const https = require('https');

// ❌ Never disable certificate validation
// process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; // DON'T DO THIS
```

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

# ✅ Certificate validation enabled by default
response = requests.get(
    'https://api.platform.dakota.xyz/customers',
    headers={'X-API-Key': api_key}
)

# ❌ Never disable certificate verification
# requests.get(url, verify=False)  # DON'T DO THIS
```

```go Go theme={null}
package main

import (
    "crypto/tls"
    "net/http"
)

func main() {
    // ✅ Certificate validation enabled by default
    client := &http.Client{}
    
    // ❌ Never disable certificate verification
    // client := &http.Client{
    //     Transport: &http.Transport{
    //         TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, // DON'T DO THIS
    //     },
    // }
}
```

```rust Rust theme={null}
use reqwest::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ✅ Certificate validation enabled by default
    let client = Client::new();
    
    // ❌ Never disable certificate verification
    // let client = Client::builder()
    //     .danger_accept_invalid_certs(true)  // DON'T DO THIS
    //     .build()?;
    
    Ok(())
}
```

```java Java theme={null}
import java.net.http.HttpClient;
import javax.net.ssl.SSLContext;

public class SecurityExample {
    public static void main(String[] args) {
        // ✅ Certificate validation enabled by default
        HttpClient client = HttpClient.newHttpClient();
        
        // ❌ Never disable certificate verification
        // Don't create custom trust managers that accept all certificates
    }
}
```

## Request Logging Security

When logging requests for debugging, never log sensitive headers:

```bash cURL theme={null}
# When logging cURL commands, use environment variables
echo "curl -X GET https://api.platform.dakota.xyz/customers \\
  -H \"X-API-Key: \$DAKOTA_API_KEY\""

# Never log actual API keys
# echo "curl -H \"X-API-Key: AHGlPZ...\""  # DON'T DO THIS
```

```javascript JavaScript theme={null}
function logRequest(url, headers, body) {
  const safeHeaders = { ...headers };
  
  // Remove sensitive headers from logs
  delete safeHeaders['X-API-Key'];
  delete safeHeaders['Authorization'];
  
  console.log('API Request:', {
    url,
    headers: safeHeaders,
    body
  });
}
```

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

def log_request(url, headers, body):
    safe_headers = headers.copy()
    
    # Remove sensitive headers from logs
    safe_headers.pop('X-API-Key', None)
    safe_headers.pop('Authorization', None)
    
    logging.info(f'API Request: {url}, Headers: {safe_headers}')
```

```go Go theme={null}
package main

import (
    "log"
    "net/http"
)

func logRequest(req *http.Request) {
    safeHeaders := make(map[string][]string)
    
    // Copy headers except sensitive ones
    for k, v := range req.Header {
        if k != "X-Api-Key" && k != "Authorization" {
            safeHeaders[k] = v
        }
    }
    
    log.Printf("API Request: %s %s, Headers: %v", req.Method, req.URL, safeHeaders)
}
```

```rust Rust theme={null}
use std::collections::HashMap;
use log::info;

fn log_request(url: &str, headers: &HashMap<String, String>, body: &str) {
    let mut safe_headers = headers.clone();
    
    // Remove sensitive headers from logs
    safe_headers.remove("X-API-Key");
    safe_headers.remove("Authorization");
    
    info!("API Request: {}, Headers: {:?}", url, safe_headers);
}
```

```java Java theme={null}
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

public class RequestLogger {
    private static final Logger logger = Logger.getLogger(RequestLogger.class.getName());
    
    public static void logRequest(String url, Map<String, String> headers, String body) {
        Map<String, String> safeHeaders = new HashMap<>(headers);
        
        // Remove sensitive headers from logs
        safeHeaders.remove("X-API-Key");
        safeHeaders.remove("Authorization");
        
        logger.info(String.format("API Request: %s, Headers: %s", url, safeHeaders));
    }
}
```

# Production Environment

## Base URL

Always use the production base URL (Sandbox coming soon):

```
https://api.platform.dakota.xyz
```

## Network Security

* Use private networks or VPNs when possible
* Monitor network traffic for unusual patterns

## Error Handling

Implement secure error handling that doesn't expose sensitive information:

```bash cURL theme={null}
#!/bin/bash
# Secure error handling in shell scripts
make_secure_request() {
    local endpoint="$1"
    local response
    
    response=$(curl -s -w "%{http_code}" \
        -H "X-API-Key: $DAKOTA_API_KEY" \
        -H "Content-Type: application/json" \
        "https://api.platform.dakota.xyz$endpoint")
    
    local http_code="${response: -3}"
    local body="${response%???}"
    
    if [[ "$http_code" -ge 400 ]]; then
        # Log full error details internally
        echo "API Error: $http_code" >&2
        
        # Return generic error to user
        echo "API request failed" >&2
        return 1
    fi
    
    echo "$body"
}
```

```javascript JavaScript theme={null}
async function makeSecureRequest(endpoint) {
  try {
    const response = await fetch(`https://api.platform.dakota.xyz${endpoint}`, {
      headers: {
        'X-API-Key': process.env.DAKOTA_API_KEY,
        'Content-Type': 'application/json'
      }
    });
    
    if (!response.ok) {
      // Log full error details internally
      console.error('API Error:', response.status, response.statusText);
      
      // Return generic error to client
      throw new Error('API request failed');
    }
    
    return await response.json();
  } catch (error) {
    // Log error details internally
    console.error('Request failed:', error.message);
    
    // Don't expose internal error details
    throw new Error('Service temporarily unavailable');
  }
}
```

```python Python theme={null}
import requests
import logging
from typing import Dict, Any

def make_secure_request(endpoint: str) -> Dict[Any, Any]:
    try:
        response = requests.get(
            f'https://api.platform.dakota.xyz{endpoint}',
            headers={
                'X-API-Key': os.getenv('DAKOTA_API_KEY'),
                'Content-Type': 'application/json'
            },
            timeout=30
        )
        
        if not response.ok:
            # Log full error details internally
            logging.error(f'API Error: {response.status_code} {response.reason}')
            
            # Return generic error to client
            raise Exception('API request failed')
        
        return response.json()
    except requests.exceptions.RequestException as e:
        # Log error details internally
        logging.error(f'Request failed: {str(e)}')
        
        # Don't expose internal error details
        raise Exception('Service temporarily unavailable')
```

```go Go theme={null}
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "os"
)

func makeSecureRequest(endpoint string) (map[string]interface{}, error) {
    client := &http.Client{}
    req, err := http.NewRequest("GET", "https://api.platform.dakota.xyz"+endpoint, nil)
    if err != nil {
        log.Printf("Request creation failed: %v", err)
        return nil, fmt.Errorf("service temporarily unavailable")
    }
    
    req.Header.Set("X-API-Key", os.Getenv("DAKOTA_API_KEY"))
    req.Header.Set("Content-Type", "application/json")
    
    resp, err := client.Do(req)
    if err != nil {
        // Log error details internally
        log.Printf("Request failed: %v", err)
        
        // Don't expose internal error details
        return nil, fmt.Errorf("service temporarily unavailable")
    }
    defer resp.Body.Close()
    
    if resp.StatusCode >= 400 {
        // Log full error details internally
        log.Printf("API Error: %d %s", resp.StatusCode, resp.Status)
        
        // Return generic error to client
        return nil, fmt.Errorf("API request failed")
    }
    
    var result map[string]interface{}
    if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
        log.Printf("JSON decode failed: %v", err)
        return nil, fmt.Errorf("service temporarily unavailable")
    }
    
    return result, nil
}
```

```rust Rust theme={null}
use reqwest::header::{HeaderMap, HeaderValue};
use serde_json::Value;
use std::env;
use log::error;

async fn make_secure_request(endpoint: &str) -> Result<Value, Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    
    let mut headers = HeaderMap::new();
    let api_key = env::var("DAKOTA_API_KEY")
        .map_err(|_| "API key not configured")?;
    headers.insert("X-API-Key", HeaderValue::from_str(&api_key)?);
    headers.insert("Content-Type", HeaderValue::from_static("application/json"));
    
    let url = format!("https://api.platform.dakota.xyz{}", endpoint);
    
    match client.get(&url).headers(headers).send().await {
        Ok(response) => {
            if !response.status().is_success() {
                // Log full error details internally
                error!("API Error: {} {}", response.status(), response.status().canonical_reason().unwrap_or("Unknown"));
                
                // Return generic error to client
                return Err("API request failed".into());
            }
            
            match response.json::<Value>().await {
                Ok(data) => Ok(data),
                Err(e) => {
                    error!("JSON decode failed: {}", e);
                    Err("Service temporarily unavailable".into())
                }
            }
        }
        Err(e) => {
            // Log error details internally
            error!("Request failed: {}", e);
            
            // Don't expose internal error details
            Err("Service temporarily unavailable".into())
        }
    }
}
```

```java Java theme={null}
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.logging.Logger;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class SecureApiClient {
    private static final Logger logger = Logger.getLogger(SecureApiClient.class.getName());
    private final HttpClient client;
    private final ObjectMapper mapper;
    
    public SecureApiClient() {
        this.client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(30))
            .build();
        this.mapper = new ObjectMapper();
    }
    
    public JsonNode makeSecureRequest(String endpoint) throws Exception {
        String apiKey = System.getenv("DAKOTA_API_KEY");
        if (apiKey == null) {
            throw new IllegalStateException("API key not configured");
        }
        
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.platform.dakota.xyz" + endpoint))
            .header("X-API-Key", apiKey)
            .header("Content-Type", "application/json")
            .GET()
            .build();
        
        try {
            HttpResponse<String> response = client.send(request, 
                HttpResponse.BodyHandlers.ofString());
            
            if (response.statusCode() >= 400) {
                // Log full error details internally
                logger.severe("API Error: " + response.statusCode());
                
                // Return generic error to client
                throw new Exception("API request failed");
            }
            
            return mapper.readTree(response.body());
        } catch (IOException | InterruptedException e) {
            // Log error details internally
            logger.severe("Request failed: " + e.getMessage());
            
            // Don't expose internal error details
            throw new Exception("Service temporarily unavailable");
        }
    }
}
```

# Webhook Security

## Verify Webhook Signatures

Webhook signatures use **Ed25519** (not HMAC). See [Webhooks → Webhook Signature Verification](/documentation/webhooks#webhook-signature-verification) for the canonical algorithm, headers, and code examples in every supported language.

## Webhook Endpoint Security

* Use HTTPS for all webhook endpoints
* Implement request size limits
* Add rate limiting to webhook endpoints
* Validate webhook payload structure

# Monitoring and Alerting

## Security Monitoring

Set up monitoring for:

* Unusual API usage patterns
* Failed authentication attempts
* Requests from unexpected IP addresses
* High error rates that might indicate attacks

## Logging Security Events

Log security-relevant events:

```bash cURL theme={null}
#!/bin/bash
# Security event logging in shell scripts
log_security_event() {
    local event="$1"
    local endpoint="$2"
    local ip_address="$3"
    
    echo "$(date -u +%Y-%m-%dT%H:%M:%S.%3NZ) | SECURITY | $event | endpoint=$endpoint ip=$ip_address source=dakota-shell-client" >> /var/log/dakota-security.log
}

# Example usage
log_security_event "api_key_used" "/customers" "$CLIENT_IP"
```

```javascript JavaScript theme={null}
function logSecurityEvent(event, details) {
  console.log(JSON.stringify({
    timestamp: new Date().toISOString(),
    event: event,
    details: details,
    source: 'dakota-api-client'
  }));
}

// Example usage
logSecurityEvent('api_key_used', {
  endpoint: '/customers',
  ip_address: req.ip,
  user_agent: req.get('User-Agent')
});
```

```python Python theme={null}
import json
import logging
from datetime import datetime, timezone

def log_security_event(event: str, details: dict):
    security_log = {
        'timestamp': datetime.now(timezone.utc).isoformat(),
        'event': event,
        'details': details,
        'source': 'dakota-api-client'
    }
    
    # Use structured logging
    logging.info(json.dumps(security_log))

# Example usage
log_security_event('api_key_used', {
    'endpoint': '/customers',
    'ip_address': request.remote_addr,
    'user_agent': request.headers.get('User-Agent')
})
```

```go Go theme={null}
package main

import (
    "encoding/json"
    "log"
    "net/http"
    "time"
)

type SecurityEvent struct {
    Timestamp string                 `json:"timestamp"`
    Event     string                 `json:"event"`
    Details   map[string]interface{} `json:"details"`
    Source    string                 `json:"source"`
}

func logSecurityEvent(event string, details map[string]interface{}) {
    securityEvent := SecurityEvent{
        Timestamp: time.Now().UTC().Format(time.RFC3339),
        Event:     event,
        Details:   details,
        Source:    "dakota-api-client",
    }
    
    eventJSON, err := json.Marshal(securityEvent)
    if err != nil {
        log.Printf("Error marshaling security event: %v", err)
        return
    }
    
    log.Println(string(eventJSON))
}

// Example usage
func handleRequest(w http.ResponseWriter, r *http.Request) {
    details := map[string]interface{}{
        "endpoint":   r.URL.Path,
        "ip_address": r.RemoteAddr,
        "user_agent": r.UserAgent(),
    }
    
    logSecurityEvent("api_key_used", details)
}
```

```rust Rust theme={null}
use serde_json::{json, Value};
use chrono::{DateTime, Utc};
use log::info;

fn log_security_event(event: &str, details: Value) {
    let security_event = json!({
        "timestamp": Utc::now().to_rfc3339(),
        "event": event,
        "details": details,
        "source": "dakota-api-client"
    });
    
    info!("{}", security_event.to_string());
}

// Example usage
fn handle_request(req: &HttpRequest) {
    let details = json!({
        "endpoint": req.uri().path(),
        "ip_address": req.connection_info().remote_addr(),
        "user_agent": req.headers().get("user-agent")
            .and_then(|h| h.to_str().ok())
            .unwrap_or("unknown")
    });
    
    log_security_event("api_key_used", details);
}
```

```java Java theme={null}
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.time.Instant;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;

public class SecurityLogger {
    private static final Logger logger = Logger.getLogger(SecurityLogger.class.getName());
    private static final ObjectMapper mapper = new ObjectMapper();
    
    public static void logSecurityEvent(String event, ObjectNode details) {
        try {
            ObjectNode securityEvent = mapper.createObjectNode();
            securityEvent.put("timestamp", Instant.now().toString());
            securityEvent.put("event", event);
            securityEvent.set("details", details);
            securityEvent.put("source", "dakota-api-client");
            
            logger.info(securityEvent.toString());
        } catch (Exception e) {
            logger.severe("Error logging security event: " + e.getMessage());
        }
    }
    
    // Example usage
    public static void handleRequest(HttpServletRequest request) {
        ObjectNode details = mapper.createObjectNode();
        details.put("endpoint", request.getRequestURI());
        details.put("ip_address", request.getRemoteAddr());
        details.put("user_agent", request.getHeader("User-Agent"));
        
        logSecurityEvent("api_key_used", details);
    }
}
```

## Alert Setup

Configure alerts for:

* Multiple consecutive API authentication failures
* Requests from new or suspicious IP addresses
* Unusual request volume patterns
* Webhook signature validation failures

# Data Protection

## Sensitive Data Handling

* Never log sensitive customer data
* Use data encryption at rest for stored API responses
* Implement data retention policies

# Security Checklist

Before going to production, verify:

* [ ] API keys stored as environment variables
* [ ] No sensitive data in code or logs
* [ ] HTTPS used for all requests
* [ ] SSL certificate validation enabled
* [ ] Webhook signatures verified
* [ ] Error handling doesn't expose sensitive info
* [ ] Request/response logging excludes sensitive headers
* [ ] Monitoring and alerting configured
* [ ] Data retention policies implemented
* [ ] Security testing completed

# Incident Response

If you suspect a security incident:

1. **Immediately rotate** your API keys
2. **Review logs** for suspicious activity
3. **Contact Dakota Platform support** with incident details
4. **Document** the incident and response
5. **Update security measures** to prevent recurrence
