Skip to main content

Overview

Tresa Contafy API implements rate limiting to ensure fair usage and protect against abuse. Rate limits vary by endpoint and are enforced using a combination of IP-based and user-based throttling.
Rate limits are designed to accommodate normal usage patterns. If you consistently hit rate limits, consider optimizing your integration or upgrading your plan.

Global API Rate Limit

All API endpoints under /api/ are protected by a global rate limiter:
  • Window: 15 minutes
  • Max requests: 1,000 requests per window (production)
  • Max requests: 2,000 requests per window (development)
  • Key: IP address
  • Standard headers: Included in response

Configuration

Set via environment variable:
API_RATE_LIMIT_MAX=1000  # Defaults: 1000 prod, 2000 dev

Response Headers

RateLimit-Limit: 1000
RateLimit-Remaining: 847
RateLimit-Reset: 1709251200

Error Response

When limit is exceeded:
{
  "error": "Demasiadas solicitudes desde esta IP, por favor intenta nuevamente más tarde."
}
HTTP Status: 429 Too Many Requests

Authentication Endpoints

Authentication endpoints have stricter rate limits to prevent brute force attacks:

Endpoints Covered

  • POST /api/auth/login
  • POST /api/auth/register
  • POST /api/auth/google
  • POST /api/auth/request-password-reset

Limits

  • Window: 15 minutes
  • Max requests: 5 requests per window (production)
  • Max requests: 100 requests per window (development)
  • Key: IP address
  • Skip successful requests: Yes (only failed attempts count)
After 5 failed login attempts in 15 minutes, users must wait for the window to reset. Implement exponential backoff in your client.

Error Response

{
  "error": "Demasiados intentos de autenticación, por favor intenta nuevamente más tarde."
}

Invoice Upload Endpoints

XML parsing and upload endpoints have per-user rate limits:

Endpoints Covered

  • POST /api/invoices/parse
  • POST /api/invoices/upload
  • POST /api/expenses/parse
  • POST /api/expenses/upload

Limits

  • Window: 5 minutes
  • Max requests: 300 requests per window
  • Key: User ID (authenticated user)
  • Fallback: IP address (if not authenticated)
Rate limit is per user, not per IP. This allows multiple users from the same network to upload simultaneously.

Key Generation

keyGenerator: (req) => {
  const userId = req.userId; // From JWT token
  const ip = req.ip || req.socket.remoteAddress || "0.0.0.0";
  return userId || ip;
}

Error Response

{
  "error": "Demasiadas solicitudes para procesar XML. Intenta nuevamente en unos minutos."
}

Plan-Based Limits

Certain features have limits based on your subscription plan:

Profile Limits

PlanMax Profiles
FREE1
BASIC5
PRO20
ENTERPRISEUnlimited
Enforced by: validateProfileLimit middleware
{
  "error": "Límite de plan alcanzado",
  "message": "Has alcanzado el límite de 5 perfiles para el plan BASIC",
  "limit": 5,
  "currentCount": 5
}

Invoice and Expense Limits

All plans have unlimited invoices and expenses per month.
While there’s no monthly limit, the 300 requests per 5 minutes upload rate limit still applies.

Public Report Tokens

PlanMax Active Tokens
FREE0 (feature disabled)
BASIC10
PRO50
ENTERPRISEUnlimited
Enforced by: validatePublicReportTokenLimit middleware
{
  "error": "Límite de plan alcanzado",
  "message": "Has alcanzado el límite de 10 tokens activos para el plan BASIC",
  "limit": 10,
  "currentCount": 10
}

SAT AI Search Limits

PlanAI Searches per Month
FREE5
BASIC100
PROUnlimited
ENTERPRISEUnlimited
Basic (non-AI) searches are unlimited on all plans. Enforced by: validateSATSearchLimit middleware
{
  "error": "Límite de plan alcanzado",
  "message": "Has alcanzado el límite de 5 búsquedas IA para el plan FREE",
  "limit": 5,
  "currentCount": 5,
  "remaining": 0
}

Feature Access Limits

Some features are restricted by plan:

Public Reports

Required: BASIC plan or higher
{
  "error": "Feature no disponible en tu plan",
  "message": "Esta funcionalidad requiere plan BASIC o superior"
}

SAT Download (FIEL/e.firma)

Required: PRO plan or higher
{
  "error": "Feature no disponible en tu plan",
  "message": "La descarga masiva SAT requiere plan PRO o superior"
}

API Access

Required: PRO plan or higher All endpoints are available to PRO and ENTERPRISE plans. FREE and BASIC plans can use the web interface only.

File Upload Limits

XML file uploads are limited by size:
  • Max file size: 10 MB
  • Enforced by: express-fileupload middleware
{
  "error": "File too large"
}

Handling Rate Limits

Check Rate Limit Headers

Always check response headers to monitor your usage:
const response = await fetch('https://api.contafy.com/api/profiles', {
  headers: { 'Authorization': `Bearer ${token}` }
});

const limit = response.headers.get('RateLimit-Limit');
const remaining = response.headers.get('RateLimit-Remaining');
const reset = response.headers.get('RateLimit-Reset');

if (remaining < 10) {
  console.warn(`Only ${remaining} requests remaining until ${new Date(reset * 1000)}`);
}

Implement Exponential Backoff

When receiving a 429 error, wait before retrying:
async function uploadWithRetry(xmlFile, profileId, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await uploadInvoice(xmlFile, profileId);
      return response;
    } catch (error) {
      if (error.status === 429) {
        const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
        console.log(`Rate limited. Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        throw error;
      }
    }
  }
  throw new Error('Max retries exceeded');
}

Batch Requests

Avoid making sequential requests in loops:
// DON'T: Sequential requests
for (const file of files) {
  await uploadInvoice(file, profileId);
}

Cache Responses

Cache responses that don’t change frequently:
// Cache profile list for 5 minutes
const CACHE_TTL = 5 * 60 * 1000;
let profilesCache = null;
let cacheTime = 0;

async function getProfiles() {
  const now = Date.now();
  if (profilesCache && (now - cacheTime) < CACHE_TTL) {
    return profilesCache;
  }
  
  profilesCache = await fetchProfiles();
  cacheTime = now;
  return profilesCache;
}

Monitoring Rate Limits

Application Logging

Log rate limit hits to identify issues:
if (response.status === 429) {
  console.error('Rate limit exceeded', {
    endpoint: response.url,
    resetTime: response.headers.get('RateLimit-Reset'),
    userId: currentUserId
  });
}

User Notifications

Inform users when approaching limits:
const remaining = parseInt(response.headers.get('RateLimit-Remaining'));
if (remaining < 50) {
  showWarning(`You have ${remaining} API requests remaining`);
}

Rate Limit Bypass

Never attempt to bypass rate limits by:
  • Using multiple accounts
  • Rotating IP addresses
  • Forging rate limit headers
These actions may result in account suspension.
If you need higher limits:
  1. Upgrade to PRO or ENTERPRISE plan
  2. Contact [email protected] for custom limits
  3. Optimize your integration to reduce requests

Proxy Considerations

The API runs behind a reverse proxy (Railway) in production:
if (process.env.NODE_ENV === 'production') {
  app.set('trust proxy', 1);
}
This ensures:
  • req.ip reflects the real client IP
  • Rate limiting works correctly for users behind the same proxy
  • X-Forwarded-For headers are trusted

OPTIONS Requests

CORS preflight requests (OPTIONS) are excluded from rate limits:
skip: (req) => req.method === 'OPTIONS'
OPTIONS requests don’t count toward your rate limit quota.

Best Practices

  1. Monitor headers: Always check RateLimit-* headers
  2. Implement backoff: Use exponential backoff for retries
  3. Batch operations: Group related requests together
  4. Cache aggressively: Cache static data like profiles and plans
  5. Respect limits: Don’t attempt to circumvent rate limits
  6. Upgrade when needed: Use appropriate plan for your usage
  7. Handle 429 gracefully: Show user-friendly error messages
  8. Log rate limit hits: Monitor and optimize high-traffic endpoints

Plan-Specific Recommendations

FREE Plan

  • Focus on web interface usage
  • Cache profile data locally
  • Upload invoices in small batches
  • Use parse endpoint to test before uploading

BASIC Plan

  • Implement basic caching for profile lists
  • Batch invoice uploads with delays
  • Monitor public report token usage

PRO Plan

  • Utilize full API access
  • Implement robust caching layer
  • Use webhooks for real-time updates
  • Batch operations with higher concurrency

ENTERPRISE Plan

  • Custom rate limits available on request
  • Dedicated support for optimization
  • Advanced monitoring and analytics

Getting Help

If you’re experiencing rate limit issues:
  1. Review this guide and optimize your integration
  2. Check API Status for incidents
  3. Contact [email protected] with:
    • Your user ID or email
    • Affected endpoints
    • Request patterns and frequency
    • Business use case

Next Steps

Build docs developers (and LLMs) love