# API de RESET Verifica — referencia técnica

URL canónica: https://resetparatodos.com/docs/api.md
Última actualización: 2026-08-19
Versión del motor: 1.0.0
Especificación OpenAPI: `{BASE}/openapi.json` (también publicada como
[openapi.json](openapi.json) junto a este documento)

RESET Verifica es un servicio mexicano de verificación determinística (sin IA en
el motor) con tres servicios: **Empresa** (hechos oficiales públicos de personas
morales), **Factura** (validación de CFDI y estado ante SAT) y **Pago**
(procesamiento de CEP y conciliación SPEI). Toda operación devuelve JSON y genera
un `verification_id` auditable.

## Base URL

```
https://api.resetparatodos.com
```

### Servidor MCP (para agentes de IA)

Los clientes que hablan Model Context Protocol (Claude Desktop, Claude Code,
etc.) pueden conectarse directamente:

```
https://mcp.resetparatodos.com/mcp
```

Transporte streamable HTTP. Envía tu llave en el header `X-Api-Key` (la misma
`rv_live_` o `rv_test_`). El servidor expone cada operación como una herramienta
con el mismo cobro, registro y aislamiento que la API REST — es una fachada
sobre esta base URL, no un servicio distinto. Sin llave solo responden
`consultar_precios` y `validar_constancia`.

En este documento `{BASE}` representa esa base. La API sirve exclusivamente
respuestas JSON (y los documentos que generas); la documentación vive en
resetparatodos.com.

## Autenticación

¿Aún no tienes llave? El registro es **autoservicio**: crea tu cuenta en
[resetparatodos.com/verifica/registro](https://resetparatodos.com/verifica/registro/)
y al confirmar tu correo recibes al instante una llave de sandbox y una de
producción. El formulario acepta agentes de IA (es un POST HTTP normal), solo
necesitas poder recibir el correo de confirmación.

Header `X-Api-Key` en cada petición. Hay dos tipos de llave:

| Prefijo | Modo | Comportamiento |
|---|---|---|
| `rv_live_` | live | Fuentes reales (copia local versionada + SAT en vivo). Consume saldo prepagado del wallet. |
| `rv_test_` | sandbox | Respuestas **sintéticas y deterministas**. Nunca consulta fuentes reales. Sin costo. Ideal para desarrollar la integración. |

## Precios y wallet (prepago)

Modelo **100% prepago** durante esta etapa (postpago por contrato, más adelante).
**Todos los precios están en pesos mexicanos (MXN) y ya incluyen IVA** — el
desglose solo aparece en tu CFDI. Hay dos formas de comprar:

| Servicio | En paquete | Individual | Incluye |
|---|---|---|---|
| `COMPANY` — Empresa | **$12** | $14 | 69-B con historial + art. 69 (firmes, no localizados, CSD sin efectos) + contratación pública + sancionados + Verification Record |
| `SCREEN` — Screen | **$12** | $14 | Screening de nombre o ID fiscal contra sanciones OFAC/UE/UK/Canadá + PEP + listas nacionales de 5 países (MX, BR, CO, AR, DO), con evidencia por lista y constancia PDF |
| `CFDI` — Factura | **$2** | $3 | XSD oficial + Anexo 20 + estado en SAT + cruce 69-B del emisor |
| `SPEI` — Pago | **$3** | $4 | Procesamiento de CEP + conciliación contra obligaciones |
| `COMBO` — Transacción completa | **$18** | $22 | Empresa + Factura + Pago en una sola llamada |
| `LABORAL` — Cálculo laboral | **$1** | $1.50 | Finiquito, liquidación, aguinaldo, prima, PTU (LFT) con desglose, fundamento y deslinde |
| `NOMINA` — Cálculo de nómina | **$0.50** | $0.75 | ISR de nómina (LISR art. 96) con tabla vigente declarada |
| `LEGAL` — Legislación mexicana | **$0.10** | $0.15 | Texto de artículos y búsqueda en 198 ordenamientos (Constitución, códigos y leyes federales, nacionales y de los 32 estados), con fuente, fecha de reforma y deslinde. El índice de ordenamientos es gratis |
| `DATO` — Catálogos y datos | **$0.05** | $0.05 | Bancos SPEI, catálogos SAT, teléfono/LADA. Cobra siempre (aun con paquete); si se usa internamente para enriquecer otro producto, va incluido |
| `UTIL` — Validadores | **incluido** | $0.10 | CLABE, RFC, CURP, NSS, tarjeta (Luhn). Incluidos sin costo con saldo de paquete vigente; sueltos $0.10 |

> **Fuente única de precios:** esta tabla es una copia de referencia. Los precios
> vigentes los sirve la API en `GET /v1/precios`: es la fuente autoritativa
> que también usan el MCP y la web.

- **Paquete** (`{"tipo": "paquete", "monto": 500}`): compra explícita de saldo
  general — desde $500, en múltiplos de $100. El saldo se consume en cualquier
  servicio a tarifa de paquete. Depositas exactamente lo que compras.
- **Compra individual** (`{"tipo": "individual", "servicio": "COMPANY",
  "cantidad": 3}`): usos de UN producto específico a tarifa individual
  (depositas cantidad × precio, p. ej. 3 × $6 = $18 exactos). Esos usos son
  **exclusivos de ese producto**: no se transfieren, no se convierten y no
  pasan a saldo general.
- Al verificar, se consumen **primero los usos individuales** del producto;
  agotados, se descuenta del saldo de paquete.
- Créditos y usos **vencen a los 365 días** y **no son reembolsables**.

Reglas de cobro:
- Solo se cobra una verificación **completada** (`*_OK` o `CFDI_CON_OBSERVACIONES`).
- `INPUT_INVALID` y `SOURCE_UNAVAILABLE` **no** generan cargo.
- Un CEP duplicado (`SPEI_DUPLICADO`) **no** genera un segundo cargo.
- El sandbox nunca cobra.
- Sin usos ni saldo, la API responde **HTTP 402** con las dos opciones de compra.

Fondeo (por SPEI):
1. `POST /v1/wallet/fondeos` → regresa referencia, CLABE y el monto exacto a
   depositar (que es el precio publicado: el IVA ya viene incluido).
   **Registra tus datos fiscales** (`PUT /v1/organizacion`) antes del cierre
   del mes: si faltan, el depósito se factura a **público en general**
   (XAXX010101000) y ese CFDI **no puede refacturarse después** (la respuesta
   del fondeo incluye esta advertencia cuando aplica).
2. Transfieres por SPEI y descargas el CEP en XML (tu banca o banxico.org.mx/cep).
**Pago con x402 (USDC, para agentes)**: alternativa al SPEI, pensada para
agentes de IA. `POST /v1/wallet/fondeos/x402` con `{monto_mxn}` responde **402**
con los requisitos de pago x402 (monto exacto en USDC = MXN × 1.10 ÷ tipo de
cambio FIX, red Base, dirección de depósito). Pagas con tu wallet x402 y liquidas
en `POST /v1/wallet/fondeos/{referencia}/x402` con el header `X-PAYMENT`; el
facilitador de Coinbase verifica y liquida, y se acredita tu saldo. Los USDC se
liquidan directamente; RESET solo recibe el pago.

3. `POST /v1/wallet/fondeos/{referencia}/cep` con el XML → validación del CEP
   (monto, cuenta destino, clave de rastreo sin reutilizar) y **confirmación
   contra Banxico** de que la transferencia liquidó; con todo en orden la
   acreditación es automática. Si Banxico aún no reporta la operación (por
   ejemplo, subiste el CEP segundos después de transferir), espera unos
   minutos y vuelve a subirlo; las discrepancias quedan `en_revision` para
   revisión manual.
- `GET /v1/wallet` muestra saldo de paquete, usos individuales por producto con
  su vencimiento, y movimientos. `GET /v1/precios` publica la tabla (sin auth).
- **Tu factura**: el CFDI de cada fondeo se emite dentro del mismo mes y queda
  descargable en `GET /v1/wallet/fondeos/{referencia}/cfdi?formato=xml` (o
  `pdf`); el panel indica cuándo está disponible.

Las llaves se emiten por organización y nunca se almacenan en claro.
Errores: `401` si falta la llave o es inválida/inactiva.

## Capa x402 — pago por llamada (sin cuenta)

Además del modelo prepago con llave, cada producto de verificación se ofrece por
**pago por llamada con x402**: sin registro, sin llave, sin saldo. Pensado para
agentes de IA que descubren y pagan el servicio en el momento.

El flujo es el estándar x402 (HTTP 402): pides el endpoint sin pago y recibes un
**402** con los requisitos (monto exacto en USDC, red Base `eip155:8453`,
dirección de cobro); tu wallet firma el micropago y reintentas con el header de
pago; el facilitador de Coinbase verifica y liquida, y recibes el **200** con el
resultado. RESET no custodia fondos: el pago se liquida directo a la dirección
de cobro anclada en el código.

`GET /x402/v1/discovery` lista todos los productos, su precio en USDC y su
endpoint (sin costo). Los productos también quedan indexados en **Bazaar**.

| Producto | Endpoint (`POST`) | USDC | Entrada |
|---|---|---|---|
| Validar RFC (MX) | `/x402/v1/rfc/validate` | $0.03 | `{"rfc": "..."}` |
| Validar CLABE (MX) | `/x402/v1/clabe/validate` | $0.03 | `{"clabe": "..."}` |
| Validar CNPJ (BR) | `/x402/v1/brazil/cnpj/validate` | $0.02 | `{"cnpj": "..."}` |
| Verificar LEI (GLEIF, global) | `/x402/v1/lei/verify` | $0.03 | `{"lei": "..."}` |
| Verificar entidad SEC/EDGAR (US) | `/x402/v1/us/sec/verify` | $0.03 | `{"query": "ticker o CIK"}` |
| Verificar empresa UK (Companies House) | `/x402/v1/uk/company/verify` | $0.03 | `{"company": "número o nombre"}` |
| Validar FEL XML (GT) | `/x402/v1/guatemala/fel/validate` | $0.03 | `{"xml": "..."}` |
| Parsear FEL a JSON (GT) | `/x402/v1/guatemala/fel/parse` | $0.03 | `{"xml": "..."}` |
| Screening AML (LatAm + global) | `/x402/v1/screen` | $0.61 | `{"name": "..."}` |
| Verificar empresa (MX, 69-B + más) | `/x402/v1/company/verify` | $0.61 | `{"rfc": "..."}` |

Precios x402 en USD; los productos mexicanos también viven en el modelo prepago
en MXN (tabla de arriba). Cada endpoint acepta `GET` (con querystring) o `POST`
(con JSON).

## Sandbox: datos de prueba

Con una llave `rv_test_`, estos insumos producen respuestas fijas
(campo `"sandbox": true` en toda respuesta sintética):

| Entrada de prueba | Resultado |
|---|---|
| RFC `EFO010101AA1` | 69-B **Definitivo** (sintético) |
| RFC `PRE010101AA1` | 69-B **Presunto** |
| RFC `DES010101AA1` | 69-B **Desvirtuado** |
| RFC `SEN010101AA1` | 69-B **Sentencia Favorable** |
| RFC `CON010101AA1` | Sin 69-B, **2 contratos públicos** sintéticos |
| RFC `SAN010101AA1` | **Sancionado** (sintético) |
| RFC `FIR010101AA1` | Art. 69: lista **Firmes** (moral, sintético) |
| RFC `NOLO010101AA1` | Art. 69: **No localizados** (persona física, sintético) |
| Cualquier otro RFC válido | Sin coincidencia en ninguna fuente |
| CFDI con UUID que inicia `11111111` | Estado SAT **Vigente** |
| CFDI con UUID que inicia `22222222` | Estado SAT **Cancelado** |
| CFDI con cualquier otro UUID | Estado SAT **No Encontrado** |

Las validaciones locales del CFDI (XSD, Anexo 20, formato) son reales también en
sandbox; solo el estado SAT y los cruces con fuentes son sintéticos. Las
obligaciones y CEPs del sandbox viven aislados en tu organización de pruebas.

## Validadores (servicio `UTIL`) — incluidos con paquete

Validadores estructurales instantáneos de puro algoritmo (no consultan
fuentes). **Incluidos sin costo mientras tengas saldo de paquete vigente**;
sueltos $0.10 (IVA incluido). El sandbox no cobra; una entrada malformada no
genera cargo. Para los hechos oficiales están Empresa/Factura/Pago.

- `GET /v1/utilidades/clabe/{clabe}` — 18 dígitos, dígito de control y banco.
- `GET /v1/utilidades/rfc/{rfc}` — formato, tipo de persona, fecha y dígito.
- `GET /v1/utilidades/curp/{curp}` — formato, dígito verificador y decodificación
  (fecha, sexo, entidad).
- `GET /v1/utilidades/nss/{nss}` — formato y dígito Luhn del seguro social.
- `POST /v1/utilidades/tarjeta` — Luhn + BIN + marca (body `{"pan":"..."}`; POST
  para no exponer el número; no se conserva completo).

## Catálogos y datos (servicio `DATO`) — $0.05 por consulta

Cuesta un mínimo siempre (aun con paquete), porque implica mantener el catálogo.
Cada respuesta lleva la fuente y la versión del catálogo.

- `GET /v1/catalogo/banco/{clave}` — banco/participante SPEI por clave.
- `GET /v1/catalogo/sat/{tipo}/{clave}` — catálogo SAT (`regimen`, `uso_cfdi`,
  `forma_pago`).
- `GET /v1/catalogo/telefono/{numero}` — formato, LADA y zona.

## Cálculo fiscal y laboral (servicios `LABORAL` y `NOMINA`)

Cálculos determinísticos con **deslinde**: cada resultado incluye `base_calculo`
con el fundamento legal, la tabla/versión y su vigencia, la fórmula y un aviso
de que es un resultado matemático, no una resolución oficial. Si un parámetro
no está vigente para la fecha pedida, la respuesta **no calcula**: advierte que
falta actualizar. Cuestan `LABORAL` $1/$1.50 y `NOMINA` $0.50/$0.75.

- `POST /v1/fiscal/aguinaldo` — body `{salario_diario, dias_trabajados,
  dias_aguinaldo}` (LFT art. 87).
- `POST /v1/fiscal/prima-vacacional` — body `{salario_diario, anios_antiguedad,
  porcentaje}` (LFT arts. 80 y 76).
- `POST /v1/fiscal/finiquito` — body `{salario_diario, fecha_ingreso,
  fecha_baja, dias_pendientes_salario, incluir_indemnizacion}` (LFT).
- `POST /v1/fiscal/isr` — body `{base_gravable, fecha_calculo}` (LISR art. 96).
- `POST /v1/fiscal/imss` — body `{sbc_diario, dias, fecha_calculo, prima_riesgo}`
  — cuotas IMSS + Infonavit (Ley del Seguro Social); Riesgos de Trabajo solo si
  pasas tu prima.

`GET /v1/economia/tipo-cambio?fecha=&monto=` (servicio `DATO`) — tipo de cambio
FIX (USD/MXN) oficial de Banxico con la fecha del dato y conversión opcional.

La verificación de Factura (`POST /v1/factura/verificar`) ahora incluye además
un bloque `validacion_aritmetica`: comprueba que el subtotal sea la suma de los
conceptos, que el total cuadre (subtotal − descuento + trasladados − retenidos)
y que cada impuesto sea base × tasa. Sin costo adicional; va incluido en CFDI.

## Legislación mexicana (servicio `LEGAL`) — $0.10/$0.15 por consulta

El texto exacto de la ley, en vez de alucinarlo. Corpus de **198 ordenamientos**
(Constitución, códigos y leyes federales, nacionales y de los 32 estados;
~180 000 artículos) con **fuente oficial, fecha de última reforma integrada y
deslinde** en cada respuesta. Es texto de referencia con **fecha de corte**, no
la ley viva ni asesoría jurídica: puede no reflejar reformas posteriores, y el
consumidor verifica la vigencia en el DOF o la gaceta oficial. Mismo principio
anti-multa que el motor fiscal.

- `GET /v1/legal/documentos?materia=&ambito=&entidad=&q=` — **índice libre** (no
  cobra): lista los ordenamientos y te da el `documento_id` que necesitas.
  Filtra por materia (Civil/Penal/Fiscal/Laboral/…), ámbito
  (Federal/Estatal/Nacional), entidad o texto del nombre.
- `GET /v1/legal/{documento_id}/articulo/{numero}` — texto exacto de un artículo
  con su cita, ubicación, fuente y deslinde. Cobra `LEGAL` cuando existe; si no
  se encuentra, no cobra. Ej.: `/v1/legal/codigo_civil_federal/articulo/1793`.
- `GET /v1/legal/buscar?q=&materia=&ambito=&entidad=&documento=&limite=` —
  búsqueda de texto completo (español) en el articulado; devuelve extractos
  resaltados con cita y fuente. Cobra `LEGAL` cuando hay resultados; una
  búsqueda vacía no cobra.

## Sin costo por diseño

- `GET /v1/constancias/{folio}/validar` — valida cualquier constancia emitida
  por RESET Verifica. **Recibo portátil**: quien pagó una verificación puede
  compartir su folio y cualquier tercero (humano o agente) confirma gratis,
  las veces que quiera, que la verificación existió, cuándo y con qué
  resultado. La validación gratuita es precisamente lo que hace valiosa la
  constancia.
- `GET /v1/salud` — estado de las fuentes oficiales: cuándo publicó el SAT la
  última versión de cada lista (69-B, art. 69) y su SHA-256, frescura de
  Compras MX y estado de los jobs.

## Endpoints

### GET /v1/salud

Sin autenticación. Estado del servicio, frescura de cada fuente (con SHA-256 de
la versión publicada) y última corrida de cada job de ingesta.

```json
{
  "servicio": "RESET Verifica",
  "engine_version": "1.0.0",
  "fuentes": [{"source": "sat_69b_completo", "sha256": "9b4884…",
               "registros": 14490, "publicada": "2026-08-19T02:46:25+00:00"}],
  "jobs": [{"job": "sat_69b_download", "status": "ok", "corrida": "…"}]
}
```

### GET /v1/empresa/{rfc}

Verificación anclada a RFC: personas morales y, en las listas del artículo 69
habilitadas, también personas físicas (solo por RFC exacto; no existe búsqueda
por nombre). Query params: `sancionados=false` omite la consulta al directorio
de sancionados.

Respuesta (campos principales):

```json
{
  "verification_id": "RV-20260819-39F1C7A2",
  "service": "COMPANY",
  "rfc": "AAA120730823",
  "tipo_persona": "moral",
  "sat_69b": {
    "estado": "COINCIDENCIA",
    "situaciones": [{"situacion": "Definitivo", "nombre": "…",
                     "detalle": {"…": "columnas oficiales del listado SAT"}}],
    "historial_eventos": [{"evento": "ADDED", "situacion": "Definitivo",
                           "fecha": "…"}],
    "fuente": {"id": "sat_69b_completo", "url": "…", "sha256": "…",
               "registros_en_version": 14490, "publicada_en_reset": "…"}
  },
  "sat_art69": {
    "estado": "COINCIDENCIA",
    "listas": [{"lista": "FIRMES", "etiqueta_oficial": "Firmes",
                "fundamento": "CFF art. 69, parrafo decimo segundo, fraccion I: creditos fiscales firmes",
                "nombre": "…", "tipo_persona": "moral | fisica",
                "registros_oficiales": [{"…": "columnas oficiales del CSV del SAT"}]}],
    "historial_eventos": [{"evento": "ADDED | REMOVED", "lista": "FIRMES", "fecha": "…"}],
    "listas_consultadas": [{"id": "sat_art69_firmes", "sha256": "…", "publicada_en_reset": "…"}],
    "advertencia": "El estado puede haber cambiado despues de la fecha de la version consultada…"
  },
  "proveedores_sancionados": {"estado": "SIN_COINCIDENCIA | COINCIDENCIA | SOURCE_UNAVAILABLE"},
  "contratacion_publica": {"estado": "COINCIDENCIA", "contratos": 18,
                           "por_anio": [{"anio": 2023, "contratos": 4,
                                         "monto_total": "…"}]},
  "result_code": "COMPANY_OK",
  "consultado": "…",
  "engine_version": "1.0.0",
  "advertencia": "RESET Verifica organiza informacion de fuentes oficiales y no emite una calificacion crediticia…"
}
```

### GET /v1/empresa/{rfc}/contratos

Detalle de contratos públicos del RFC (datos abiertos Compras MX / CompraNet).
Query: `limite` (default 50, máx 500). Devuelve `total_contratos` y lista con
`proveedor`, `dependencia`, `num_contrato`, `procedimiento`, `monto`, `moneda`,
`fecha`, `anio`.

### POST /v1/factura/verificar

Cuerpo: el XML del CFDI tal cual (`Content-Type: application/xml`).
Query: `consultar_sat=false` para validación solo local.

```bash
curl -X POST -H "X-Api-Key: $KEY" -H "Content-Type: application/xml" \
     --data-binary @factura.xml {BASE}/v1/factura/verificar
```

Respuesta (campos principales):

```json
{
  "verification_id": "…",
  "service": "CFDI",
  "xml_sha256": "…",
  "campos": {"version": "4.0", "uuid": "…", "emisor_rfc": "…",
             "receptor_rfc": "…", "total": "11600.00", "moneda": "MXN"},
  "validaciones_formato": [{"check": "uuid_formato", "ok": true}],
  "estructura_anexo20": {"aplicado": true, "ok": true, "faltantes": []},
  "validacion_xsd": {"aplicado": true, "ok": true, "errores": []},
  "estado_sat": {"CodigoEstatus": "S - …", "Estado": "Vigente",
                 "EsCancelable": "…", "EstatusCancelacion": "",
                 "ValidacionEFOS": "200", "disponible": true},
  "emisor_69b": {"estado": "SIN_COINCIDENCIA_EN_LA_VERSION_CONSULTADA"},
  "duplicado_en_organizacion": false,
  "result_code": "CFDI_OK",
  "retencion": "El XML no se almacena; se conserva una huella irreversible, campos minimos y resultado."
}
```

El XML **no se almacena** (process-and-discard). La detección de duplicados por
UUID opera solo dentro de tu organización, nunca entre clientes.

### POST /v1/pago/obligaciones

Registra una obligación a conciliar. Cuerpo JSON:

```json
{"referencia": "F-1001", "monto": 11600.00,
 "descripcion": "opcional", "moneda": "MXN"}
```

Errores: `409` si la referencia ya existe; `422` si faltan campos.

### GET /v1/pago/obligaciones

Lista tus obligaciones (máx 500). Query opcional:
`estado` = `abierta` | `liquidada` | `sobrepagada` | `cancelada`.

### POST /v1/pago/cep

Cuerpo: el XML del CEP. Query opcional: `refs` con referencias de obligaciones
separadas por coma.

```bash
curl -X POST -H "X-Api-Key: $KEY" --data-binary @cep.xml \
     "{BASE}/v1/pago/cep?refs=F-1001"
```

Respuesta (campos principales):

```json
{
  "verification_id": "…",
  "service": "SPEI",
  "cep_sha256": "…",
  "evidencia": {"clave_rastreo": "…", "fecha_operacion": "…",
                "monto": "11600.00", "moneda": "MXN",
                "banco_ordenante": "…", "banco_beneficiario": "…",
                "cuenta_ordenante_last4": "7895",
                "cuenta_beneficiario_last4": "1234"},
  "conciliacion": {"tipo": "MATCH_EXACT",
                   "aplicaciones": [{"obligation_id": 1,
                                     "monto_aplicado": "11600.00",
                                     "nuevo_estado": "liquidada"}],
                   "detalle": {}},
  "result_code": "SPEI_OK"
}
```

Tipos de conciliación: `MATCH_EXACT`, `MATCH_ONE_TO_MANY` (varias refs cuya suma
de saldos es exacta), `MATCH_PARTIAL` (registra remanente), `MATCH_OVERPAYMENT`
(registra excedente), `MATCH_DUPLICATE` (mismo CEP ya usado en tu organización;
`result_code` = `SPEI_DUPLICADO`), `SIN_MATCH` (con motivo). Sin `refs`, intenta
primero `referencia == clave de rastreo` y luego monto exacto único. De las
cuentas bancarias solo se conservan los últimos 4 dígitos y un código derivado
irreversible; el XML se descarta.

**Alertas de posible duplicado.** Además del CEP idéntico, cada CEP se
compara contra los pagos previos de tu organización: si existe otro CEP distinto
con la **misma cuenta beneficiaria y el mismo monto** registrado en los últimos
7 días, la respuesta incluye una alerta `POSIBLE_DUPLICADO` con la referencia
del pago previo (regla determinística sobre el código derivado de cuenta; no bloquea la
operación, la hace visible).

### POST /v1/pago/cep-lote

Conciliación masiva: envía un **ZIP con hasta 500 CEPs XML**
(`multipart/form-data`, campo `zip`, máx. 50 MB) y cada uno se procesa y
concilia individualmente:

```bash
curl -X POST -H "X-Api-Key: $KEY" -F "zip=@ceps.zip" {BASE}/v1/pago/cep-lote
```

Respuesta: resumen por resultado, lista archivo por archivo
(`verification_id`, conciliación, clave de rastreo, alertas) y los ignorados
con motivo. Se cobra solo cada CEP procesado con éxito; los duplicados no
cobran. Si el saldo se agota a medio lote, se detiene e informa el avance.

### POST /v1/transaccion/verificar

Transacción completa (precio `COMBO`): verifica **empresa + factura + pago** en
una sola llamada `multipart/form-data`:

```bash
curl -X POST -H "X-Api-Key: $KEY" \
     -F "cfdi=@factura.xml" -F "cep=@cep.xml" \
     -F "rfc=ABC010203XX1" -F "refs=F-1001" \
     {BASE}/v1/transaccion/verificar
```

Campos: `cfdi` (archivo XML, obligatorio), `cep` (archivo XML, obligatorio),
`rfc` (opcional; por defecto el emisor del CFDI), `refs` (opcional, referencias
de obligaciones). Devuelve los tres resultados completos + un `verification_id`
de la transacción que referencia los tres individuales.

### GET /v1/precios

Sin autenticación. Tabla de precios vigente, modelo prepago, fondeo mínimo y
vigencia de créditos.

### GET /v1/wallet

Saldo disponible, créditos vigentes (con vencimiento) y últimos movimientos.

### POST /v1/wallet/fondeos

Crea una solicitud de fondeo. Cuerpo: `{"monto_credito": 500}`.
Regresa instrucciones SPEI (referencia, CLABE, monto exacto con IVA).

### POST /v1/wallet/fondeos/{referencia}/cep

Sube el CEP XML del depósito como comprobante; si el monto y la cuenta destino
coinciden, el saldo se acredita automáticamente.

### GET /v1/verificaciones/{verification_id}

Recupera una verificación previa de tu organización con el resultado completo tal
como se generó (evidencia inmutable con hashes de entrada/salida).

## Screening AML — Screen (`SCREEN`)

Cotejo de un nombre o identificador fiscal contra listas de sanciones y personas
políticamente expuestas (PEP). Devuelve un **ledger** con cada lista consultada y
si hubo o no coincidencia, las coincidencias con score y fuente, un resumen y,
opcional, una **constancia PDF** sellada con folio verificable. Un resultado
*clear* en todas las listas sirve como evidencia de debida diligencia. El cotejo
de nombre es aproximado (fuzzy): revisa cada coincidencia.

### POST /v1/screen

Cuerpo: `{"name": "Nombre o razón social", "country": "MX", "tax_id": "..."}`
(`name` obligatorio, ≥3 caracteres significativos; `country` y `tax_id`
opcionales, afinan las listas nacionales). Con `"certificate": true` la respuesta
incluye la constancia PDF en base64.

Cubre, por corrida: sanciones **OFAC (SDN + Consolidated)**, **UE (FSF)**,
**Reino Unido (OFSI)** y **Canadá (SEMA/JVCFOA)**; listas nacionales de **MX, BR,
CO, AR, DO**; y **PEP** — políticos nacionales de los países con servicio (**MX,
BR, CO, AR, DO, CA, US**), vivos o de muerte reciente (Wikidata CC0). La
respuesta trae `match_found`, `summary`, `checked` (el ledger),
`international_hits`, `national`, `pep_hits` y `certificate`. No cubre la Lista de
Personas Bloqueadas (LPB) de la SHCP (fuente restringida).

### POST /v1/screen/monitoreo

Da de alta la entidad en **monitoreo continuo**: RESET la re-screenea de forma
periódica y te avisa por webhook (`MONITOREO_SCREEN`) cuando cambia el conjunto
de coincidencias. Cuerpo igual que `/v1/screen`. La primera corrida fija la línea
base; a partir de ahí solo notifica cambios.

### GET /v1/screen/monitoreo

Lista tus entidades en monitoreo con su última revisión.

### DELETE /v1/screen/monitoreo/{watch_id}

Retira una entidad del monitoreo.

### GET /v1/screen/constancia/{folio}

Descarga la constancia PDF de un screening por su folio (sin llave; el folio es el
token). El PDF incluye el ledger de listas, las coincidencias y el sello SHA-256
del resultado.

## Constancias con validación pública

Cada verificación puede emitir **una constancia**: documento HTML imprimible con
folio único, timestamps, fuentes con SHA-256 y sello de integridad. El folio
funciona como token: quien lo tenga (tu contador, un auditor) puede ver el
documento y validar su autenticidad sin llave de API.

| Endpoint | Auth | Qué hace |
|---|---|---|
| `POST /v1/verificaciones/{vid}/constancia` | sí | Emite la constancia (re-emitir regresa el mismo folio) |
| `GET /v1/constancias/{folio}` | no | Documento HTML imprimible |
| `GET /v1/constancias/{folio}/validar` | no | Validación de autenticidad e integridad (JSON) |

La validación recalcula el SHA-256 del contenido canónico contra el sello: si el
registro fue alterado, responde `"valida": false` con alerta. Lenguaje del
documento: *constancia de consulta a fuentes oficiales* — no es un certificado
de autoridad.

## Log de consumo

### GET /v1/uso

Consumo por mes (`?mes=2026-08`) o por rango (`?desde=YYYY-MM-DD&hasta=YYYY-MM-DD`),
máximo un año. Regresa totales por servicio (consultas, facturables, monto),
saldo actual, y con `detalle=true` el log consulta por consulta:
`verification_id`, timestamp, `result_code`, monto cobrado y folio de constancia
si existe.

### Reporte mensual por correo

El día 1 de cada mes se genera un reporte del mes anterior por organización
(consultas, montos y saldo) y se envía al correo registrado de la organización.
Los reportes quedan almacenados y consultables aunque el correo no esté
configurado.

## Expediente de auditoría

### GET /v1/auditoria/expediente

Para contingencias (revisión del SAT, auditoría interna o disputa): genera el
paquete probatorio completo de un periodo (`?mes=` o `?desde=&hasta=`, máx. un
año): cada verificación con su resultado íntegro y hashes, sus constancias, las
versiones exactas de fuente utilizadas y el rastro de cobro. El expediente tiene
su propio id único (`RVA-…`), timestamp y SHA-256 de contenido, y su emisión
queda registrada.

### GET /v1/auditoria/fuente/{source_version_id}

Descarga el **snapshot original** de la fuente oficial (por ejemplo, el CSV 69-B
tal como lo publicó el SAT, comprimido) cuya versión se usó en las
verificaciones — el SHA-256 permite comprobar que es byte a byte el archivo
oficial. Con esto cualquier tercero puede reproducir la consulta.

## Organización y datos fiscales

| Endpoint | Qué hace |
|---|---|
| `GET /v1/organizacion` | Datos de tu organización, incluidos los fiscales, y si están completos |
| `PUT /v1/organizacion` | Actualiza `razon_social`, `rfc_fiscal`, `cp`, `regimen_fiscal`, `uso_cfdi`, `email` |

Completa tus datos fiscales para recibir el CFDI de tus fondeos. Se validan el
formato del RFC y el código postal.

**Multi-empresa (cuenta madre).** Si tu operación abarca varias razones
sociales, cada una recibe su propia llave y sus datos (verificaciones,
obligaciones, monitoreo) viven **estrictamente separados** — pero todas
comparten el **wallet de la cuenta madre**: cualquier razón social fondea, el
saldo y los usos son comunes, y el CFDI se emite a los datos fiscales de la
madre. El alta de la estructura se hace al solicitar tus llaves.

## Monitoreo 69-B con webhooks

Vigila los RFC que te importan (tus proveedores) y recibe un webhook cuando
alguno **entre, cambie o salga** de los listados 69-B del SAT — la
sincronización con el SAT es diaria y el despacho corre cada 15 minutos.

| Endpoint | Qué hace |
|---|---|
| `POST /v1/monitoreo/rfcs` | Alta de un RFC a vigilar (`{"rfc": "..."}`, hasta 500) |
| `GET /v1/monitoreo/rfcs` | Tus RFC vigilados con su situación 69-B actual |
| `DELETE /v1/monitoreo/rfcs/{rfc}` | Baja del monitoreo |
| `POST /v1/webhooks` | Registra tu endpoint (`{"url": "https://..."}`, hasta 3). Devuelve el `secreto` UNA sola vez |
| `GET /v1/webhooks` | Tus endpoints con última entrega OK y último error |
| `DELETE /v1/webhooks/{id}` | Desactiva un endpoint |
| `POST /v1/webhooks/{id}/probar` | Envía un evento sintético firmado, al momento |

Cada entrega es un `POST` JSON con estos campos principales:

```json
{
  "evento": "MONITOREO_69B",
  "tipo": "ADDED | UPDATED | REMOVED",
  "rfc": "ABC010203XX1",
  "situacion": "Definitivo",
  "detalle_anterior": { "…": "renglón previo del listado o null" },
  "detalle_nuevo": { "…": "renglón nuevo del listado o null" },
  "fecha_evento": "…", "fuente": {"source": "sat_69b_completo", "sha256": "…"},
  "entrega_id": 123, "enviado": "…"
}
```

**Verificación de autenticidad**: cada entrega lleva el header
`X-Reset-Firma: sha256=<hex>`, que es `HMAC-SHA256(secreto, cuerpo_crudo)`.
Recalcula y compara antes de confiar en el contenido. Respuestas fuera de 2xx se
reintentan (hasta 5 intentos). El monitoreo aplica hacia adelante: no se
notifican eventos anteriores a tu alta.

## Códigos de resultado (`result_code`)

| Código | Significado |
|---|---|
| `COMPANY_OK` | Verificación de empresa completada; cada fuente reporta su propio estado. |
| `CFDI_OK` | CFDI procesado. |
| `CFDI_CON_OBSERVACIONES` | CFDI procesado con fallas de formato (ver `validaciones_formato`). |
| `SPEI_OK` | CEP procesado y conciliado. El desenlace va en `conciliacion.result_code`. |
| `SPEI_DUPLICADO` | Ese CEP ya fue procesado por tu organización. |
| `SCREEN_OK` | Screening ejecutado. El desenlace va en `resultado`. |
| `COMBO_OK` | Transacción completa; `resumen` trae el `result_code` de empresa, factura y pago. |
| `INPUT_INVALID` | Entrada no procesable. No genera cargo. |
| `SOURCE_UNAVAILABLE` | Fuente oficial no disponible; el dato se reporta como faltante, nunca se inventa. |

### Desenlace de una conciliación (`conciliacion.result_code`)

| Valor | Significado |
|---|---|
| `MATCH_EXACT` | El CEP casó con una obligación por monto y referencia. |
| `MATCH_PARTIAL` | Casó, pero el monto pagado es menor al esperado. |
| `MATCH_OVERPAYMENT` | Casó, pero el monto pagado excede al esperado. |
| `MATCH_ONE_TO_MANY` | Un solo pago cubre varias obligaciones. |
| `MATCH_DUPLICATE` | Ese CEP ya se había procesado antes. |
| `SIN_MATCH` | No hay obligación registrada que corresponda al pago. |

### Desenlace de un screening (`resultado`)

| Valor | Significado |
|---|---|
| `SIN_MATCH` | El nombre o ID no aparece en ninguna lista consultada. |
| `MATCH_EXACT` | Coincidencia exacta en al menos una lista. |
| `MATCH_PARTIAL` | Coincidencia parcial: revisar manualmente antes de decidir. |

## Estados de fuente dentro de un resultado

| Estado | Significado |
|---|---|
| `COINCIDENCIA` | El identificador aparece; se entrega el detalle oficial con fechas. |
| `SIN_COINCIDENCIA_EN_LA_VERSION_CONSULTADA` | No aparece en esa versión de la fuente. No es un juicio de confiabilidad. |
| `SOURCE_NOT_LOADED` | Fuente aún no cargada en la copia local. |
| `SOURCE_UNAVAILABLE` | La fuente no respondió al momento de la consulta. |

## Errores HTTP

| Código | Cuándo |
|---|---|
| `400` | El cuerpo dice ser JSON pero no lo es. |
| `401` | Falta `X-Api-Key` o la llave es inválida/inactiva. |
| `402` | Sin usos ni saldo. La consulta **no se ejecutó ni se cobró**; recarga y reintenta. |
| `403` | Llave válida sin permiso para esa operación. |
| `404` | Recurso inexistente o de otra organización. |
| `409` | Conflicto (referencia de obligación duplicada). |
| `413` | El archivo excede el tamaño permitido. |
| `415` | Falta `Content-Type: application/json`. |
| `422` | Entrada inválida (cuerpo vacío, JSON incompleto, RFC malformado). No genera cargo. |

Cuerpo del `402`:

```json
{ "detail": { "error": "Sin usos ni saldo suficiente", "servicio": "COMPANY",
              "saldo": "0.00", "precio_individual": "14" } }
```

## Cómo leer una respuesta

1. **¿Funcionó?** HTTP `200` y `result_code` terminado en `_OK`.
2. **¿Hay algo que revisar?** Recorre los bloques de fuente buscando
   `estado == "COINCIDENCIA"`. "Sin coincidencia" **no** equivale a aprobado.
3. **¿Faltó información?** `SOURCE_UNAVAILABLE` / `SOURCE_NOT_LOADED` en un
   bloque: esa fuente no se pudo consultar. No lo trates como sin coincidencia.
4. **¿Se cobra?** Sí con `_OK`. No con `INPUT_INVALID`, `402`, `4xx` ni en sandbox.

Ejemplos de cuerpos reales (caso limpio, caso con hallazgo, cada error) y
snippets listos para Python, JavaScript, PHP y C# en
<https://resetparatodos.com/docs/#catalogo>.

## Principios de diseño relevantes para integradores

1. **Determinismo**: sin IA; misma entrada + misma versión de fuente = mismo resultado.
2. **Evidencia**: todo resultado incluye fuente, SHA-256 de la versión y fechas.
3. **Retención mínima**: XML de CFDI/CEP nunca se persiste; de las cuentas solo
   los últimos 4 dígitos y un código derivado.
4. **Segregación**: obligaciones, conciliaciones, duplicados y verificaciones son
   estrictamente por organización.
5. **Honestidad de fuente**: si una fuente falla, se dice; no se rellena.
