API de ClouraAPI da Cloura

Cloura ofrece una API REST de solo lectura para llevar sus hallazgos priorizados a sus propias herramientas —SIEM, tableros, data warehouse— sin entrar a la app.

A Cloura oferece uma API REST somente leitura para levar seus achados priorizados às suas próprias ferramentas —SIEM, painéis, data warehouse— sem entrar no app.

Nada es público Toda la API exige iniciar sesión. La documentación la ve cualquier usuario con cuenta (incluido el plan Free); para consumir datos necesita el plan Pro o superior.
Nada é público Toda a API exige login. A documentação é vista por qualquer usuário com conta (incluindo o plano Free); para consumir dados é necessário o plano Pro ou superior.

En todos los planes (incluido Free): ver la documentaciónEm todos os planos (incluindo Free): ver a documentação

Con cualquier cuenta se explora la referencia de la API —sus endpoints, parámetros y respuestas—. Se encuentra en la app, en Ajustes → Referencia de la API. Tiene su propia fila, sin candado de plan: es documentación, no una credencial.

Com qualquer conta explora-se a referência da API —seus endpoints, parâmetros e respostas—. Você a encontra no app, em Configurações → Referência da API. Tem sua própria linha, sem cadeado de plano: é documentação, não uma credencial.

Referencia de la API en la app de Cloura
En la app: Ajustes → Referencia de la API.
No app: Configurações → Referência da API.

Se abre la especificación OpenAPI (Redoc) con el contrato completo. Es útil para entender qué ofrece la API antes de integrarla. Para usarla con sus datos, siga con la siguiente sección.

Abre a especificação OpenAPI (Redoc) com o contrato completo. É útil para entender o que a API oferece antes de integrá-la. Para usá-la com seus dados, continue na próxima seção.

Desde el plan Pro: usar la APIA partir do plano Pro: usar a API

1. Genere sus credenciales1. Gere suas credenciais

En Ajustes → Credenciales de API (solo Admin), pulse Generar credencial. Póngale un nombre para reconocerla (por ejemplo, «SIEM producción»).

Em Configurações → Credenciais de API (apenas Admin), clique em Gerar credencial. Dê um nome para reconhecê-la (por exemplo, «SIEM produção»).

Sección Credenciales de API en Ajustes
Ajustes → Credenciales de API (disponible desde Pro).
Configurações → Credenciais de API (disponível a partir do Pro).

Cloura le muestra el Client ID, el Client Secret y el Token endpoint. El secreto se muestra una sola vez: cópielo y guárdelo en un gestor seguro. Si se pierde, revoque esa credencial y cree otra.

A Cloura mostra o Client ID, o Client Secret e o Token endpoint. O segredo é exibido apenas uma vez: copie e guarde num cofre seguro. Se for perdido, revogue essa credencial e crie outra.

Client ID, Client Secret y Token endpoint (una sola vez)
El Client Secret solo aparece al crearla. Guárdelo ahí mismo.
O Client Secret só aparece na criação. Guarde-o ali mesmo.

Se pueden tener varias credenciales y revocar cualquiera en cualquier momento: deja de funcionar al instante. Las credenciales son de solo lectura y solo ven su organización.

É possível ter várias credenciais e revogar qualquer uma quando quiser: para de funcionar na hora. As credenciais são somente leitura e só veem a sua organização.

Lista de credenciales con opción de revocar
Gestione y revoque sus credenciales desde la misma sección.
Gerencie e revogue suas credenciais na mesma seção.

2. Obtenga un token2. Obtenha um token

La API usa OAuth2 client-credentials. Pida un token al Token endpoint que Cloura entregó al crear la credencial, usando su Client ID y su Client Secret. La respuesta trae el token y expires_in en segundos.

A API usa OAuth2 client-credentials. Peça um token ao Token endpoint que a Cloura entregou ao criar a credencial, usando seu Client ID e seu Client Secret. A resposta traz o token e expires_in em segundos.

Use el Token endpoint que indica la app Es una URL propia de su instalación, con la forma https://<dominio>.auth.<región>.amazoncognito.com/oauth2/token. Cópiela tal cual de la pantalla de creación de la credencial: no la escriba de memoria.
Use o Token endpoint que o app mostra É uma URL própria da sua instalação, no formato https://<domínio>.auth.<região>.amazoncognito.com/oauth2/token. Copie-a tal como aparece na tela de criação da credencial: não a escreva de memória.
TOKEN_ENDPOINT="https://<dominio>.auth.<region>.amazoncognito.com/oauth2/token"  # el que te muestra Cloura
CLIENT_ID="..."
CLIENT_SECRET="..."

RESP=$(curl -s -X POST "$TOKEN_ENDPOINT" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials")

ACCESS_TOKEN=$(echo "$RESP" | jq -r .access_token)
echo "$RESP" | jq '{expires_in, token_type}'
# → { "expires_in": 3600, "token_type": "Bearer" }
TOKEN_ENDPOINT="https://<dominio>.auth.<region>.amazoncognito.com/oauth2/token"  # o que o Cloura mostra
CLIENT_ID="..."
CLIENT_SECRET="..."

RESP=$(curl -s -X POST "$TOKEN_ENDPOINT" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials")

ACCESS_TOKEN=$(echo "$RESP" | jq -r .access_token)
echo "$RESP" | jq '{expires_in, token_type}'
# → { "expires_in": 3600, "token_type": "Bearer" }

El token se acota a un scope concreto añadiendo &scope=cloura-api/findings.read al cuerpo. Los scopes disponibles son cloura-api/findings.read, cloura-api/analyses.read y cloura-api/accounts.read. Si no indica ninguno, la credencial usa los que tenga asignados.

O token se restringe a um scope específico adicionando &scope=cloura-api/findings.read ao corpo. Os scopes disponíveis são cloura-api/findings.read, cloura-api/analyses.read e cloura-api/accounts.read. Se nenhum for indicado, a credencial usa os que tiver atribuídos.

Renovar el token sin pedir uno en cada llamadaRenovar o token sem pedir um a cada chamada

El token dura una hora. Pedir uno nuevo en cada request es lento e innecesario: guárdelo en memoria y renuévelo solo cuando esté por vencer. Este patrón, con un margen de 60 segundos, sirve para cualquier integración:

O token dura uma hora. Pedir um novo a cada request é lento e desnecessário: guarde-o em memória e renove-o só quando estiver perto de vencer. Este padrão, com uma margem de 60 segundos, serve para qualquer integração:

import os, time, requests

TOKEN_ENDPOINT = os.environ["CLOURA_TOKEN_ENDPOINT"]   # el que te muestra Cloura
CID, SECRET = os.environ["CLOURA_CLIENT_ID"], os.environ["CLOURA_CLIENT_SECRET"]

_cache = {"token": None, "exp": 0}

def token() -> str:
    """Devuelve un access token válido, renovándolo 60 s antes de que expire."""
    if _cache["token"] and time.time() < _cache["exp"] - 60:
        return _cache["token"]
    r = requests.post(TOKEN_ENDPOINT, auth=(CID, SECRET),
                      data={"grant_type": "client_credentials"}, timeout=10)
    r.raise_for_status()
    data = r.json()
    _cache["token"] = data["access_token"]
    _cache["exp"] = time.time() + int(data.get("expires_in", 3600))
    return _cache["token"]
import os, time, requests

TOKEN_ENDPOINT = os.environ["CLOURA_TOKEN_ENDPOINT"]   # o que o Cloura mostra
CID, SECRET = os.environ["CLOURA_CLIENT_ID"], os.environ["CLOURA_CLIENT_SECRET"]

_cache = {"token": None, "exp": 0}

def token() -> str:
    """Devuelve un access token válido, renovándolo 60 s antes de que expire."""
    if _cache["token"] and time.time() < _cache["exp"] - 60:
        return _cache["token"]
    r = requests.post(TOKEN_ENDPOINT, auth=(CID, SECRET),
                      data={"grant_type": "client_credentials"}, timeout=10)
    r.raise_for_status()
    data = r.json()
    _cache["token"] = data["access_token"]
    _cache["exp"] = time.time() + int(data.get("expires_in", 3600))
    return _cache["token"]

Si una llamada responde 401, el token venció o la credencial fue revocada: pida uno nuevo y, si vuelve a fallar, revise en la app que la credencial siga activa.

Se uma chamada responder 401, o token venceu ou a credencial foi revogada: peça um novo e, se falhar de novo, verifique no app se a credencial continua ativa.

3. Llame a la API3. Chame a API

La URL base es https://api.cloura.ai. Adjunte el token en la cabecera Authorization en cada llamada:

A URL base é https://api.cloura.ai. Anexe o token no cabeçalho Authorization em cada chamada:

curl -s "https://api.cloura.ai/api/v1/analyses" \
  -H "Authorization: Bearer $ACCESS_TOKEN" | jq

EndpointsEndpoints

Todos cuelgan de https://api.cloura.ai y son de solo lectura. El contrato /api/v1 es estable: si algún día hubiera un cambio incompatible, viviría en /api/v2.

Todos partem de https://api.cloura.ai e são somente leitura. O contrato /api/v1 é estável: se um dia houver mudança incompatível, ela viverá em /api/v2.

EndpointParámetrosDevuelve
GET /api/v1/meSu identidad de API: organización, plan y alcance de la credencial.
GET /api/v1/accounts{"accounts": [...]}. Cada cuenta trae su provider (aws, azure o gcp).
GET /api/v1/analysesaccountId, limit, offset{"analyses": [...], "count", "returned"}. count es el total tras filtros; returned, los de esta página.
GET /api/v1/analyses/{id}Un análisis: score FinOps, ahorro estimado, estado y cobertura. 404 si no es de su organización.
GET /api/v1/analyses/{id}/findingscategory, severity{"findings": [...], "count", "entitledPacks", "locked"}. 404 si el análisis no es de su organización.
EndpointParâmetrosRetorna
GET /api/v1/meSua identidade de API: organização, plano e escopo da credencial.
GET /api/v1/accounts{"accounts": [...]}. Cada conta traz seu provider (aws, azure ou gcp).
GET /api/v1/analysesaccountId, limit, offset{"analyses": [...], "count", "returned"}. count é o total após filtros; returned, os desta página.
GET /api/v1/analyses/{id}Uma análise: score FinOps, economia estimada, status e cobertura. 404 se não for da sua organização.
GET /api/v1/analyses/{id}/findingscategory, severity{"findings": [...], "count", "entitledPacks", "locked"}. 404 se a análise não for sua.

Ejemplo con filtros: los hallazgos críticos de costo de un análisis, en una sola llamada.

Exemplo com filtros: os achados críticos de custo de uma análise, numa única chamada.

curl -s "https://api.cloura.ai/api/v1/analyses/$ID/findings?severity=critical&category=cost" \
  -H "Authorization: Bearer $ACCESS_TOKEN" | jq '.count'

Referencia OpenAPI (requiere su sesión de la app)Referência OpenAPI (requer sua sessão do app)

Además del contrato de datos, hay dos rutas de documentación. No son públicas y no se abren con el token M2M: usan su sesión de usuario, por eso lo natural es entrar desde la app.

Além do contrato de dados, há duas rotas de documentação. Não são públicas e não abrem com o token M2M: usam sua sessão de usuário, por isso o natural é entrar pelo app.

  • GET /api/v1/openapi.json — la especificación OpenAPI completa.
  • GET /api/v1/docs — el portal de referencia navegable (Redoc).
  • GET /api/v1/openapi.json — a especificação OpenAPI completa.
  • GET /api/v1/docs — o portal de referência navegável (Redoc).
Portal de referencia de la API con los endpoints, sus parámetros y los códigos de respuesta
La referencia detalla cada endpoint: parámetros, autorización y respuestas.
A referência detalha cada endpoint: parâmetros, autorização e respostas.

ErroresErros

  • 401 — token ausente, vencido o de una credencial revocada. Pida uno nuevo.
  • 403 — su plan no incluye la API. Las credenciales están disponibles desde Pro.
  • 404 — el recurso no existe o no pertenece a su organización. Cloura no distingue ambos casos a propósito: así una credencial no puede averiguar qué existe en otra organización.
  • 401 — token ausente, vencido ou de uma credencial revogada. Peça um novo.
  • 403 — seu plano não inclui a API. As credenciais estão disponíveis a partir do Pro.
  • 404 — o recurso não existe ou não pertence à sua organização. A Cloura não distingue os dois casos de propósito: assim uma credencial não consegue descobrir o que existe em outra organização.

Ejemplos útilesExemplos úteis

Hallazgos críticos de su último análisis, ordenados por ahorroAchados críticos da sua última análise, ordenados por economia

BASE="https://api.cloura.ai/api/v1"
AUTH="Authorization: Bearer $ACCESS_TOKEN"

# id del análisis más reciente
ID=$(curl -s "$BASE/analyses" -H "$AUTH" | jq -r '.analyses | sort_by(.createdAt) | last | .analysisId')

# sus hallazgos críticos, del mayor ahorro al menor
curl -s "$BASE/analyses/$ID/findings" -H "$AUTH" | jq '
  [ .findings[] | select(.severity == "critical") ]
  | sort_by(.monthlySavingsEstimate) | reverse
  | .[] | { title, resourceId, severity, monthlySavingsEstimate }'
BASE="https://api.cloura.ai/api/v1"
AUTH="Authorization: Bearer $ACCESS_TOKEN"

# id da análise mais recente
ID=$(curl -s "$BASE/analyses" -H "$AUTH" | jq -r '.analyses | sort_by(.createdAt) | last | .analysisId')

# seus achados críticos, da maior economia para a menor
curl -s "$BASE/analyses/$ID/findings" -H "$AUTH" | jq '
  [ .findings[] | select(.severity == "critical") ]
  | sort_by(.monthlySavingsEstimate) | reverse
  | .[] | { title, resourceId, severity, monthlySavingsEstimate }'

Exportar todos los hallazgos a JSON (para SIEM / data warehouse)Exportar todos os achados para JSON (para SIEM / data warehouse)

Ejemplo en Python: recorre sus análisis y vuelca cada hallazgo a un archivo.

Exemplo em Python: percorre suas análises e grava cada achado num arquivo.

import os, json, requests

BASE = "https://api.cloura.ai/api/v1"
TOKEN_ENDPOINT = os.environ["CLOURA_TOKEN_ENDPOINT"]   # el que te muestra Cloura
CID, SECRET = os.environ["CLOURA_CLIENT_ID"], os.environ["CLOURA_CLIENT_SECRET"]

# 1) token
tok = requests.post(TOKEN_ENDPOINT, auth=(CID, SECRET),
                    data={"grant_type": "client_credentials"}).json()["access_token"]
H = {"Authorization": f"Bearer {tok}"}

# 2) recorrer análisis y juntar hallazgos
rows = []
for a in requests.get(f"{BASE}/analyses", headers=H).json()["analyses"]:
    aid = a["analysisId"]
    fs = requests.get(f"{BASE}/analyses/{aid}/findings", headers=H).json()["findings"]
    for f in fs:
        rows.append({"analysisId": aid, **f})

# 3) volcar a un archivo para el SIEM / warehouse
with open("cloura_hallazgos.json", "w", encoding="utf-8") as out:
    json.dump(rows, out, ensure_ascii=False, indent=2)
print(f"{len(rows)} hallazgos exportados")
import os, json, requests

BASE = "https://api.cloura.ai/api/v1"
TOKEN_ENDPOINT = os.environ["CLOURA_TOKEN_ENDPOINT"]   # o que o Cloura mostra
CID, SECRET = os.environ["CLOURA_CLIENT_ID"], os.environ["CLOURA_CLIENT_SECRET"]

# 1) token
tok = requests.post(TOKEN_ENDPOINT, auth=(CID, SECRET),
                    data={"grant_type": "client_credentials"}).json()["access_token"]
H = {"Authorization": f"Bearer {tok}"}

# 2) percorrer análises e juntar achados
rows = []
for a in requests.get(f"{BASE}/analyses", headers=H).json()["analyses"]:
    aid = a["analysisId"]
    fs = requests.get(f"{BASE}/analyses/{aid}/findings", headers=H).json()["findings"]
    for f in fs:
        rows.append({"analysisId": aid, **f})

# 3) despejar num arquivo para o SIEM / warehouse
with open("cloura_achados.json", "w", encoding="utf-8") as out:
    json.dump(rows, out, ensure_ascii=False, indent=2)
print(f"{len(rows)} achados exportados")

Buenas prácticas y seguridadBoas práticas e segurança

  • Guarde el Client Secret en un gestor de secretos, nunca en el código ni en el repositorio.
  • Rote las credenciales cada cierto tiempo y revoque las que ya no se usen.
  • La API es de solo lectura y cada credencial solo ve su organización.
  • Pagina con limit y offset si hay muchos análisis.
  • El token expira (~1 h): reutilícelo mientras sea válido y pida otro al vencer.
  • Guarde o Client Secret num cofre de segredos, nunca no código nem no repositório.
  • Rotacione as credenciais periodicamente e revogue as que não usa mais.
  • A API é somente leitura e cada credencial só vê a sua organização.
  • Pagine com limit e offset se houver muitas análises.
  • O token expira (~1 h): reutilize-o enquanto for válido e peça outro ao vencer.
Referencia técnica exacta La lista completa de campos de cada respuesta vive en el documento OpenAPI de su cuenta (Ajustes → Credenciales de API → Referencia de la API). Esta guía cubre el uso más común.
Referência técnica exata A lista completa de campos de cada resposta fica no documento OpenAPI da sua conta (Configurações → Credenciais de API → Referência da API). Este guia cobre o uso mais comum.