Un beneficiario es una cuenta destino guardada bajo el user_id del API key (lista blanca por usuario, nunca compartida entre cuentas). Persistir un beneficiario tiene tres efectos concretos: 1) auto-completa banco y tipo en validaciones futuras, 2) sirve de fuente prioritaria para resolver PAN enmascarados que el OCR no puede completar, y 3) habilita los alias bilingües que usan las exportaciones y el estado de cuenta de Finanzas.
Los tres tipos de cuenta
MexCep detecta el account_type por el número de dígitos (src/Support/CardBins.php::detectAccountType):
clabe— 18 dígitos. El banco se deriva del prefijo de 3 dígitos contraBanxicoBanks::bankFromClabe. No requierebank_codeen el body.card— 13 a 19 dígitos, excluyendo 18 (reservado para CLABE) y 10 (reservado para teléfono). El banco se infiere por BIN/dictionary. No requierebank_code.phone— 10 dígitos exactos. Es una clave DiMo del SPEI.bank_codees obligatorio en el body porque no existe un mapeo público de teléfono → banco; el endpoint responde422 bank_code_required_for_phonecuando falta. El catálogo de códigos vive enGET /v1/public/banks.
Para validar la estructura sin persistir (CLABE checksum o Luhn) usa GET /v1/beneficiaries/validate-account.
PAN enmascarado y OCR
Cuando POST /v1/validate-ocr extrae una cuenta de un comprobante con la forma ••••5678 o 4111 •••• •••• 1111, el pipeline llama a NormalizationService::resolveMaskedAccount. La búsqueda usa los últimos dígitos visibles y se ejecuta en este orden:
- Lista blanca del usuario —
BeneficiaryRepository::findByPartialAccountfiltra los beneficiarios activos del usuario por sufijo +length_hint+visible_first. Coincidencia única → resuelto. - Catálogo global por sufijo — solo si la lista blanca no resuelve. Devuelve
masked_catalog_uniquecuando hay match único,masked_probe_pendingcon candidatos cuando hay 2..N (N =clabe.probe_max_candidates, default 3),masked_ambiguous_in_catalogcuando hay más, omasked_unresolvablecuando no aparece nadie con ese sufijo.
Sin beneficiarios registrados un comprobante enmascarado cae al global por sufijo y puede quedar ambiguo. Registrar las cuentas que validás frecuentemente convierte estos casos en resoluciones determinísticas.
Crear, archivar, importar
POST /v1/beneficiariescrea uno. Acepta unaliasopcional que el sistema usa en exportaciones.GET /v1/beneficiarieslista con filtro tri-estado?with_archived=(0/null = activos, 1 = archivados, omitido = ambos).DELETE /v1/beneficiaries/{id}archiva — es un soft-delete (UPDATE user_beneficiaries SET status='inactive'). El API público no expone hard-delete; los registros archivados pueden recuperarse desde el panel de admin si el operador del deploy lo necesita.PATCH /v1/beneficiaries/{id}edita alias obank_code(obligatorio si el tipo esphoney el campo se incluye en la edición).
Para alta masiva el endpoint es POST /v1/beneficiaries/imports — ver Imports masivos para el flujo preview → commit y el parser híbrido manual+Gemini.