SDKs oficiales
Emitoo tiene SDKs oficiales para tu lenguaje — Python, Node/TypeScript y Go — construidos y verificados contra la misma API: mismos endpoints, misma semántica de reintentos, idempotencia y errores. Para cualquier otro lenguaje, la API es REST + JSON y publicamos su especificación OpenAPI 3.1 para generar un cliente tipado.
Todos son capas finas sobre el cliente HTTP nativo de cada lenguaje:
los métodos aceptan y devuelven diccionarios/objetos planos (sin modelos
generados por schema). Todos leen la API key de la variable de entorno
EMITOO_API_KEY (y la URL base de EMITOO_BASE_URL)
si no las pasas explícitas, y envían el header X-API-Key por
ti.
Aún no publicados en los registries
SDK de Python
Cliente síncrono sobre httpx (única dependencia en runtime).
Requiere Python ≥ 3.10.
Instalación
pip install emitoo # próximamente en PyPIQuickstart
from emitoo import EmitooClient
client = EmitooClient(api_key="fpk_...") # o export EMITOO_API_KEY=fpk_...
# 1. Emitir una factura. Con idempotency_key, reintentar el mismo POST
# devuelve la MISMA factura (no la duplica).
factura = client.facturas.crear(
{
"tipo_identificacion": "04", # 04 = RUC, 05 = cédula
"identificacion": "0991234567001",
"razon_social": "ACME S.A.",
"email": "facturacion@acme.example",
"detalles": [
{"codigo_principal": "LIC-1", "descripcion": "Licencia mensual",
"cantidad": 1, "precio_unitario": 75.0, "tarifa_iva": 15},
],
},
idempotency_key="orden-8912",
)
print(factura["id"], factura["estado"]) # 177 "PENDIENTE"
# 2. El envío al SRI es asíncrono: espera a un estado final
# (lanza TimeoutError si se agota el tiempo).
factura = client.facturas.esperar_autorizacion(factura["id"], timeout=60.0)
print(factura["estado"]) # "AUTORIZADO"
# 3. Descargar el RIDE (PDF) — devuelve bytes.
pdf = client.facturas.ride(factura["id"])
client.close()También funciona como context manager (cierra la conexión HTTP al salir):
with EmitooClient(api_key="fpk_...") as client:
facturas = client.facturas.listar()Manejo de errores
from emitoo import EmitooError, ValidationError, RateLimitError
try:
client.facturas.crear(payload, idempotency_key="orden-8912")
except ValidationError as exc:
print(exc.status_code, exc.errors) # 422, detail de FastAPI/Pydantic
except RateLimitError as exc:
print("reintenta en", exc.retry_after, "segundos")
except EmitooError as exc:
print("error de Emitoo:", exc.status_code, exc.message)SDK de Node/TypeScript
Cliente sobre el fetch global — cero dependencias en
runtime. Requiere Node ≥ 18. Se publica como ESM + CJS, con
tipos incluidos.
Instalación
npm install emitoo # próximamente en npmQuickstart
import { Emitoo } from "emitoo";
const client = new Emitoo({ apiKey: "fpk_..." }); // o export EMITOO_API_KEY=fpk_...
// 1. Emitir una factura. Con idempotencyKey, reintentar el mismo POST
// devuelve la MISMA factura (no la duplica).
const factura = await client.facturas.crear(
{
tipo_identificacion: "04", // 04 = RUC, 05 = cédula
identificacion: "0991234567001",
razon_social: "ACME S.A.",
email: "facturacion@acme.example",
detalles: [
{ codigo_principal: "LIC-1", descripcion: "Licencia mensual",
cantidad: 1, precio_unitario: 75.0, tarifa_iva: 15 },
],
},
{ idempotencyKey: "orden-8912" },
);
console.log(factura.id, factura.estado); // 177 "PENDIENTE"
// 2. El envío al SRI es asíncrono: espera a un estado final
// (lanza TimeoutError si se agota el tiempo).
const autorizada = await client.facturas.esperarAutorizacion(factura.id, {
timeoutMs: 60_000,
});
console.log(autorizada.estado); // "AUTORIZADO"
// 3. Descargar el RIDE (PDF) — devuelve Uint8Array.
const pdf = await client.facturas.ride(factura.id);Manejo de errores
import { EmitooError, ValidationError, RateLimitError } from "emitoo";
try {
await client.facturas.crear(payload, { idempotencyKey: "orden-8912" });
} catch (exc) {
if (exc instanceof ValidationError) {
console.log(exc.status, exc.errors); // 422, detail de FastAPI/Pydantic
} else if (exc instanceof RateLimitError) {
console.log("reintenta en", exc.retryAfter, "segundos");
} else if (exc instanceof EmitooError) {
console.log("error de Emitoo:", exc.status, exc.message);
} else {
throw exc;
}
}SDK de Go
Cliente sobre net/http — cero dependencias
fuera de la librería estándar. Requiere Go ≥ 1.22. Todos los métodos
reciben context.Context y el cliente es seguro para uso
concurrente entre goroutines (no necesita Close()).
Instalación
go get github.com/Killkanacode/emitoo-go # próximamenteQuickstart
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/Killkanacode/emitoo-go"
)
func main() {
client, err := emitoo.New("fpk_...") // o export EMITOO_API_KEY=fpk_...
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// 1. Emitir una factura. Con WithIdempotencyKey, reintentar el mismo
// POST devuelve la MISMA factura (no la duplica).
factura, err := client.Facturas.Crear(ctx, emitoo.M{
"tipo_identificacion": "04", // 04 = RUC, 05 = cédula
"identificacion": "0991234567001",
"razon_social": "ACME S.A.",
"email": "facturacion@acme.example",
"detalles": []emitoo.M{
{"codigo_principal": "LIC-1", "descripcion": "Licencia mensual",
"cantidad": 1, "precio_unitario": 75.0, "tarifa_iva": 15},
},
}, emitoo.WithIdempotencyKey("orden-8912"))
if err != nil {
log.Fatal(err)
}
fmt.Println(factura["id"], factura["estado"]) // 177 PENDIENTE
// 2. El envío al SRI es asíncrono: espera a un estado final
// (retorna un error que envuelve emitoo.ErrTimeout si se agota).
id := int(factura["id"].(float64))
factura, err = client.Facturas.EsperarAutorizacion(ctx, id, 60*time.Second, 2*time.Second)
if err != nil {
log.Fatal(err)
}
fmt.Println(factura["estado"]) // AUTORIZADO
// 3. Descargar el RIDE (PDF) — devuelve []byte.
pdf, err := client.Facturas.Ride(ctx, id)
if err != nil {
log.Fatal(err)
}
_ = pdf
}Manejo de errores
En Go los errores de API son un único tipo *emitoo.APIError
(.StatusCode, .Message, .Body,
.RetryAfter, .Errors) que se distingue con
predicados basados en errors.As:
factura, err := client.Facturas.Crear(ctx, payload)
if err != nil {
var apiErr *emitoo.APIError
switch {
case emitoo.IsValidation(err): // 422
errors.As(err, &apiErr)
fmt.Println(apiErr.StatusCode, apiErr.Errors) // detail de FastAPI/Pydantic
case emitoo.IsRateLimit(err): // 429
errors.As(err, &apiErr)
fmt.Println("reintenta en", *apiErr.RetryAfter, "segundos")
default:
fmt.Println("error de Emitoo:", err)
}
}Errores y reintentos (todos los SDKs)
La semántica es la misma en todos ellos. Python y TypeScript usan una
jerarquía de excepciones; Go usa *APIError + predicados:
| Status | Python / TypeScript | Go |
|---|---|---|
| 401 | AuthenticationError | IsAuthentication(err) |
| 403 | PermissionDeniedError | IsPermissionDenied(err) |
| 404 | NotFoundError | IsNotFound(err) |
| 409 | ConflictError | IsConflict(err) |
| 422 | ValidationError (.errors) | IsValidation(err) (.Errors) |
| 429 | RateLimitError (.retry_after / .retryAfter) | IsRateLimit(err) (.RetryAfter) |
| 5xx | ServerError | IsServer(err) |
| — (red) | APIConnectionError | *APIConnectionError |
Todos reintentan automáticamente (hasta max_retries /
maxRetries / WithMaxRetries, default 2, con
backoff exponencial) ante 429 y errores de red/5xx — pero un
POST solo se reintenta si le pasaste la idempotency key (ver
Idempotency-Key): sin ella, un
reintento podría duplicar el comprobante.
Recursos disponibles
Los SDKs oficiales exponen los mismos 14 recursos. Todos aceptan y devuelven
diccionarios/objetos planos, salvo donde se indica (PDF →
bytes/Uint8Array/[]byte, CSV →
str/string).
Convención de nombres por lenguaje
client.notasCredito.esperarAutorizacion(...),
estadoCuentaPdf) y en Go PascalCase con
ctx como primer argumento
(client.NotasCredito.EsperarAutorizacion(ctx, ...)). Dos
diferencias puntuales en Go: estado_cuenta(id, formato="csv")
es un método aparte (EstadoCuentaCSV) y el PDF del estado de
cuenta es EstadoCuentaPDF.
| Recurso | Para qué | Métodos principales |
|---|---|---|
facturas | Facturas electrónicas | crear, listar, obtener, status, reenviar, ride, email, anular, esperar_autorizacion |
notas_credito | Notas de crédito | iguales a facturas |
notas_debito | Notas de débito | iguales a facturas |
liquidaciones | Liquidaciones de compra | iguales a facturas |
guias | Guías de remisión | como facturas sin reenviar |
retenciones | Comprobantes de retención | como facturas sin reenviar |
compras | Documentos de compra de proveedores | listar, crear, obtener, actualizar, eliminar, categorias, importar_xml |
cobros | Cuentas por cobrar (CxC) | listar, crear, cartera, estado_cuenta, estado_cuenta_pdf, obtener, anular |
pagos_proveedor | Cuentas por pagar (CxP) | listar, crear, agenda, obtener, anular |
cuentas_dinero | Cajas y bancos | listar, crear, obtener, actualizar, eliminar, listar_movimientos, crear_movimiento, transferir |
personas_empresas | Clientes y proveedores (catálogo) | listar, lookup, obtener, crear, actualizar, eliminar |
servicios | Catálogo de servicios/productos | listar, obtener, crear, actualizar, eliminar |
sucursales | Sucursales (establecimientos) | listar, crear, actualizar, eliminar |
eventos | Feed de eventos (reconciliación pull) | listar, obtener |
Los SDKs no se interponen entre tú y la API
Otros lenguajes
La API es REST estándar con JSON: cualquier cliente HTTP funciona. Para un cliente tipado en un lenguaje sin SDK oficial, genera uno a partir de la especificación OpenAPI 3.1.
OpenAPI: genera tu cliente tipado
La especificación de la API pública vive en
https://api.emitoo.io/api/v1/public/openapi.json (y su
Swagger UI en /api/v1/public/docs). Con ella puedes generar
tipos y clientes:
# Tipos TS a partir de la OpenAPI
npx openapi-typescript https://api.emitoo.io/api/v1/public/openapi.json \
-o src/emitoo.d.ts
# O un cliente completo
npx @hey-api/openapi-ts \
-i https://api.emitoo.io/api/v1/public/openapi.json \
-o src/emitoo# Cliente Python tipado (pydantic + httpx)
pip install openapi-python-client
openapi-python-client generate \
--url https://api.emitoo.io/api/v1/public/openapi.json¿Quieres un SDK oficial en otro lenguaje?
Postman
Si prefieres explorar la API sin escribir código, descarga la especificación y una colección de Postman lista para importar, generada directamente desde la misma OpenAPI que usan los SDKs:
- Colección de Postman (
emitoo.postman_collection.json) — un request por endpoint, organizados por recurso. - OpenAPI 3.1 (
openapi.json) — la misma especificación pública de arriba, para importar en Postman, Insomnia o generar tu propio cliente.
Para importar: en Postman, Import → File y elige
emitoo.postman_collection.json; luego edita la variable de
colección api_key (pestaña Variables) con tu
key fpk_… — base_url ya viene apuntando a
https://api.emitoo.io.
Versionado y compatibilidad
La API REST está versionada en la URL (/api/v1): los cambios
incompatibles solo llegarían con un /api/v2, sin romper
integraciones existentes. Campos y endpoints nuevos se agregan de forma
retrocompatible y aparecen en la OpenAPI el mismo día.