OpenMercantil Risk Signals API
Documentary risk signals from public sources (AEPD, CNMC, concursos, AEAT moroso, CENDOJ)
Documentary risk signals from public sources (AEPD, CNMC, concursos, AEAT moroso, CENDOJ)
openapi: 3.1.0
info:
title: OpenMercantil Risk Signals API
version: 1.9.3
summary: Versioned public-read, browser-account, billing, support and provider-callback contracts.
description: 'Public JSON API for Spanish company information derived from BORME and other public sources.
OpenMercantil is an independent informational service; it is NOT the BOE, BORME or Registro Mercantil
and does NOT replace official certificates or registry extracts.
**Rate limits.** Free: 60 req/min y 200 req/día por IP. Planes superiores (Profesional 5.000 req/día,
MAX 50.000 req/día, Enterprise 500.000+ req/día) según cuenta y API key. Cabeceras `X-RateLimit-Limit`,
`X-RateLimit-Remaining`, `X-RateLimit-Reset`, `X-OpenMercantil-Plan`, `Retry-After`.
**License and attribution.** Source-specific metadata in each response and the active versioned source
catalog prevails. OpenMercantil does not relicense upstream content under a blanket license. Unknown,
review and restricted datasets are omitted or return `503 legal_layer_unavailable`. BOE/BORME material
is re-used under Ley 37/2007 and its official version remains boe.es. Court judgments are not exposed;
CENDOJ remains citation-index only under CGPJ Reglamento 3/2010.
**Machine-readable catalog (DCAT-AP-ES):** https://openmercantil.es/catalog.rdf'
termsOfService: https://openmercantil.es/terminos-de-uso
contact:
name: OpenMercantil
url: https://openmercantil.es/soporte
email: social@openmercantil.es
license:
name: Source-specific upstream terms; see response catalog metadata
url: https://openmercantil.es/terminos-de-uso
x-publisher:
name: OpenMercantil
url: https://openmercantil.es/
email: social@openmercantil.es
x-spatial: http://publications.europa.eu/resource/authority/country/ESP
x-temporal: 2009-01-01/..
x-language: es
x-dcat-catalog: https://openmercantil.es/catalog.rdf
x-rate-limit:
free:
per_min: 60
per_day: 200
kind: anonymous-ip
profesional:
per_min: 120
per_day: 5000
kind: api-key
max:
per_min: 600
per_day: 50000
kind: api-key
enterprise:
per_min: 1200
per_day: 500000
kind: contract
x-methodology: https://openmercantil.es/metodologia
x-sources: https://openmercantil.es/fuentes
x-corrections: https://openmercantil.es/correcciones
x-contract-status: Public read, browser-account and provider-callback surfaces are explicitly separated
in this contract. Operator/admin routes are excluded. The public MCP consumes only the allowlisted
GET read plane.
x-account-segment-contract:
projection: company_public_v2 immutable corporate sidecar
synchronous_row_cap: 500
bounded_count_cap: 50001
count_semantics: The segment run response count is the number of rows returned, never a global total.
Dataset preview uses total_is_lower_bound=true and total_lower_bound when the bounded count reaches
50001.
related_web_dataset_surface:
preview_path: /mi-cuenta/datasets/preview
export_path: /mi-cuenta/datasets/export.csv
synchronous_export_max_rows: 500
overflow_status: 503
overflow_error: async_export_required
x-company-identity-contract:
version: '1.0'
projection: company_public_v2 immutable generation-bound corporate sidecar
applies_to: Every /api/v1/company/{slug}*, /api/v1/empresa/{slug}* and /api/v1/grafo/{slug} read before
any report, cache, graph or dataset lookup. /api/v1/companies/compare resolves both requested subjects
in one bounded company_public_v2 batch before either row is exposed; MCP company tools inherit these
preflights through REST.
resolution:
published: canonical corporate slug admitted
safe_alias: internally canonicalized and Content-Location emitted
withheld: neutral 404; includes absent, personal and ambiguous/quarantined identities
unavailable: 503 with no-store; clients must not infer absence
search: Exact corporate CIF, exact canonical/safe-alias slug, or bounded name_prefix2 pool scored
in application code. DNI/NIE and ambiguous CIFs return zero items.
public_company_count: company_public_projection_state.row_count
servers:
- url: https://openmercantil.es
description: Production
tags:
- name: Risk Signals
description: Documentary risk signals from public sources (AEPD, CNMC, concursos, AEAT moroso, CENDOJ)
paths:
/api/v1/company/{slug}/sanctions:
get:
operationId: getCompanyBySlugSanctions
tags:
- Companies
- Risk Signals
summary: Get policy-gated sanctions dataset
description: This route is fail-closed. It returns data only when the exact sanctions dataset has
a valid public decision, license metadata and identity policy in the active source catalog. OpenSanctions
is currently in review, so the route returns 503 without reading or serializing its payload.
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: Sanctions list when the exact dataset is authorized
content:
application/json:
schema:
$ref: '#/components/schemas/CompanySanctionsResponse'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/TooManyRequests'
'503':
$ref: '#/components/responses/LegalLayerUnavailable'
/api/v1/company/{slug}/risk-signals:
get:
operationId: getCompanyBySlugRiskSignals
tags:
- Companies
- Risk Signals
summary: Get documentary risk signals
description: Return only documentary signals whose exact dataset and negative-claim surface are
authorized by the active source catalog. Other integrated sources are omitted without implying
absence of the underlying fact. CENDOJ judgment text, OpenSanctions, AEPD and any unknown dataset
are not exposed unless a future version records a field-specific public decision. Appearance never
implies guilt, infringement, responsibility or current liability.
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: Risk signals with disclaimers
content:
application/json:
schema:
type: object
properties:
slug:
type: string
signals_count:
type: integer
signals:
type: array
items:
type: object
properties:
type:
type: string
enum:
- aepd_sanction
- cnmc_sanction
- concurso
- aeat_moroso
- cendoj_judgment
- opensanctions
- other
source_slug:
type: string
source_url:
type: string
date:
type: string
format: date
summary:
type: string
confidence:
type: string
enum:
- high
- medium
- low
homonymy_warning:
type: boolean
disclaimer:
type: string
source_catalog_version:
type: string
policy_scope:
type: string
_legal_notice:
type: string
example: Documentary signals only. Appearance does not imply guilt, infringement or
current liability.
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/TooManyRequests'
'503':
$ref: '#/components/responses/PublicReadUnavailable'
/api/v1/company/{slug}/aeat-moroso:
get:
operationId: getCompanyBySlugAeatMoroso
tags:
- Companies
- Risk Signals
summary: Check policy-gated AEAT debtor-list mention
description: Negative-claim route gated before lookup. It returns 503 until the exact AEAT dataset
has validated reuse, identity-match and cite-or-abstain policy metadata. Appearance would be documentary
only and never imply current liability.
x-rate-limit: free 60/min · 200/day
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: Debtor list mention or empty
content:
application/json:
schema:
$ref: '#/components/schemas/CompanyAeatDebtorResponse'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/TooManyRequests'
'503':
$ref: '#/components/responses/LegalLayerUnavailable'
/api/v1/company/{slug}/embargoes:
get:
operationId: getCompanyBySlugEmbargoes
tags:
- Companies
- Risk Signals
summary: Documentary embargo/garnishment mentions
description: Return documentary mentions of embargoes (embargo de bienes, anotaciones registrales)
when published in public registries. Documentary only — does not certify current status.
x-rate-limit: free 60/min · 200/day
parameters:
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: Embargo mentions
content:
application/json:
schema:
$ref: '#/components/schemas/CompanyEmbargoesResponse'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/TooManyRequests'
'503':
$ref: '#/components/responses/LegalLayerUnavailable'
components:
headers:
NoStoreCacheControl:
description: Error responses must not be stored.
schema:
type: string
const: no-store
responses:
LegalLayerUnavailable:
description: 'Controlled fail-closed denial: the required dataset or legal layer is absent, invalid,
unsupported or not authorized for this public surface.'
headers:
Cache-Control:
$ref: '#/components/headers/NoStoreCacheControl'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
example:
error: legal_layer_unavailable
detail: Este dataset no esta habilitado para redistribucion publica por la politica de fuentes
activa.
source_catalog_version: 2026-07-12.2
NotFound:
description: Resource not found
headers:
Cache-Control:
$ref: '#/components/headers/NoStoreCacheControl'
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
PublicReadUnavailable:
description: The public read failed closed because its legal source catalog, subject classification,
bounded projection, database helper or required artifact is unavailable. Clients must not infer
an empty result.
headers:
Cache-Control:
description: Unavailable public reads are never cacheable.
schema:
type: string
const: no-store
Retry-After:
description: Optional number of seconds to wait before retrying.
schema:
type: integer
minimum: 1
content:
application/json:
schema:
anyOf:
- $ref: '#/components/schemas/ProjectionUnavailableError'
- $ref: '#/components/schemas/ErrorResponse'
examples:
legal_layer:
value:
error: legal_layer_unavailable
company_identity:
value:
error: company_public_projection_unavailable
projection:
value:
error: projection_unavailable
detail: La proyección pública requerida no está disponible.
projection: wikidata_company_v1
TooManyRequests:
description: Rate limit exceeded
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
schemas:
CompanyAeatDebtorResponse:
type: object
required:
- slug
- listed
properties:
slug:
type: string
cif:
type:
- string
- 'null'
listed:
type: boolean
debt_eur:
type:
- number
- 'null'
period:
type:
- string
- 'null'
published_date:
type:
- string
- 'null'
history:
type: array
items:
$ref: '#/components/schemas/JsonValue'
additionalProperties:
$ref: '#/components/schemas/JsonValue'
CompanyEmbargoesResponse:
type: object
required:
- slug
- count
- items
- source
- note
properties:
slug:
type: string
count:
type: integer
summary:
anyOf:
- type: object
properties:
count:
type: integer
total_amount_eur:
type:
- number
- 'null'
latest_date:
type:
- string
- 'null'
additionalProperties:
$ref: '#/components/schemas/JsonValue'
- type: 'null'
items:
type: array
items:
$ref: '#/components/schemas/EmbargoRecord'
maxItems: 100
source:
type: string
note:
type: string
additionalProperties: false
CompanySanctionsResponse:
type: object
properties:
slug:
type: string
count:
type: integer
items:
type: array
items:
$ref: '#/components/schemas/DocumentarySanction'
source:
type:
- string
- 'null'
note:
type:
- string
- 'null'
additionalProperties:
$ref: '#/components/schemas/JsonValue'
DocumentarySanction:
type: object
description: Sanitized documentary sanction record; appearance does not imply current liability.
properties:
source:
type:
- string
- 'null'
date:
type:
- string
- 'null'
authority:
type:
- string
- 'null'
summary:
type:
- string
- 'null'
official_url:
type:
- string
- 'null'
format: uri
status:
type:
- string
- 'null'
additionalProperties:
$ref: '#/components/schemas/JsonValue'
EmbargoRecord:
type: object
description: Documentary official-notice record; may not reflect later unpublished resolutions.
properties:
date:
type:
- string
- 'null'
authority:
type:
- string
- 'null'
summary:
type:
- string
- 'null'
amount_eur:
type:
- number
- 'null'
source_url:
type:
- string
- 'null'
format: uri
additionalProperties:
$ref: '#/components/schemas/JsonValue'
ErrorResponse:
type: object
description: Closed compatibility envelope for public/account errors. Route-specific schemas narrow
these fields further where required.
required:
- error
properties:
error:
type: string
minLength: 1
message:
type: string
detail:
type: string
code:
type: string
status:
type:
- integer
- string
projection:
type: string
reason:
type: string
source_catalog_version:
type: string
allowed_parameters:
type: array
uniqueItems: true
items:
type: string
slug:
type: string
key:
type: string
maximum:
type: integer
minimum: 1
parameter:
type: string
fields:
type: array
items:
type: string
max_bytes:
type: integer
minimum: 1
allowed:
type: array
items:
$ref: '#/components/schemas/JsonValue'
valid:
type: array
items:
$ref: '#/components/schemas/JsonValue'
date:
type: string
login_url:
type: string
plan:
type: string
limited_by:
type: string
enum:
- minute
- day
daily_limit:
type: integer
minimum: 1
reset_at:
type: integer
minimum: 1
reset_at_human:
type: string
format: date-time
retry_after_s:
type: integer
minimum: 1
retry_after:
type: integer
minimum: 1
upgrade:
type: string
format: uri
upgrade_url:
type: string
action:
type: string
limit:
type: integer
minimum: 0
remaining:
type: integer
minimum: 0
needed:
type: integer
minimum: 0
shortfall:
type: integer
minimum: 0
ok:
type: boolean
_alias_of:
type: string
additionalProperties: false
JsonValue:
description: A JSON value used only inside explicitly documented extension maps.
oneOf:
- type:
- string
- number
- boolean
- 'null'
- type: array
items:
$ref: '#/components/schemas/JsonValue'
- type: object
additionalProperties:
$ref: '#/components/schemas/JsonValue'
ProjectionUnavailableError:
type: object
description: Fail-closed projection outage. Clients must not reinterpret this response as an empty
or negative result.
required:
- error
- detail
- projection
properties:
error:
type: string
const: projection_unavailable
detail:
type: string
projection:
type: string
additionalProperties: false