# Divr API — referencia completa > La API de la bolsa española: dividendos, calendario, resultados, cuentas anuales, ratios y hechos relevantes de las empresas cotizadas en BME, leídos de los registros oficiales de la CNMV y de BME. JSON en UTF-8; cada cifra dice de qué documento sale, con qué fórmula se calculó o por qué falta. Esta es la versión larga de https://api.divr.es/llms.txt, para asistentes que necesitan la referencia entera en un solo fichero. La especificación OpenAPI 3.1 está en https://api.divr.es/openapi.json; la documentación con explorador, en https://api.divr.es/docs. Las cifras de los ejemplos son inventadas: tienen la forma y los nombres de campo reales, pero ningún número sale de un documento. Sólo las respuestas reales de la API son datos. ## Empezar - URL base: `https://api.divr.es` - Todo es GET bajo `/v1/`, responde JSON y pide `Authorization: Bearer `. La clave nunca va en la URL. - Clave gratis al momento, sin tarjeta, en https://api.divr.es/docs#clave. Una por correo; se enseña una sola vez. - Plan gratuito: 100 peticiones al día por clave, con el contador a cero a las 00:00 UTC. - Empieza por el catálogo (`GET /v1/issuers`): de ahí salen los identificadores del resto. ``` curl https://api.divr.es/v1/issuers/TEF.MC/dividends \ -H "Authorization: Bearer $DIVR_API_KEY" ``` ```python import os, requests r = requests.get("https://api.divr.es/v1/events", params={"from": "2026-11-01", "to": "2026-12-31"}, headers={"Authorization": f"Bearer {os.environ['DIVR_API_KEY']}"}) r.raise_for_status() for e in r.json()["events"]: pago = (e.get("payment_date") or {}).get("value") bruto = (e.get("amount_gross") or {}).get("value") print(pago, bruto) ``` ## Convenciones - Identificador de emisor (`{id}`): ticker con sufijo (`TEF.MC`), ISIN o NIF. - Fechas `AAAA-MM-DD`; horas RFC 3339 en UTC. - Cupo: cada respuesta del plan gratuito lleva `X-RateLimit-Limit`, `X-RateLimit-Remaining` y `X-RateLimit-Reset` (segundos Unix). Al pasarse: `429 rate_limited` con `Retry-After`. - Caché: las respuestas buenas llevan `Cache-Control: private, max-age=86400`; los errores, `no-store`. - Versión: añadir campos o códigos no rompe `/v1`. Ignora lo que no conozcas. ## Procedencia: una cifra nunca es un escalar Reportada, apunta al documento y al concepto XBRL exactos: ```json "revenue": {"value": 41315000000, "origin": "reported", "doc": 1, "concept": "I1010"} ``` Derivada, dice con qué se calculó: ```json "ebitda": {"value": 13100000000, "origin": "derived", "formula": "operating_income + depreciation", "inputs": ["operating_income", "depreciation"]} ``` Hueco con motivo, de una lista cerrada (`no_existe_en_taxonomia`, `no_reportado`, `no_aplica_al_emisor`, `error_de_parseo`): ```json "gross_profit": {"value": null, "reason": "no_existe_en_taxonomia"} ``` En dividendos, una fecha anunciada lleva la frase de la que sale: ```json "payment_date": {"value": "2026-06-18", "origin": "reported", "quote": "se abonará el 18 de junio de 2026"} ``` ## Errores Forma: `{"error": {"code", "message", "ticker"}}`. | Código | HTTP | Qué significa | ¿Reintentar? | |---|---|---|---| | issuer_unknown | 404 | El identificador no es de ningún emisor conocido | No | | issuer_no_source | 404 | Se sabe quién es y nunca tendrá datos aquí | Nunca | | issuer_not_ingested | 404 | Conocido, con fuente, aún sin cargar | Sí, más tarde | | events_not_scanned | 404 | El registro de comunicaciones aún no se ha recorrido | Sí, más tarde | | bad_request | 400 | Parámetro mal escrito, ventana de más de 400 días o falta `symbol` | Corrige la petición | | unauthorized | 401 | Falta la clave o no vale | Con otra clave | | rate_limited | 429 | Gastadas las 100 peticiones de hoy | Tras las 00:00 UTC | | plan_not_allowed | 403 | Ruta de uso interno que el plan gratuito no incluye | No | | not_found | 404 | Esa ruta no existe en `/v1` | Corrige la ruta | | method_not_allowed | 405 | Sólo se responde a GET | Usa GET | | not_implemented | 501 | Ruta reservada (hechos crudos) | No | | internal_error | 500 | Falló; nunca un 200 parcial | Sí | ## Empresas ### GET /v1/issuers — catálogo Todos los valores del mercado continuo, también los que no se sirven, con el motivo. Sin parámetros. - `issuers[]`: `ticker`, `isin`, `nif`, `lei`, `name`. - `issuers[].ingestion`: `loaded`, `not_ingested`, `identity_unverified` o `no_source`. - `issuers[].coverage`: `from`, `to`, `missing`, `source_ends_after`, `mixed_perimeter`. - `generated_at`, con `derivation_version`. ### GET /v1/issuers/{id}/annual — cuentas anuales Un objeto por ejercicio, desde el XBRL que el emisor deposita en la CNMV (desde 2016). - `issuer`, `coverage`: quién es y qué ejercicios hay de verdad. - `years[]`: `year`, `perimeter`, `taxonomy`, `currency`, `sources[]`. - `years[].fields`: `revenue`, `ebitda`, `net_income`, `eps_basic`, `total_debt`, `free_cash_flow`, `dividend_per_share`… cada uno con su procedencia. ### GET /v1/issuers/{id}/results — resultados por periodo Lo presentado en cada periodo: `H1`, `H2` (ejercicio menos primer semestre), `FY` y, si hay, `Q1`–`Q4`. - `years[].periods[]`: `period`, `period_start`, `period_end`, `perimeter`, `currency`, `source` (`{url, filed}`, o `null` si el periodo es una resta), `fields`. - `quarters`: `{available, reason}`. ### GET /v1/issuers/{id}/ratios — ratios Calculados al vuelo con las cifras de `/annual`; cada ratio lleva `formula` e `inputs`. - `ratios_version`: sube si cambia una fórmula. - `years[].ratios.{ratio}`: `value`, `unit` (`fraction`: 0,12 = 12 %; `currency`: importe), `formula`, `inputs`, o `value: null` con `reason` (hereda el de la entrada que falta, o `denominador_cero`, `denominador_negativo`, `sin_ejercicio_anterior`, `cambio_de_perimetro`). - Ratios: `operating_margin`, `ebitda_margin`, `net_margin`, `fcf_margin`, `roe`, `roa`, `net_debt`, `net_debt_to_ebitda`, `debt_to_equity`, `liabilities_to_assets`, `payout_ratio`, `fcf_payout_ratio`, `capex_to_operating_cash_flow`, `revenue_growth`, `net_income_growth`, `eps_growth`, `dividend_per_share_growth`. ### GET /v1/issuers/{id}/facts Reservada: responde `501 not_implemented`. ## Dividendos ### GET /v1/issuers/{id}/dividends — dividendos de un emisor Tres bloques que no se mezclan: - `events[]`: lo anunciado a la CNMV. `kind`, `status`, `amount_gross`, `ex_date`, `record_date`, `payment_date`, `confirmed_by_bme`, `source`. - `market[]` y `market_coverage.served_through`: el calendario que publica BME. - `estimates[]`: lo estimado a partir de años anteriores. `payment_window {from, to, expected}`, `amount_gross`, `basis_years`, `dispersion_days`. Da ventana, no fecha. - `coverage.scanned_through`: hasta qué día se ha leído la CNMV; `stale` si no se ha leído el último día laborable (el fin de semana vale el viernes). ### GET /v1/events — calendario del mercado español Qué se paga entre dos fechas en todos los emisores, en una petición. - Parámetros: `from` (por defecto hoy), `to` (por defecto hoy + 90). Ventana máxima: 400 días. - `events[]`, `market[]`, `estimates[]`: como en los dividendos de un emisor; `security.isin` dice de quién es cada fila. - `bonus_issues[]`: ampliaciones liberadas (scrip) cuyo periodo de derechos toca la ventana: `rights_from`, `rights_to`, `admission_date`, `new_shares` y la proporción `ratio_old` → `ratio_new` (p. ej. 20 → 1; null si BME no la publica). - `results_dates[]`: presentaciones de resultados anunciadas: `date`, `fiscal_year`, `period`, `quote`, `source`. Sólo anunciadas, nunca estimadas. Ejemplo: `GET /v1/events?from=2026-10-01&to=2026-12-31` ## Hechos relevantes ### GET /v1/filings y GET /v1/issuers/{id}/filings Cada comunicación de las cotizadas en los registros de la CNMV (Otra Información Relevante e Información Privilegiada): dividendos, resultados, juntas, consejo, recompras. Es el equivalente español del 8-K. Se leen cada hora en días laborables. - Parámetros: `id` (en `/v1/filings`), `from`, `to` (máximo 400 días; por defecto la última semana, o el último año para un emisor), `topic` (`dividendo`, `resultados`, `junta`, `consejo`, `recompra`), `register` (`oir` o `ip`), `limit` (1–500, por defecto 100). - `filings[]`: `register`, `registro` (número de la CNMV), `published_at`, `issuer` (`nif`, `name`, `ticker`; `null` si no cotiza en el continuo), `entity`, `title`, `category`, `topics[]`, `url`. - `coverage.stored_from`: antes de ese día no hay nada guardado. `scanned_through`, `stale`. - `truncated`: `true` si había más filas que `limit`. ## Otros mercados ### GET /v1/us/dividends — calendario de EE. UU. (Nasdaq) - Parámetros: `symbol` (opcional, p. ej. `KO`), `from` (por defecto hoy), `to` (por defecto hoy + 45; máximo 400 días). - `market[]`: `symbol`, `company`, `amount`, `annual_dividend`, `ex_date`, `record_date`, `payment_date`, `announced_on`, `source`. La divisa va a `null` con `currency_reason: nasdaq_no_declara_divisa`. - `coverage`: `fetched_at`, `read_from`, `read_through`, `days_failed`, `stale`. ### GET /v1/market/dividends — cualquier valor NYSE, Londres y cualquier mercado que Yahoo conozca; para EE. UU. junta Yahoo y Nasdaq por ex-date. - Parámetros: `symbol` (obligatorio, con sufijo fuera de EE. UU.: `DGE.L`), `from` (por defecto hace 30 días), `to` (por defecto dentro de un año; máximo 400 días). - `market[]`: la misma forma que en el calendario de EE. UU. - `coverage`: `source` (`yahoo` o `yahoo+nasdaq`), `fetched_at`, `stale`, `last_error`. ## Sistema ### GET /health Sin clave. `200 {"status":"ok"}` si el servicio llega a su base de datos; `503` si no. ## Uso y licencia Para uso propio. La nota legal de la CNMV autoriza el uso privado y los cálculos derivados; para redistribuir los registros a terceros, escribe antes. Planes: https://api.divr.es/precios. Qué empresas hay y de qué años: https://api.divr.es/cobertura.