Pular para o conteúdo

Guia rápido

Seu primeiro pagamento de teste, passo a passo

Faça um pagamento de teste no ambiente Stage depois do onboarding e da configuração inicial.

  • Stage: sem dinheiro real
  • cURL e Node.js
  • Dados de teste fictícios

Visão geral

Três fases, seis passos

Tudo a seguir acontece no Stage, o ambiente de testes que espelha a produção. O acesso à produção vem no final, após as verificações do passo 6.

  1. 01

    Configure o acesso

    Receba as credenciais do Stage, guarde-as em um gerenciador de segredos e cadastre os IPs dos seus servidores.

    Passos 1–2

  2. 02

    Faça as primeiras chamadas

    Obtenha um token, crie um pay-in de teste e verifique o webhook que o confirma.

    Passos 3–5

  3. 03

    Entre em produção

    Conclua a revisão de segurança e a verificação da empresa (KYB) e troque para credenciais de produção.

    Passo 6

Passo 1 de 6

Receba suas credenciais do Stage

As credenciais do Stage, um usuário e uma senha de API para api.stage.localpayment.com, são emitidas no início da sua parceria com a Localpayment. Trate-as como segredos de produção desde o primeiro dia.

  • Carregue as credenciais de um gerenciador de segredos ou de variáveis de ambiente; nunca faça commit delas
  • Stage e produção usam credenciais e URLs base diferentes
  • Use apenas dados de teste fictícios, nunca dados reais de clientes
secrets.js
// Carregue as credenciais do Stage do AWS Secrets Manager na inicialização (AWS SDK v3).
// Qualquer cofre serve: o importante é que segredos nunca fiquem no código-fonte.
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);
}

Passo 2 de 6

Cadastre os IPs dos seus servidores

A API só aceita chamadas dos endereços IP que você cadastrou. Adicione os IPs de saída dos seus servidores no Business Portal do Stage antes da primeira requisição.

  • Business Portal → Whitelist your IP
  • Requisições de qualquer outro IP são rejeitadas
  • Serverless ou autoescalável? Envie o tráfego de saída por um IP fixo (NAT)
  • Repita a configuração na produção antes de entrar no ar

Passo 3 de 6

Obtenha um token de acesso

Troque seu usuário e senha de API por um par de JWTs. Envie o token de acesso como token Bearer em cada chamada e renove-o antes que expire.

  • Token de acesso: válido por 5 minutos
  • Token de renovação: válido por 24 horas; use POST /api/token/refresh/
  • Mantenha os tokens em memória e nunca os grave em logs
# Obtenha um token de acesso no 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\"}"

Passo 4 de 6

Crie um pay-in de teste

Este exemplo cria um pay-in Pix no Brasil. A resposta traz um QR Code e um código Pix Copia e Cola, com status 100 INPROGRESS até o pagador concluir o pagamento.

  • Gere um UUID novo como externalId para cada transação
  • Reenviar com o mesmo externalId retorna 409 Conflict em vez de criar um segundo pay-in
  • Valor em USD: a resposta traz o valor em BRL que o pagador paga e a cotação aplicada
# Pay-in Pix ilustrativo no Stage (Brasil). Valores fictícios;
# veja docs.localpayment.com para o 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" }
    }
  }'

Passo 5 de 6

Processe o webhook

Quando o pagamento é concluído, a Localpayment envia uma notificação assinada para o seu endpoint HTTPS. Verifique a assinatura sobre o corpo bruto, responda 200 na hora e faça o processamento de forma assíncrona.

  • Cadastre sua URL em Business Portal → Configurations → Clients → Notifications
  • Compare o x-Signature com o seu próprio HMAC-SHA256 usando uma comparação de tempo constante
  • Entregas sem resposta 200 são reenviadas com backoff exponencial
webhook.js
// Receptor Express para webhooks da Localpayment (Node.js 18+).
import crypto from 'node:crypto';
import express from 'express';
import { jobQueue } from './queue.js'; // sua própria fila de jobs assíncronos

const app = express();

// Carregue o segredo do webhook do seu gerenciador de segredos na inicialização. Nunca o deixe no 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 do header: "x-Signature: HMAC-SHA256 <hex>". Remova o prefixo antes.
  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);
}

// O corpo é JSON enviado como Content-Type text/plain: mantenha o texto bruto para o 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); // responda rápido, antes de qualquer processamento pesado
  // Processe de forma assíncrona. Deduplique por internalId/externalId + status
  // para aplicar cada reentrega uma única vez. Nunca registre o payload completo.
  jobQueue.enqueue(event);
});

Passo 6 de 6

Checklist para entrar em produção

As credenciais de produção só são emitidas após estas verificações. Planeje-as cedo: elas ajudam a proteger cada empresa na plataforma, inclusive a sua.

  • Conclua os testes no Stage

    Cubra os caminhos de sucesso, recusa, pendência e erro para cada método e país que você vai lançar.

  • Passe na revisão de segurança

    Nossa equipe revisa e certifica sua integração antes de liberar o acesso à produção.

  • Conclua a verificação da empresa

    A equipe de compliance verifica sua empresa, os sócios e o caso de uso (KYB) como parte do credenciamento.

  • Guarde bem as credenciais de produção

    Mantenha-as em um gerenciador de segredos, separadas do Stage, com acesso restrito aos serviços que precisam delas.

  • Cadastre os IPs de produção

    Adicione os IPs de saída dos seus servidores de produção no Business Portal de produção.

  • Configure os webhooks de produção

    Cadastre seu endpoint HTTPS de produção e confirme que a verificação de assinaturas funciona antes da primeira transação real.

Solução de problemas

Problemas comuns nas primeiras chamadas

Recebo 401 Unauthorized. O que devo verificar?

Os tokens de acesso expiram em 5 minutos. Renove com POST /api/token/refresh/ ou peça um token novo, e confirme que o cabeçalho é Authorization: Bearer seguido do token de acesso.

Minha requisição é rejeitada mesmo com um token válido.

Verifique se o IP de saída do servidor que faz a chamada está cadastrado no Business Portal daquele ambiente. Stage e produção são configurados separadamente.

Por que recebi 409 Conflict?

Esse externalId já foi usado. Consulte a transação existente com GET /api/transactions/{externalId}/status em vez de criar uma nova.

O pay-in continua em 100 INPROGRESS.

É o esperado em métodos assíncronos como Pix, transferências bancárias e contas virtuais: o status muda quando o pagador paga, e o status final chega por webhook.

A assinatura do meu webhook não confere.

Calcule o HMAC sobre o corpo bruto da requisição exatamente como recebido, antes de interpretar o JSON, e remova o prefixo "HMAC-SHA256 " do cabeçalho antes de comparar.

Precisa de credenciais do Stage?

Conte seu caso de uso e seus mercados. Nossa equipe vai acompanhar você no credenciamento e liberar o acesso ao Stage quando a parceria começar.

Como podemos ajudar?

Baixe o seu exemplar

Deixe seus dados e receba a edição completa na hora.