Saltar al contenido

Guía rápida

Tu primer pago de prueba, paso a paso

Realiza un pago de prueba en el entorno Stage después del onboarding y la configuración inicial.

  • Stage: sin dinero real
  • cURL y Node.js
  • Datos de prueba ficticios

Resumen

Tres fases, seis pasos

Todo lo que sigue ocurre en Stage, el sandbox que replica producción. El acceso a producción llega al final, tras las verificaciones del paso 6.

  1. 01

    Configura el acceso

    Recibe tus credenciales de Stage, guárdalas en un gestor de secretos y registra las IP de tus servidores.

    Pasos 1–2

  2. 02

    Haz tus primeras llamadas

    Obtén un token, crea un cobro de prueba y verifica el webhook que lo confirma.

    Pasos 3–5

  3. 03

    Sal a producción

    Completa la revisión de seguridad y la verificación de tu empresa (KYB) y cambia a credenciales de producción.

    Paso 6

Paso 1 de 6

Obtén tus credenciales de Stage

Las credenciales de Stage, un usuario y una contraseña de API para api.stage.localpayment.com, se emiten al iniciar tu alianza con Localpayment. Trátalas como secretos de producción desde el primer día.

  • Carga las credenciales desde un gestor de secretos o variables de entorno; nunca las subas al repositorio
  • Stage y producción usan credenciales y URL base distintas
  • Usa solo datos de prueba ficticios, nunca datos reales de clientes
secrets.js
// Carga las credenciales de Stage desde AWS Secrets Manager al iniciar (AWS SDK v3).
// Sirve cualquier bóveda: lo importante es que los secretos nunca estén en el código.
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager';

const client = new SecretsManagerClient({ region: process.env.AWS_REGION });

export async function loadMerchantSecrets() {
  const { SecretString } = await client.send(
    new GetSecretValueCommand({ SecretId: 'localpayment/stage/api' }),
  );
  // JSON esperado: { "username": "…", "password": "…", "webhookSecret": "…" }
  return JSON.parse(SecretString);
}

Paso 2 de 6

Registra las IP de tus servidores

La API solo acepta llamadas desde las direcciones IP que registraste. Agrega las IP de salida de tus servidores en el Business Portal de Stage antes de tu primera solicitud.

  • Business Portal → Whitelist your IP
  • Las solicitudes desde cualquier otra IP se rechazan
  • ¿Serverless o autoescalado? Envía el tráfico saliente por una IP de salida fija (NAT)
  • Repite esta configuración en el entorno de producción antes del lanzamiento

Paso 3 de 6

Obtén un token de acceso

Intercambia tu usuario y contraseña de API por un par de JWT. Envía el token de acceso como token Bearer en cada llamada y renuévalo antes de que venza.

  • Token de acceso: válido por 5 minutos
  • Token de refresco: válido por 24 horas; usa POST /api/token/refresh/
  • Guarda los tokens en memoria y nunca los escribas en los registros de la aplicación
# Obtén un token de acceso en Stage (válido por 5 minutos)
curl -X POST https://api.stage.localpayment.com/api/token/ \
  -H "Content-Type: application/json" \
  -d "{\"username\": \"$LP_API_USER\", \"password\": \"$LP_API_PASSWORD\"}"

Paso 4 de 6

Crea un cobro de prueba

Este ejemplo crea un cobro Pix en Brasil. La respuesta devuelve un código QR y un texto Pix Copia e Cola, con estado 100 INPROGRESS hasta que el pagador completa el pago.

  • Genera un UUID nuevo como externalId para cada transacción
  • Reintentar con el mismo externalId devuelve 409 Conflict en lugar de crear un segundo cobro
  • Monto en USD: la respuesta devuelve el monto en BRL que se le cobra al pagador y la cotización aplicada
# Cobro Pix ilustrativo en Stage (Brasil). Valores ficticios;
# consulta docs.localpayment.com para el contrato completo.
curl -X POST https://api.stage.localpayment.com/api/payin/ \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentMethod": { "type": "BankTransfer", "code": "1314", "flow": "DIRECT" },
    "externalId": "7c1e2f7a-0000-4000-8000-000000000001",
    "country": "BRA",
    "currency": "USD",
    "amount": 100,
    "accountNumber": "<your-account-number>",
    "conceptCode": "0003",
    "merchant": { "type": "COMPANY", "name": "Nortia Commerce Ltda" },
    "payer": {
      "type": "INDIVIDUAL",
      "name": "Maria",
      "lastname": "Silva",
      "document": { "type": "CPF", "id": "000.000.000-00" }
    }
  }'

Paso 5 de 6

Procesa el webhook

Cuando el pago se completa, Localpayment envía una notificación firmada a tu endpoint HTTPS. Verifica la firma sobre el cuerpo crudo, responde 200 de inmediato y haz el trabajo de forma asíncrona.

  • Registra tu URL en Business Portal → Configurations → Clients → Notifications
  • Compara x-Signature con tu propio HMAC-SHA256 usando una comparación de tiempo constante
  • Las entregas sin respuesta 200 se reintentan con backoff exponencial
webhook.js
// Receptor Express para webhooks de Localpayment (Node.js 18+).
import crypto from 'node:crypto';
import express from 'express';
import { jobQueue } from './queue.js'; // tu propia cola de trabajos asíncronos

const app = express();

// Carga el secreto del webhook desde tu gestor de secretos al iniciar. Nunca lo escribas en el código.
const WEBHOOK_SECRET = process.env.LP_WEBHOOK_SECRET;
if (!WEBHOOK_SECRET) throw new Error('LP_WEBHOOK_SECRET is not configured');

function hasValidSignature(rawBody, header) {
  if (typeof rawBody !== 'string') return false;
  // Formato del header: "x-Signature: HMAC-SHA256 <hex>". Quita el prefijo primero.
  const received = String(header ?? '').replace(/^HMAC-SHA256\s+/i, '').trim();
  if (!/^[0-9a-f]{64}$/i.test(received)) return false;

  const expected = crypto.createHmac('sha256', WEBHOOK_SECRET).update(rawBody, 'utf8').digest();
  return crypto.timingSafeEqual(Buffer.from(received, 'hex'), expected);
}

// El cuerpo es JSON enviado como Content-Type text/plain: conserva el texto crudo para el HMAC.
app.post('/webhooks/localpayment', express.text({ type: '*/*', limit: '1mb' }), (req, res) => {
  if (!hasValidSignature(req.body, req.get('x-signature'))) return res.sendStatus(401);

  let event;
  try {
    event = JSON.parse(req.body);
  } catch {
    return res.sendStatus(400);
  }

  res.sendStatus(200); // responde rápido, antes de cualquier trabajo pesado
  // Procesa de forma asíncrona. Deduplica por internalId/externalId + estado
  // para aplicar una sola vez cada reintento. Nunca registres el payload completo.
  jobQueue.enqueue(event);
});

Paso 6 de 6

Lista para salir a producción

Las credenciales de producción se emiten solo después de estas verificaciones. Planifícalas desde temprano: ayudan a proteger a cada comercio de la plataforma, incluido el tuyo.

  • Completa las pruebas en Stage

    Cubre los caminos de éxito, rechazo, pendiente y error para cada medio de pago y país que vas a lanzar.

  • Aprueba la revisión de seguridad

    Nuestro equipo revisa y certifica tu integración antes de otorgar el acceso a producción.

  • Completa la verificación de tu empresa

    Cumplimiento verifica tu empresa, sus accionistas y tu caso de uso (KYB) como parte del proceso de incorporación.

  • Guarda bien las credenciales de producción

    Mantenlas en un gestor de secretos, separadas de Stage, y limita el acceso a los servicios que las necesitan.

  • Registra las IP de producción

    Agrega las IP de salida de tus servidores de producción en el Business Portal de producción.

  • Configura los webhooks de producción

    Registra tu endpoint HTTPS de producción y confirma que la verificación de firmas funciona antes de la primera transacción real.

Solución de problemas

Problemas comunes en las primeras llamadas

Recibo 401 Unauthorized. ¿Qué reviso?

Los tokens de acceso vencen a los 5 minutos. Renueva con POST /api/token/refresh/ o pide un token nuevo, y confirma que el encabezado sea Authorization: Bearer seguido del token de acceso.

Mi solicitud se rechaza aunque el token es válido.

Verifica que la IP de salida del servidor que llama esté registrada en el Business Portal de ese entorno. Stage y producción se configuran por separado.

¿Por qué recibí 409 Conflict?

Ese externalId ya se usó. Consulta la transacción existente con GET /api/transactions/{externalId}/status en lugar de crear una nueva.

El cobro sigue en 100 INPROGRESS.

Es lo esperado en medios asíncronos como Pix, transferencias bancarias y cuentas virtuales: el estado cambia cuando el pagador paga y el estado final llega por webhook.

La firma de mi webhook no coincide.

Calcula el HMAC sobre el cuerpo crudo de la solicitud tal como llega, antes de interpretar el JSON, y quita el prefijo "HMAC-SHA256 " del encabezado antes de comparar.

¿Necesitas credenciales de Stage?

Cuéntanos tu caso de uso y tus mercados. Nuestro equipo te acompañará durante la incorporación y emitirá tu acceso a Stage cuando comience la alianza.

¿Cómo podemos ayudarte?

Descarga tu ejemplar

Déjanos tus datos y obtén la edición completa al instante.