> ## Documentation Index
> Fetch the complete documentation index at: https://docs.emiti.fravelabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Referencia de la API

> Información general antes de explorar los endpoints.

Esta sección describe los endpoints públicos del API de e-Miti, los shapes de request/response y los errores que podés encontrar.

## Base URL

```
https://api.emiti.fravelabs.com
```

Todos los paths de esta referencia son relativos a esta base.

## Autenticación

Todos los endpoints (excepto `/health` y `/openapi.json`) requieren el header `Authorization`. Para integraciones máquina-a-máquina usá `ApiKey`; el panel usa `Bearer`. Mirá la [guía de autenticación](/getting-started/authentication) para más detalle.

```bash theme={null}
curl https://api.emiti.fravelabs.com/v1/de \
  -H "Authorization: ApiKey emiti_k_xxxxxxxxxxxxxxxxxxxxxxxx"
```

## Rate limits

Los límites se aplican por **principal** (API key individual o usuario JWT) en ventanas de **1 minuto**. Un tenant con múltiples API keys tiene cuota independiente por key.

| Plan              | Límite por principal |
| ----------------- | -------------------- |
| `emiti` (starter) | 100 req/min          |
| `api`             | 600 req/min          |
| `hybrid`          | 600 req/min          |
| `pro`             | 2 000 req/min        |
| `enterprise`      | 10 000 req/min       |

Toda respuesta incluye estos headers:

| Header                  | Descripción                                         |
| ----------------------- | --------------------------------------------------- |
| `X-RateLimit-Limit`     | Límite del plan (req/min).                          |
| `X-RateLimit-Remaining` | Requests restantes en la ventana actual.            |
| `X-RateLimit-Reset`     | Epoch UTC (segundos) en que se reinicia la ventana. |

Cuando excedés el límite recibís `429` con header `Retry-After` (segundos hasta que se reinicia la ventana) y este body:

```json theme={null}
{
  "error": {
    "codigo": "RATE_LIMIT_EXCEDIDO",
    "mensaje": "Excediste el límite de 600 requests/min. Reintentá en 38s.",
    "request_id": "01HXY4Z...",
    "limit": 600,
    "reset_at": 1751916060
  }
}
```

## Formato de errores

Todas las respuestas de error siguen este shape:

```json theme={null}
{
  "error": {
    "codigo": "DE_NO_ENCONTRADO",
    "mensaje": "No se encontró el documento solicitado.",
    "request_id": "01HXY4Z..."
  }
}
```

Códigos comunes:

| Código                        | Status HTTP | Significado                                                                                                                |
| ----------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
| `AUTH_APIKEY_INVALIDA`        | 401         | Falta el header `Authorization` o la clave es inválida.                                                                    |
| `TENANT_SUSPENDIDO`           | 403         | El tenant está suspendido (impago, baja, etc.).                                                                            |
| `RATE_LIMIT_EXCEDIDO`         | 429         | Superaste el límite de requests por minuto de tu plan.                                                                     |
| `VALIDACION_MULTIPLES_CAMPOS` | 400         | Errores de validación del request. El campo `errores[]` detalla cada uno.                                                  |
| `DE_NO_ENCONTRADO`            | 404         | El CDC consultado no existe o pertenece a otro tenant.                                                                     |
| `SIFEN_RECHAZO`               | 422         | SIFEN rechazó el documento. `extra.codigo_sifen` y `extra.cdc` traen el detalle. Ver [errores SIFEN](/errors/sifen-codes). |
| `SIFEN_NO_DISPONIBLE`         | 503         | SIFEN está caído o respondió error de red. Reintentar después.                                                             |

Para errores de validación, el body incluye un array `extra.errores[]`:

```json theme={null}
{
  "error": {
    "codigo": "VALIDACION_MULTIPLES_CAMPOS",
    "mensaje": "Hay errores en el request.",
    "request_id": "01HXY4Z...",
    "extra": {
      "errores": [
        { "campo": "items.0.precio_unitario", "mensaje": "debe ser mayor o igual a 0" },
        { "campo": "receptor.numero_documento", "mensaje": "campo requerido" }
      ]
    }
  }
}
```

## Versionado

La API está bajo el prefijo `/v1`. Cambios incompatibles van a publicarse bajo `/v2` sin romper `v1` por un período de deprecación previsible.

## Endpoints públicos (sin auth)

| Path                | Para qué                                                                     |
| ------------------- | ---------------------------------------------------------------------------- |
| `GET /health`       | Healthcheck — devuelve `{"status": "ok", "db": "connected"}`.                |
| `GET /openapi.json` | Schema OpenAPI 3.x del API. Usado por este sitio para generar el playground. |
