Skip to main content
This guide will help you perform your first SAT invoice extraction using the Taxo API.

Before you start

You need:
  • A Taxo API key (get it here)
  • CIEC or FIEL credentials from a taxpayer
  • A tool to make HTTP requests (cURL, Postman, or code)

Step 1: Set up authentication

Store your API key securely:
export TAXO_API_KEY="your_api_key_here"

Step 2: Create your first extraction

Let’s extract received invoices from 2024 for a specific RFC:
curl -X POST "https://api.taxo.co/v1/extractions" \
  -H "Authorization: Bearer $TAXO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": {
      "identifier": "ABC010101ABC",
      "name": "Mi Empresa S.A. de C.V."
    },
    "credentials": {
      "type": "CIEC",
      "password": "'"$(echo -n 'my_sat_password' | base64)"'"
    },
    "options": {
      "informationType": "INVOICE",
      "period": {
        "from": "2024-01-01",
        "to": "2024-12-31"
      },
      "direction": "RECEIVED"
    }
  }'
Expected response:
{
  "publicId": "JOB20250104123456789A",
  "status": "PENDING",
  "createdAt": "2025-01-04T12:34:56.789Z",
  "subject": {
    "identification": "ABC010101ABC",
    "fullName": "Mi Empresa S.A. de C.V.",
    "personType": "MORAL"
  },
  "discoveryCount": 0,
  "completedCount": 0,
  "failedCount": 0
}
Save the publicId - you’ll need it to check status and download documents.

Step 3: Monitor progress

Extraction is an asynchronous process. Check the status regularly:
# Replace JOB20250104123456789A with your publicId
curl -X GET "https://api.taxo.co/v1/extractions/JOB20250104123456789A" \
  -H "Authorization: Bearer $TAXO_API_KEY"

Step 4: Download documents

Once the extraction is complete, you can download the documents:
# Download the first document in XML format
curl -X GET "https://api.taxo.co/v1/extractions/JOB20250104123456789A/documents/DOCUMENT_ID/download?type=XML" \
  -H "Authorization: Bearer $TAXO_API_KEY" \
  -o "factura.xml"

Complete example script

Here’s a complete script that performs the entire process:
const fetch = require('node-fetch');
const fs = require('fs');

const API_KEY = process.env.TAXO_API_KEY;
const BASE_URL = 'https://api.taxo.co';

async function main() {
  try {
    console.log('🚀 Iniciando extracción de facturas...');
    
    // 1. Crear extracción
    const extraction = await createExtraction();
    console.log(`✅ Extracción creada: ${extraction.publicId}`);
    
    // 2. Esperar a que complete
    const result = await waitForCompletion(extraction.publicId);
    
    // 3. Descargar primeros 5 documentos
    await downloadDocuments(result, 5);
    
    console.log('🎉 ¡Proceso completado exitosamente!');
    
  } catch (error) {
    console.error('❌ Error:', error.message);
    process.exit(1);
  }
}

async function createExtraction() {
  const response = await fetch(`${BASE_URL}/v1/extractions`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      subject: {
        identifier: 'ABC010101ABC', // Reemplaza con el RFC real
        name: 'Mi Empresa S.A. de C.V.'
      },
      credentials: {
        type: 'CIEC',
        password: Buffer.from('my_sat_password').toString('base64') // Reemplaza
      },
      options: {
        informationType: 'INVOICE',
        period: {
          from: '2024-01-01',
          to: '2024-03-31' // Solo Q1 para el ejemplo
        },
        direction: 'RECEIVED'
      }
    })
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Error creando extracción: ${error.error?.message}`);
  }
  
  return await response.json();
}

async function waitForCompletion(extractionId) {
  console.log('⏳ Esperando que se complete la extracción...');
  
  const delays = [5, 10, 20, 30, 60]; // Backoff exponencial
  let delayIndex = 0;
  
  while (true) {
    const response = await fetch(`${BASE_URL}/v1/extractions/${extractionId}`, {
      headers: { 'Authorization': `Bearer ${API_KEY}` }
    });
    
    const status = await response.json();
    const progress = status.progress || {};
    
    console.log(`   Estado: ${status.status} - Progreso: ${progress.percentage || 0}%`);
    
    if (status.status === 'COMPLETED') {
      console.log(`✅ ¡Completado! ${progress.completedCount} documentos extraídos`);
      return status;
    }
    
    if (status.status === 'FAILED') {
      throw new Error(`Extracción falló: ${status.error?.message}`);
    }
    
    // Esperar con backoff exponencial
    const delay = delays[Math.min(delayIndex++, delays.length - 1)] * 1000;
    await new Promise(resolve => setTimeout(resolve, delay));
  }
}

async function downloadDocuments(extractionStatus, maxDocuments = 5) {
  const documents = extractionStatus.documents.slice(0, maxDocuments);
  
  console.log(`📥 Descargando ${documents.length} documentos...`);
  
  for (let i = 0; i < documents.length; i++) {
    const doc = documents[i];
    const format = doc.availableFormats[0];
    
    console.log(`   Descargando ${i + 1}/${documents.length}: ${doc.uuid}`);
    
    const response = await fetch(
      `${BASE_URL}/v1/extractions/${extractionStatus.publicId}/documents/${doc.id}/download?type=${format}`,
      { headers: { 'Authorization': `Bearer ${API_KEY}` } }
    );
    
    if (!response.ok) {
      console.warn(`   ⚠️  Error descargando ${doc.uuid}: ${response.status}`);
      continue;
    }
    
    const buffer = Buffer.from(await response.arrayBuffer());
    const filename = `documento_${i + 1}_${doc.uuid}.${format.toLowerCase()}`;
    
    fs.writeFileSync(filename, buffer);
    console.log(`   ✅ Guardado: ${filename}`);
  }
}

// Ejecutar si es llamado directamente
if (require.main === module) {
  main();
}

Next steps

Congratulations! You now know how to use the basic Taxo API. You can now:

Set up webhooks

Receive automatic notifications when extractions are ready

Explore endpoints

Discover all advanced filtering and configuration options

Best practices

Learn how to optimize performance and handle errors

Official SDKs

Use our official libraries for your favorite language

Need help?

If you have problems following this guide, contact our support team: