Ejemplo en JAVASCRIPT

Ejemplo de uso del API SAT en javascript.

Archivo fuente: nodejs.js

#!/usr/bin/env node
/**
 * Ejemplo Node.js — POST /api/v1/usuario/datos-fiscales
 * Usa fetch nativo (Node 18+).
 *
 * Uso:
 *   export SAT_API_KEY="sat_xxxxxxxxxxxx"
 *   node nodejs.js [RFC]
 */

class SatApiClient {
    constructor(apiKey, baseUrl = 'https://api.cfdi4.com', userAgent = 'nodejs-sat-api/1.0') {

        this.apiKey = apiKey;
        this.baseUrl = baseUrl.replace(/\/$/, '');
        this.userAgent = userAgent;
    }

    async _post(endpoint, body) {
        const url = `${this.baseUrl}${endpoint}`;
        try {
            const r = await fetch(url, {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${this.apiKey}`,
                    'User-Agent': this.userAgent,
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(body),
            });

            if (!r.ok) {
                // Status HTTP no 2xx, pero leemos el body igual

                const data = await r.json().catch(() => ({}));
                return data.body || { cfdi_codigo: 4001, cfdi_texto: `HTTP ${r.status}` };
            }

            const data = await r.json();
            return data.body || {};
        } catch (err) {
            if (err.name === 'AbortError') {
                return { cfdi_codigo: 3001, cfdi_texto: 'Timeout' };
            }
            return { cfdi_codigo: 5001, cfdi_texto: err.message };
        }
    }

    datosFiscales(rfc) {
        return this._post('/api/v1/usuario/datos-fiscales', { rfc: rfc.toUpperCase().trim() });
    }

    opinionCumplimiento(rfc) {
        return this._post('/api/v1/sat/opinion-cumplimiento', { rfc: rfc.toUpperCase().trim() });
    }

    csf(rfc) {
        return this._post('/api/v1/sat/constancia-situacion-fiscal', { rfc: rfc.toUpperCase().trim() });
    }
}

async function main() {
    const apiKey = process.env.SAT_API_KEY;
    if (!apiKey) {
        console.error('ERROR: configura la variable de entorno SAT_API_KEY');
        console.error('  export SAT_API_KEY="sat_xxxxxxxxxxxx"');
        process.exit(1);
    }

    const rfc = process.argv[2] || 'XAXX010101000';
    const client = new SatApiClient(apiKey);
    console.log(`Consultando datos fiscales de RFC: ${rfc}\n`);

    const result = await client.datosFiscales(rfc);

    console.log(`  Código:    ${result.cfdi_codigo || 0}`);
    console.log(`  Texto:     ${result.cfdi_texto || ''}`);
    console.log(`  Detalle:   ${result.cfdi_descripcion || ''}`);
    console.log(`  Saldo:     ${result.saldo || 0} créditos`);

    if (result.cfdi_codigo === 1 && result.data) {
        console.log(`\n  Datos fiscales:`);
        console.log(`  ${JSON.stringify(result.data, null, 2)}`);
    } else if (result.cfdi_codigo === 1004) {
        console.log('\n  ⚠️  Saldo insuficiente. Recarga en https://panel.cfdi4.com/saldos');

    } else if (result.cfdi_codigo === 1001) {
        console.log('\n  ⚠️  API key inválida. Verifica la variable SAT_API_KEY');
    }

    process.exit(result.cfdi_codigo === 1 ? 0 : 1);
}

main().catch((err) => {
    console.error('Error fatal:', err);
    process.exit(1);
});