POSThttps://api.veriko.mx/v1/validate-ocr

Validar una transferencia SPEI (OCR)

Audiencia
public
Autenticación
API key
Permiso
validations_ocr:create
Guía de uso →

Recibe la imagen de un comprobante, extrae de ella los campos y valida contra el CEP de Banxico en una sola llamada. La imagen viaja como base64 en image o como dirección remota en image_url. cuenta_beneficiaria es opcional aquí, a diferencia de la validación directa: cuando el comprobante muestra la cuenta enmascarada, se resuelve contra las cuentas registradas en /v1/beneficiaries. Es la razón práctica para tener beneficiarios dados de alta antes de usar este endpoint. Modo asíncrono. Con ?async=1 la respuesta es un 202 inmediato y el veredicto se recoge sondeando GET /v1/validations/{id}. La imagen se procesa antes de responder incluso en este modo, así que el 202 tarda más que el de la validación directa. Cada llamada consume cuota del plan, igual que la validación directa y con el mismo descuento al aceptar la petición. Agotar la cuota responde 429; el detalle está en cuotas y planes. La cabecera Idempotency-Key funciona igual que en POST /v1/validate, que es la vía preferible cuando los campos del comprobante ya se conocen: evita el paso de extracción y su margen de error. Tras el veredicto, el detalle completo —con ocr_result, image_path y retry_state— está en GET /v1/validations/{id}.

Parámetros
ParámetroUbicaciónTipoObligatorioDescripción
asyncquerystringopcional

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: 0

Idempotency-Keyheaderstringopcional

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 + _ + -.

p. ej. 11111111-2222-3333-4444-555555555555
Parámetros
ParámetroTipoObligatorioDescripción
imagestring (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.

p. ej. iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==
image_urlstring (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_beneficiariastring (patrón)opcional

Pista opcional de la cuenta beneficiaria: CLABE (18 dígitos), tarjeta (16 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
retry_policyobjectopcional

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.

Petición
curl -X POST 'https://api.veriko.mx/v1/validate-ocr' \
  -H 'Authorization: Bearer veriko_••••' \
  -H 'Content-Type: application/json' \
  -d '{
    "image": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
  }'

Ejemplo en Python — próximamente.

Ejemplo en JavaScript — próximamente.

Ejemplo en PHP — próximamente.

Respuesta 2xxValidation
CampoTipoDescripción
type*string

Tipo de recurso JSON:API. Siempre validation.

p. ej. validation
id*string (uuid)

Identificador único de la validación (UUID v4).

p. ej. 3fa85f64-5717-4562-b3fc-2c963f66afa6
attributes*object

Datos canónicos de la validación.

validation_typestring

direct para peticiones con parámetros textuales; ocr para peticiones con imagen de comprobante.

p. ej. direct
is_playgroundboolean

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.

p. ej. false
statusstring

Estado del ciclo de vida: queued — encolado para trabajador; processing — trabajador 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).

p. ej. valid
banxico_statusstring | nullanulable

Estado reportado por Banxico tras la consulta. null antes de consultar.

p. ej. valid
processing_time_msinteger | nullanulable

Milisegundos transcurridos entre encolado y resolución terminal.

p. ej. 1320
request_dataobject

Snapshot literal de los campos del request original.

created_atstring (date-time)

Marca temporal UTC del encolado.

p. ej. 2025-03-15T14:22:10Z
completed_atstring | nullanulable

Marca temporal UTC de resolución terminal. null mientras status esté en queued/processing.

p. ej. 2025-03-15T14:22:11Z
enqueued_atstring | nullanulable

Marca temporal del encolado en el bus de mensajería.

p. ej. 2026-04-30T10:15:00Z
processing_started_atstring | nullanulable

Marca temporal del primer XCLAIM del trabajador.

p. ej. 2026-04-30T10:15:00Z
expires_atstring | nullanulable

Marca temporal de expiración para validaciones encoladas. Tras esta marca, la importación pasa a failed.

p. ej. 2026-04-30T10:15:00Z
etag_versioninteger | nullanulable

Versión incremental para If-None-Match en consultas polling.

p. ej. 1
image_pathstring | nullanulable

Ruta relativa de la imagen del comprobante. Solo OCR.

p. ej. ocr/2026/04/a1b2c3d4.jpg
ocr_resultobject | nullanulable

Resultado bruto del OCR. Solo OCR.

ocr_confidencenumber | nullanulable

Puntaje OCR 0–1. Solo OCR; null para direct.

p. ej. 0.94
normalized_dataobject | nullanulable

Campos normalizados post-OCR para consulta a Banxico.

normalization_warningsarray | nullanulable

Advertencias de la pipeline de normalización.

is_maskedboolean | nullanulable

Indica si el PAN viene enmascarado en el comprobante OCR.

banxico_resultobject | nullanulable

Payload literal devuelto por Banxico CEP.

error_messagestring | nullanulable

Mensaje legible del error terminal cuando aplique.

p. ej. Banxico no respondió tras tres intentos.
error_codeValidationErrorCode | null

Código machine-readable del error terminal.

batch_idinteger | nullanulable

Identificador del lote de import masivo si aplica.

p. ej. 318
batch_positioninteger | nullanulable

Posición dentro del lote (1-indexed).

p. ej. 12
retry_stateobject

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.

enabledboolean

Indica si el ciclo de reintentos está activo para esta validación.

p. ej. true
max_retriesinteger | nullanulable

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.

p. ej. 3
interval_secondsinteger | nullanulable

Intervalo entre reintentos en segundos (300–86400). null si enabled=false.

p. ej. 600
outcomesarray | nullanulable

Resultados de validación que habilitan un reintento (not_found, cep_unavailable, error). null si enabled=false.

p. ej. ["not_found","cep_unavailable","error"]
attempts_completedinteger

Número de reintentos completados hasta el momento.

p. ej. 1
next_attempt_atTimestampUTC | null

Timestamp del próximo reintento programado. null si el ciclo está en estado terminal o si no hay reintentos activos.

resolved_atTimestampUTC | null

Timestamp cuando un reintento resolvió la validación a valid. null si el ciclo no ha terminado por resolución.

exhausted_atTimestampUTC | null

Timestamp cuando se agotaron los reintentos sin resolución. null si el ciclo no ha terminado por agotamiento.

cancelled_atTimestampUTC | null

Timestamp cuando el ciclo fue cancelado explícitamente. null si no fue cancelado.

terminal_statestring | nullanulable

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. null si la validación no tiene ciclo de reintentos.

p. ej. pending
linksobject

Enlaces relacionados (JSON:API links).

selfstring

URL de la validación.

p. ej. /v1/validations/3fa85f64-5717-4562-b3fc-2c963f66afa6
cep_xmlstring | nullanulable

URL del CEP en formato XML. null si status no es valid.

p. ej. /v1/validations/a1b2c3d4-e5f6-7890-abcd-ef0123456789/cep.xml
cep_pdfstring | nullanulable

URL del CEP en formato PDF. null si status no es valid.

p. ej. /v1/validations/a1b2c3d4-e5f6-7890-abcd-ef0123456789/cep.pdf
Códigos de respuestaPOST /v1/validate-ocr
CódigoClaseDescripciónCuerpo
2002xxVeredicto 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
2022xxValidació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
4004xxEl valor de la cabecera Idempotency-Key no cumple el formato permitido (alfanumérico + _ + -, 1–255 caracteres). ErrorResponse
4014xxSe requiere autenticación o las credenciales son inválidasErrorResponse
4094xxUna 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
4134xxEl cuerpo de la petición supera el tamaño máximo admitido (body_too_large).ErrorResponse
4224xxFalló 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
4294xxLímite de tasa excedidoErrorResponse
5035xxOCR 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
Cabeceras de respuesta200
CabeceraTipoDescripción
Idempotent-ReplayedstringPresente solo cuando el cliente envió Idempotency-Key. false para respuestas frescas; true cuando es replay del caché.
Errores de POST /v1/validate-ocr
CódigoClaveEjemplo
400invalid_idempotency_key

Formato de Idempotency-Key inválido. Se admiten A-Z a-z 0-9 _ - (de 1 a 255 caracteres).

Envelope
meta.request_id
3c4d5e6f7a8b
401unauthorized

Credenciales de autenticación ausentes o inválidas.

Envelope
meta.request_id
c4d5e6f7a8b9
409idempotency_key_in_progress

Una petición con esta Idempotency-Key sigue en proceso.

Envelope
meta.request_id
2b3c4d5e6f7a
Cabeceras de respuesta
  • Retry-After: integer — Segundos a esperar antes de reintentar
413body_too_large

El cuerpo de la petición es demasiado grande.

Envelope
meta.request_id
1a2b3c4d5e6f
429rate_limit_exceeded

Límite de peticiones excedido. Inténtalo de nuevo en 45 segundos.

Envelope
meta.request_id
f7a8b9c0d1e2
Cabeceras de respuesta
  • Retry-After: integer — Segundos a esperar antes de reintentar. Coincide con la ventana de rate-limit del endpoint (típicamente 60s para listas, 1-5s para operaciones idempotentes en vuelo).
  • X-RateLimit-Limit: integer — Límite de solicitudes configurado para este bucket (emitido sólo en 429).
  • X-RateLimit-Remaining: integer — Solicitudes restantes en la ventana actual — siempre 0 en el momento del 429 (emitido sólo en 429).
  • X-RateLimit-Reset: integer — Unix epoch absoluto (segundos) en que se reinicia la ventana. Emitido sólo en 429, junto con Retry-After. Puede existir sobreescritura por endpoint (p. ej. `rate_limited_login`).

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.