Metadata-Version: 2.4
Name: apiempresas
Version: 1.4.0
Summary: SDK oficial de APIEmpresas.es para Python
Home-page: https://apiempresas.es
Author: APIEmpresas
Author-email: soporte@apiempresas.es
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.4.2
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# APIEmpresas.es - SDK para Python

SDK oficial para consultar la API de [APIEmpresas.es](https://apiempresas.es) desde Python 3.7 o superior.

## Instalación

```bash
pip install apiempresas
```

## Uso

```python
from apiempresas import ApiEmpresas, ApiError

api = ApiEmpresas('TU_API_KEY')

# Datos de una empresa (devuelve directamente el objeto de la empresa)
empresa = api.companies.get('A15075062')
print(empresa['name'])

# Con administradores y cargos (Pro/Business)
empresa = api.companies.get('A15075062', admin=True)

# Varias empresas por nombre, con paginación (devuelve data y meta)
pagina = api.companies.search_multiple('software', limit=20)
siguiente = pagina['meta'].get('next_cursor')
if siguiente:
    pagina = api.companies.search_multiple('software', cursor=siguiente)

# Consulta múltiple (devuelve data y meta)
lote = api.companies.batch(['A15075062', 'A46103834'])

# Match (Business): el sector del vendedor es obligatorio
match = api.companies.match('A15075062', 'software')

# Radar de empresas nuevas (todos los planes: 10 resultados en Free con nombre y CIF ocultos, 100 en Pro, 1.000 en Business). range: 'hoy' (por defecto) o días atrás ('7', '30')
nuevas = api.companies.radar(province='Madrid', range='7')
```

Los métodos devuelven el contenido de `data`, salvo cuando la respuesta trae también `meta` (`batch`, `search_multiple`, `radar`), que devuelven la respuesta completa.

### Verificación KYB (Pro) — 2 consultas

```python
v = api.companies.verify('A46103834', name='Mercadona SA', person='Juan Roig Alfonso', vat=True)
print(v['decision_hint'])   # pass | review | fail
```

Cada empresa trae además `status_code` (ACTIVE, INSOLVENCY, EXTINCT...), `status_source`, `status_date` y, en Pro/Business, `financials`. Los administradores traen `since`. Desde la 1.3.0 la respuesta lleva también `identifiers` (código LEI) y `legal_form` (forma jurídica con su código ISO 20275) en todos los planes, y en Pro/Business `group` (matriz directa y última según GLEIF) y `ownership` (socio único según el BORME). En `verify`, con `person`, `checks.person.is_sole_shareholder` dice si quien firma es el socio único.

El Radar acepta también `cnae`, `min_score`, `main_act_type` y `has_phone`.

### Nombre a CIF (Pro)

```python
r = api.companies.reconcile(['Mercadona', {'name': 'Talleres Pérez', 'province': 'Madrid'}])
# r['data'][i]['status']: match (con company.cif) | ambiguous (candidates) | no_match. Solo se cobran los match.
```

### Segmentos de empresas

```python
total = api.companies.count(cnae=['62'], province='MADRID', has_phone=True)   # gratis
pagina = api.companies.filter(cnae=['62'], province='MADRID', limit=100)      # Business: 5 consultas por fila
# Siguiente página: cursor=pagina['meta']['next_cursor'] con los mismos filtros
```

### Vigilancia de empresas (Pro: 100, Business: 1.000) — sin coste

```python
api.watchlist.add(['A46103834', 'A28015865'])
lista = api.watchlist.list()                     # {'success', 'data', 'meta'}
cambios = api.watchlist.events(since='2026-09-01', types=['borme_act', 'status_change'])
api.watchlist.remove('A28015865')
```

### Webhooks (Business)

```python
hook = api.webhooks.create('https://tu-servidor.com/apiempresas', 'watchlist.*')
# Guarda hook['secret']: con él se comprueba la firma.
api.webhooks.test(hook['id'])

# Historial de entregas (lo más reciente primero): estado, intentos, código HTTP y error
r = api.webhooks.deliveries(hook['id'], status='dead', limit=20)
print(r['meta']['total'], r['data'][:1])
```

En tu servidor, comprueba la firma con el cuerpo en bruto (Flask):

```python
from apiempresas import construct_webhook_event, ApiError

@app.post('/apiempresas')
def apiempresas_webhook():
    try:
        evento = construct_webhook_event(request.get_data(), request.headers.get('X-ApiEmpresas-Signature'), SECRET)
    except ApiError:
        return '', 400
    # evento['event']: company.borme_act | company.status_changed | company.risk_level_changed | test.ping
    return '', 200
```

Si tu servidor no responde 2xx, se reintenta a los 1 min, 5 min, 30 min, 2 h y 6 h.

### Licitaciones públicas abiertas (Business) — 1 consulta

```python
r = api.tenders.list(q="limpieza", province="Madrid", type="services")
for t in r["data"]["tenders"]:
    print(t["title"], t["deadline"], t["url"])

# Las parecidas a los contratos que una empresa ya ha ganado (ordenadas por match_score)
r = api.tenders.for_company("A82018474")
```

### Listas de sanciones (Business) — 1 consulta

```python
# Una empresa y sus administradores vigentes, en las listas de la UE, la ONU y OFAC
r = api.sanctions.screen(cif="A46103834")
print(r["summary"]["result"])  # clear | possible_match | match

# Un nombre suelto
r = api.sanctions.screen(name="Vladimir Putin", type="person")
# Cada coincidencia trae level (strong | possible), list, programs, countries y birth_dates
```

Con Business, `companies.verify()` incluye `checks.sanctions`.

## Sandbox

Para probar sin gastar consultas, con tu misma API Key y datos simulados:

```python
api = ApiEmpresas('TU_API_KEY', base_url='https://apiempresas.es/api/sandbox/v1')
```

## Consumo

```python
u = api.usage()  # no gasta consultas; no está en el Sandbox
print(u['stats']['remaining_calls'])
```

## Valores de los filtros

```python
cat = api.catalog()  # no gasta consultas; también en el Sandbox
print(cat['province'], cat['size_band'], cat['radar']['priority'], cat['webhook_events'])
```

## Errores

```python
try:
    api.companies.get('A15075062')
except ApiError as e:
    print(e.status)      # código HTTP
    print(str(e))        # mensaje legible
    print(e.code)        # p. ej. QUOTA_EXCEEDED, TOO_MANY_REQUESTS, API_KEY_INVALID
    print(e.error_code)  # campo "error" de la respuesta (como en versiones anteriores)
    print(e.request_id)  # dáselo a soporte
    print(e.retry_after) # segundos, en los 429 por velocidad
    print(e.required_plan, e.checkout_url)  # en los 403 de plan
```

Un `429` con `code == 'TOO_MANY_REQUESTS'` se resuelve esperando y reintentando; con `QUOTA_EXCEEDED` no: hay que recargar saldo o cambiar de plan.

## Licencia

MIT
