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.
Overview
Follow these best practices to ensure your Taxo API integration is secure, reliable, and performant in production environments.
Authentication & Security
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
# 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!
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
// Good: Using secure credential storage
const credentials = await secretsManager . getSecret ( 'sat-credentials' );
// Bad: Hardcoded credentials
const password = "plaintext-password" ; // Never do this!
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
Error Handling & Resilience
Retry Strategy
Implement exponential backoff for transient errors:
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 ));
}
}
Circuit Breaker Pattern
Implement circuit breaker to prevent cascading failures:
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' ;
}
}
}
Rate Limiting
Respect API rate limits to avoid throttling:
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:
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:
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:
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
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
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
Testing Strategy
Integration Testing
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
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
Log all API requests and responses
Monitor extraction success/failure rates
Set up alerts for repeated failures
Keep track of API usage limits
Security Checklist
Next Steps
Webhook Setup Configure real-time notifications for your integration.
Error Handling Learn how to handle and troubleshoot common issues.
Use Cases Explore specific implementation patterns for common use cases.
API Reference Dive deep into the complete API documentation.