Autenticación
La API pública de Fenicia (api.fenicia.io) recibe la credencial en el header Authorization: Bearer <credencial>. Ese mismo endpoint acepta dos tipos de credencial: el JWT de sesión que usa el panel (app.fenicia.io) y la API key (fkapi_...), que es la credencial soportada para integraciones externas.
Esta sección documenta el flujo de API key — es el único mecanismo que debes usar si estás integrando de forma programática contra Fenicia.
Hosts y URLs base
| Host | Rol |
|---|---|
api.fenicia.io | La API pública. Aquí van todas tus peticiones de negocio (pedidos, productos, inventario, etc.). Base URL: https://api.fenicia.io, sin prefijo de versión (no existe /v1). |
account.fenicia.io | Emite el JWT de sesión del panel y aloja la gestión de API keys (crear, listar, revocar, eliminar). No se usa para consumir la API pública. Ojo: es account, en singular — accounts.fenicia.io no resuelve. |
webhooks.fenicia.io | Recibe webhooks entrantes de terceros (marketplaces, pasarelas de pago). No participa en la autenticación saliente de tu integración. |
La gestión de keys no vive en api.fenicia.io
Crear, listar, revocar o eliminar una API key son operaciones del panel, no rutas de la API pública. El único camino soportado para gestionarlas hoy es la interfaz de Fenicia — ver Gestión de API Keys.
Ambientes
La tabla de límites de tasa más abajo distingue dev/sandbox/prod, pero cada ambiente vive en un host distinto — tu API key de un tenant de prueba no funciona contra el host de producción, y viceversa:
| Ambiente | Host | Estado (verificado en vivo) |
|---|---|---|
| Producción | https://api.fenicia.io | Responde 401 sin credencial — activo. |
| Desarrollo | https://api-dev.fenicia.io | Responde 401 sin credencial — activo. |
| Sandbox | — | El DNS de api-sandbox.fenicia.io no resuelve hoy (NXDOMAIN). Pese a que existe una fila sandbox en la tabla de rate limits, no hay un host público al que apuntar en este ambiente todavía. |
Sandbox no tiene host público hoy
Si necesitas un ambiente de pruebas antes de integrar contra producción, usa api-dev.fenicia.io con una API key de un tenant de desarrollo. La fila sandbox de la tabla de rate limits documenta un límite configurado a nivel de infraestructura, no un host disponible para conectarte — no lo uses como referencia de a dónde apuntar tu integración.
Cómo se envía la credencial
Toda petición autenticada lleva la API key en el header Authorization con el esquema Bearer:
Authorization: Bearer fkapi_1m8x2z9k_3f9a1c2d4e5f6789abcd0123ef456789curl https://api.fenicia.io/orders \
-H "Authorization: Bearer $FENICIA_API_KEY" \
-H "Content-Type: application/json"Qué devuelve un fallo de autenticación
El autorizador de api.fenicia.io no devuelve un cuerpo JSON con un catálogo de códigos propio: cuando deniega una petición genera una política IAM de rechazo, y API Gateway la traduce al cuerpo por defecto de AWS — {"message": "<detalle>"} — sin un campo code. No hay ningún GatewayResponse con plantilla personalizada configurada para estos casos.
| Situación | HTTP | Cuerpo |
|---|---|---|
Falta el header Authorization o no cumple el formato Bearer <token> | 401 | {"message": "..."} |
| La API key no existe, fue revocada, o no tiene permisos suficientes | 403 | {"message": "..."} |
El tenant está en estado blocked o terminated | 403 | {"message": "..."} — bloqueado por el autorizador antes de llegar al handler |
El tenant está en suspended (o terminated, en las pocas rutas que el autorizador sí deja pasar) y la operación es de escritura | 402 | {"code": "TENANT_PAYMENT_REQUIRED", "message": "..."} |
El único código estructurado es TENANT_PAYMENT_REQUIRED
Si automatizas manejo de errores contra api.fenicia.io, no dependas de un catálogo de códigos de autenticación — no existe. El único caso con un code estructurado en el cuerpo de la respuesta es el bloqueo por facturación (TENANT_PAYMENT_REQUIRED, HTTP 402), que lo emite el handler de negocio, no el autorizador. Todo lo demás llega como 401/403 genérico. Un tenant en payment-required (el periodo de gracia de dunning) no está bloqueado — sus escrituras siguen pasando.
No hay un envelope de respuesta único en toda la API
Verifica el envelope del dominio antes de escribir tu parser
Fenicia no tiene un contrato de respuesta homogéneo entre dominios. Cada uno documenta el suyo en su propio artículo — lee esta tabla antes de asumir que lo que viste en un dominio aplica a otro.
| Dominio | Envelope de éxito | Envelope de error | Detalle |
|---|---|---|---|
Órdenes (/orders/*) | { "data": ..., "meta": {...} } (en recurso único, meta es opcional; meta.pagination es obligatorio en listas) | { "error": { "code": "namespace:motivo", "message": "..." } } | Visión general de Órdenes |
Productos (/products/*) | Sin envelope único — array plano, objeto directo, o shape ad-hoc según el endpoint; solo un endpoint usa {data, meta} | Varía por endpoint | Visión general de Productos |
Colecciones (/collections/*) | Cuerpo plano (sigue el patrón legado de Productos) | Varía por endpoint | Colecciones |
Categorías (/categories/*) | { "success": true, ... } | { "success": false, "error": "<texto>", "code": "SCREAMING_SNAKE" } — nota: aquí error es un string, no un objeto, y code sí va en mayúsculas, al revés que Órdenes | Categorías |
Inventario (/inventory/*) | Forma propia por recurso ({ items, pagination }, { transfers, pagination }, etc.), documento crudo en detalle | Varía por endpoint | Visión general de Inventarios |
| Autenticación (fallos del autorizador) | N/A | { "message": "..." } de AWS, sin code (excepto TENANT_PAYMENT_REQUIRED) | Esta página, arriba |
Errores que no vienen de Fenicia
Algunas respuestas de borde las genera la infraestructura, no la plataforma
Ciertas peticiones nunca llegan a un handler de Fenicia — las rechaza una capa de infraestructura (API Gateway o el load balancer que está delante) antes de eso. Esas respuestas no siguen ningún envelope de la plataforma: no traen un objeto data/error, solo el {"message": "..."} de AWS — y el caso 414 ni siquiera es JSON. Si tu cliente asume que toda respuesta de api.fenicia.io es JSON con la forma de la tabla de arriba, estos casos lo van a romper.
| Situación | HTTP | Cuerpo real (verificado) |
|---|---|---|
Ruta fuera del árbol de rutas conocido (ej. /kittens), sin header Authorization | 403 | {"message":"Missing Authentication Token"} — JSON de AWS, sin code |
Ruta fuera del árbol de rutas conocido, con header Authorization | 403 | API Gateway intenta leer el header como AWS SigV4 y falla: {"message":"Invalid key=value pair (missing equal-sign) in Authorization header (hashed with SHA-256 and encoded with Base64): '<hash>'."} — sigue siendo JSON, pero habla de SigV4, no de tu API key |
| API key inválida o revocada en una ruta que sí existe | 403 | {"message":"User is not authorized to access this resource with an explicit deny in an identity-based policy"} |
| URI de la petición demasiado larga | 414 | HTML, no JSON — lo genera el load balancer (Server: awselb/2.0): <html><head><title>414 Request-URI Too Large</title></head><body><center><h1>414 Request-URI Too Large</h1></center></body></html> |
Un 403 en una ruta desconocida no es un problema de credenciales
Si escribes mal una ruta, API Gateway responde con una queja de parseo SigV4 que menciona el header Authorization. Se lee como si tu API key estuviera mal — no lo está. Revisa primero la ruta: una ruta que no existe en el árbol nunca llega al autorizador de Fenicia.
No parsees estos casos como si fueran de Fenicia
Si tu cliente hace response.json() sin comprobar antes el Content-Type, el caso de URI larga (HTML) va a tronar el parseo. Comprueba el status HTTP y el Content-Type antes de asumir que el cuerpo es JSON del envelope de la plataforma.
Límites de tasa (rate limiting)
El límite de tasa es un throttle a nivel de stage completo de API Gateway — un token bucket compartido entre todos los clientes de ese ambiente —, no un límite por IP ni por API key. Los valores reales varían por ambiente:
| Ambiente | Rate (peticiones/segundo) | Burst |
|---|---|---|
| dev | 100 | 200 |
| sandbox | 500 | 1000 |
| prod | 2000 | 5000 |
Si excedes el límite recibes 429 Too Many Requests. Igual que con los errores de autenticación, no hay una plantilla de respuesta personalizada configurada para este caso.
Tip
Implementa reintentos con backoff exponencial ante un 429. Como el límite es compartido a nivel de todo el ambiente (no por API key), un pico de tráfico de otro cliente en tu mismo ambiente puede acercarte al límite aunque tu integración se mantenga estable.
Siguientes pasos
- Gestión de API Keys — ciclo de vida completo: generación, formato, límites, revocar vs eliminar.
- Permisos y scopes — cómo se definen y evalúan los permisos de una API key.
- API de Órdenes — el primer recurso que probablemente vas a consumir.