Aller au contenu
Support

Exemples d'intégration

Des programmes complets, prêts à exécuter dans la sandbox. Chacun est testé contre l'API à chaque mise à jour de cette documentation.

Fichiers à télécharger

LangageClient (signature comprise)Parcours complet
Node.js 18+coveraf.jsparcours-complet.js
Python 3.8+coveraf.pyparcours-complet.py
PHP 7.4+coveraf.phpparcours-complet.php
bash (curl, openssl)coveraf.sh-

Aucune dépendance : seulement la bibliothèque standard de chaque langage (et l'extension curl pour PHP). Les fichiers Node.js sont des modules ES : placez-les dans un projet dont le package.json contient "type": "module", ou renommez-les en .mjs (import compris : ./coveraf.mjs).

Parcours complet

Du devis aux documents : devis, Conditions Générales, souscription, paiement (mode A ou B selon votre compte), contrat, puis téléchargement des PDF.

// Parcours complet de souscription, du devis aux documents (Node.js 18+).
// Utilise le client coveraf.js (même dossier). Modules ES : "type": "module"
// dans package.json, ou fichiers renommés en .mjs (import compris). En sandbox :
//   COVERAF_CLE_API=cvr_test_... COVERAF_SECRET=cvr_sig_... node parcours-complet.js
import crypto from 'node:crypto'
import { writeFile } from 'node:fs/promises'

import { appelCoveraf } from './coveraf.js'

const BASE_URL = process.env.COVERAF_BASE_URL || 'https://api.coveraf.com'
const attendre = (ms) => new Promise((ok) => setTimeout(ok, ms))

async function telecharger(chemin, fichier) {
  const reponse = await fetch(BASE_URL + chemin, { headers: { Authorization: `Bearer ${process.env.COVERAF_CLE_API}` } })
  if (!reponse.ok) throw new Error(`Document ${chemin} : ${(await reponse.json()).erreur.code}`)
  await writeFile(fichier, Buffer.from(await reponse.arrayBuffer()))
  console.log('  enregistré :', fichier)
}

// 1. Devis : le prix est calculé par l'API.
const devis = await appelCoveraf('POST', '/v1/devis', {
  offre: 'securvie_500k',
  donnees: { assure: { date_naissance: '1985-06-15' } },
  reference_partenaire: 'CMD-2026-0042',
})
console.log(`1. Devis ${devis.id} : ${devis.prime.totale} FCFA, valable jusqu'au ${devis.expire_le}`)

// 2. Conditions Générales, à présenter au client AVANT le paiement.
console.log('2. Conditions Générales')
await telecharger(`/v1/produits/${devis.offre}/conditions-generales`, 'conditions-generales.pdf')

// 3. Souscription : la demande du client. Aucun contrat n'existe encore.
const souscription = await appelCoveraf('POST', '/v1/souscriptions', {
  devis_id: devis.id,
  souscripteur: { nom: 'KONE', prenom: 'Awa', telephone: '+2250701020304', email: 'awa.kone@example.com' },
  informations: { profession: 'Commerçante', beneficiaires: [{ nom: 'KONE Moussa', lien: 'Conjoint', part: 100 }] },
}, { idempotencyKey: crypto.randomUUID() })
console.log(`3. Souscription ${souscription.id} : ${souscription.montant_a_payer.montant} FCFA à payer (${souscription.mode_paiement})`)

// 4. Paiement, selon le mode du compte.
let numero
if (souscription.mode_paiement === 'encaissement_partenaire') {
  // Mode A : vous avez encaissé le client, vous le déclarez.
  const payee = await appelCoveraf('POST', `/v1/souscriptions/${souscription.id}/confirmer-paiement`, {
    reference_transaction: `OM-${Date.now()}`,
    operateur: 'orange',
    montant: souscription.montant_a_payer.montant,
  }, { idempotencyKey: crypto.randomUUID() })
  numero = payee.contrat.numero
} else {
  // Mode B : COVERAF encaisse en Mobile Money. En sandbox, 0700000001 réussit.
  const enCours = await appelCoveraf('POST', `/v1/souscriptions/${souscription.id}/paiement`, {
    operateur: 'orange',
    telephone_payeur: '0700000001',
  }, { idempotencyKey: crypto.randomUUID() })
  console.log(`   paiement ${enCours.paiement.id} en attente, le client valide sur son téléphone`)
  // Sans notifications : consultation toutes les 5 secondes, 3 minutes au plus.
  for (let i = 0; i < 36 && !numero; i++) {
    await attendre(5000)
    const etat = await appelCoveraf('GET', `/v1/souscriptions/${souscription.id}`)
    if (etat.paiement?.statut === 'echoue') throw new Error(`Paiement échoué : ${etat.paiement.motif_echec}`)
    numero = etat.contrat?.numero
  }
  if (!numero) throw new Error('Paiement toujours en attente : réessayez plus tard.')
}
console.log(`4. Paiement confirmé, contrat ${numero} émis`)

// 5. Contrat et documents.
const contrat = await appelCoveraf('GET', `/v1/contrats/${numero}`)
console.log(`5. Contrat ${contrat.statut}, du ${contrat.date_effet} au ${contrat.date_echeance}`)
for (const document of contrat.documents.filter((d) => d.disponible)) {
  await telecharger(document.adresse, `${document.type}.pdf`)
}
export COVERAF_CLE_API="cvr_test_..."
export COVERAF_SECRET="cvr_sig_..."
node parcours-complet.js

Résultat attendu dans la sandbox :

1. Devis dev_... : 12980 FCFA, valable jusqu'au 2026-11-19T...
2. Conditions Générales
  enregistré : conditions-generales.pdf
3. Souscription sou_... : 12980 FCFA à payer (encaissement_partenaire)
4. Paiement confirmé, contrat TEST-CVR-API-... émis
5. Contrat actif, du 2026-11-04 au 2027-11-03
  enregistré : conditions_generales.pdf
  enregistré : conditions_particulieres.pdf

Recevoir les notifications

Serveur minimal qui vérifie la signature de chaque notification avant de la traiter :

import crypto from 'node:crypto'
import express from 'express'

const SECRET_NOTIFICATIONS = process.env.COVERAF_SECRET_NOTIFICATIONS // cvr_whsec_...

export function signatureValide(corpsBrut, timestamp, signature) {
  if (!timestamp || !signature) return false
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false // 5 minutes
  const attendue = 'v1=' + crypto.createHmac('sha256', SECRET_NOTIFICATIONS).update(`${timestamp}.${corpsBrut}`).digest('hex')
  return attendue.length === signature.length && crypto.timingSafeEqual(Buffer.from(attendue), Buffer.from(signature))
}

const app = express()
// Corps BRUT : la signature porte sur les octets reçus, pas sur un JSON relu.
app.post('/coveraf/notifications', express.text({ type: 'application/json' }), (req, res) => {
  if (!signatureValide(req.body, req.get('X-Coveraf-Timestamp'), req.get('X-Coveraf-Signature'))) {
    return res.status(401).end()
  }
  const evenement = JSON.parse(req.body)
  // Dédoublonnez avec evenement.id : un événement peut arriver plusieurs fois.
  res.status(200).end() // répondez vite, traitez ensuite
  traiter(evenement)
})

Explications détaillées : Notifications (webhooks).

Pour Postman ou Insomnia

Importez openapi.json : tous les appels sont prêts, avec leurs exemples. La signature des écritures reste à calculer (un script de pré-requête, ou nos clients ci-dessus).