Qué es Hermes
Hermes es el middleware de integraciones que conecta nuestras aplicaciones con servicios externos como Zoho y Kraken.
Hermes actúa como puente entre tus aplicaciones y terceros. Gestiona la autenticación OAuth, reenvía peticiones REST y GraphQL, y enruta webhooks entrantes hacia las apps suscritas.
¿Para qué sirve?
- Proxy autenticado hacia Zoho CRM, Books y WorkDrive
- Relay GraphQL hacia Kraken sin queries embebidas
- Recepción y reenvío de webhooks de Zoho con firma HMAC
- Centralización de tokens OAuth y reintentos HTTP
URL base de producción:https://hermes.oees.tech/api/v1
Para despliegue, variables de entorno y operaciones, consulta el repositorio: https://github.com/oees/hermes
Arquitectura
Hermes expone una API FastAPI y un worker Celery que comparten PostgreSQL para credenciales, clientes API y suscripciones de webhooks.
Llamadas salientes
Your App ──(X-API-Key)──▶ Hermes ──(OAuth / JWT)──▶ Third party
│
▼
┌──────────────────────┐
│ PostgreSQL (DO) │
└──────────────────────┘Webhooks entrantes
Zoho ──webhook──▶ Hermes ──route by subscription_name──▶ Your App(s)
│
▼
Celery worker
│
▼
POST + HMAC signatureComponentes principales
- FastAPI API — Endpoints HTTP, CORS, validación de API keys
- Celery worker — Entrega asíncrona de webhooks con reintentos
- PostgreSQL — Credenciales OAuth, clientes API, suscripciones
- Integrations — Clientes REST/GraphQL en app/integrations/
Autenticación
Las peticiones a endpoints protegidos requieren una API key válida. Hermes gestiona por separado la autenticación con cada tercero.
API key (caller → Hermes)
Incluye el header en cada petición a endpoints protegidos:
X-API-Key: hms_live_{32_hex}Generar una API key
python -m app.cli.commands create-api-key my-appErrores
Una API key inválida o ausente devuelve HTTP 401 — Invalid or missing API key.
Hermes → terceros
- Zoho CRM, Books, WorkDrive: OAuth2 refresh token → access token
- Kraken: client credentials → JWT via auth server
Integraciones
Hermes soporta cuatro familias de integración. Cada una expone endpoints de setup y proxy (o relay) bajo /api/v1/.
Zoho CRM
Proxy REST hacia la API v8 y consultas COQL de solo lectura.
POST /zoho/setup — almacenar tokens OAuthPOST /zoho/proxy — proxy REST (GET/POST/PUT/PATCH/DELETE)POST /zoho/query — consultas COQL
Zoho Books
Proxy REST contable; Hermes inyecta organization_id automáticamente.
POST /zoho-books/setup — bootstrap con refresh_tokenPOST /zoho-books/proxy — proxy REST Books v3
Zoho WorkDrive
Proxy REST, descargas y subida de archivos (máx. 250 MB).
POST /zoho-workdrive/setup — bootstrap con refresh_tokenPOST /zoho-workdrive/proxy — proxy REST WorkDrivePOST /zoho-workdrive/upload — subida multipart
Kraken
Relay GraphQL puro: el caller envía query, variables y operationName.
POST /kraken/graphql — relay sin queries embebidas
Referencia de API
Todos los paths son relativos a https://hermes.oees.tech/api/v1. OpenAPI (/docs) solo está disponible con APP_DEBUG=true.
| Método | Path | Auth | Descripción |
|---|---|---|---|
GET | /health | No | Health check (DB + zoho_configured) |
POST | /zoho/setup | Sí | Configure OAuth CRM tokens |
POST | /zoho/proxy | Sí | Proxy to Zoho CRM API |
POST | /zoho/query | Sí | COQL read-only queries |
POST | /zoho-books/setup | Sí | Configure Zoho Books OAuth |
POST | /zoho-books/proxy | Sí | Proxy to Zoho Books API |
POST | /zoho-workdrive/setup | Sí | Configure WorkDrive OAuth |
POST | /zoho-workdrive/proxy | Sí | Proxy to WorkDrive API |
POST | /zoho-workdrive/upload | Sí | Upload file (multipart, max 250 MB) |
POST | /kraken/graphql | Sí | Relay GraphQL to Kraken |
POST | /webhooks/zoho | No | Zoho webhook receiver |
POST | /webhooks/webhook-subscriptions | Sí | Create webhook subscription |
DELETE | /webhooks/webhook-subscriptions/{id} | Sí | Delete subscription (owner only) |
Webhooks
Hermes recibe webhooks de Zoho y los reenvía de forma asíncrona a las apps suscritas, firmados con HMAC-SHA256.
Flujo
- Zoho envía POST /api/v1/webhooks/zoho con subscription_name en el body
- Hermes busca suscripciones activas cuyo name coincida
- Celery encola la entrega a cada target_url
- Tu app verifica X-Hermes-Signature con el secret de la suscripción
Enrutado por subscription_name
Zoho puede enviar un nombre o varios. Formatos soportados:
String simple: "my-app"String entre corchetes: "[app-a, app-b]"Array JSON: ["app-a", "app-b"]
Crear suscripción
El campo name es la clave de enrutado. module y events son solo metadata; Hermes no filtra webhooks entrantes por ellos.
Payload que recibe tu app
- integration, module, event, data, timestamp, subscription_id
- Headers: X-Hermes-Signature, X-Hermes-Subscription-Id
Verificar firma
Compara el HMAC-SHA256 del body JSON con el header:
X-Hermes-Signature: sha256={hex}Reintentos
Hasta 5 reintentos con backoff exponencial (10s, 20s, 40s, 80s, 160s).
Primeros pasos
Ejemplos mínimos para comprobar conectividad y empezar a integrar. Sustituye hms_live_xxx por tu API key.
Health check
curl https://hermes.oees.tech/api/v1/healthProxy Zoho CRM
curl -X POST https://hermes.oees.tech/api/v1/zoho/proxy \
-H "X-API-Key: hms_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"method": "GET",
"endpoint": "/Leads/12345"
}'Crear suscripción webhook
curl -X POST https://hermes.oees.tech/api/v1/webhooks/webhook-subscriptions \
-H "X-API-Key: hms_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"name": "my-app",
"integration": "zoho",
"module": "Leads",
"events": ["create", "edit"],
"target_url": "https://my-app.com/webhooks"
}'