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

# Recaudo

> Errores de cobros, cargos, links de captura, solicitudes de pago Nequi y Daviplata, intentos de pago, sesión de cliente y campañas.

Esta página cubre la sección Recaudo de la API. Además de lo que se lista acá, cualquiera de estos endpoints puede devolver los [errores comunes](/client/base/errors/common). Los que tienen un ID en la ruta también responden `404 record_not_found` si el ID no es un UUID, y `404 environment_key_mismatch` si el recurso es del otro ambiente. La excepción es la [sesión de cliente](#sesión-de-cliente), donde un cargo que no existe responde `404` sin código.

**Endpoints:** [Cobros](#cobros) · [Plantillas](#listar-plantillas) · [Cargos](#cargos) · [Links de captura](#links-de-captura) · [Nequi y Daviplata](#solicitudes-de-pago-nequi-y-daviplata) · [Intentos de pago](#intentos-de-pago) · [Sesión de cliente](#sesión-de-cliente) · [Campañas](#importar-mensajes-de-campaña)

<Note>
  Un cargo que el banco rechaza no es un error HTTP: el cargo se crea (`200`) y queda `failed` con
  el motivo en `remarks`. Los motivos posibles están en [Motivos de rechazo de
  cargos](/client/base/errors/codes).
</Note>

## Cobros

### Listar cobros

`GET /payments` · [Referencia](/client/payments/list)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 400 | Requested filter(s) \`...\` are not allowed. Allowed filter(s) are \`id, status, reference, external\_id\`. | Enviaste un filtro que no existe. | Usa solo los filtros de la lista. | Sí, tras corregir |
| Sin código | 400 | Requested sort(s) \`...\` is not allowed. Allowed sort(s) are \`created\_at, paid\_at\`. | Enviaste un orden que no existe. | Ordena por `created_at` o `paid_at`. | Sí, tras corregir |

Un `filter[id]` o `filter[status]` con un valor inválido no da error: devuelve una lista vacía.

### Detalle de un cobro

`GET /payments/{payment_id}` · [Referencia](/client/payments/detail)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Pago no existe | El cobro no existe, se eliminó o es de otra empresa. | Revisa el `payment_id`. | No |

### Crear un cobro

`POST /payments` · [Referencia](/client/payments/create)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El campo título es obligatorio. | Falta `title` o `amount`, o un campo no cumple su formato (`title` de 4 a 255, `description` de 4 a 2.000, `reference` de 6 a 30, `external_id` de 4 a 100, `currency` de 3 letras en mayúscula). | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | El monto mínimo es COP \$1.000 | `amount` está por debajo del mínimo de la moneda (COP 1.000, USD 1, MXN 5). | Envía un monto igual o mayor al mínimo. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | El monto máximo por transacción no puede ser mayor a \$500.000.000 | `amount` supera el límite por transacción de tu empresa. | Divide el cobro o pídele a soporte revisar tu límite. | No |
| `10001`<br />`validation_error` | 422 | El numero de teléfono no es valido, debe ser un numero en formato E.164 | `phone` no es un celular válido. | Envía el celular en formato E.164, por ejemplo `+573001234567`. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | La plantilla seleccionada no existe, no está aprobada, no es una plantilla de cobro o no está disponible para esta empresa. | `template_id` no es una plantilla de cobro que puedas usar. | Usa un `id` con `selectable: true` de [listar plantillas](/client/templates/list). | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | El campo metadata.template id está prohibido. | Enviaste `template_id` dentro de `metadata`. | Envía `template_id` como campo de primer nivel. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | El balance destino no existe o no pertenece a la empresa. | `target_wallet_id` no es un balance tuyo en este ambiente, o es de una moneda que no puede recibir este cobro. | Usa un balance tuyo del mismo ambiente y moneda compatible. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | The partial payment feature is not enabled for this company. | Enviaste `partial_payment_config` y tu empresa no tiene pagos parciales. | Quita `partial_payment_config` o pídele a soporte activar pagos parciales. | No |
| `10001`<br />`validation_error` | 422 | The Bre-B key is only available for payments in COP. | Pediste `options.breb_key` en un cobro que no es en COP, que acepta pagos parciales o que no tiene Bre-B habilitado. | Quita `options.breb_key` o ajusta el cobro. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | The total percentage splits cannot exceed 100%. | Un split supera el total del cobro o apunta a una cuenta, un cliente o una billetera inválidos. El detalle llega en `errors.splits.N.*`. | Corrige el split indicado. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | Los splits solo se pueden repartir sobre un cobro que liquide en pesos. | Enviaste `splits` con un `target_wallet_id` que no es COP. | Liquida en un balance COP o quita los splits. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | El campo document url no puede apuntar al almacenamiento interno de OnePay. | `document_url` apunta al almacenamiento de OnePay. | Aloja el documento en tu propio almacenamiento. | Sí, tras corregir |
| Sin código | 500 | Server Error | Un error inesperado. En algunos casos el cobro alcanza a crearse antes del error. | Antes de reintentar, busca el cobro por `external_id` con [listar cobros](/client/payments/list). | Solo si no se creó |

### Actualizar un cobro

`PUT /payments/{payment_id}` · [Referencia](/client/payments/update)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Pago no existe | El cobro no existe, se eliminó o es de otra empresa. | Revisa el `payment_id`. | No |
| `10001`<br />`validation_error` | 422 | El campo título debe contener al menos 4 caracteres. | Un campo enviado no cumple su formato (mismas reglas que al crear). | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | El monto mínimo es COP \$1.000 | `amount` está por debajo del mínimo o por encima de tu límite por transacción. | Ajusta el monto. | Sí, tras corregir |
| `15007`<br />`cant_update_payment` | 422 | Este pago ya no se puede actualizar por su estado actual. | El cobro ya está aprobado, pagado por fuera, cancelado, vencido, reembolsado o en disputa. | Crea un cobro nuevo. | No |
| `15004`<br />`payment_charge_in_progress` | 422 | Este pago tiene una transacción activa en proceso. Por favor espera a que expire e intenta nuevamente. | Quieres cambiar `amount` o `tax` mientras hay un intento de pago en curso. | Espera a que el intento termine o venza. | Sí, con espera |
| `15003`<br />`payment_already_paid` | 422 | Este pago ya fue pagado. | El cobro se terminó de pagar mientras lo actualizabas. | Consulta el cobro: ya está pagado. | No |

### Reenviar un cobro

`POST /payments/{payment_id}` · [Referencia](/client/payments/resend)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Pago no existe | El cobro no existe, se eliminó o es de otra empresa. | Revisa el `payment_id`. | No |
| `10001`<br />`validation_error` | 422 | La plantilla seleccionada no existe, no está aprobada, no es una plantilla de cobro o no está disponible para esta empresa. | `template_id` no es una plantilla de cobro que puedas usar, o viene dentro de `metadata`. | Usa una plantilla seleccionable como campo de primer nivel. | Sí, tras corregir |
| `15002`<br />`cant_retry_payment` | 422 | Este pago fue aprobado, no se puede reintentar | El cobro no está en un estado que se pueda reenviar. Sale también si está cancelado, vencido o reembolsado, aunque el texto diga «aprobado». | No reenvíes cobros cerrados; crea uno nuevo. | No |

### Cancelar un cobro

`DELETE /payments/{payment_id}` · [Referencia](/client/payments/delete)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Pago no existe | El cobro no existe, se eliminó o es de otra empresa. | Revisa el `payment_id`. | No |
| `10001`<br />`validation_error` | 422 | El campo notify debe tener un valor verdadero o falso. | `notify` no es booleano. | Envía `true` o `false`, o no lo envíes. | Sí, tras corregir |
| `15003`<br />`payment_already_paid` | 422 | Este pago ya fue pagado. | El cobro ya está pagado. | No se puede cancelar; gestiona un reembolso si aplica. | No |
| `15004`<br />`payment_cancelled` | 422 | El pago fue cancelado | El cobro ya estaba cancelado. | Nada: trátalo como éxito. | No |
| `15001`<br />`cant_cancel_payment` | 422 | El pago no puede ser cancelado | El cobro es de una factura de servicio y se gestiona desde la factura. | Cancélalo desde la factura. | No |
| `15004`<br />`payment_charge_in_progress` | 422 | Este pago tiene una transacción activa en proceso. Por favor espera a que expire e intenta nuevamente. | Hay un intento de pago en curso (PSE, Bre-B u otro) que todavía puede pagarse. | Espera a que el intento termine o venza. | Sí, con espera |

<Warning>
  `payment_cancelled` y `payment_charge_in_progress` comparten el código `15004`. Distínguelos por
  `code_name`: el primero no se reintenta, el segundo sí.
</Warning>

### Intentos de un cobro

`GET /payments/{payment_id}/intents` · [Referencia](/client/payments/intents)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Pago no existe | El cobro no existe, se eliminó o es de otra empresa. | Revisa el `payment_id`. | No |

### Resolver un cobro de prueba

`POST /payments/{payment_id}/resolve` · [Referencia](/client/payments/resolve)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Pago no existe | El cobro no existe, se eliminó o es de otra empresa. | Revisa el `payment_id`. | No |
| `10001`<br />`validation_error` | 422 | El campo remarks es obligatorio cuando action es reject. | Falta `action` o no es `approve`/`reject`, o falta `remarks` en un `reject`, o no es un [motivo válido](/client/base/errors/codes). | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| Sin código | 403 | This endpoint is only available for test payments. | Usaste la llave de producción sobre un cobro real. | Usa la llave de pruebas (`sk_test_`) y un cobro de prueba. | No |
| Sin código | 422 | Only payments in pending, in\_progress or declined status can be resolved. | El cobro de prueba ya no está abierto. | Crea otro cobro de prueba. | No |
| `15003`<br />`payment_already_paid` | 422 | Este pago ya fue pagado. | El cobro ya tiene un intento pagado. | Consulta el cobro. | No |

## Listar plantillas

`GET /templates` · [Referencia](/client/templates/list)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 400 | Requested filter(s) \`...\` are not allowed. Allowed filter(s) are \`status, stage, provider, predefined, selectable\`. | Enviaste un filtro que no existe. | Usa solo los filtros de la lista. | Sí, tras corregir |
| Sin código | 400 | Requested sort(s) \`...\` is not allowed. Allowed sort(s) are \`name, created\_at, updated\_at\`. | Enviaste un orden que no existe. | Ordena por `name`, `created_at` o `updated_at`. | Sí, tras corregir |
| Sin código | 500 | Server Error | `filter[predefined]` no es `true` ni `false`. | Envía `filter[predefined]=true` o `false`. | Sí, tras corregir |

## Cargos

`GET /charges/{id}` usa el `id` que devuelve `POST /charges`. `cancel` y `resolve` usan el `charge_id`; `refund` acepta los dos.

### Listar cargos

`GET /charges` · [Referencia](/client/charges/list)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 400 | Requested filter(s) \`...\` are not allowed. Allowed filter(s) are \`id, status, created\_at, currency, amount, title, payment\_method\_type, external\_id, customer\_id, key\`. | Enviaste un filtro que no existe. | Usa solo los filtros de la lista. | Sí, tras corregir |
| Sin código | 400 | Requested sort(s) \`...\` is not allowed. Allowed sort(s) are \`created\_at, paid\_at\`. | Enviaste un orden que no existe. | Ordena por `created_at` o `paid_at`. | Sí, tras corregir |
| Sin código | 500 | Server Error | Usaste `filter[amount]` o `filter[created_at]`. Hoy esos dos filtros fallan. | Filtra por `external_id`, `status` o `customer_id`. | No |

### Detalle de un cargo

`GET /charges/{id}` · [Referencia](/client/charges/detail)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Pago no existe | El `id` no existe o es de otra empresa. Este endpoint busca por el `id` que devuelve `POST /charges`, no por `charge_id`. | Usa el `id` de la respuesta de creación. | No |

### Crear un cargo

`POST /charges` · [Referencia](/client/charges/create)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El customer id seleccionado es inválido. | Un campo falta o no es válido: `amount`, `title` (5 a 100), `customer_id` (un cliente tuyo, y con llave de producción no de prueba), `account_id` o `card_id` (uno de los dos, del mismo cliente), `splits` o `test_scenario`. | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | El monto máximo por transacción no puede ser mayor a \$500.000.000 | `amount` supera el límite por transacción de tu empresa. | Divide el cargo o pídele a soporte revisar tu límite. | No |
| `10001`<br />`validation_error` | 422 | Los splits solo se pueden repartir sobre un cobro que liquide en pesos. | Enviaste `splits` con un `target_wallet_id` que no es COP. | Liquida en un balance COP o quita los splits. | Sí, tras corregir |
| `90005`<br />`charge_persistence_lost` | 503 | Charge could not be confirmed, please retry. | El cargo se procesó pero OnePay no pudo confirmar que quedó guardado. Es raro. | Busca el cargo por `external_id`; si no aparece, reintenta con un `x-idempotency` nuevo. | Sí, tras verificar |
| Sin código | 500 | Server Error | `currency` llegó como `null`, u otro error inesperado. | Omite `currency` o envía `COP`, `USD` o `MXN`. Antes de reintentar, busca el cargo por `external_id`. | Sí, tras verificar |

Un cargo rechazado por el banco o por las reglas de riesgo responde `200` con el cargo en `failed` y el motivo en `remarks`. Mira [Motivos de rechazo de cargos](/client/base/errors/codes).

### Crear un cargo PSE

`POST /charges/pse` · [Referencia](/client/charges/link)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El tamaño de cantidad debe ser de al menos 1000. | `amount` falta o es menor que 1.000, `bank_id` no existe, `customer_id` no es un cliente tuyo o `redirect_url` no es una URL. | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `15005`<br />`pse_payment_duplicate` | 429 | Ya existe un pago PSE en proceso para esta misma operación. Espera a que el cliente complete el flujo actual o a que expire antes de reintentar. | Ya creaste un PSE con el mismo cliente, banco y monto hace menos de 2 minutos. La respuesta trae `previous_payment_id`, `previous_payment_created_at` y `time_elapsed_seconds`. | Reusa el link de `previous_payment_id` o espera a que pase la ventana. Cambiar `external_id` o `reference` no lo evita. | Sí, tras la ventana |

### Crear un cargo Bre-B

`POST /charges/bre-b` · [Referencia](/client/charges/bre-b)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El tamaño de cantidad debe ser de al menos 1000. | `amount` falta o es menor que 1.000, `customer_id` no es un cliente tuyo, o `expires_in` está fuera de 5 a 64.800 minutos. | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `90100`<br />`qr_generation_failed` | 400 | No se pudo generar el código QR. Intente nuevamente. | No se pudo registrar la llave dinámica en Bre-B o generar el QR. No queda ningún cargo creado. | Reintenta en unos segundos con un `x-idempotency` nuevo. Si persiste, ofrece otro medio de pago. | Sí, con espera |

### Reembolsar un cargo

`POST /charges/{charge_id}/refund` · [Referencia](/client/charges/refund)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Cargo no existe | No hay un cargo tuyo con ese ID. | Usa el `charge_id` o el `id` de creación. | No |
| `10805`<br />`charge_refunded` | 422 | El cargo ya ha sido reembolsado, no se puede volver a reembolsar | El cargo ya está reembolsado, o hay otro reembolso del mismo cargo en curso. | Consulta el cargo antes de reintentar. | No |
| `10806`<br />`charge_is_test` | 422 | El cargo es de prueba, no se puede reembolsar | El cargo es de pruebas. | Los reembolsos solo aplican a cargos reales. | No |
| `10807`<br />`charge_is_not_paid` | 422 | El cargo no ha sido pagado, no se puede reembolsar | El cargo todavía no está pagado. | Espera a que quede pagado, o cancélalo si sigue en proceso. | Sí, cuando esté pagado |
| Sin código | 500 | Server Error | Falló la devolución del saldo después de marcar el cargo. | No reintentes a ciegas: consulta el cargo y escribe a soporte con el `x-request-id`. | No, sin verificar |

### Cancelar un cargo

`POST /charges/{charge_id}/cancel` · [Referencia](/client/charges/cancel)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Cargo no existe | El ID no es un `charge_id` (por ejemplo, enviaste el `id` del cobro) o el cargo es de otra empresa. | Usa el `charge_id`. | No |
| `10808`<br />`charge_not_cancellable` | 422 | El cargo no se puede cancelar, solo cargos en estado creado o procesando pueden ser cancelados | El cargo ya está pagado, fallido o reembolsado. | Consulta el cargo; si está pagado, usa el reembolso. | No |

### Resolver un cargo de prueba

`POST /charges/{charge_id}/resolve` · [Referencia](/client/charges/resolve)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El campo remarks es obligatorio cuando action es reject. | Falta `action` o no es `approve`/`reject`, o falta `remarks` en un `reject`, o no es un [motivo válido](/client/base/errors/codes). | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado | El cargo no existe o es de otra empresa. | Usa el `charge_id` de un cargo tuyo. | No |
| Sin código | 403 | This endpoint is only available for test charges. | El cargo es real. | Usa este endpoint solo con cargos de prueba. | No |
| Sin código | 422 | Only charges in processing or created status can be resolved. | El cargo ya no está en `created` ni `processing`, o enviaste el `id` del cobro en vez del `charge_id`. | Usa el `charge_id` de un cargo abierto. | No |

## Links de captura

### Crear un link de captura

`POST /connect-links` · [Referencia](/client/connections/create)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El customer id seleccionado es inválido. | Falta `customer_id` o `single_use`, `customer_id` no es un cliente tuyo del mismo ambiente, o `redirect_url` no es una URL `https`. | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| Sin código | 500 | Server Error | `redirect_url` tiene más de 255 caracteres. | Usa una `redirect_url` de máximo 255 caracteres. | Sí, tras corregir |

### Eliminar un link de captura

`DELETE /connect-links/{connect_link_id}` · [Referencia](/client/connections/delete)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, ConnectLink no existe | El link no existe, ya se eliminó o es de otra empresa. | Si era un reintento, trátalo como eliminado. | No |

## Solicitudes de pago Nequi y Daviplata

### Solicitar pago por Nequi

`POST /request-to-pay/nequi` · [Referencia](/client/request-to-pay/nequi)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El tamaño de cantidad debe ser de al menos 500. | `amount` falta, es menor que 500 o supera tu límite por transacción, `customer_id` no es un cliente tuyo, o `phone` no es un celular colombiano válido (`+57`). | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `10141`<br />`request_to_pay_in_progress` | 422 | Una solicitud de pago ya se encuentra en proceso. | Llegó otra solicitud con el mismo `external_id` para la misma cuenta Nequi y todavía se está procesando. | Espera unos segundos y busca la solicitud por `external_id` en [intentos de pago](/client/payment-intent/list). | Sí, con espera |
| `90005`<br />`charge_persistence_lost` | 503 | Charge could not be confirmed, please retry. | OnePay no pudo confirmar que el cargo quedó guardado. Es raro. | Busca por `external_id` antes de reintentar. | Sí, tras verificar |

### Confirmar pago por Nequi

`POST /request-to-pay/nequi/{id}/confirm` · [Referencia](/client/request-to-pay/nequi-confirm)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Cargo no existe | El ID no es de una solicitud tuya. | Usa el `id` que devolvió la solicitud. | No |
| Sin código | 500 | Server Error | Nequi no respondió al consultar el estado. | Reintenta más tarde; el estado también se actualiza solo. | Sí, con espera |

Este endpoint no exige `x-idempotency`.

### Solicitar pago por Daviplata

`POST /request-to-pay/daviplata` · [Referencia](/client/request-to-pay/daviplata)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El tamaño de cantidad debe ser de al menos 500. | Falta o no es válido `amount` (mínimo 500 y tu límite), `document` (7 a 11), `document_type`, `customer_id` o `phone` (`+57`). | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `10141`<br />`request_to_pay_in_progress` | 422 | Una solicitud de pago ya se encuentra en proceso. | La cuenta Daviplata de ese cliente ya tiene una solicitud abierta. | Confirma o espera la solicitud abierta (vence a los 10 minutos). | Sí, cuando termine |
| `10126`<br />`customer_data_invalid` | 422 | Datos del cliente inválidos. | El documento, su tipo o el celular no corresponden a una cuenta Daviplata. | Revisa los datos del pagador. | Sí, tras corregir |
| Sin código | 500 | Server Error | Daviplata no respondió. | Reintenta con espera. | Sí, con espera |

### Confirmar pago por Daviplata

`POST /request-to-pay/daviplata/{id}/confirm` · [Referencia](/client/request-to-pay/daviplata-confirm)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El campo otp debe contener 6 caracteres. | Falta `otp` o no tiene 6 caracteres. | Envía el OTP de 6 dígitos que recibió el pagador. | Sí, tras corregir |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Cargo no existe | El ID no es de una solicitud tuya. | Usa el `id` que devolvió la solicitud. | No |
| `10140`<br />`request_to_pay_not_available` | 422 | La cuenta no se encuentra disponible para realizar transacciones por solicitud de pago. | El ID no es de una solicitud Daviplata. | Confirma solo solicitudes creadas con `POST /request-to-pay/daviplata`. | No |
| `10136`<br />`transaction_otp_invalid` | 422 | El OTP de la transacción es inválido, por favor intente nuevamente. | El OTP no es correcto. La solicitud queda fallida. | Crea una solicitud nueva; esta ya no acepta otro OTP. | No, crea otra |
| `10148`<br />`transaction_otp_expired` | 422 | El OTP de la transacción ha expirado, por favor inicie nuevamente el proceso. | El OTP venció o Daviplata respondió con un error. La solicitud queda fallida. | Crea una solicitud nueva. | No, crea otra |
| `90005`<br />`charge_persistence_lost` | 503 | Charge could not be confirmed, please retry. | OnePay no pudo confirmar que el pago quedó guardado. Es raro. | Consulta el [intento de pago](/client/payment-intent/get) antes de reintentar. | Sí, tras verificar |
| Sin código | 500 | Server Error | Daviplata no respondió. | Consulta la solicitud y reintenta con espera. | Sí, con espera |

## Intentos de pago

### Listar intentos de pago

`GET /payment-intents` · [Referencia](/client/payment-intent/list)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 400 | Requested filter(s) \`...\` are not allowed. Allowed filter(s) are \`id, status, external\_id, network\_id\`. | Enviaste un filtro que no existe. | Usa solo los filtros de la lista. | Sí, tras corregir |
| Sin código | 400 | Requested sort(s) \`...\` is not allowed. Allowed sort(s) are \`created\_at, paid\_at\`. | Enviaste un orden que no existe. | Ordena por `created_at` o `paid_at`. | Sí, tras corregir |

### Detalle de un intento de pago

`GET /payment-intents/{id}` · [Referencia](/client/payment-intent/get)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado, Cargo no existe | El ID no es de un intento de pago tuyo (por ejemplo, enviaste el `id` del cobro). | Usa el `charge_id` o un `id` del listado de intentos. | No |

## Sesión de cliente

Los errores propios de la sesión (los `401`, el `418`, el `404` de cargo y los `422` de negocio) no traen
`code` ni `code_name`: para esos decide por el HTTP y el endpoint. Los de validación sí traen `10001`
`validation_error`; cuando venga `code_name`, úsalo. Los de sesión (`/customers/session/*`) exigen el header `X-Customer-Token`.

Tienen límites propios de peticiones, además del general:

| Endpoint | Límite |
| - | - |
| `POST /customers/login/request` y `POST /customers/login/verify` | 1 cada 30 segundos y 3 por hora, por teléfono |
| `GET /customers/session/*` | 30 por minuto, por cliente |
| `POST /customers/session/*` | 5 por minuto, por cliente (compartido entre los dos `POST`) |

### Solicitar código de acceso

`POST /customers/login/request` · [Referencia](/client/customer-session/request-otp)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El numero de teléfono no es valido, debe ser un numero en formato E.164 | Falta `phone` o no está en formato E.164. | Envía el teléfono con indicativo, por ejemplo `+573001234567`. | Sí, tras corregir |
| Sin código | 418 | Ya se envió un código recientemente | Ya se envió un código a ese cliente hace menos de un minuto. | Espera al menos 60 segundos antes de pedir otro. | Sí, tras esperar |
| Sin código | 429 | Too Many Attempts. | Superaste 1 solicitud cada 30 segundos o 3 por hora para ese teléfono. | Espera lo que indique `Retry-After`. | Sí, tras esperar |

### Verificar código de acceso

`POST /customers/login/verify` · [Referencia](/client/customer-session/verify-otp)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| `10001`<br />`validation_error` | 422 | El campo otp debe tener 6 dígitos. | `phone` no está en formato E.164 u `otp` no es un número de 6 dígitos. | Corrige `phone` u `otp`. | Sí, tras corregir |
| Sin código | 422 | Las credenciales proporcionadas no son válidas. | El código no coincide o venció (dura una hora). | Pide al cliente revisar el código o solicita uno nuevo. Cada intento fallido cuenta. | Sí, con el código correcto |
| Sin código | 429 | Too Many Attempts. | Superaste 1 intento cada 30 segundos o 3 por hora para ese teléfono. | Espera lo que indique `Retry-After`. | Sí, tras esperar |

<Warning>
  Varios intentos fallidos seguidos sobre el mismo código bloquean al cliente en OnePay. No
  reintentes la verificación en un bucle: pide el código de nuevo al cliente.
</Warning>

### Listar métodos de pago del cliente

`GET /customers/session/payment-methods` · [Referencia](/client/customer-session/list-payment-methods)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 401 | Token de sesión del cliente requerido. | Falta el header `X-Customer-Token`. | Envía el token que devolvió la verificación. | Sí, con el header |
| Sin código | 401 | Token de sesión inválido o expirado. | El token no existe, venció (dura 7 días) o se emitió con la llave de otra empresa. | Inicia sesión de nuevo. | Sí, tras renovar la sesión |

### Agregar método de pago del cliente

`POST /customers/session/payment-methods` · [Referencia](/client/customer-session/create-payment-method)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 401 | Token de sesión del cliente requerido. | Falta el header `X-Customer-Token`. | Envía el token de la sesión. | Sí, con el header |
| Sin código | 401 | Token de sesión inválido o expirado. | El token no existe, venció o es de otra empresa. | Inicia sesión de nuevo. | Sí, tras renovar la sesión |
| `10001`<br />`validation_error` | 422 | El campo token es obligatorio. | Falta `token`. | Envía el token temporal de la tarjeta. | Sí, tras corregir |
| `10104`<br />`card_number` | 422 | Número de tarjeta inválido. | La tarjeta fue rechazada al tokenizarla. | Pide otra tarjeta o que revise el número, y genera un token nuevo. | Sí, con otro token |
| `10122`<br />`card_expired` | 422 | Tarjeta expirada, Pídele al usuario que actualice su tarjeta. | La fecha de vencimiento no es válida. | Pide la fecha correcta o una tarjeta vigente. | Sí, tras corregir |
| `10102`<br />`card_cvv` | 422 | CVV inválido. | El código de seguridad no es válido. | Pide que vuelva a ingresar el CVV. | Sí, tras corregir |
| `10002`<br />`record_not_found` | 404 | Registro no encontrado | No se pudo leer el token temporal de la tarjeta (venció o falló la conexión con la bóveda). | Genera un token nuevo y reintenta. | Sí, con otro token |
| Sin código | 500 | Server Error | Falló la tokenización de la tarjeta. | Reintenta con un token nuevo. | Sí, con espera |

### Crear cargo desde la sesión

`POST /customers/session/charges` · [Referencia](/client/customer-session/create-charge)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 401 | Token de sesión del cliente requerido. | Falta el header `X-Customer-Token`. | Envía el token de la sesión. | Sí, con el header |
| Sin código | 401 | Token de sesión inválido o expirado. | El token no existe, venció o es de otra empresa. | Inicia sesión de nuevo. | Sí, tras renovar la sesión |
| `10001`<br />`validation_error` | 422 | El tamaño de cantidad debe ser de al menos 100. | Falta o no es válido `payment_method_id`, `amount` (entero en centavos, mínimo 100), `currency` o `description`. | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| Sin código | 422 | Método de pago no encontrado. | `payment_method_id` no es una tarjeta del cliente de la sesión. | Usa un `id` de [listar métodos de pago](#listar-métodos-de-pago-del-cliente). | Sí, tras corregir |
| Sin código | 422 | El método de pago no pertenece al cliente. | La tarjeta es del otro ambiente. | Usa una tarjeta del mismo ambiente que tu llave. | Sí, tras corregir |
| Sin código | 422 | El método de pago está expirado. | La tarjeta venció. | Pide al cliente una tarjeta vigente. | No |
| Sin código | 422 | Ya existe un cobro pendiente para este método de pago. | Hay un cargo en esa tarjeta esperando la aprobación del cliente (vence a los 5 minutos). | Consulta el cargo pendiente y espera a que se apruebe o venza. | Sí, cuando termine |

### Consultar cargo de la sesión

`GET /customers/session/charges/{chargeId}` · [Referencia](/client/customer-session/show-charge)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 401 | Token de sesión del cliente requerido. | Falta el header `X-Customer-Token`. | Envía el token de la sesión. | Sí, con el header |
| Sin código | 401 | Token de sesión inválido o expirado. | El token no existe, venció o es de otra empresa. | Inicia sesión de nuevo. | Sí, tras renovar la sesión |
| Sin código | 404 | Cargo no encontrado. | El cargo no existe o no es del cliente de la sesión. | Usa el `charge_id` que devolvió la creación. | No |

## Importar mensajes de campaña

`POST /campaigns/import-messages` · [Referencia](/client/campaigns/import-messages)

| Código | HTTP | Mensaje | Causa probable | Qué hacer | ¿Reintentar? |
| - | - | - | - | - | - |
| Sin código | 403 | Company does not have this feature. | Tu empresa no tiene activas las campañas. | Pídele a soporte que las active. | No |
| `10001`<br />`validation_error` | 422 | El campo phones es obligatorio. | Falta `template`, `phones`, `image_url` (o `video_url` si `type` es `video`), o un teléfono no está en formato E.164. | Revisa `errors` y corrige el cuerpo. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | La plantilla «...» no existe en la cuenta de WhatsApp de la empresa. | La plantilla no existe, no está aprobada, su encabezado no coincide con `type`, o el número de variables no coincide con los `optional_*` enviados. | Usa una plantilla aprobada y llena `optional_1` a `optional_3` según sus variables. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | Dejaste «optional\_1» vacío y llenaste un campo posterior. Los campos optional\_1…optional\_3 son las variables de la plantilla en orden: llénalos desde el primero, sin saltarte ninguno. | Hay un `optional_N` vacío antes de uno lleno. | Llena los `optional_*` en orden. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | Las dimensiones de la imagen no son válidas. | La imagen no se pudo descargar o no cumple: máximo 2 MB, JPEG o PNG, lado corto de 600 px o más, lado largo de 2.048 px o menos, proporción 4:3, 9:16, 2:3 o 1:1. | Ajusta la imagen. | Sí, tras corregir |
| `10001`<br />`validation_error` | 422 | El video no debe superar los 16 MB. | El video no se pudo descargar, pesa más de 16 MB o no es MP4. | Usa un MP4 público de 16 MB o menos. | Sí, tras corregir |
| Sin código | 500 | Server Error | La URL de `image_url` no respondió. | Usa una URL pública que responda rápido. | Sí, tras corregir |


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