Tableau de bord ↗

Un endpoint serveur pour créer l’intent, puis une page de paiement hébergée par lahsab qui affiche vos coordonnées et récolte la preuve. Base : https://api.lahsab.com. Tous les montants sont des entiers en dinars (DZD). L’environnement est déduit du préfixe de la clé (lsk_sandbox_ / lsk_live_).

Créer un intent

POST /payments/intents

Crée une intention d’encaissement et renvoie un checkoutUrl — le lien de paiement hébergé, valable 48 h. Redirigez l’acheteur dessus.

ChampTypeRequisDétail
amountintOuiEntier strictement positif (DZD).
customerRefstringNonVotre référence (ex. identifiant utilisateur).
methodstringNonccp ou baridimob (indicatif).
metadataobjectNonObjet JSON libre.

En production, les coordonnées de réception (titulaire + RIP) doivent être renseignées, sinon 409 MERCHANT_PAYMENT_DETAILS_MISSING. La sandbox n’a pas cette contrainte.

Erreurs : 400 VALIDATION_ERROR, 401 AUTH_UNAUTHORIZED, 409 MERCHANT_PAYMENT_DETAILS_MISSING.

Requête
curl -X POST https://api.lahsab.com/payments/intents \
  -H "x-api-key: lsk_live_CLE" \
  -H "content-type: application/json" \
  -d '{
    "amount": 2500,
    "customerRef": "user_abc123",
    "metadata": { "orderId": "CMD-1042" }
  }'

Réponse 201

{
  "id": "a7f3c2e1-9b4d-4e6a-8c1f-2d3e4f5a6b7c",
  "environment": "live",
  "customerRef": "user_abc123",
  "amount": 2500,
  "status": "pending",
  "checkoutUrl": "https://app.lahsab.com/pay/a7f3c2e1-9b4d-4e6a-8c1f-2d3e4f5a6b7c",
  "metadata": { "orderId": "CMD-1042" },
  "expiresAt": "2026-07-13T10:00:00.000Z",
  "proofs": [],
  "createdAt": "2026-07-11T10:00:00.000Z"
}

Consulter un intent

GET /payments/intents/:id

Retourne l’état courant, si l’intent appartient à la clé et à son environnement. Sinon 404 — un intent d’un autre environnement est invisible.

Erreurs : 401 AUTH_UNAUTHORIZED, 404 PAYMENT_INTENT_NOT_FOUND.

Requête
curl https://api.lahsab.com/payments/intents/INTENT_ID \
  -H "x-api-key: lsk_live_CLE"

Réponse 200

{
  "id": "a7f3c2e1-9b4d-4e6a-8c1f-2d3e4f5a6b7c",
  "environment": "live",
  "amount": 2500,
  "status": "proof_submitted",
  "checkoutUrl": "https://app.lahsab.com/pay/a7f3c2e1-9b4d-4e6a-8c1f-2d3e4f5a6b7c",
  "expiresAt": "2026-07-13T10:00:00.000Z",
  "proofs": [
    {
      "id": "9c8b7a6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
      "originalName": "recu-baridimob.jpg",
      "mimeType": "image/jpeg",
      "size": 184230,
      "submittedAt": "2026-07-11T10:12:00.000Z"
    }
  ],
  "createdAt": "2026-07-11T10:00:00.000Z"
}

Page de paiement

GET /payments/checkout/:id

Aucune authentification — c’est ce que sert la page hébergée au navigateur de l’acheteur. Renvoie une vue publique de l’intent : le montant, vos coordonnées de réception, l’état. Jamais de clé API, de secret webhook, ni de metadata.

Un intent expiré (au-delà de 48 h) est renvoyé avec status: "expired".

Erreurs : 404 PAYMENT_INTENT_NOT_FOUND.

Requête
curl https://api.lahsab.com/payments/checkout/INTENT_ID

Réponse 200

{
  "id": "a7f3c2e1-9b4d-4e6a-8c1f-2d3e4f5a6b7c",
  "environment": "live",
  "amount": 2500,
  "method": "baridimob",
  "status": "pending",
  "expiresAt": "2026-07-13T10:00:00.000Z",
  "hasProof": false,
  "merchantConfigured": true,
  "merchant": {
    "displayName": "ACME Store",
    "receivingHolder": "SARL ACME",
    "receivingCcpNumber": "0123456789",
    "receivingCcpKey": "12",
    "receivingRip": "00799999012345678912",
    "receivingBaridimobPhone": "0770000000",
    "paymentInstructions": "Virement BaridiMob, puis téléversez la capture.",
    "supportEmail": "support@acme.dz",
    "supportPhone": "0770000000"
  }
}

Déposer une preuve

POST /payments/intents/:id/proof

Aucune authentification — endpoint public, utilisé par la page de paiement (ou votre propre page si vous en construisez une). Envoi multipart/form-data, champ file. L’intent passe en proof_submitted.

Erreurs : 400 PAYMENT_PROOF_FILE_MISSING, 404 PAYMENT_INTENT_NOT_FOUND, 409 PAYMENT_INVALID_TRANSITION, 409 PAYMENT_INTENT_EXPIRED, 413 FILE_TOO_LARGE.

Requête
curl -X POST https://api.lahsab.com/payments/intents/INTENT_ID/proof \
  -F "file=@recu-baridimob.jpg"

Réponse 201 — l’intent mis à jour, status à proof_submitted.

Enveloppe d’erreur

Toutes les erreurs partagent la même forme. Testez l’errorCode (stable), pas le message.

{
  "statusCode": 404,
  "errorCode": "PAYMENT_INTENT_NOT_FOUND",
  "message": "Payment intent not found",
  "timestamp": "2026-07-11T10:00:00.000Z",
  "path": "/payments/intents/a7f3c2e1-9b4d-4e6a-8c1f-2d3e4f5a6b7c"
}
errorCodeStatutSignification
VALIDATION_ERROR400Corps de requête invalide.
PAYMENT_PROOF_FILE_MISSING400Aucun fichier de preuve.
AUTH_UNAUTHORIZED401Clé API manquante ou invalide.
PAYMENT_INTENT_NOT_FOUND404Intent inconnu, d’un autre marchand ou environnement.
PAYMENT_INVALID_TRANSITION409Transition d’état impossible.
PAYMENT_INTENT_EXPIRED409Lien de paiement expiré (au-delà de 48 h).
MERCHANT_PAYMENT_DETAILS_MISSING409Coordonnées de réception requises avant la production.
FILE_TOO_LARGE413Fichier de preuve trop volumineux.
RATE_LIMITED429Trop de requêtes.