Devs
February 6, 2026

Primera Integración API: Tutorial Paso a Paso con Código Real | gigstack API 2026

Introducción: Por Qué Integrar gigstack API

Si estás construyendo un producto SaaS, e-commerce o plataforma en México, necesitas facturación electrónica CFDI 4.0. En lugar de construir desde cero (complejidad masiva, certificaciones PAC, mantenimiento de cambios SAT), integras gigstack API en <2 horas y olvidas el problema.

En este tutorial crearás tu primera integración: automatizar facturación al recibir un pago. Incluye código real en Node.js, Python y PHP listo para producción 2026.

Lo que construirás

  • Autenticación con API key
  • Crear cliente (validación RFC)
  • Generar factura CFDI 4.0
  • Descargar XML y PDF
  • Manejo de errores

Requisitos Previos

  • Cuenta gigstack: app.gigstack.pro
  • API Key: Disponible en Settings → API
  • RFC y Certificados SAT: Configurados en tu cuenta gigstack
  • Entorno desarrollo: Node.js 18+, Python 3.9+ o PHP 8.0+

Paso 1: Autenticación

Obtener API Key

  1. Login a app.gigstack.pro
  2. Settings → API → Generate New Key
  3. Copia la key (empieza con gsk_live_...)

IMPORTANTE: Nunca expongas tu API key en código frontend o repos públicos.

Autenticación en Requests

gigstack usa Bearer token en header Authorization:

Authorization: Bearer gsk_live_tu_api_key

Paso 2: Setup del Proyecto

Node.js

mkdir gigstack-integration
cd gigstack-integration
npm init -y
npm install axios dotenv

Crea .env:

GIGSTACK_API_KEY=gsk_live_tu_api_key
GIGSTACK_BASE_URL=https://api.gigstack.io/v2

Python

mkdir gigstack-integration
cd gigstack-integration
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install requests python-dotenv

Crea .env igual que Node.js.

PHP

mkdir gigstack-integration
cd gigstack-integration
composer require guzzlehttp/guzzle vlucas/phpdotenv

Crea .env igual que Node.js.

Paso 3: Crear Cliente (Validar RFC)

Antes de facturar, valida que el RFC del cliente esté activo en SAT.

Node.js

// createClient.js
require('dotenv').config();
const axios = require('axios');

const API_KEY = process.env.GIGSTACK_API_KEY;
const BASE_URL = process.env.GIGSTACK_BASE_URL;

const headers = {
  'Authorization': `Bearer ${API_KEY}`,
  'Content-Type': 'application/json'
};

async function createClient(clientData) {
  try {
    const response = await axios.post(
      `${BASE_URL}/clients`,
      clientData,
      { headers }
    );
    
    console.log('✅ Cliente creado:', response.data.data);
    return response.data.data;
  } catch (error) {
    console.error('❌ Error:', error.response?.data || error.message);
    throw error;
  }
}

// Ejemplo de uso
const newClient = {
  rfc: 'XAXX010101000',  // RFC genérico para pruebas
  name: 'Cliente Demo SA de CV',
  email: 'cliente@demo.com',
  postal_code: '01000',
  tax_regime: '601'  // General de Ley Personas Morales
};

createClient(newClient);

Python

# create_client.py
import os
import requests
from dotenv import load_dotenv

load_dotenv()

API_KEY = os.getenv('GIGSTACK_API_KEY')
BASE_URL = os.getenv('GIGSTACK_BASE_URL')

headers = {
    'Authorization': f'Bearer {API_KEY}',
    'Content-Type': 'application/json'
}

def create_client(client_data):
    try:
        response = requests.post(
            f'{BASE_URL}/clients',
            json=client_data,
            headers=headers
        )
        response.raise_for_status()
        
        print('✅ Cliente creado:', response.json()['data'])
        return response.json()['data']
    except requests.exceptions.RequestException as e:
        print('❌ Error:', e.response.json() if e.response else str(e))
        raise

# Ejemplo de uso
new_client = {
    'rfc': 'XAXX010101000',
    'name': 'Cliente Demo SA de CV',
    'email': 'cliente@demo.com',
    'postal_code': '01000',
    'tax_regime': '601'
}

create_client(new_client)

PHP

<?php
// createClient.php
require 'vendor/autoload.php';

use GuzzleHttp\Client;
use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

$apiKey = $_ENV['GIGSTACK_API_KEY'];
$baseUrl = $_ENV['GIGSTACK_BASE_URL'];

$client = new Client([
    'base_uri' => $baseUrl,
    'headers' => [
        'Authorization' => 'Bearer ' . $apiKey,
        'Content-Type' => 'application/json'
    ]
]);

function createClient($httpClient, $clientData) {
    try {
        $response = $httpClient->post('/clients', [
            'json' => $clientData
        ]);
        
        $data = json_decode($response->getBody(), true);
        echo "✅ Cliente creado: " . json_encode($data['data']) . "\n";
        return $data['data'];
    } catch (Exception $e) {
        echo "❌ Error: " . $e->getMessage() . "\n";
        throw $e;
    }
}

// Ejemplo de uso
$newClient = [
    'rfc' => 'XAXX010101000',
    'name' => 'Cliente Demo SA de CV',
    'email' => 'cliente@demo.com',
    'postal_code' => '01000',
    'tax_regime' => '601'
];

createClient($client, $newClient);

Paso 4: Generar Factura CFDI 4.0

Una vez creado el cliente, genera su factura.

Node.js

// createInvoice.js
require('dotenv').config();
const axios = require('axios');

const API_KEY = process.env.GIGSTACK_API_KEY;
const BASE_URL = process.env.GIGSTACK_BASE_URL;

const headers = {
  'Authorization': `Bearer ${API_KEY}`,
  'Content-Type': 'application/json'
};

async function createInvoice(invoiceData) {
  try {
    const response = await axios.post(
      `${BASE_URL}/invoices`,
      invoiceData,
      { headers }
    );
    
    console.log('✅ Factura generada:', response.data.data);
    console.log('   UUID:', response.data.data.uuid);
    console.log('   PDF:', response.data.data.pdf_url);
    console.log('   XML:', response.data.data.xml_url);
    
    return response.data.data;
  } catch (error) {
    console.error('❌ Error:', error.response?.data || error.message);
    throw error;
  }
}

// Ejemplo de uso
const invoice = {
  client_id: 'cliente_id_del_paso_anterior',
  payment_form: '04',  // Tarjeta de crédito
  payment_method: 'PUE',  // Pago en una sola exhibición
  cfdi_use: 'G03',  // Gastos en general
  items: [
    {
      description: 'Suscripción mensual Premium',
      quantity: 1,
      unit_price: 999.00,
      tax_rate: 0.16,  // IVA 16%
      product_key: '84111506',  // Servicios de suscripción
      unit_key: 'E48'  // Servicio
    }
  ],
  notes: 'Gracias por tu compra'
};

createInvoice(invoice);

Python

# create_invoice.py
import os
import requests
from dotenv import load_dotenv

load_dotenv()

API_KEY = os.getenv('GIGSTACK_API_KEY')
BASE_URL = os.getenv('GIGSTACK_BASE_URL')

headers = {
    'Authorization': f'Bearer {API_KEY}',
    'Content-Type': 'application/json'
}

def create_invoice(invoice_data):
    try:
        response = requests.post(
            f'{BASE_URL}/invoices',
            json=invoice_data,
            headers=headers
        )
        response.raise_for_status()
        
        data = response.json()['data']
        print('✅ Factura generada:', data)
        print(f'   UUID: {data["uuid"]}')
        print(f'   PDF: {data["pdf_url"]}')
        print(f'   XML: {data["xml_url"]}')
        
        return data
    except requests.exceptions.RequestException as e:
        print('❌ Error:', e.response.json() if e.response else str(e))
        raise

# Ejemplo de uso
invoice = {
    'client_id': 'cliente_id_del_paso_anterior',
    'payment_form': '04',
    'payment_method': 'PUE',
    'cfdi_use': 'G03',
    'items': [
        {
            'description': 'Suscripción mensual Premium',
            'quantity': 1,
            'unit_price': 999.00,
            'tax_rate': 0.16,
            'product_key': '84111506',
            'unit_key': 'E48'
        }
    ],
    'notes': 'Gracias por tu compra'
}

create_invoice(invoice)

PHP

<?php
// createInvoice.php
require 'vendor/autoload.php';

use GuzzleHttp\Client;
use Dotenv\Dotenv;

$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();

$apiKey = $_ENV['GIGSTACK_API_KEY'];
$baseUrl = $_ENV['GIGSTACK_BASE_URL'];

$client = new Client([
    'base_uri' => $baseUrl,
    'headers' => [
        'Authorization' => 'Bearer ' . $apiKey,
        'Content-Type' => 'application/json'
    ]
]);

function createInvoice($httpClient, $invoiceData) {
    try {
        $response = $httpClient->post('/invoices', [
            'json' => $invoiceData
        ]);
        
        $data = json_decode($response->getBody(), true)['data'];
        echo "✅ Factura generada: " . json_encode($data) . "\n";
        echo "   UUID: {$data['uuid']}\n";
        echo "   PDF: {$data['pdf_url']}\n";
        echo "   XML: {$data['xml_url']}\n";
        
        return $data;
    } catch (Exception $e) {
        echo "❌ Error: " . $e->getMessage() . "\n";
        throw $e;
    }
}

// Ejemplo de uso
$invoice = [
    'client_id' => 'cliente_id_del_paso_anterior',
    'payment_form' => '04',
    'payment_method' => 'PUE',
    'cfdi_use' => 'G03',
    'items' => [
        [
            'description' => 'Suscripción mensual Premium',
            'quantity' => 1,
            'unit_price' => 999.00,
            'tax_rate' => 0.16,
            'product_key' => '84111506',
            'unit_key' => 'E48'
        ]
    ],
    'notes' => 'Gracias por tu compra'
];

createInvoice($client, $invoice);

Paso 5: Descargar XML y PDF

Una vez generada la factura, descarga archivos para almacenar o enviar al cliente.

Node.js

// downloadFiles.js
const fs = require('fs');
const axios = require('axios');

async function downloadFile(url, filename) {
  try {
    const response = await axios.get(url, { responseType: 'arraybuffer' });
    fs.writeFileSync(filename, response.data);
    console.log(`✅ Descargado: ${filename}`);
  } catch (error) {
    console.error(`❌ Error descargando ${filename}:`, error.message);
  }
}

// Uso después de crear factura
const invoiceData = response.data.data;  // Del paso anterior
downloadFile(invoiceData.pdf_url, `factura_${invoiceData.uuid}.pdf`);
downloadFile(invoiceData.xml_url, `factura_${invoiceData.uuid}.xml`);

Paso 6: Manejo de Errores Comunes

RFC Inválido

{
  "error": {
    "code": "invalid_rfc",
    "message": "RFC no válido o inactivo en padrón SAT"
  }
}

Solución: Validar RFC antes de crear cliente. gigstack valida contra SAT en tiempo real.

Cliente Ya Existe

{
  "error": {
    "code": "client_exists",
    "message": "Cliente con este RFC ya existe",
    "existing_client_id": "cliente_123"
  }
}

Solución: Usar existing_client_id para crear factura directamente.

Monto Inválido

{
  "error": {
    "code": "invalid_amount",
    "message": "El monto debe ser mayor a 0"
  }
}

Solución: Verificar cálculos antes de enviar request.

Paso 7: Integración Completa (Ejemplo Real)

Automatizar facturación al recibir pago Stripe:

Node.js + Stripe Webhook

// server.js
require('dotenv').config();
const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const axios = require('axios');

const app = express();
app.use(express.json());

const GIGSTACK_API_KEY = process.env.GIGSTACK_API_KEY;
const GIGSTACK_BASE_URL = process.env.GIGSTACK_BASE_URL;

app.post('/webhooks/stripe', async (req, res) => {
  const event = req.body;
  
  if (event.type === 'payment_intent.succeeded') {
    const paymentIntent = event.data.object;
    
    // Obtener datos cliente desde metadata
    const clientData = {
      rfc: paymentIntent.metadata.rfc,
      name: paymentIntent.metadata.customer_name,
      email: paymentIntent.receipt_email,
      postal_code: paymentIntent.metadata.postal_code,
      tax_regime: paymentIntent.metadata.tax_regime || '601'
    };
    
    // Crear factura automáticamente
    try {
      const invoiceData = {
        client: clientData,  // gigstack crea cliente si no existe
        payment_form: '04',
        payment_method: 'PUE',
        cfdi_use: paymentIntent.metadata.cfdi_use || 'G03',
        items: [
          {
            description: paymentIntent.description,
            quantity: 1,
            unit_price: paymentIntent.amount / 100,  // Stripe usa centavos
            tax_rate: 0.16,
            product_key: '84111506',
            unit_key: 'E48'
          }
        ]
      };
      
      const response = await axios.post(
        `${GIGSTACK_BASE_URL}/invoices`,
        invoiceData,
        { headers: { 'Authorization': `Bearer ${GIGSTACK_API_KEY}` } }
      );
      
      console.log('✅ Factura generada:', response.data.data.uuid);
    } catch (error) {
      console.error('❌ Error facturando:', error.response?.data);
    }
  }
  
  res.json({ received: true });
});

app.listen(3000, () => console.log('🚀 Servidor corriendo en puerto 3000'));

Próximos Pasos Avanzados

  • Webhooks gigstack: Notificaciones cuando factura se timbra/cancela
  • Complementos de pago: Facturación anticipada + complementos
  • Portales de autofactura: Clientes generan sus propias facturas
  • Multi-tenant: Múltiples RFC emisores desde una cuenta

Preguntas Frecuentes

¿Cuánto tarda en generarse una factura?

Promedio <2 segundos desde request hasta factura timbrada. El endpoint es sincrónico: cuando devuelve respuesta, la factura ya está lista.

¿Cómo pruebo sin generar facturas reales?

Usa API key de test (empieza con gsk_test_...). Facturas en modo test no se envían al SAT.

¿Puedo cancelar facturas vía API?

Sí. Endpoint POST /invoices/{uuid}/cancel con motivo de cancelación.

Recursos

Blogs que te pueden gustar