https://api.veriko.mx/v1/validate-ocr Validar una transferencia SPEI (OCR)
Guía de uso →Sube una imagen de comprobante, extrae los campos vía OCR y valida contra Banxico CEP en una sola llamada. Acepta imagen como base64 (image) o como URL remota (image_url). El campo cuenta_beneficiaria es opcional: si la imagen muestra la cuenta enmascarada, el sistema la resuelve desde las cuentas registradas en /v1/beneficiaries. Usa ?async=1 para encolar la pipeline OCR y recibir 202 inmediato; la imagen se sanea y persiste síncronamente antes del encolado. Sondea GET /v1/validations/{id} hasta el estado terminal. Acepta Idempotency-Key opcional con la misma semántica que POST /v1/validate — usa este último cuando ya conoces los campos del comprobante. Tras el veredicto, el detalle completo (incluyendo ocr_result, image_path y retry_state) se consulta vía GET /v1/validations/{id}.
| Parámetro | Ubicación | Tipo | Obligatorio | Descripción |
|---|---|---|---|---|
async | query | string | opcional | Cuando es `1`/`true`/`yes`, encola la validación y responde 202 inmediato con `validation_id`; el cliente sondea `GET /v1/validations/{id}` hasta el estado terminal. Sin el flag o con `0`, la respuesta es síncrona y devuelve el resultado final en el mismo POST. Predeterminado: |
Idempotency-Key | header | string | opcional | Llave opcional generada por el cliente (estilo Stripe) que garantiza que la petición se procese **exactamente una vez** dentro de un TTL de 24 horas. El alcance es `(user_id, endpoint, llave)`. Los reintentos con la misma llave y el mismo cuerpo devuelven la respuesta cacheada byte a byte con la cabecera `Idempotent-Replayed: true`, sin consumir cuota de rate-limit, sin re-disparar webhooks y sin crear una nueva fila en `validations`. Misma llave con cuerpo distinto → 422 `idempotency_key_reused`. Misma llave con una petición en vuelo → 409 `idempotency_key_in_progress`. Las respuestas 5xx no se cachean (los reintentos con la misma llave procesan de verdad). Formato: 1–255 caracteres, alfanuméricos + `_` + `-`. |
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
image | string (byte) | Obligatorio si no se envía image_url | Imagen del comprobante codificada en base64 (JPEG, PNG o WebP). Tamaño máximo: 12 MB. Dimensiones máximas: 12 000 px por lado. Mutuamente excluyente con `image_url`; si ambos se envían, `image` tiene precedencia. |
image_url | string (uri) | Obligatorio si no se envía image | URL pública HTTPS de la imagen del comprobante. El servidor descarga la imagen al recibir la petición y la persiste igual que en el flujo `image`. Tamaño y formato idénticos (JPEG, PNG o WebP, máximo 12 MB). p. ej.https://storage.example.com/receipts/comprobante-2025-03.jpg |
cuenta_beneficiaria | string (patrón) | opcional | Pista opcional de la cuenta beneficiaria: CLABE (18 dígitos), tarjeta (13-19 dígitos) o celular DiMo (10 dígitos), autodetectada por longitud. Se usa para desambiguar cuando el OCR extrae un número parcial o enmascarado del comprobante. p. ej.012180004412345678 |
banco_emisor | string (patrón) | opcional | Override opcional del banco emisor. Solo se aplica cuando el valor es un código numérico Banxico de 4 a 5 dígitos. Valores textuales se ignoran — el texto extraído por OCR es más confiable que el override del cliente. p. ej.40012 |
banco_receptor | string (patrón) | opcional | Override opcional del banco receptor. Solo se aplica cuando el valor es un código numérico Banxico de 4 a 5 dígitos. Valores textuales se ignoran. Útil cuando el OCR no pudo derivar el banco receptor o cuando el cliente conoce el código Banxico exacto. p. ej.40002 |
retry_policy | object | opcional | Política de reintentos automáticos para esta validación. Si se omite, se aplica la política configurada en `PUT /v1/users/me/retry-policy`. Los reintentos no consumen cuota de validaciones. |
curl -X POST 'https://api.veriko.mx/v1/validate-ocr' \
-H 'Authorization: Bearer mxcep_••••' \
-H 'Content-Type: application/json' \
-d '{
"image": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
}'
Ejemplo en Python — próximamente.
Ejemplo en JavaScript — próximamente.
Ejemplo en PHP — próximamente.
| Campo | Tipo | Descripción |
|---|---|---|
id * | string (uuid) | Identificador único de la validación (UUID v4). |
type * | string | Tipo de recurso JSON:API. Siempre `validation`. |
attributes * | object | Datos canónicos de la validación. |
validation_type | string | `direct` para peticiones con parámetros textuales; `ocr` para peticiones con imagen de comprobante. |
is_playground | boolean | Indica si la validación fue ejecutada en modo playground. Las ejecuciones playground sí consultan Banxico pero no consumen cuota, no emiten webhooks ni notificaciones. |
status | string | Estado del ciclo de vida: `queued` — encolado para worker; `processing` — worker procesando; `valid` — CEP encontrado y datos coinciden; `not_found` — Banxico consultado, transferencia no encontrada; `cep_unavailable` — servicio Banxico no disponible; `invalid` — payload rechazado post-encolado; `failed` — fallo terminal; `error` — error retriable (Banxico HTTP 5xx). |
banxico_status | string | null anulable | Estado reportado por Banxico tras la consulta. `null` antes de consultar. |
processing_time_ms | integer | null anulable | Milisegundos transcurridos entre encolado y resolución terminal. |
request_data | object | Snapshot literal de los campos del request original. |
created_at | string (date-time) | Marca temporal UTC del encolado. |
completed_at | string | null anulable | Marca temporal UTC de resolución terminal. `null` mientras `status` esté en `queued`/`processing`. |
enqueued_at | string | null anulable | Marca temporal del encolado en el bus de mensajería. |
processing_started_at | string | null anulable | Marca temporal del primer XCLAIM del worker. |
expires_at | string | null anulable | Marca temporal de expiración para validaciones encoladas. Tras esta marca, el job pasa a `failed`. |
etag_version | integer | null anulable | Versión incremental para `If-None-Match` en consultas polling. |
image_path | string | null anulable | Ruta relativa de la imagen del comprobante. Solo OCR. |
ocr_result | object | null anulable | Resultado bruto del OCR. Solo OCR. |
ocr_confidence | number | null anulable | Puntaje OCR 0–1. Solo OCR; `null` para `direct`. |
normalized_data | object | null anulable | Campos normalizados post-OCR para consulta a Banxico. |
normalization_warnings | array | null anulable | Advertencias de la pipeline de normalización. |
is_masked | boolean | null anulable | Indica si el PAN viene enmascarado en el comprobante OCR. |
banxico_result | object | null anulable | Payload literal devuelto por Banxico CEP. |
error_message | string | null anulable | Mensaje legible del error terminal cuando aplique. |
error_code | string | null anulable | Código machine-readable del error terminal. |
batch_id | integer | null anulable | Identificador del lote de import masivo si aplica. |
batch_position | integer | null anulable | Posición dentro del batch (1-indexed). |
retry_state | object | Estado completo del ciclo de reintentos. Siempre presente; si la validación no tiene reintentos activos, `enabled=false` y los campos de política son `null`. Las validaciones de import masivo siempre tienen `enabled=false`. |
enabled | boolean | Indica si el ciclo de reintentos está activo para esta validación. |
max_retries | integer | null anulable | Número máximo de reintentos configurado. El tope superior depende del plan (`retry_max_retries`) o del default global `max_retries_cap` (típicamente 5–10). `null` si `enabled=false`. |
interval_seconds | integer | null anulable | Intervalo entre reintentos en segundos (300–86400). `null` si `enabled=false`. |
outcomes | array | null anulable | Resultados de validación que habilitan un reintento (`not_found`, `cep_unavailable`, `error`). `null` si `enabled=false`. |
attempts_completed | integer | Número de reintentos completados hasta el momento. |
next_attempt_at | union | Timestamp del próximo reintento programado. `null` si el ciclo está en estado terminal o si no hay reintentos activos. |
resolved_at | union | Timestamp cuando un reintento resolvió la validación a `valid`. `null` si el ciclo no ha terminado por resolución. |
exhausted_at | union | Timestamp cuando se agotaron los reintentos sin resolución. `null` si el ciclo no ha terminado por agotamiento. |
cancelled_at | union | Timestamp cuando el ciclo fue cancelado explícitamente. `null` si no fue cancelado. |
terminal_state | string | null anulable | Estado terminal del ciclo: `pending` — activo, sin resultado final aún; `resolved` — un reintento obtuvo `valid`; `exhausted` — se agotaron los intentos; `cancelled` — cancelado por el usuario. |
links | object | Enlaces relacionados (JSON:API `links`). |
self | string | URL de la validación. |
cep_xml | string | null anulable | URL del CEP en formato XML. `null` si `status` no es `valid`. |
cep_pdf | string | null anulable | URL del CEP en formato PDF. `null` si `status` no es `valid`. |
| Código | Clase | Descripción | Cuerpo |
|---|---|---|---|
| 200 | 2xx | Veredicto de la validación con los campos extraídos por OCR. El campo `ocr_confidence` (0–1) indica la confianza de la extracción. | Sin cuerpo |
| 202 | 2xx | Validación encolada. El cliente debe sondear `GET /v1/validations/{id}` hasta uno de los estados terminales (`valid`, `not_found`, `cep_unavailable`, `invalid`, `failed`, `error`). `meta.next_poll_after_seconds` indica el intervalo recomendado para el primer poll. | ValidationQueued |
| 400 | 4xx | El valor de la cabecera `Idempotency-Key` no cumple el formato permitido (alfanumérico + `_` + `-`, 1–255 caracteres). | ErrorResponse |
| 401 | 4xx | Se requiere autenticación o las credenciales son inválidas | ErrorResponse |
| 409 | 4xx | Una petición con la misma `Idempotency-Key` aún se está procesando. El cliente debe reintentar después de los segundos que indica la cabecera `Retry-After`. Las filas en vuelo más antiguas que `idempotency.in_flight_timeout_seconds` (300 por defecto) se tratan automáticamente como zombies y se limpian en el siguiente intento. | ErrorResponse |
| 422 | 4xx | Falló la validación de la petición. Códigos de body: `image_or_image_url_required`, `invalid_image`, `invalid_image_format`, `image_too_large`, `invalid_url`, `invalid_url_scheme`, `url_ssrf_blocked`, `invalid_clabe_checksum`. Códigos de sanitización post-decode (path sync y async pre-dispatch): `image_too_small`, `image_mime_mismatch`, `image_dimensions_too_large`, `image_decompression_bomb`, `image_polyglot_detected`, `image_url_unreachable`, `image_url_too_large`, `image_url_too_many_redirects`. En modo async la falla genérica de sanitización se reporta como `image_invalid`. Reusó `Idempotency-Key` con cuerpo distinto → `idempotency_key_reused`. | ErrorResponse |
| 429 | 4xx | Límite de tasa excedido | ErrorResponse |
| 503 | 5xx | OCR no configurado en este deploy (`ocr_not_configured`), falla del upstream Banxico (`banxico_rate_limit_exhausted`), o fallo de despacho async (Redis caído → `dispatch_failed`). Espera unos minutos y reintenta. | ErrorResponse |
| Cabecera | Tipo | Descripción |
|---|---|---|
Idempotent-Replayed | string | Presente solo cuando el cliente envió `Idempotency-Key`. `false` para respuestas frescas; `true` cuando es replay del caché. |
| Código | Clave | Detalle |
|---|---|---|
| 400 | invalid_idempotency_key | Invalid Idempotency-Key format. Allowed: A-Z a-z 0-9 _ - (1-255 chars). Envelope
|
| 401 | unauthorized | Invalid or missing authentication credentials. Envelope
|
| 409 | idempotency_key_in_progress | A request with this Idempotency-Key is still being processed. Envelope
Cabeceras de respuesta
|
| 429 | rate_limit_exceeded | Rate limit exceeded. Try again in 45 seconds. Envelope
Cabeceras de respuesta
|
Política de reintentos
POST /v1/validate-ocr
Política de reintentos automáticos. Configura cuándo y cuántas veces el sistema reintenta una validación cuyo resultado es elegible (`not_found`, `cep_unavailable` o `error` por defecto).
- Intentos
- —
- Intervalo
- 5 min – 1 h × 24
- Resultados elegibles
-
not_found,cep_unavailable,error
Esta operación admite una política de reintentos opcional.