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

# Verificación de titular de cuenta bancaria en Sudáfrica

> Verifica titulares de cuentas bancarias en Sudáfrica con Didit en bases de datos oficiales. Desde $0.40 por consulta, sin contratos ni mínimos.

Confirma que una cuenta bancaria sudafricana pertenece al titular indicado mediante el servicio interbancario de verificación del titular de la cuenta (Account Holder Verification). Didit ofrece este servicio a través de `POST /v3/database-validation/`, para que puedas cotejar los datos enviados con la fuente autorizada y recibir resultados de coincidencia normalizados.

## Cobertura

* **Cobertura:** —
* **País:** Sudáfrica
* **ID del servicio:** `zaf_bank_account_holder`
* **Dominio de datos:** Financiero
* **Categoría:** Banca

## Datos de entrada

| Campo | Obligatorio | Ejemplo |
| - | -: | - |
| `national_id` | Sí | `8708150847085` |
| `bank_account_number` | Sí | `1234567890` |
| `bank_name` | Sí | `ABSA` |
| `account_type` | No | `current` |
| `first_name` | No | `John` |
| `last_name` | No | `Doe` |
| `initials` | No | `JD` |
| `email` | No | `john.doe@example.com` |
| `phone_number` | No | `+15550101000` |
| `vendor_data` | No | `user-1234` |

* **Datos de entrada obligatorios:** `national_id`, `bank_account_number`, `bank_name`
* **Datos de entrada opcionales:** `account_type`, `first_name`, `last_name`, `initials`, `email`, `phone_number`, `vendor_data`
* **Consentimiento:** Obligatorio
* **Disponibilidad en flujos de verificación:** Disponible en el flujo de verificación (workflow) con mapeo de campos
* **Cobertura:** —
* **Precio:** \$0.40 por consulta exitosa

En un flujo, `bank_account_number` y `bank_name` no figuran impresos en ningún documento de identidad, por lo que ningún paso los genera por sí solo. Obtenlos de la respuesta de un cuestionario, de un campo extraído por Document AI o de un valor que envíes al crear la sesión, y mapea cada uno en el paso de Validación de base de datos. Mientras no estén mapeados, el editor de flujos muestra este servicio desactivado e indica el dato de entrada que falta; en tiempo de ejecución, si falta un dato de entrada, la comprobación se omite antes de realizar cualquier consulta, así que nunca se te factura por una base de datos que no se pudo consultar.

## Parámetros del cuerpo

**issuing\_state** `string` *required* (default: ZAF)

Código de país ISO 3166-1 alfa-3 de este servicio de base de datos.

Ejemplo: `ZAF`

**services** `string` *required* (default: zaf\_bank\_account\_holder)

Array que contiene este ID de servicio. Fijar el servicio limita la solicitud a esta base de datos concreta.

Ejemplo: `zaf_bank_account_holder`

**consent** `boolean` *required* (default: true)

Consentimiento explícito del usuario final para este servicio.

Ejemplo: `true`

**national\_id** `string` *required* (default: 8708150847085)

Número de identidad nacional para este servicio.

Ejemplo: `8708150847085`

**bank\_account\_number** `string` *required* (default: 1234567890)

Valor de `bank_account_number` que requiere este servicio de base de datos.

Ejemplo: `1234567890`

**bank\_name** `string` *required* (default: ABSA)

Valor de `bank_name` que requiere este servicio de base de datos.

Ejemplo: `ABSA`

**account\_type** `string` (default: current)

Valor de `account_type` que requiere este servicio de base de datos.

Ejemplo: `current`

**first\_name** `string`

Nombre de pila que se va a validar.

Ejemplo: `John`

**last\_name** `string` (default: Doe)

Apellido que se va a validar.

Ejemplo: `Doe`

**initials** `string` (default: JD)

Valor de `initials` que requiere este servicio de base de datos.

Ejemplo: `JD`

**email** `string`

Dirección de correo electrónico.

Ejemplo: `john.doe@example.com`

**phone\_number** `string`

Valor de `phone_number` que requiere este servicio de base de datos.

Ejemplo: `+15550101000`

**vendor\_data** `string` (default: user-1234)

Tu referencia estable para esta persona, como tu ID de usuario interno. Didit la usa para vincular las comprobaciones independientes al mismo usuario final y reducir el ruido en la detección de duplicados.

Ejemplo: `user-1234`

## Reglas de entrada y notas de validación

* `account_type` debe ser uno de los tipos de cuenta AVS de Sudáfrica: `current`, `savings`, `transmission`, `subscriptionShare`, `notKnown`. La comparación no distingue entre mayúsculas y minúsculas. Omite el campo si no conoces el tipo de cuenta: en ese caso, Didit envía `notKnown` y la comprobación cruzada del tipo de cuenta se marca como no confirmada en lugar de que falle la solicitud.

## Cómo invocarlo

```bash cURL theme={null}
curl -X POST "https://verification.didit.me/v3/database-validation/" \
  -H "x-api-key: YOUR_API_KEY" \
  -F "issuing_state=ZAF" \
  -F "services=zaf_bank_account_holder" \
  -F "vendor_data=user-1234" \
  -F "consent=true" \
  -F "national_id=8708150847085" \
  -F "bank_account_number=1234567890" \
  -F "bank_name=ABSA" \
  -F "account_type=current" \
  -F "last_name=Doe" \
  -F "initials=JD"
```

Toda llamada exitosa devuelve HTTP `200`. El campo **`outcome_code`** te indica lo que ocurrió realmente; distingue, por ejemplo, una no coincidencia biométrica real (`BIOMETRIC_NO_MATCH`) de una selfie que no se pudo leer (`BIOMETRIC_IMAGE_UNUSABLE`). El `status` que se muestra es el estado predeterminado de la función; las [acciones de coincidencia parcial / sin coincidencia](https://docs.didit.me/es/core-technology/database-validation/database-validation-warnings.md) que hayas configurado pueden sobrescribirlo.

**`MATCH`**: el registro confirmó la identidad y todos los campos comprobados coincidieron.

```json 200 OK — MATCH theme={null}
{
  "request_id": "req_01H…",
  "status": "Approved",
  "issuing_state": "ZAF",
  "match_type": "full_match",
  "validations": [
    {
      "outcome_code": "MATCH",
      "service_id": "zaf_bank_account_holder",
      "service_name": "South Africa - Bank Account Holder Verification",
      "source_data": {
        "accepts_credits": true,
        "accepts_debits": true,
        "account_found": true,
        "account_number_length_valid": true,
        "account_open": true,
        "account_type_match": true,
        "id_match": true,
        "identification_number": "SAMPLE-ID-12345",
        "initials_match": true,
        "surname_match": true
      },
      "validation": {
        "full_name": "full_match",
        "identification_number": "full_match"
      }
    }
  ]
}
```

**`PARTIAL_MATCH`**: se encontró el número de identificación, pero uno o más campos personales (normalmente el nombre o la fecha de nacimiento) no coincidieron por completo.

```json 200 OK — PARTIAL_MATCH theme={null}
{
  "request_id": "req_01H…",
  "status": "In Review",
  "issuing_state": "ZAF",
  "match_type": "partial_match",
  "validations": [
    {
      "outcome_code": "PARTIAL_MATCH",
      "service_id": "zaf_bank_account_holder",
      "service_name": "South Africa - Bank Account Holder Verification",
      "source_data": {
        "accepts_credits": true,
        "accepts_debits": true,
        "account_found": true,
        "account_number_length_valid": false,
        "account_open": true,
        "account_type_match": true,
        "id_match": true,
        "identification_number": "SAMPLE-ID-12345",
        "initials_match": true,
        "surname_match": false
      },
      "validation": {
        "full_name": "partial_match",
        "identification_number": "full_match"
      }
    }
  ]
}
```

**`NO_MATCH`**: el registro no devolvió ninguna coincidencia para los datos enviados.

```json 200 OK — NO_MATCH theme={null}
{
  "request_id": "req_01H…",
  "status": "Declined",
  "issuing_state": "ZAF",
  "match_type": "no_match",
  "validations": [
    {
      "outcome_code": "NO_MATCH",
      "service_id": "zaf_bank_account_holder",
      "service_name": "South Africa - Bank Account Holder Verification",
      "source_data": {
        "accepts_credits": false,
        "accepts_debits": false,
        "account_found": false,
        "account_number_length_valid": false,
        "account_open": false,
        "account_type_match": false,
        "id_match": false,
        "identification_number": "NO_MATCH",
        "initials_match": false,
        "surname_match": false
      },
      "validation": {
        "identification_number": "no_match"
      }
    }
  ]
}
```

## Datos devueltos

Los campos exactos que aparecen en `source_data` dependen de lo que devuelve el registro. El ejemplo generado para `zaf_bank_account_holder` documenta actualmente esta estructura normalizada:

* `accepts_credits`
* `accepts_debits`
* `account_found`
* `account_number_length_valid`
* `account_open`
* `account_type_match`
* `id_match`
* `identification_number`
* `initials_match`
* `surname_match`

## Precios y SLA

Las consultas de verificación del titular de cuenta bancaria de Sudáfrica solo se facturan cuando Didit recibe un resultado concluyente de la fuente de validación.

* **Precio por llamada:** \$0.40 USD.
* **Facturación:** por consulta exitosa. No se te cobra cuando no se puede acceder al registro, cuando faltan campos obligatorios o cuando la solicitud se rechaza antes de llegar a la fuente.
* **Latencia:** p95 típico \< 2 s.
* **Disponibilidad:** 99.9% por trimestre por parte de Didit; la disponibilidad de la fuente externa varía según el país y el conjunto de datos.

## Qué confirma un MATCH

La verificación del titular de cuenta (AVS) es un conjunto de comprobaciones cruzadas de sí o no, no una consulta de registros. La fuente nunca devuelve un nombre, un número de identificación ni un saldo de cuenta: toma los datos que envías, los compara con lo que el banco tiene registrado para esa cuenta y responde a cada comparación con un indicador. `source_data` contiene esos indicadores:

* **`account_found`**: el banco tiene una cuenta con este número. Todo lo demás carece de sentido cuando es `false`.
* **`account_open`**: la cuenta está abierta. Una cuenta puede encontrarse pero estar cerrada.
* **`id_match`**: la cuenta está a nombre de la persona con el número de identificación nacional que enviaste. Esta es la comprobación para la que existe el servicio.
* **`initials_match`**, **`surname_match`**: los `initials` y el `last_name` enviados coinciden con el titular de la cuenta registrado.
* **`account_type_match`**: el `account_type` enviado coincide con el tipo real de la cuenta.
* **`email_match`**, **`phone_match`**: el `email` y el `phone_number` enviados coinciden con los datos de contacto que tiene el banco.
* **`accepts_debits`**, **`accepts_credits`**: la cuenta puede recibir órdenes de débito y créditos.
* **`account_number_length_valid`**: el número de cuenta tiene la longitud que espera el banco.

El código de resultado los resume:

* **`MATCH`**: la cuenta existe y todos los campos que enviaste coincidieron, `id_match` incluido.
* **`PARTIAL_MATCH`**: la cuenta está a nombre de la persona con el número de identificación nacional enviado, pero al menos otro de los campos que enviaste no coincidió (por ejemplo, un apellido escrito de otra forma en los registros del banco). `outcome_detail` indica los campos que fallaron.
* **`NO_MATCH`**: o bien el banco no tiene ninguna cuenta con ese número, o bien la cuenta existe pero pertenece a otra persona. Ambas son respuestas concluyentes sobre la persona.

Una comprobación cruzada que no solicitaste ni se contabiliza ni se informa. AVS responde `N` para cada campo que no se proporcionó, por lo que `surname_match`, `initials_match`, `email_match`, `phone_match` y `account_type_match` aparecen en `source_data` solo cuando enviaste el dato correspondiente. Por tanto, enviar solo `national_id`, `bank_account_number` y `bank_name` sigue produciendo un `MATCH` completo.

## Valores aceptados de bank\_name y account\_type

`bank_name` y `account_type` son enumeraciones. Un valor que no esté en ninguna de las dos listas se rechaza antes de ejecutar la consulta, así que un error tipográfico te cuesta una solicitud adicional, no un cargo.

`account_type` es opcional y acepta, sin distinguir mayúsculas de minúsculas:

`current` · `savings` · `transmission` · `subscriptionShare` · `notKnown`

Omítelo cuando no conozcas el tipo de cuenta. En ese caso, Didit envía `notKnown`, la solicitud se completa correctamente y `account_type_match` devuelve `false` porque no había nada que comparar. Cualquier otro valor (`checking`, `cheque`, `bond`) se rechaza con un `400` que enumera el conjunto aceptado.

`bank_name` es obligatorio, y estos valores están confirmados como aceptados (sin distinguir mayúsculas de minúsculas):

`ABSA` · `Capitec` · `FNB` · `Nedbank` · `Standard Bank` · `Investec` · `African Bank` · `Discovery Bank` · `Old Mutual` · `Bank Zero` · `Tyme` · `Grindrod`

Las cuentas de particulares de todos ellos están incluidas, Capitec también. Envía la forma corta exactamente como aparece en la lista: `Capitec`, no `Capitec Bank`; `Tyme`, no `TymeBank`. Un banco no reconocido devuelve un resultado `REGISTRY_ERROR` cuyo `outcome_detail` indica el campo que la fuente rechazó.

## Cómo distinguir una cuenta inexistente de una fuente no disponible

Son resultados HTTP distintos, por lo que no es necesario analizar cadenas de error:

* **La cuenta no existe**: `200 OK`, `match_type: "no_match"`, `outcome_code: "NO_MATCH"`, `source_data.account_found: false`. Es una respuesta real del banco. Se factura y se aplica tu acción para el caso sin coincidencia.
* **La fuente no respondió**: `502 Bad Gateway` con `validation_errors[].code` = `empty_provider_response` y `retryable: true`. No se estableció nada sobre la persona, no se factura nada y es seguro reintentar la solicitud.
* **La fuente se negó a ejecutar la consulta**: `400 Bad Request` con `validation_errors[].code` = `provider_rejected_input` y `retryable: false`. La fuente nunca realizó la búsqueda porque no aceptaba lo que se le envió. Corrige los datos; reintentar con los mismos valores no puede funcionar. No se factura nada.
* **La fuente respondió y rechazó tus datos**: `502 Bad Gateway` con `validation_errors[].code` = `provider_invalid_input` (por ejemplo, un número de cuenta que no supera la comprobación de formato del propio banco). No tiene sentido reintentar hasta corregir los datos; no se factura nada.
* **Tu solicitud nunca salió de Didit**: `400 Bad Request`, con el campo que debes corregir. No se factura nada.

Solo el primero de estos casos es una respuesta sobre la persona. Trata un `502` como transitorio (AVS reenvía la consulta al banco del titular de la cuenta en lugar de leer un registro, por lo que es el más lento de los servicios sudafricanos) y reintenta con una espera progresiva.

## Sigue leyendo

* [Descripción general de la validación de bases de datos de Sudáfrica](https://docs.didit.me/api-reference/database-validation/south-africa.md)
* [Descripción general de la validación de bases de datos](https://docs.didit.me/es/core-technology/database-validation/overview.md)
* [Códigos de resultado](https://docs.didit.me/es/core-technology/database-validation/database-validation-outcome-codes.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.