Autenticación y Rate Limiting
API Key
Section titled “API Key”Todos los endpoints requieren autenticación mediante API key en el header:
Authorization: Bearer sk-normatia-xxxxxLa API B2B es un producto separado de la aplicación web. La key se solicita durante el periodo beta a través de normatia.com/es/api. El acceso se activa manualmente.
La API key define el país y el plan
Section titled “La API key define el país y el plan”Toda API key está ligada a un api_plan que incluye exactamente un country_code (ISO 3166-1 alpha-2). No existen planes multi-país en la v1.
API key → api_plan → country_codeEl middleware extrae el country_code del plan y lo inyecta en el contexto de cada request. El developer no necesita pasar el país explícitamente.
Ejemplo de plan:
| Campo | Valor |
|---|---|
name | beta-es |
country_code | es |
monthly_limit | 500 |
rate_limit_pm | 10 req/min para /verify |
Si en el futuro un cliente necesita España y Portugal, usará dos keys en dos planes distintos.
Scoping automático por país
Section titled “Scoping automático por país”El country_code del plan filtra automáticamente todas las búsquedas:
/location/search— solo devuelve geografías del país de la key/codes/search— solo devuelve normativas del país de la key/verify— el RAG busca únicamente en los embeddings del país de la key
Si una request intenta acceder a datos de otro país (p. ej. pasando geo_id=PT-110300 con una key española), la API devuelve 403 country_mismatch.
Rate limiting y quota mensual
Section titled “Rate limiting y quota mensual”| Tipo | Límite | Scope |
|---|---|---|
| Rate limit | 60 req/min | /location y /codes |
| Rate limit | 10 req/min | /verify |
| Quota mensual | Según api_plan.monthly_limit | /verify únicamente |
La quota se reinicia en la fecha aniversario de activación de la key, no el día 1 del mes. Si la key se activó el 15 de marzo, el próximo ciclo empieza el 15 de abril.
Cuando la quota está agotada, /verify devuelve 429 quota_exceeded hasta el inicio del siguiente ciclo. Los endpoints de /location y /codes no consumen quota y siguen funcionando.
Manejo de errores
Section titled “Manejo de errores”Todos los errores siguen la misma estructura:
{ "error": "ambiguous_location", "message": "Se encontraron varios municipios para 'Villanueva'. Selecciona uno de los candidatos.", "candidates": [ { "geo_id": "ES-28185", "name": "Villanueva de la Cañada", "level": "municipality" } ]}| Campo | Tipo | Descripción |
|---|---|---|
error | string | Código de error legible por máquina (snake_case) |
message | string | Descripción legible por humanos |
candidates | array | Opciones de desambiguación cuando error = ambiguous_location |
Códigos de error comunes:
| Status | Código | Condición |
|---|---|---|
| 400 | missing_scope | Ni geo_id ni codes fueron proporcionados |
| 400 | invalid_code | Un slug de normativa no existe |
| 400 | invalid_version | La versión especificada no existe |
| 403 | country_mismatch | El geo_id pertenece a otro país |
| 403 | plan_not_allowed | El plan no tiene acceso al endpoint |
| 404 | not_found | El identificador referenciado no existe |
| 429 | quota_exceeded | Se han agotado los créditos del plan |