Documentación de integración

API REST de primepagos para procesar cobros (pay-ins) y envíos (pay-outs) por transferencia bancaria en Argentina (ARS).

Introducción

La integración se hace 100% server-to-server contra nuestra API. Tu backend autentica con una API key, crea pagos y recibe el resultado por webhooks firmados. Toda la operación de dinero ocurre del lado de primepagos; vos sólo consumís la API.

Entornos y URL base

Todas las rutas cuelgan de la URL base (incluye el prefijo de versión /v1):

https://api.primepagos.com/v1

No hay un host separado para sandbox: el modo de prueba se define a nivel de cuenta (tu merchant puede estar en estado sandbox o active). Ver Sandbox.

Autenticación

Cada request a la API se autentica con tu API key en el header x-api-key. La key se entrega una sola vez al crearla; guardala de forma segura y nunca la expongas en el frontend.

x-api-key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Nunca uses la API key en el navegador ni la incrustes en apps cliente. Es secreta y de servidor. Si se filtra, pedí su rotación a soporte.

Idempotencia

Los endpoints de creación (payins y payouts) requieren el header Idempotence-Key: un identificador único que vos generás por cada operación. Si reintentás con la misma key y el mismo cuerpo, la API devuelve el pago ya creado en lugar de duplicarlo.

POST/v1/payments/payins

Crea un cobro. Devuelve un payment_url e instrucciones (el CVU destino) para que el pagador transfiera.

Cuerpo

CampoTipoDetalle
amountstringMonto con hasta 2 decimales, ej. "15000.00". String para no perder precisión.
currencystring"ARS" (3 letras).
paymentMethodstring"bank_transfer".
payerobjectdocumentNumber (DNI: 7-8 dígitos · CUIT: 11) + documentType (DNI por defecto, o CUIT).
returnUrlstring?Opcional. URL https a la que volver tras pagar.
metadataobject?Opcional. Objeto plano, hasta 20 claves, valores primitivos, máx. 4 kB. Te lo devolvemos en el webhook.

Ejemplo

curl -X POST https://api.primepagos.com/v1/payments/payins \
  -H "x-api-key: TU_API_KEY" \
  -H "Idempotence-Key: order-A-1024" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "15000.00",
    "currency": "ARS",
    "paymentMethod": "bank_transfer",
    "payer": { "documentNumber": "20123456", "documentType": "DNI" },
    "returnUrl": "https://tu-sitio.com/gracias",
    "metadata": { "order_id": "A-1024" }
  }'

Respuesta

{
  "payment_url": "https://pay.primepagos.com/pay/pm_x8q6oJ9l0v",
  "payment": {
    "id": "pm_x8q6oJ9l0v",
    "input_amount": "15000",
    "fact_amount": null,
    "currency": "ARS",
    "status": "pending",
    "method": "bank_transfer",
    "metadata": { "order_id": "A-1024" },
    "created_at": "2026-06-15T00:37:41.015Z",
    "expires_at": "2026-06-15T01:37:40.993Z"
  },
  "instructions": { "destination_cvu": "0000151500038783109135" }
}
El pago nace en estado pending y expira en 1 hora si no se acredita. Mostrale al pagador el payment_url o el destination_cvu de instructions.

POST/v1/payments/payouts

Envía dinero a un CBU/CVU. Requiere saldo disponible del merchant (en cuentas active).

Cuerpo

CampoTipoDetalle
amountstringMonto con hasta 2 decimales.
currencystring"ARS".
paymentMethodstring"bank_transfer".
payeeobjectcbu (22-23 dígitos), documentNumber (CUIT: 11 dígitos), documentType (CUIT por defecto).
metadataobject?Igual que en pay-in.

Ejemplo

curl -X POST https://api.primepagos.com/v1/payments/payouts \
  -H "x-api-key: TU_API_KEY" \
  -H "Idempotence-Key: withdrawal-W-77" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "20000.00",
    "currency": "ARS",
    "paymentMethod": "bank_transfer",
    "payee": {
      "cbu": "0000076500000123456789",
      "documentNumber": "20123456789",
      "documentType": "CUIT"
    },
    "metadata": { "withdrawal_id": "W-77" }
  }'

GET/v1/payments/payins/:id · GET/v1/payments/payouts/:id

Consultá el estado de un pago por su id público (el que devuelve la creación, ej. pm_x8q6oJ9l0v).

curl https://api.primepagos.com/v1/payments/payins/pm_x8q6oJ9l0v \
  -H "x-api-key: TU_API_KEY"
Los webhooks son la forma recomendada de enterarte de los cambios de estado; usá el GET para reconciliar o consultar puntualmente.

Estados de un pago

EstadoSignificado
newCreado (típico al iniciar un pay-out).
pendingA la espera de la acreditación/confirmación.
succeededAcreditado/confirmado. Estado final exitoso.
expiredPay-in que venció sin acreditarse (1 h).
failedFalló el procesamiento (ej. pay-out rechazado).
cancelledCancelado.
reversedRevertido por una corrección/ajuste.

Webhooks

Cuando configurás una URL de webhook y un secret en tu cuenta, primepagos te envía un POST JSON ante cada evento relevante. Los eventos son idempotentes (pueden reintentarse): deduplicá por id.

Eventos

EventoCuándo
payin.succeededSe acreditó un cobro.
payout.succeededSe confirmó un envío.
payout.failedEl envío falló definitivamente.
payout.cancelledEl envío fue cancelado.
webhook.testEvento de prueba que podés disparar para validar tu endpoint.

Payload

El cuerpo es un sobre con id, type, created_at y data:

{
  "id": "payin_succeeded_8c1e...e0b",
  "type": "payin.succeeded",
  "created_at": "2026-06-15T00:37:41.071Z",
  "data": {
    "id": "pm_x8q6oJ9l0v",
    "status": "succeeded",
    "currency": "ARS",
    "input_amount": "15000",
    "fact_amount": "15000",
    "metadata": { "order_id": "A-1024" },
    "created_at": "2026-06-15T00:37:41.015Z"
  }
}

Verificar la firma

Cada webhook incluye el header x-primepagos-webhook-signature: un HMAC-SHA256 (hex) del cuerpo crudo calculado con tu secret. Validalo siempre antes de procesar.

import { createHmac } from 'crypto';
import express from 'express';

const app = express();

// IMPORTANTE: la firma se calcula sobre el body CRUDO (raw), no sobre el JSON
// re-serializado. Capturá el Buffer original.
app.post(
  '/webhooks/primepagos',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const signature = req.header('x-primepagos-webhook-signature');

    const expected = createHmac('sha256', process.env.PRIMEPAGOS_WEBHOOK_SECRET)
      .update(req.body)        // req.body es un Buffer (raw)
      .digest('hex');

    if (signature !== expected) {
      return res.status(401).send('invalid signature');
    }

    const event = JSON.parse(req.body.toString('utf8'));

    // Procesá de forma idempotente usando event.id (puede reintentarse).
    switch (event.type) {
      case 'payin.succeeded':  /* acreditar la orden */ break;
      case 'payout.succeeded': /* marcar retiro enviado */ break;
      case 'payout.failed':
      case 'payout.cancelled': /* revertir / reintentar */ break;
    }

    res.sendStatus(200); // respondé 2xx para confirmar la recepción
  },
);
Calculá el HMAC sobre el body exacto recibido (bytes crudos). Si parseás y re-serializás el JSON, la firma no va a coincidir.

Sandbox / pruebas

Si tu merchant está en estado sandbox, los pagos se simulan y se resuelven automáticamente sin tocar el banco — ideal para integrar de punta a punta. Usá tu API key normal.

# Merchant en modo SANDBOX: los pagos se aprueban solos, sin tocar el banco.
# Pay-in de prueba que se aprueba automáticamente -> usar DNI 11111111
curl -X POST https://api.primepagos.com/v1/payments/payins \
  -H "x-api-key: TU_API_KEY_SANDBOX" \
  -H "Idempotence-Key: test-1" \
  -H "Content-Type: application/json" \
  -d '{ "amount":"10000","currency":"ARS","paymentMethod":"bank_transfer",
        "payer":{"documentNumber":"11111111","documentType":"DNI"} }'

# Pay-out de prueba que se aprueba automáticamente -> usar CBU de 22 unos
#   payee.cbu = "1111111111111111111111"

Límites y validaciones

ReglaValor (ARS)
Monto de pay-inentre 1.000 y 50.000.000
Monto de pay-outentre 15.000 y 30.000.000
Decimales del montohasta 2 (se envía como string)
DNI (payer)7 u 8 dígitos
CUIT11 dígitos
CBU (payee)22 o 23 dígitos
Expiración de pay-in1 hora
metadata≤ 20 claves · valores primitivos · ≤ 4 kB

Errores

La API responde con códigos HTTP estándar y un cuerpo JSON con el detalle:

CódigoSignificado
400Datos inválidos (validación) o key de idempotencia reusada con otro cuerpo.
401API key faltante o inválida (x-api-key).
403Merchant sin permiso / estado no habilitado.
404Recurso no encontrado.
500Error interno. Reintentá con la misma Idempotence-Key.
{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "documentNumber must be string with 7-8 numbers when documentType is DNI",
  "path": "/v1/payments/payins"
}

Soporte

Para obtener credenciales (API key), configurar tu URL/secret de webhook o pasar tu cuenta a producción, escribinos a soporte@primepagos.com.