Saltar al contenido principal

Autenticación y ámbitos

La platform API se autentica con una clave de tu organización. Se presenta en dos formas — misma organización, mismos scopes, distinto runtime:

FormCredentialSent as
Server (backend)kld_sk_live_…Authorization: Bearer … o X-Api-Key
Publishable (browser)kld_pk_live_…el SDK la intercambia por una sesión de corta duración; nunca se envía como raw bearer
Authorization: Bearer kld_sk_live_…
# or
X-Api-Key: kld_sk_live_…

Las server keys son el bearer que envías desde tu backend en cada solicitud. Las publishable keys son para el navegador: el SDK intercambia una por un session token de corta duración vinculado al origin en runtime, por lo que la publishable key nunca queda como una credencial permanente en el código fuente de la página. Una publishable key presentada directamente como bearer se rechaza — úsala mediante el SDK. Una server key no recibe ningún permiso CORS, por lo que una página nunca puede leer una respuesta generada con ella — pero CORS no puede impedir que la solicitud salga del navegador, de modo que una server key incluida en el código fuente ya se ha filtrado cuando la API la rechaza. El SDK rechaza claves kld_sk_… al montar precisamente por este motivo: mantén siempre las server keys del lado del servidor.

Las claves heredadas kld_live_… existentes siguen funcionando como direct bearer en ambos lugares.

Ámbitos

Una clave contiene capability scopes; cada familia de rutas requiere uno:

ScopeRoute familyUsed by
ai/inference-api/b2b/v1/chat/*, /retrieval/*chat embed
design/inference-api/b2b/v1/design/*editor embed
mapsdesigned basemapsthe tile embed
vendor(modifier, not a route)the chat embed, on your own data

De forma predeterminada, una clave Pro/Enterprise se crea con ai, design y maps. Las claves del plan Free están restringidas a maps + el producto tile; consulta Obtener una clave API para la tabla canónica plan × scope × producto.

Admisión efectiva = clave almacenada × nivel actual. El session-exchange en runtime vuelve a calcular la admisión en cada llamada, de modo que una clave Pro-tier degradada a Free solo crea sesiones tile a partir de ese momento — incluso si la clave almacenada sigue incluyendo ai y design entre sus restricciones. El subcode de rechazo distingue los dos casos:

  • insufficient_scope — la clave nunca tuvo la capacidad.
  • tier_capability_not_allowed — la clave la tenía, pero el nivel actual ya no la admite. Mejora el plan para restaurarla.

Un allowed_products vacío en la clave almacenada significa todos los productos (no ninguno). El nivel sigue reduciendo ese superset a lo que admite el plan.

vendor — solicítalo deliberadamente y solo donde realmente lo necesites

vendor no es un control de acceso de ruta. No admite ni rechaza una solicitud; decide si el chat de AI puede consultar los datos vendor cargados por tu organización al responder. Los demás scopes responden "¿puede esta clave llamar a este endpoint?"; vendor responde "¿puede esta clave hablar en nombre de nuestros datos internos?".

Por eso nunca se incluye de forma predeterminada — solicítalo explícitamente al hacer mint:

{ "name": "our-site-widget", "scopes": ["ai", "vendor"] }

Qué clave contiene vendor constituye toda la decisión de seguridad. El chat embed es un widget del navegador: intercambia una publishable key por una sesión de corta duración, por lo que una clave con vendor necesariamente reside en una página pública. Eso está bien para datos que te parece correcto mostrar a todos los visitantes del sitio — una lista de propiedades, horarios, tarifas públicas. No está bien para información que no publicarías. La origin allowlist que protege el intercambio es una convención del navegador, no un límite de confidencialidad: un cliente que establezca su propio header Origin no queda detenido por ella.

Por tanto:

  • Una clave por superficie. Un sitio de marketing, una página de demo y tu aplicación para clientes no deberían compartir una clave. Solo la superficie que necesita responder con tus datos recibe vendor.
  • Nunca pongas una hoja de tarifas, base de costes o cualquier dato no publicado detrás de una publishable key. Si la respuesta te incomodaría en una página pública, esos datos no deben estar en un embed con scope vendor.
  • Las sesiones se restringen a su producto, por lo que una sesión tile o viewer nunca contiene vendor, incluso si su parent key lo tiene.

Para retirarlo, edita los scopes de la clave o revócala — ambos cambios tienen efecto en la siguiente solicitud, incluso para sesiones que ya estén activas. La retirada no se pospone hasta que expire la sesión.

401 frente a 403

Son distintos deliberadamente:

  • 401 Unauthorized — clave ausente / inválida / revocada / caducada. Vuelve a comprobar el valor de la clave y que no esté revocada. También publishable_requires_session cuando una publishable key se envía como raw bearer.
  • 403 Forbidden — la clave existe, pero no está admitida aquí. Subcodes habituales: insufficient_scope (nunca lo tuvo), tier_capability_not_allowed (lo tenía, el nivel ya no lo admite), session_origin_mismatch, ip_not_allowed (server keys), server_key_in_browser, product_not_allowed.

Ambos fallan de forma cerrada: una clave sin scopes se rechaza en todas partes.

Session tokens

La sesión por la que el SDK intercambia una publishable key tiene este aspecto:

kld_sess_{env}_{jwt}

por ejemplo kld_sess_live_eyJhbGciOi…. Se presenta en llamadas de runtime como Authorization: Bearer o X-Api-Key. TTL predeterminado de 900 segundos (15 minutos); el máximo del servidor es de 30 minutos. Las sesiones se restringen al producto para el que se crearon, y cada solicitud vuelve a leer la política activa de la parent key.

La retirada es inmediata; una nueva concesión no. Las dos direcciones son deliberadamente asimétricas y fallan de forma cerrada:

Change to the parent keyEffect on a session already in flight
Revoked or deletedSe rechaza en su siguiente solicitud
A scope removedDesaparece en su siguiente solicitud
Plan downgradedLas capacidades limitadas por nivel se rechazan en la siguiente solicitud
Rate limit or monthly cap set to a new valueSe aplica en la siguiente solicitud
A scope added, plan upgraded, or a limit lifted entirelyNo visible — crea una sesión nueva

Una sesión solo puede reducir los permisos respecto a su parent, nunca ampliarlos más allá de los scopes con los que fue creada, por lo que una nueva concesión requiere un nuevo intercambio. Las sesiones son cortas (15 minutos por defecto) precisamente para que esa brecha sea pequeña.

Consulta Errors para ver la tabla completa de estados.