Guia de Integracion
Punto de Venta (POS)
Conecta tu sistema POS a FiscaFacil para facturar ventas, consultar facturas recibidas y sincronizar con el SAT — todo via API, sin que tus usuarios necesiten entrar al dashboard.
Arquitectura
Tu POS actua como intermediario: registra cuentas, sube certificados (CSD/FIEL) y timbra facturas en nombre de cada cliente. Cada cliente es una empresa en FiscaFacil, y tu POS usa API keys con scoping para aislar el acceso por empresa y por accion.
Requisitos previos
- Cuenta en FiscaFacil (registro via API o dashboard)
- CSD (.cer + .key + contrasena) de cada cliente — para timbrar facturas
- FIEL (.cer + .key + contrasena) de cada cliente — para descargar facturas del SAT (opcional)
- Entorno: Sandbox (pruebas) o Produccion
Flujo completo paso a paso
Registrar cuenta de usuario
Crea una cuenta para tu POS. Esta cuenta administrara todas las empresas de tus clientes.
curl -X POST https://api.fiscafacil.mx/auth/register \
-H "Content-Type: application/json" \
-d '{
"name": "Mi POS System",
"email": "pos@miempresa.com",
"password": "SecureP@ssword123"
}'Respuesta: usuario creado con ID.
Crear API key con scoping
Crea un API key con permisos restringidos. Puedes limitar por empresas, acciones permitidas, rate limit e IP.
curl -X POST https://api.fiscafacil.mx/api-keys \
-H "Content-Type: application/json" \
-d '{
"email": "pos@miempresa.com",
"password": "SecureP@ssword123",
"name": "POS Production Key",
"description": "Key para operaciones de facturacion desde POS",
"allowedActions": [
"empresa:view", "empresa:csd",
"cfdi:timbrar", "cfdi:cancelar", "cfdi:view", "cfdi:create",
"cfdi:descargar", "cfdi:leer",
"cliente:create", "cliente:view",
"producto:create", "producto:view"
],
"rateLimit": 120,
"expiresInDays": 365
}'ff_<64 hex chars>.Opciones de scoping:
| Campo | Tipo | Descripcion |
|---|---|---|
| allowedEmpresaIds | string[] | IDs de empresas permitidas. [] = todas. |
| allowedActions | string[] | Acciones permitidas. [] = todas del rol. |
| rateLimit | number | Requests por minuto. Default: 60, max: 10,000. |
| ipWhitelist | string[] | IPs permitidas. [] = cualquier IP. |
| expiresInDays | number | Dias hasta expiracion. Omitir = sin expiracion. |
Crear empresa por cada cliente
Cada cliente de tu POS necesita una empresa en FiscaFacil con su RFC y regimen fiscal.
curl -X POST https://api.fiscafacil.mx/empresas \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"rfc": "XAXX010101000",
"razonSocial": "Tienda Don Juan SA de CV",
"regimenFiscal": "601",
"codigoPostal": "44100",
"sandbox": false
}'Guarda el id de la empresa — lo necesitas como header x-empresa-id en todas las llamadas.
Subir CSD (certificado de sello digital)
El CSD permite timbrar facturas. Sube el .cer, .key y contrasena en base64. FiscaFacil valida que el RFC del certificado coincida con la empresa.
# Convertir archivos a base64
CER_B64=$(base64 -i certificado.cer)
KEY_B64=$(base64 -i llave.key)
curl -X POST https://api.fiscafacil.mx/empresas/{empresaId}/certificados \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}" \
-H "Content-Type: application/json" \
-d "{
\"cerBase64\": \"$CER_B64\",
\"keyBase64\": \"$KEY_B64\",
\"password\": \"12345678a\"
}"Subir FIEL (e.firma) — opcional
La FIEL permite descargar facturas recibidas del SAT. Solo necesaria si quieres consultar lo que tus clientes han recibido.
curl -X POST https://api.fiscafacil.mx/empresas/{empresaId}/fiel \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}" \
-H "Content-Type: application/json" \
-d '{
"cerBase64": "<base64 del .cer de FIEL>",
"keyBase64": "<base64 del .key de FIEL>",
"password": "contrasena_fiel"
}'Timbrar una venta
Envia el XML sin sellar — FiscaFacil sella y timbra con el PAC certificado.
curl -X POST https://api.fiscafacil.mx/cfdi/timbrar \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}" \
-H "Content-Type: application/json" \
-d '{
"receptor": {
"rfc": "XAXX010101000",
"nombre": "Cliente Mostrador",
"usoCfdi": "S01",
"regimenFiscal": "616",
"codigoPostal": "44100"
},
"conceptos": [{
"claveProdServ": "01010101",
"claveUnidad": "H87",
"descripcion": "Venta mostrador",
"cantidad": 1,
"valorUnitario": 100.00
}],
"formaPago": "01",
"metodoPago": "PUE",
"moneda": "MXN"
}'Respuesta incluye: UUID, XML timbrado, sello SAT, cadena original, y URL del PDF/XML.
Consultar facturas
Lista facturas emitidas y recibidas con filtros y paginacion.
# Listar facturas del mes actual
curl "https://api.fiscafacil.mx/cfdi?page=1&limit=50&tipo=EMITIDA" \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}"
# Buscar por RFC del receptor
curl "https://api.fiscafacil.mx/cfdi?receptorRfc=XAXX010101000" \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}"Descargar factura por UUID (instantaneo)
Descarga una factura recibida del portal del SAT en 5-10 segundos. Requiere FIEL configurada.
curl -X POST https://api.fiscafacil.mx/cfdi/descargar-por-uuid \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}" \
-H "Content-Type: application/json" \
-d '{ "uuid": "6A8B1234-5678-9ABC-DEF0-123456789ABC" }'Tres posibles respuestas: cache (ya existia), sat_portal (descargada), o sat_metadata_only (solo metadata, sin XML completo).
Sync masiva de facturas recibidas
Sincroniza todas las facturas recibidas de un mes completo. Se ejecuta en background.
# Iniciar sync del mes
curl -X POST https://api.fiscafacil.mx/cfdi/sync-recibidos \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}" \
-H "Content-Type: application/json" \
-d '{ "year": 2026, "month": 4 }'
# Consultar estado del sync
curl "https://api.fiscafacil.mx/cfdi/sync-recibidos" \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}"Configurar webhooks
Recibe notificaciones cuando una factura se timbra, cancela, o cuando termina un sync.
curl -X POST https://api.fiscafacil.mx/webhooks \
-H "Authorization: Bearer ff_your_api_key_here" \
-H "x-empresa-id: {empresaId}" \
-H "Content-Type: application/json" \
-d '{
"url": "https://mi-pos.com/webhooks/fiscafacil",
"eventos": [
"cfdi.timbrado",
"cfdi.cancelado",
"cfdi.sync_completado",
"cfdi.sync_error"
]
}'Los webhooks incluyen firma HMAC-SHA256 en el header X-FiscaFacil-Signature.
Rate Limiting
Cada API key tiene su propio rate limit (configurable al crearla, default: 60 req/min). Los headers de respuesta indican el estado:
X-RateLimit-Limit: 60 # Limite configurado
X-RateLimit-Remaining: 45 # Requests restantes en la ventana
X-RateLimit-Reset: 1712764800 # Epoch cuando se reinicia la ventana
# Si excedes el limite:
HTTP 429 Too Many Requests
Retry-After: 35 # Segundos hasta que puedes reintentarCORS (Cross-Origin)
La API permite requests cross-origin desde cualquier dominio cuando usas autenticacion por API key. Esto permite que tu POS frontend (si es web) llame directamente a la API. Los headers CORS se incluyen automaticamente en todas las respuestas de /api/*.
Seguridad
API Keys con scoping
Crea keys con el minimo de permisos necesarios. Un POS tipicamente solo necesita:cfdi:timbrar, cfdi:view,empresa:view, y empresa:csd.
IP Whitelist
Si tu POS tiene IPs fijas, usa ipWhitelist al crear el API key. Requests desde IPs no autorizadas seran rechazados silenciosamente.
Rotacion de keys
Puedes crear un nuevo API key usando uno existente (en el header Authorization), luego revocar el anterior. Zero downtime.
Encripcion de certificados
Los archivos CSD y FIEL se encriptan con AES-256-GCM antes de almacenarse. Las contrasenas nunca se guardan en texto plano.
Ejemplo: JavaScript / Node.js
const API_BASE = 'https://api.fiscafacil.mx';
const API_KEY = 'ff_your_api_key_here';
async function timbrarVenta(empresaId, venta) {
const res = await fetch(`${API_BASE}/api/cfdi/timbrar`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
'x-empresa-id': empresaId,
},
body: JSON.stringify({
receptor: venta.cliente,
conceptos: venta.items.map(item => ({
claveProdServ: item.claveSAT,
claveUnidad: item.unidadSAT,
descripcion: item.nombre,
cantidad: item.cantidad,
valorUnitario: item.precio,
})),
formaPago: venta.formaPago,
metodoPago: 'PUE',
moneda: 'MXN',
}),
});
const json = await res.json();
if (!json.success) {
throw new Error(json.error?.message || 'Error al timbrar');
}
// Check rate limit headers
const remaining = res.headers.get('X-RateLimit-Remaining');
if (remaining && parseInt(remaining) < 10) {
console.warn(`Rate limit bajo: ${remaining} requests restantes`);
}
return json.data; // { uuid, xml, pdf, ... }
}Ejemplo: Python
import requests
import base64
API_BASE = "https://api.fiscafacil.mx"
API_KEY = "ff_your_api_key_here"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
# 1. Crear empresa
def crear_empresa(rfc, razon_social, regimen, cp):
res = requests.post(f"{API_BASE}/api/empresas", headers=headers, json={
"rfc": rfc,
"razonSocial": razon_social,
"regimenFiscal": regimen,
"codigoPostal": cp,
})
return res.json()["data"]["id"]
# 2. Subir CSD
def subir_csd(empresa_id, cer_path, key_path, password):
with open(cer_path, "rb") as f:
cer_b64 = base64.b64encode(f.read()).decode()
with open(key_path, "rb") as f:
key_b64 = base64.b64encode(f.read()).decode()
h = {**headers, "x-empresa-id": empresa_id}
res = requests.post(
f"{API_BASE}/api/empresas/{empresa_id}/certificados",
headers=h,
json={"cerBase64": cer_b64, "keyBase64": key_b64, "password": password},
)
return res.json()
# 3. Timbrar
def timbrar(empresa_id, receptor, conceptos, forma_pago="01"):
h = {**headers, "x-empresa-id": empresa_id}
res = requests.post(f"{API_BASE}/api/cfdi/timbrar", headers=h, json={
"receptor": receptor,
"conceptos": conceptos,
"formaPago": forma_pago,
"metodoPago": "PUE",
"moneda": "MXN",
})
data = res.json()
if not data["success"]:
raise Exception(data["error"]["message"])
return data["data"]Eventos de webhook disponibles
| Evento | Descripcion |
|---|---|
| cfdi.timbrado | Una factura fue timbrada exitosamente |
| cfdi.cancelado | Una factura fue cancelada |
| cfdi.sync_completado | Sync de facturas recibidas completo |
| cfdi.sync_error | Error durante sync de facturas |
| cfdi.cancelacion_pendiente | Solicitud de cancelacion enviada al receptor |
| cfdi.cancelacion_aceptada | Cancelacion aceptada por el receptor |
| cfdi.cancelacion_rechazada | Cancelacion rechazada por el receptor |
Codigos de error relevantes para POS
| Codigo | HTTP | Descripcion |
|---|---|---|
| AUTH_001 | 401 | API key invalido o expirado |
| SCOPE_001 | 403 | API key no tiene acceso a la empresa especificada |
| SCOPE_002 | 403 | API key no tiene permiso para la accion solicitada |
| RATE_001 | 429 | Rate limit excedido. Ver header Retry-After. |
| EMPRESA_001 | 400 | Falta header x-empresa-id |
| CSD_004 | 400 | RFC del certificado no coincide con la empresa |
| FIEL_004 | 400 | RFC de la FIEL no coincide con la empresa |
Formato de respuesta
Todas las respuestas siguen el mismo formato:
Exitosa
{
"success": true,
"data": { ... }
}Error
{
"success": false,
"error": {
"code": "CSD_004",
"message": "RFC no coincide"
}
}