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:

Need help?

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