Ir al contenido

Visión general de la API

Cada llamada a la API de CORE-M pasa por un único API gateway. El gateway sirve gRPC en el puerto 9090 y REST en el puerto 8080, y utiliza gRPC-Gateway para transcodificar las peticiones REST en la llamada gRPC equivalente al servicio de backend. Hay un solo contrato — las definiciones de servicio de protobuf — expuesto de dos maneras.

Esta página documenta el comportamiento transversal que aplica a cada llamada: cómo se autentican, paginan y limitan (rate limit) las peticiones, y cómo se devuelven los errores. Para el catálogo de recursos, consulta las tablas por servicio más abajo y el OpenAPI/Swagger integrado en la aplicación.

AspectoRESTgRPC
Puerto80809090
CodificaciónJSONProtobuf
EnrutamientoPath + método → método gRPCDespacho nativo de servicio/método
Fuente de verdadAnotaciones protobuf google.api.httpDefiniciones de servicio de protobuf
Propagación de metadataHeaders HTTP → metadata gRPCMetadata nativa
Contexto de trazaHeaders traceparent / tracestateInterceptor gRPC de OTel

Una llamada REST GET /api/v1/devices/{device_id} se transcodifica a la llamada gRPC DeviceRegistryService.GetDevice contra el device registry; la respuesta protobuf se serializa de nuevo a JSON. Un cliente gRPC nativo que llama al mismo método en el puerto 9090 se proxea con propagación completa de metadata y la respuesta se devuelve sin modificar.

ServicioPropósitoRutas REST confirmadas
authTenants, login, tokens, API keys, grupos, SSO, MFA, sesionesPOST /api/v1/auth/login, POST /api/v1/auth/refresh, POST /api/v1/auth/validate, POST /api/v1/auth/api-keys — consulta Swagger para el conjunto completo
device-registryCRUD de dispositivos, grupos, tags, estadoPOST /api/v1/devices, GET /api/v1/devices/{device_id}, GET /api/v1/devices, PATCH/DELETE /api/v1/devices/{device_id}
device-linkRPC de dispositivos, atributos, provisioning, gateways, OTAPOST /api/v1/provision, POST /api/v1/devices/{device_id}/rpc, GET /api/v1/devices/rpc/{correlation_id}, POST /api/v1/gateway/{gateway_device_id}/connect
telemetryIngesta, snapshot más reciente, consulta histórica, métricasPOST /api/v1/telemetry, GET /api/v1/telemetry/{device_id}/latest, GET /api/v1/telemetry/{device_id}
rules-engineCRUD de reglas CEL, habilitar/deshabilitar, validaciónPOST /api/v1/rules, GET /api/v1/rules/{rule_id}, PATCH/DELETE /api/v1/rules/{rule_id}, POST /api/v1/rules/{rule_id}/enable
chain-anchorEstado de lotes (batch), historial de anchorsGET /api/v1/anchors, GET /api/v1/anchors/batches/{batch_id}
verifierPruebas en blockchain verificables públicamenteGET /api/v1/verify/hash/{data_hash_hex}, POST /api/v1/verify/raw, GET /api/v1/verify/batch/{batch_id}
dashboard-bffFan-out en tiempo real al dashboardWebSocket /ws (no REST)
gatewayPunto de entrada, auth, rate limiting, callback de ARC, saludPOST /api/v1/callbacks/arc, GET /healthz, GET /readyz

Toda petición se autentica excepto los endpoints de salud y readiness (/healthz, /readyz) y el callback de ARC (/api/v1/callbacks/arc, que se valida con HMAC en su lugar). El middleware de auth del gateway valida la credencial llamando al RPC ValidateToken del servicio de auth, extrae tenant_id y user_id al contexto de la petición y luego la reenvía.

Se aceptan dos tipos de credencial:

TipoFormatoHeaderUsado por
JWT access tokenJWT firmado con Ed25519Authorization: Bearer <jwt>Usuarios / dashboard
API keysk_live_...Authorization: Bearer sk_live_... o X-API-Key: sk_live_...Dispositivos, cuentas de servicio, integraciones
GET /api/v1/devices HTTP/1.1
Host: api.example.com:8080
Authorization: Bearer eyJhbGciOiJFZERTQSIs...
CondiciónRESTgRPC
Credencial válidala petición continúala petición continúa
Falta la credencial en una ruta protegida401UNAUTHENTICATED
JWT expirado401 (el cuerpo sugiere el endpoint de refresh)UNAUTHENTICATED
El token carece del scope requerido403PERMISSION_DENIED
Endpoint de salud/readinesspermitido sin authn/a

Los JWT access tokens son de corta duración; intercambia un refresh token en POST /api/v1/auth/refresh para obtener un nuevo par. Los API tokens con scope llevan un conjunto de scopes explícito — consulta Seguridad y cumplimiento para la tabla de scopes y el comportamiento de la IP allowlist, y Auth y multi-tenancy para saber cómo se aplica el aislamiento de tenant.

Todos los endpoints de listado usan paginación por cursor opaco, nunca offsets numéricos.

ParámetroDóndeSignificado
page_sizequeryResultados por página. Los valores por defecto varían según el endpoint (comúnmente 50); los endpoints de listado limitan el máximo.
page_tokenqueryCursor opaco del next_page_token de la respuesta anterior. Omítelo para la primera página.
next_page_tokenresponseCursor para la siguiente página. Un valor vacío significa que no hay más resultados.
Ventana de terminal
# First page
curl "https://api.example.com:8080/api/v1/devices?page_size=20" \
-H "Authorization: Bearer $TOKEN"
# Next page — pass the cursor back verbatim
curl "https://api.example.com:8080/api/v1/devices?page_size=20&page_token=eyJ..." \
-H "Authorization: Bearer $TOKEN"

El gateway aplica un contador de ventana deslizante por tenant, respaldado por un incremento atómico sobre la clave de Aerospike ratelimit:{tenant_id}:{window_minute}. La ventana se reinicia automáticamente mediante el TTL de la clave.

  • Límite por defecto: 1000 peticiones por minuto por tenant.
  • Ventana: un minuto, deslizante.
  • Almacenamiento: namespace sessions de Aerospike, incremento atómico por petición.

Cada respuesta lleva el estado actual del rate limit:

HeaderDescripciónPresente en
X-RateLimit-LimitMáximo de peticiones permitidas en la ventanacada respuesta
X-RateLimit-RemainingPeticiones restantes en la ventana actualcada respuesta
X-RateLimit-ResetSegundo del epoch Unix en que se reinicia la ventana (vía TTL)cada respuesta
Retry-AfterSegundos hasta que la ventana se reiniciasolo en 429

Cuando se excede el límite, el gateway devuelve 429 Too Many Requests (gRPC RESOURCE_EXHAUSTED) con un header Retry-After, e incrementa corem_gateway_rate_limited_total{tenant=...}.

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711000080
Retry-After: 12
Content-Type: application/json
{"code": "RESOURCE_EXHAUSTED", "message": "rate limit exceeded"}

Los errores se devuelven como un objeto JSON consistente sin importar qué servicio los produjo. La cadena code es el nombre del código de estado gRPC; el estado HTTP se deriva de él mediante gRPC-Gateway.

{
"code": "NOT_FOUND",
"message": "device not found: dev-770e8400-..."
}
Código gRPCHTTPSignificado
OK200Éxito
INVALID_ARGUMENT400Petición mal formada o inválida
FAILED_PRECONDITION400Política de tenant o prerrequisito faltante
UNAUTHENTICATED401Credencial faltante o inválida
PERMISSION_DENIED403Rol, permiso de grupo o scope insuficiente, o IP no permitida (allowlist)
NOT_FOUND404El recurso no existe, o ruta desconocida
ALREADY_EXISTS409Recurso duplicado
RESOURCE_EXHAUSTED429Rate limit o quota de tenant excedidos
INTERNAL500Error del servidor
UNAVAILABLE503Servicio temporalmente no disponible

Una petición a una ruta que el gateway no puede emparejar devuelve 404 con el cuerpo de error estándar:

HTTP/1.1 404 Not Found
Content-Type: application/json
{"code": "NOT_FOUND", "message": "route not found"}

POST /api/v1/callbacks/arc es la única ruta pública de la API sin autenticación. Recibe callbacks de confirmación de transacciones desde la API Merchant de ARC y reenvía el payload al pipeline de chain-anchor a través de Redpanda. La autenticidad se establece mediante HMAC, no mediante una credencial bearer.

PasoComportamiento
FirmaARC envía X-ARC-Signature: sha256=<hex>
VerificaciónEl gateway calcula HMAC-SHA256(body, ARC_CALLBACK_HMAC_SECRET) y compara en tiempo constante
Si coincideEl payload se publica en Redpanda anchor.tx.confirmed; se devuelve 200
Si no coincide / falta401; el payload no se reenvía; se incrementa corem_arc_callback_rejected_total{reason="invalid_signature"}
JSON mal formado400; el payload se registra para depuración
Modo devSi ARC_CALLBACK_HMAC_SECRET no está definido y ARC_CALLBACK_SKIP_VALIDATION=true, se omite la validación y se registra una advertencia

Consulta Visión general del anchoring para saber cómo fluye la confirmación hasta la finalización de la prueba.

Ambos endpoints no requieren autenticación y están expuestos por el gateway y por cada servicio de backend.

EndpointSondaComportamiento
GET /healthzLivenessSiempre 200 mientras el proceso esté vivo
GET /readyzReadiness200 si todas las dependencias están saludables; 503 si alguna no lo está
// GET /readyz — 200
{"auth": "healthy", "device-registry": "healthy", "telemetry": "healthy", "aerospike": "healthy"}
// GET /readyz — 503
{"auth": "healthy", "telemetry": "unhealthy: connection refused", "aerospike": "healthy"}

/healthz reporta liveness y /readyz reporta readiness: una caída de una dependencia falla el readiness sin fallar el liveness.

El gateway permite peticiones cross-origin desde el origen del dashboard configurado, incluyendo las peticiones preflight OPTIONS con los correspondientes Access-Control-Allow-Origin y las concesiones de método/header. A otros orígenes no se les otorga acceso CORS.