Quickstart
Votre premier paiement de test, étape par étape
Effectuez un paiement de test dans l’environnement Stage après l’onboarding et la configuration initiale.
- Stage : pas d’argent réel
- cURL et Node.js
- Données de test fictives
Vue d’ensemble
Trois phases, six étapes
Tout ce qui suit s’exécute sur Stage, la sandbox qui reproduit la production. L’accès à la production arrive à la fin, après les vérifications de l’étape 6.
- 01
Configurer l’accès
Recevez vos identifiants Stage, stockez-les dans un gestionnaire de secrets et autorisez les IP de vos serveurs.
Étapes 1–2
- 02
Passer vos premiers appels
Obtenez un jeton, créez un encaissement de test et vérifiez le webhook qui le confirme.
Étapes 3–5
- 03
Passer en production
Finalisez la revue de sécurité et la vérification de l’entreprise (KYB), puis basculez sur les identifiants de production.
Étape 6
Étape 1 sur 6
Obtenez vos identifiants Stage
Les identifiants Stage – un utilisateur et un mot de passe API pour api.stage.localpayment.com – sont délivrés au démarrage de votre partenariat avec Localpayment. Traitez-les comme des secrets de production dès le premier jour.
- Chargez les identifiants depuis un gestionnaire de secrets ou des variables d’environnement, ne les commitez jamais
- Stage et Production utilisent des identifiants et des URL de base différents
- Utilisez uniquement des données de test fictives, jamais de vraies données clients
// Chargez les identifiants Stage depuis AWS Secrets Manager au démarrage (AWS SDK v3).
// Tout coffre-fort convient : l’essentiel est que les secrets ne soient jamais dans le code source.
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 attendu : { "username": "…", "password": "…", "webhookSecret": "…" }
return JSON.parse(SecretString);
}Étape 2 sur 6
Autorisez les IP de vos serveurs
L’API n’accepte que les appels provenant d’adresses IP que vous avez autorisées. Ajoutez les IP sortantes de vos serveurs dans le Business Portal de Stage avant votre première requête.
- Business Portal → Whitelist your IP
- Les requêtes provenant de toute autre IP sont rejetées
- Serverless ou autoscaling ? Faites sortir le trafic par une IP de sortie fixe (NAT)
- Refaites la configuration pour la production avant la mise en ligne
- PCI DSS v4.0.1
- SOC 2 Type II
- ISO 27001
- AML/KYC
- TLS 1.2+ · AES-256
Étape 3 sur 6
Obtenez un jeton d’accès
Échangez votre utilisateur et votre mot de passe API contre une paire de JWT. Envoyez le jeton d’accès en tant que jeton Bearer à chaque appel et renouvelez-le avant son expiration.
- Jeton d’accès : valable 5 minutes
- Jeton de rafraîchissement : valable 24 heures, utilisez POST /api/token/refresh/
- Gardez les jetons en mémoire et ne les écrivez jamais dans les logs
# Obtenez un jeton d’accès sur Stage (valable 5 minutes)
curl -X POST https://api.stage.localpayment.com/api/token/ \
-H "Content-Type: application/json" \
-d "{\"username\": \"$LP_API_USER\", \"password\": \"$LP_API_PASSWORD\"}"Étape 4 sur 6
Créez un encaissement de test
Cet exemple crée un encaissement Pix au Brésil. La réponse renvoie un QR code et une chaîne Pix Copia e Cola, avec le statut 100 INPROGRESS jusqu’à ce que le payeur finalise le paiement.
- Générez un nouvel UUID comme externalId pour chaque transaction
- Relancer avec le même externalId renvoie 409 Conflict au lieu de créer un second encaissement
- Montant en USD : la réponse indique le montant en BRL payé par le payeur et le taux de change appliqué
# Encaissement Pix illustratif sur Stage (Brésil). Valeurs fictives ;
# consultez docs.localpayment.com pour le contrat complet.
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" }
}
}'Étape 5 sur 6
Traitez le webhook
Une fois le paiement finalisé, Localpayment envoie une notification signée à votre endpoint HTTPS. Vérifiez la signature sur le corps brut, répondez 200 immédiatement et traitez le reste de façon asynchrone.
- Enregistrez votre URL dans Business Portal → Configurations → Clients → Notifications
- Comparez x-Signature à votre propre HMAC-SHA256 avec une comparaison à temps constant
- Les livraisons sans réponse 200 sont relancées avec un backoff exponentiel
// Récepteur Express pour les webhooks Localpayment (Node.js 18+).
import crypto from 'node:crypto';
import express from 'express';
import { jobQueue } from './queue.js'; // votre propre file de tâches asynchrones
const app = express();
// Chargez le secret du webhook depuis votre gestionnaire de secrets au démarrage. Jamais en dur dans le code.
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;
// Format de l’en-tête : "x-Signature: HMAC-SHA256 <hex>". Retirez d’abord le préfixe.
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);
}
// Le corps est du JSON envoyé en Content-Type text/plain : conservez le texte brut pour le 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); // accusez réception vite, avant tout traitement lourd
// Traitez de façon asynchrone. Dédupliquez sur internalId/externalId + statut
// pour qu’une livraison renvoyée ne s’applique qu’une fois. Ne journalisez jamais le payload complet.
jobQueue.enqueue(event);
});Étape 6 sur 6
Checklist de mise en production
Les identifiants de production ne sont délivrés qu’après ces vérifications. Anticipez-les : elles protègent tous les marchands de la plateforme, vous compris.
Terminer les tests sur Stage
Couvrez les cas de succès, de refus, d’attente et d’erreur pour chaque moyen de paiement et chaque pays que vous lancerez.
Réussir la revue de sécurité
Notre équipe examine et certifie votre intégration avant d’ouvrir l’accès à la production.
Finaliser la vérification de l’entreprise
La conformité vérifie votre société, sa structure de propriété et votre cas d’usage (KYB) dans le cadre de l’onboarding.
Stocker les identifiants de production en sécurité
Conservez-les dans un gestionnaire de secrets, séparément de Stage, et limitez l’accès aux seuls services qui en ont besoin.
Autoriser les IP de production
Ajoutez les IP sortantes de vos serveurs de production dans le Business Portal de production.
Configurer les webhooks de production
Enregistrez votre endpoint HTTPS de production et vérifiez que le contrôle de signature passe avant la première transaction réelle.
Dépannage
Problèmes fréquents lors des premiers appels
Je reçois 401 Unauthorized. Que vérifier ?
Les jetons d’accès expirent au bout de 5 minutes. Renouvelez-les avec POST /api/token/refresh/ ou demandez un nouveau jeton, et vérifiez que l’en-tête est bien Authorization: Bearer suivi du jeton d’accès.
Ma requête est rejetée malgré un jeton valide.
Vérifiez que l’IP sortante du serveur appelant est autorisée dans le Business Portal pour cet environnement. Stage et Production se configurent séparément.
Pourquoi ai-je reçu 409 Conflict ?
Cet externalId a déjà été utilisé. Consultez la transaction existante avec GET /api/transactions/{externalId}/status au lieu d’en créer une nouvelle.
L’encaissement reste en 100 INPROGRESS.
C’est normal pour les moyens asynchrones comme Pix, les virements bancaires et les comptes virtuels : le statut change lorsque le payeur paie, et le statut final arrive par webhook.
La signature de mon webhook ne correspond pas.
Calculez le HMAC sur le corps brut de la requête tel qu’il est reçu, avant tout parsing JSON, et retirez le préfixe « HMAC-SHA256 » de l’en-tête avant de comparer.
Besoin d’identifiants Stage ?
Parlez-nous de votre cas d’usage et de vos marchés. Notre équipe vous accompagne pendant l’onboarding et ouvre votre accès Stage au démarrage du partenariat.

Stage : pas d’argent réel