Skip to main content

Pre-requisitos

Tienes credenciales de producción (int_id_comercio, usuario, clave).
Configuraste tu URL de retorno (estática en el comercio, o vas a enviarla con el código 104).
Si aceptas PSE, tienes tu código de servicio.

Armar el request

El body es un objeto con cuatro propiedades:
{
  "InformacionPago": { ... },
  "InformacionSeguridad": { ... },
  "AdicionalesPago": [],
  "AdicionalesConfiguracion": [ ... ]
}

Campos obligatorios mínimos

InformacionPago.flt_total_con_iva
number
required
Total a cobrar con IVA incluido.
InformacionPago.str_id_pago
string
required
Tu identificador único del pago. Máximo 30 caracteres, sin ceros a la izquierda.
InformacionPago.str_descripcion_pago
string
required
Concepto del pago (el usuario lo ve en el formulario).
InformacionSeguridad.int_id_comercio + str_usuario + str_clave
credenciales
required
Tus credenciales.
InformacionSeguridad.int_modalidad
integer
required
Valor fijo (-1 según texto normativo del instructivo oficial).
AdicionalesConfiguracion[código 50]
string
required
Solo si aceptas PSE. Tu código de servicio PSE.

Obligatorios adicionales para certificación PSE

InformacionPago.str_id_cliente (documento del pagador)
InformacionPago.str_tipo_id (tipo de documento)
InformacionPago.flt_valor_iva (IVA de la transacción)

Ejemplo completo

import axios from "axios";

async function iniciarPago({ idPedido, monto, iva, cliente }) {
  const body = {
    InformacionPago: {
      flt_total_con_iva: monto,
      flt_valor_iva: iva,
      str_id_pago: idPedido,
      str_descripcion_pago: `Pedido ${idPedido}`,
      str_email: cliente.email,
      str_id_cliente: cliente.documento,
      str_tipo_id: "1",  // CC
      str_nombre_cliente: cliente.nombre,
      str_apellido_cliente: cliente.apellido,
      str_telefono_cliente: cliente.telefono,
      str_opcional1: `canal:${cliente.canal}`
    },
    InformacionSeguridad: {
      int_id_comercio: Number(process.env.ZP_ID_COMERCIO),
      str_usuario: process.env.ZP_USUARIO,
      str_clave: process.env.ZP_CLAVE,
      int_modalidad: -1
    },
    AdicionalesPago: [],
    AdicionalesConfiguracion: [
      { int_codigo: 50,  str_valor: process.env.ZP_COD_SERVICIO },
      { int_codigo: 104, str_valor: `${process.env.APP_URL}/pago/retorno` }
    ]
  };

  const { data } = await axios.post(
    `${process.env.ZP_API_URL}/InicioPago`,
    body,
    { 
      headers: { "Content-Type": "application/json" },
      timeout: 30000
    }
  );

  if (data.int_codigo !== 1) {
    throw new Error(`Error ZP: ${data.str_descripcion_error}`);
  }

  return data.str_url;
}

Al recibir la respuesta

1

Valida int_codigo

Si no es 1, loguea el error y muestra al usuario una pantalla amigable (ej. “Hubo un problema, inténtalo de nuevo”).
2

Persiste el pago en tu BD

Guarda str_id_pago, str_url, flt_total_con_iva, timestamp, estado = pendiente. Necesitarás estos datos para la sonda y el callback.
3

Redirige al usuario

Devuelve un 302 Redirect hacia str_url, o abre en nueva pestaña si tu UX lo prefiere.
4

No modifiques str_url

El parámetro rut es un token criptográfico. Cualquier modificación invalida el pago.

Errores comunes

ErrorSolución
int_codigo: 2 con “Object reference…”Revisa credenciales y que el body tenga los 4 objetos top-level.
str_id_pago rechazadoTiene ceros a la izquierda o supera 30 caracteres.
”Código 50 requerido”Tu comercio tiene PSE habilitado y debes enviar el código 50 con tu código de servicio.
HTTP 415Falta header Content-Type: application/json.

Próximo paso

Redirigir al usuario →

Cómo redirigir correctamente y qué esperar.