stackin
SDKs

SDKs

  • Una clase, tres métodos

    Un cliente Invoice con issue(), consult() y cancel() — nada más que instanciar.

  • Modelos tipados

    Cada ítem es un Product tipado, con campos fiscales de Brasil validados en el cliente antes de que salga la solicitud.

  • El mismo contrato en cada lenguaje

    Python, Go y PHP siguen el mismo contrato de API — métodos, errores y recursos se comportan igual, así que cambiar de lenguaje no significa reaprender stackin.

¿Recién empezando?

Cree una cuenta gratuita, genere una SDK key y emita su primer documento en homologation — es gratis e ilimitado, sin tarjeta.

Copy
pip install stackin-python-sdk

Autenticación

El SDK autentica con una SDK key — pásela una vez al crear el client, la librería se encarga del resto. Nunca construye una URL ni define un header manualmente.

Cómo obtener una SDK key

  1. 1
    Regístrese e inicie sesión en .
  2. 2
    Cree una empresa — obligatorio antes de la key.
  3. 3
    Vaya a Settings → API key en el dashboard, y deje el contexto en sdk. No se necesita certificado en este paso — la key se puede crear y usar de inmediato; el certificado solo se exige después, al emitir un documento.
  4. 4
    Nombre la key y elija su entorno (homologation o production, por defecto homologation) — queda fijo durante toda la vida de la key, no se puede cambiar después.
  5. 5
    Copie la key de inmediato — se muestra , al crearla, y no se puede recuperar después. Si la pierde, revóquela y cree otra.
Copy
from stackin import Invoice

client = Invoice(api_key="$STACKIN_API_KEY")

Una empresa puede tener hasta 3 keys en total (cualquier combinación de contexto sdk/api y entorno homologation/production), así puede mantener keys separadas por superficie o entorno.

Un token ausente o inválido devuelve 401 — ver abajo.

Entornos

Cada SDK key se crea para exactamente un entorno — o or — elegido al generarla en el dashboard, fijo durante toda la vida de la key. No hay campo de entorno en las llamadas del SDK: la key con la que se autentica decide a dónde va el documento.

HomologationEntorno de prueba

Gratis e ilimitado — es el entorno de prueba real de SEFAZ/ADN, no un mock — así que integra y prueba todo antes de cambiar a production.

ProductionEntorno real

Para documentos reales. Asegúrate de que todo funcione en homologation antes de cambiar.

Una empresa puede tener keys de ambos entornos a la vez (hasta 3 en total).

Errores

Los SDKs traducen cada falla en un tipo distinto: APIError para lo que respondió la API (con status y detail), ConnectionFailedError para una falla de red antes de cualquier respuesta, y el error de validación del propio lenguaje para lo que se detecta en el cliente, antes de que salga la solicitud.

Copy
from stackin import APIError, ConnectionFailedError

try:
    result = client.issue(...)
except ValueError as error:
    # Caught before the request left — empty items, missing ncm/cfop,
    # incomplete recipient_address on an NFE.
    print(f"Invalid request: {error}")
except APIError as error:
    # 4xx/5xx from the API. 502 carries the authorizer's own message.
    print(f"[{error.status_code}] {error.detail}")
except ConnectionFailedError as error:
    print(f"Could not reach the API: {error}")
HTTPErrorCuándo
400Configuración inválidaLa configuración del emisor (certificado, dirección, campos fiscales) está ausente o es inválida.
401No autorizadoEl Bearer token está ausente, expirado, es inválido o no fue creado para el host que estás llamando (api.stackin.io vs sdk.stackin.io).
402Límite alcanzadoLa cuota del plan de la empresa para notas de production fue alcanzada y el plan no tiene precio de excedente (trial).
409Conflicto de operaciónLa operación solicitada no aplica a ese document_type (ej.: una operación exclusiva de nfse en una nfe).
422Error de validaciónEl cuerpo de la solicitud falló la validación — campo obligatorio faltante o malformado.
501No implementadoLa firma para ese tipo de documento/país aún no está implementada en el servidor.
502El autorizador rechazóRechazo del autorizadorEl autorizador (SEFAZ/estado o ADN) rechazó la solicitud. detail.message trae el error del propio autorizador, y detail.invoice_id (solo en la emisión) permite consultar el intento rechazado.

Rechazos del autorizador

Cuando la SEFAZ o ADN rechaza una operación, la respuesta incluye información adicional.

El detail del APIError lleva estos campos cuando el autorizador rechaza — usa detail.invoice_id para consultar el intento después.

Copy
{
  "detail": {
    "message": "IE do emitente inválida",
    "invoice_id": "inv_8f3c9b2e6a7d"
  }
}
detail.message
Mensaje devuelto por el autorizador.
detail.invoice_id
Identifica el intento de emisión.
Endpoints

Facturas

Emite un nuevo documento. items[].product.br (ncm, cfop) es obligatorio para , se ignora en , ignored for — un servicio no tiene código de clasificación fiscal, así que nfse solo lee description y amount de cada ítem.

La misma llamada funciona para nfse — solo cambia document_type.

Copy
from stackin import Address, DocumentType, Invoice
from stackin.br import Product

client = Invoice(api_key="$STACKIN_API_KEY")

result = client.issue(
    document_type=DocumentType.NFE,
    client_name="Buyer Company Ltd",
    tax_id="11222333000181",
    items=[
        Product(
            description="Rosa Holambra Vermelha",
            amount=112.44,
            ncm="06031100",
            cfop="5102",
        )
    ],
    recipient_address=Address(
        street="Rua das Flores",
        number="1200",
        neighborhood="Centro",
        city="Joinville",
        state="SC",
        zip_code="89201100",
        city_code="4209102",
    ),
)

Consulta el estado actual de un documento directamente en el autorizador por su access key. Requiere como query param.

Copy
result = client.consult(
    document_type=DocumentType.NFE,
    access_key="42260831112223330001815500000012341123456789",
)

Cancela un documento previamente autorizado. debe tener al menos 15 caracteres para nfe (el campo xJust del autorizador lo exige). Cancelar no devuelve la cuota del plan — la capacidad del autorizador ya se gastó en la emisión.

Copy
result = client.cancel(
    document_type=DocumentType.NFE,
    access_key="42260831112223330001815500000012341123456789",
    reason="Duplicate order, cancelled by the buyer within 24h",
)

Reenvía una emisión fallida por el `id` local del documento (no por su clave de acceso — una nota rechazada no tiene una). Útil para reintentar después de corregir un problema de configuración o una caída del autorizador. Consume crédito como una emisión nueva, ya que es una nueva transmisión.

Copy
result = client.reissue(
    invoice_id="9f2c1e3a-4b5d-6e7f-8a9b-0c1d2e3f4a5b",
)