Aller au contenu principal

Méthode HMAC — un appel signé

Avec la méthode HMAC, vous créez un paiement en un seul appel. Pas de jeton à gérer : vous signez chaque requête avec votre Client Secret, et vous envoyez la signature dans un en-tête.

POST /partners/rtp

À la fin, vous recevez un rtpLink : le lien de paiement à présenter au client.

Testez avec Postman

La collection Postman inclut une requête Create RTP Request prête à l'emploi (dossier 07). Calculez la signature avec un des exemples ci-dessous, renseignez X-Signature, et envoyez.

Vous aurez besoin de

  • Votre Client ID et votre Client Secret (depuis la Console Lodin).
  • L'horloge de votre serveur à l'heure (synchronisée NTP) — la requête est refusée si elle s'écarte de plus de 300 secondes de l'heure serveur.

Les en-têtes

En-têteRequisValeur
Content-TypeOuiapplication/json
X-Client-IdOuiVotre Client ID
X-TimestampOuiL'instant courant en ISO-8601 UTC, ex. 2026-06-10T12:00:00Z
X-SignatureOuiLa signature HMAC-SHA256 (voir ci-dessous)

Calculer la signature

La signature prouve que la requête vient bien de vous. Elle se calcule en quatre étapes.

Étape 1 — construire la chaîne à signer

Mettez bout à bout, sans aucun séparateur, dans cet ordre exact :

chaîne = X-Client-Id + X-Timestamp + montant + externalReference
  • montant : le amount formaté à 2 décimales avec un point (100.5100.50, 100100.00). Si le montant est absent, utilisez 0.00.
  • externalReference : votre référence. Si vous n'en envoyez pas, utilisez une chaîne vide.

Exemple :

X-Client-Id = CLIENT_123
X-Timestamp = 2026-06-10T12:00:00Z
amount = 100.50
externalReference= EXT-001

chaîne à signer = CLIENT_1232026-06-10T12:00:00Z100.50EXT-001

Étape 2 — préparer la clé

Votre clé de signature est votre Client Secret. Il vous est remis encodé en Base64 ; décodez-le pour obtenir la clé, exactement comme le fait le serveur.

Étape 3 — calculer le HMAC-SHA256

Calculez HMAC-SHA256(chaîne, clé).

Étape 4 — encoder en Base64URL sans padding

Encodez le résultat en Base64URL (+-, /_) et retirez les = de fin. C'est votre X-Signature.

Cohérence du calcul

Le serveur recalcule la signature de la même façon et la compare. Le moindre écart (montant non formaté à 2 décimales, séparateur ajouté, padding = laissé, mauvaise heure) donne Invalid signature. Les exemples ci-dessous reproduisent exactement le calcul serveur.

Exemples de code

$clientId = 'CLIENT_123';
$timestamp = gmdate('Y-m-d\TH:i:s\Z'); // ex. 2026-06-10T12:00:00Z
$amount = 100.50;
$externalRef= 'EXT-001';

// Clé : le Client Secret, décodé depuis sa forme Base64
$key = base64_decode($clientSecret);

$amountStr = number_format($amount, 2, '.', ''); // "100.50"
$payload = $clientId . $timestamp . $amountStr . ($externalRef ?? '');

$raw = hash_hmac('sha256', $payload, $key, true);
$signature = rtrim(strtr(base64_encode($raw), '+/', '-_'), '=');

Le corps de la requête

ChampTypeRequisRègles
amountDoubleOuiNon nul, strictement positif
payeeIbanStringOuiNon vide, max 34
payeeFullNameStringOuiNon vide, max 150
externalReferenceStringNonMax 150 (doit correspondre à la valeur signée)
currencyStringNon3 lettres ; par défaut MAD si absent — envoyez-le
descriptionStringNonMax 2000
returnUrlStringNonMax 1000 — URL de retour du client
webhookUrlStringNonMax 1000
customerNameStringNonMax 150
customerEmailStringNonE-mail valide, max 150
customerPhoneStringNonMax 30
metadataJsonStringNonMax 4000
paymentTypeStringNonMax 30
Devise

Si vous omettez currency, le service applique MAD. Envoyez currency explicitement (par exemple EUR) pour éviter toute ambiguïté.

Exemple complet

POST /partners/rtp
Content-Type: application/json
X-Client-Id: CLIENT_123
X-Timestamp: 2026-06-10T12:00:00Z
X-Signature: 9c1f...sans-padding

{
"amount": 100.50,
"currency": "EUR",
"externalReference": "EXT-001",
"description": "Demande RTP de démonstration",
"returnUrl": "https://partner.example.com/return",
"webhookUrl": "https://partner.example.com/webhook",
"customerName": "Nom Client",
"customerEmail": "[email protected]",
"customerPhone": "+212600000002",
"payeeIban": "FR7630003011300040000000000",
"payeeFullName": "Atelier Marquet SAS",
"paymentType": "INST"
}

La réponse

{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"rtpLink": "https://gateway.lodinpay.com/pay?id=ORDER-ID-123&type=PARTNER&canal=WEB",
"status": "CREATED",
"accessLogId": 123,
"remainingToday": null,
"usedToday": 1
}
ChampDescription
requestIdIdentifiant de la demande RTP.
rtpLinkLe lien de paiement à présenter au client.
statusCREATED à la création. Voir le cycle de vie.
usedTodayNombre de demandes effectuées aujourd'hui.

Présentez le rtpLink au client. À la fin du parcours, son navigateur revient sur votre returnUrl. Le statut réel se met à jour côté serveur et vous sera notifié par webhook (livraison à venir).

Erreurs courantes

HTTPMessageCause
401Invalid clientIdX-Client-Id inconnu
401Request expiredX-Timestamp hors de la fenêtre de 300 secondes
401Invalid signatureLa signature ne correspond pas (voir l'encadré plus haut)
403Inactive credentialsIdentifiant désactivé
403Application is not activeApplication inactive
400Invalid request dataUn champ du corps ne respecte pas les règles

La référence complète figure sur la page Erreurs.