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

# Integration Best Practices

> Production-ready patterns and security practices for Taxo API integration

## Overview

Follow these best practices to ensure your Taxo API integration is secure, reliable, and performant in production environments.

## Authentication & Security

<AccordionGroup>
  <Accordion title="API Key Management" icon="key">
    * Store API keys in secure environment variables, not in code
    * Rotate API keys regularly (quarterly recommended)
    * Use different API keys for different environments (dev, staging, prod)
    * Never log or expose API keys in error messages or logs

    ```bash theme={null}
    # Good: Using environment variables
    export TAXO_API_KEY="your-secure-api-key"

    # Bad: Hardcoding in source code
    const API_KEY = "sk-1234567890abcdef"; // Never do this!
    ```
  </Accordion>

  <Accordion title="Credential Security" icon="shield-check">
    * Store CIEC/FIEL passwords in encrypted vaults (AWS Secrets Manager, Azure Key Vault, etc.)
    * Never store credentials in plain text
    * Implement credential rotation procedures
    * Use least-privilege access principles

    ```javascript theme={null}
    // Good: Using secure credential storage
    const credentials = await secretsManager.getSecret('sat-credentials');

    // Bad: Hardcoded credentials
    const password = "plaintext-password"; // Never do this!
    ```
  </Accordion>

  <Accordion title="Network Security" icon="globe">
    * Always use HTTPS for API communications
    * Implement IP whitelisting when possible
    * Use VPN or private networks for sensitive integrations
    * Monitor for unusual API access patterns
  </Accordion>
</AccordionGroup>

## Error Handling & Resilience

### Retry Strategy

Implement exponential backoff for transient errors:

<CodeGroup>
  ```javascript Node.js theme={null}
  class TaxoClient {
    async withRetry(operation, maxRetries = 3) {
      let lastError;
      
      for (let attempt = 1; attempt <= maxRetries; attempt++) {
        try {
          return await operation();
        } catch (error) {
          lastError = error;
          
          // Don't retry on client errors (4xx)
          if (error.response?.status >= 400 && error.response?.status < 500) {
            throw error;
          }
          
          if (attempt < maxRetries) {
            const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000);
            await this.sleep(delay);
            console.log(`Retry attempt ${attempt} after ${delay}ms`);
          }
        }
      }
      
      throw lastError;
    }

    async createExtraction(data) {
      return this.withRetry(() => 
        axios.post('/v1/extractions', data, {
          headers: { 'Authorization': `Bearer ${this.apiKey}` }
        })
      );
    }

    sleep(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }
  }
  ```

  ```python Python theme={null}
  import time
  import random
  from typing import Callable, Any

  class TaxoClient:
      def __init__(self, api_key: str):
          self.api_key = api_key
          self.base_url = 'https://api.taxo.co'

      async def with_retry(self, operation: Callable, max_retries: int = 3) -> Any:
          """Execute operation with exponential backoff retry"""
          for attempt in range(1, max_retries + 1):
              try:
                  return await operation()
              except requests.HTTPError as e:
                  # Don't retry on client errors (4xx)
                  if 400 <= e.response.status_code < 500:
                      raise
                  
                  if attempt < max_retries:
                      # Exponential backoff with jitter
                      delay = min(2 ** (attempt - 1) + random.uniform(0, 1), 30)
                      print(f"Retry attempt {attempt} after {delay:.1f}s")
                      time.sleep(delay)
                  else:
                      raise

      async def create_extraction(self, data: dict) -> dict:
          """Create extraction with retry logic"""
          def operation():
              return requests.post(
                  f'{self.base_url}/v1/extractions',
                  json=data,
                  headers={'Authorization': f'Bearer {self.api_key}'}
              )
          
          response = await self.with_retry(operation)
          return response.json()
  ```
</CodeGroup>

### Circuit Breaker Pattern

Implement circuit breaker to prevent cascading failures:

```javascript theme={null}
class CircuitBreaker {
  constructor(threshold = 5, timeout = 60000) {
    this.failureThreshold = threshold;
    this.timeout = timeout;
    this.failureCount = 0;
    this.lastFailureTime = null;
    this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
  }

  async call(operation) {
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime > this.timeout) {
        this.state = 'HALF_OPEN';
      } else {
        throw new Error('Circuit breaker is OPEN');
      }
    }

    try {
      const result = await operation();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      throw error;
    }
  }

  onSuccess() {
    this.failureCount = 0;
    this.state = 'CLOSED';
  }

  onFailure() {
    this.failureCount++;
    this.lastFailureTime = Date.now();
    
    if (this.failureCount >= this.failureThreshold) {
      this.state = 'OPEN';
    }
  }
}
```

## Performance Optimization

### Rate Limiting

Respect API rate limits to avoid throttling:

```javascript theme={null}
class RateLimiter {
  constructor(requestsPerMinute = 100) {
    this.limit = requestsPerMinute;
    this.requests = [];
  }

  async waitForAvailableSlot() {
    const now = Date.now();
    
    // Remove requests older than 1 minute
    this.requests = this.requests.filter(time => now - time < 60000);
    
    if (this.requests.length >= this.limit) {
      const oldestRequest = Math.min(...this.requests);
      const waitTime = 60000 - (now - oldestRequest);
      
      if (waitTime > 0) {
        await new Promise(resolve => setTimeout(resolve, waitTime));
        return this.waitForAvailableSlot(); // Recursive check
      }
    }
    
    this.requests.push(now);
  }
}

// Usage
const rateLimiter = new RateLimiter(100); // 100 requests per minute

async function makeAPICall() {
  await rateLimiter.waitForAvailableSlot();
  // Make your API call here
}
```

### Batch Processing

Process documents in batches for better performance:

```javascript theme={null}
class BatchProcessor {
  constructor(batchSize = 10, concurrency = 3) {
    this.batchSize = batchSize;
    this.concurrency = concurrency;
  }

  async processBatch(items, processor) {
    const batches = this.createBatches(items);
    const results = [];
    
    for (let i = 0; i < batches.length; i += this.concurrency) {
      const batchGroup = batches.slice(i, i + this.concurrency);
      const batchPromises = batchGroup.map(batch => 
        this.processBatchItems(batch, processor)
      );
      
      const batchResults = await Promise.allSettled(batchPromises);
      results.push(...batchResults);
    }
    
    return results;
  }

  createBatches(items) {
    const batches = [];
    for (let i = 0; i < items.length; i += this.batchSize) {
      batches.push(items.slice(i, i + this.batchSize));
    }
    return batches;
  }

  async processBatchItems(batch, processor) {
    const results = [];
    for (const item of batch) {
      try {
        const result = await processor(item);
        results.push({ success: true, data: result });
      } catch (error) {
        results.push({ success: false, error: error.message });
      }
    }
    return results;
  }
}
```

## Monitoring & Observability

### Logging

Implement structured logging for better debugging:

```javascript theme={null}
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  defaultMeta: { service: 'taxo-integration' },
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

// Usage
logger.info('Creating extraction', {
  rfc: 'ABC123456789',
  period: '2024-01',
  informationType: 'INVOICE'
});

logger.error('Extraction failed', {
  rfc: 'ABC123456789',
  jobId: 'JOB123',
  error: error.message,
  stack: error.stack
});
```

### Health Checks

Implement health check endpoints:

```javascript theme={null}
class HealthChecker {
  async checkHealth() {
    const checks = await Promise.allSettled([
      this.checkTaxoAPI(),
      this.checkDatabase(),
      this.checkExternalServices()
    ]);

    const results = {
      status: 'healthy',
      timestamp: new Date().toISOString(),
      checks: {}
    };

    checks.forEach((check, index) => {
      const checkName = ['TaxoAPI', 'Database', 'ExternalServices'][index];
      
      if (check.status === 'fulfilled') {
        results.checks[checkName] = { status: 'healthy', ...check.value };
      } else {
        results.checks[checkName] = { 
          status: 'unhealthy', 
          error: check.reason.message 
        };
        results.status = 'unhealthy';
      }
    });

    return results;
  }

  async checkTaxoAPI() {
    const response = await fetch('https://api.taxo.co/v1/health', {
      headers: { 'Authorization': `Bearer ${this.apiKey}` }
    });
    
    if (!response.ok) {
      throw new Error(`Taxo API unhealthy: ${response.status}`);
    }
    
    return { responseTime: Date.now() - startTime };
  }
}
```

## Document Storage

### Simple Storage Tips

<AccordionGroup>
  <Accordion title="File Organization" icon="folder">
    * Organize downloaded documents by date and RFC
    * Use meaningful file names (e.g., `INVOICE_RFC123_2024-01-15.xml`)
    * Keep XML and PDF versions together in the same folder
    * Create separate folders for different document types
  </Accordion>

  <Accordion title="Backup & Retention" icon="shield">
    * Keep backups of all downloaded documents
    * Follow legal requirements for document retention (typically 5-10 years)
    * Store documents in a secure location
    * Regularly verify backup integrity
  </Accordion>
</AccordionGroup>

## Testing Strategy

### Integration Testing

```javascript theme={null}
describe('Taxo Integration', () => {
  let taxoClient;
  
  beforeEach(() => {
    taxoClient = new TaxoClient(process.env.TEST_API_KEY);
  });

  test('should create and complete extraction', async () => {
    // Create extraction
    const extraction = await taxoClient.createExtraction({
      subject: { identifier: 'TEST123456789' },
      credentials: { /* test credentials */ },
      options: {
        informationType: 'INVOICE',
        period: { from: '2024-01-01', to: '2024-01-31' }
      }
    });

    expect(extraction.publicId).toBeDefined();
    expect(extraction.status).toBe('PENDING');

    // Wait for completion (with timeout)
    const completed = await taxoClient.waitForCompletion(
      extraction.publicId, 
      { timeout: 300000 }
    );

    expect(completed.status).toBe('COMPLETED');
    expect(completed.completedCount).toBeGreaterThan(0);
  }, 10 * 60 * 1000); // 10 minute timeout

  test('should handle invalid credentials gracefully', async () => {
    await expect(
      taxoClient.createExtraction({
        subject: { identifier: 'INVALID123' },
        credentials: { SAT: { type: 'USERNAME_PASSWORD', username: 'invalid', password: 'invalid' } },
        options: { informationType: 'INVOICE', period: { from: '2024-01-01', to: '2024-01-31' } }
      })
    ).rejects.toThrow(/credentials/i);
  });
});
```

## Environment Setup

### Basic Configuration

<AccordionGroup>
  <Accordion title="Environment Variables" icon="cog">
    * Use different API keys for testing and production
    * Store sensitive information in environment variables
    * Never commit credentials to version control
    * Test your configuration before going live
  </Accordion>

  <Accordion title="Basic Monitoring" icon="chart-bar">
    * Log all API requests and responses
    * Monitor extraction success/failure rates
    * Set up alerts for repeated failures
    * Keep track of API usage limits
  </Accordion>
</AccordionGroup>

## Security Checklist

<Checklist>
  <Check>API keys stored securely in environment variables or secrets manager</Check>
  <Check>CIEC/FIEL passwords encrypted and stored in secure vaults</Check>
  <Check>All API communications use HTTPS/TLS</Check>
  <Check>Input validation implemented for all user inputs</Check>
  <Check>Error messages don't expose sensitive information</Check>
  <Check>Access logs are maintained and monitored</Check>
  <Check>Rate limiting implemented to prevent abuse</Check>
  <Check>Regular security audits and penetration testing</Check>
  <Check>Dependency scanning for known vulnerabilities</Check>
  <Check>Data encryption at rest for sensitive information</Check>
</Checklist>

## Next Steps

<CardGroup cols={2}>
  <Card title="Webhook Setup" icon="webhook" href="/api-reference/taxo-b2b/webhooks/overview">
    Configure real-time notifications for your integration.
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/troubleshooting/common-errors">
    Learn how to handle and troubleshoot common issues.
  </Card>

  <Card title="Use Cases" icon="lightbulb" href="/use-cases/accounting-automation">
    Explore specific implementation patterns for common use cases.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/taxo-b2b/introduction">
    Dive deep into the complete API documentation.
  </Card>
</CardGroup>
