Retour au blog

Comment créer une facturation multidevise avec une API de taux de change (Guide 2026)

V
Vlado Grigirov
July 30, 2026
Multi-Currency Currency API Exchange Rates Invoicing Developer Guide Accounting

La facturation multidevise semble un problème résolu : on choisit une devise, on multiplie par un taux de change et on imprime le total. En pratique, c'est l'un des domaines les plus propices aux erreurs de tout système de facturation, et ces erreurs coûtent cher car elles se retrouvent dans vos comptes clients, vos déclarations fiscales et les boîtes de réception de vos clients. Si vous êtes développeur et que vous intégrez la facturation multidevise à un produit SaaS, à un outil pour freelances, à une plateforme d'agence ou à une place de marché B2B, la difficulté n'est pas la multiplication. C'est de décider quel taux de change utiliser, quand le figer et comment le stocker pour qu'une facture émise en mars se rapproche encore correctement lorsqu'elle est payée en juillet.

Ce guide parcourt les décisions d'ingénierie qui comptent, avec du code exécutable qui utilise une API de taux de change pour récupérer, figer et stocker les taux. L'accent est mis spécifiquement sur la couche change (FX) — la partie que la plupart des tutoriels de facturation escamotent.

Pourquoi la facturation multidevise ne se limite pas à la conversion de devise

Une facture monodevise est un instantané : quantité fois prix, plus la taxe. Une facture multidevise est un contrat portant sur un instant précis. Lorsque vous facturez un client en EUR alors que votre comptabilité est tenue en USD, vous enregistrez une créance dont la valeur en USD est figée le jour où vous l'émettez — même si le taux du marché continue de bouger jusqu'à ce que le client paie effectivement.

Cet écart crée trois problèmes concrets que la simple conversion ignore :

  1. Quel taux s'applique. Le taux de la date de facture, de la date de paiement ou d'« aujourd'hui » ? Ils ne sont presque jamais identiques, et les normes comptables (à la fois les US GAAP et les IFRS) sont précises sur la réponse.
  2. Auditabilité. Vous devez pouvoir prouver, des mois plus tard, exactement quel taux vous avez utilisé et d'où il venait. « On l'a récupéré d'une API » ne suffit pas si vous ne pouvez pas reproduire le chiffre.
  3. Gain et perte de change. L'écart entre la valeur à la date de facture et la valeur à la date de paiement est un gain ou une perte réel qui doit être enregistré quelque part dans votre grand livre.

Faites cela correctement et la facturation multidevise devient ennuyeuse dans le bon sens. Faites-la mal et votre équipe finance passe la dernière semaine de chaque trimestre à courir après des centimes.

La règle d'or : figez le taux de change à la date de facture

La règle la plus importante de la facturation multidevise est celle-ci : figez le taux de change au moment où la facture est émise, et ne le recalculez jamais.

Les US GAAP comme les IFRS exigent d'enregistrer une transaction en devise étrangère au taux au comptant en vigueur à la date de la transaction. Pour une facture, la date de transaction est la date d'émission. Si vous facturez un client le 1er juillet mais que votre système ne la traite que le 5 juillet, vous utilisez tout de même le taux du 1er juillet. Ce n'est pas une règle de Finexly ni une préférence — c'est ainsi que la valeur de la créance dans votre devise fonctionnelle (locale) est légalement établie.

Un anti-pattern courant consiste à afficher un total converti « en direct » qui change à chaque fois que le client actualise la facture. Ne faites jamais cela. Une facture est une créance fixe pour un montant précis. Le client doit le montant dans la devise de la facture, et votre comptabilité doit une écriture au taux figé. Le marché peut ensuite faire ce qu'il veut.

La conséquence pratique : la conversion de devise pour la facturation est une opération à écriture unique. Vous récupérez le taux une fois, le stockez avec la facture et le traitez comme immuable pendant toute la vie de ce document.

Choisir une API de taux de change pour la facturation

Toutes les sources de données FX ne conviennent pas à la facturation. Pour la facturation, vous voulez :

  • La couverture de chaque devise dans laquelle vous facturez (Finexly couvre plus de 170 devises).
  • Un horodatage « au » fiable sur chaque taux, pour pouvoir prouver quelle cotation vous avez utilisée.
  • Des taux historiques par date, car les factures rétroactives et corrigées sont inévitables.
  • Des limites de débit et des tarifs prévisibles afin qu'un pic de volume de factures ne casse pas la facturation. Consultez les formules tarifaires avant de créer une dépendance dans votre parcours de paiement.

Une requête basique de taux courant ressemble à ceci :

curl "https://api.finexly.com/v1/latest?base=USD&symbols=EUR&access_key=YOUR_API_KEY"

Et la réponse vous donne un taux ainsi que l'horodatage que vous stockerez à côté :

{
  "success": true,
  "base": "USD",
  "timestamp": 1753660800,
  "rates": {
    "EUR": 0.9213
  }
}

Si vous voulez explorer les taux de manière interactive avant de câbler quoi que ce soit, le convertisseur de devises est une vérification rapide. Pour un aperçu plus large de la façon dont Finexly se compare aux autres fournisseurs, voir comparer les API de devises.

Récupérer et figer le taux de la facture

Voici un petit utilitaire Python qui récupère le taux d'une facture et renvoie tout ce que vous devez persister : le taux, l'horodatage source et le total converti. Notez qu'il renvoie le taux et des métadonnées — pas seulement un nombre.

import os
import time
import requests
from decimal import Decimal, ROUND_HALF_UP

API_KEY = os.environ["FINEXLY_API_KEY"]
BASE_URL = "https://api.finexly.com/v1/latest"

def lock_invoice_rate(home_currency, invoice_currency):
    """Fetch and lock the FX rate to convert an invoice total
    (in invoice_currency) back into home_currency for the books."""
    resp = requests.get(BASE_URL, params={
        "base": invoice_currency,
        "symbols": home_currency,
        "access_key": API_KEY,
    }, timeout=10)
    resp.raise_for_status()
    data = resp.json()
    if not data.get("success"):
        raise RuntimeError("Rate lookup failed")

    rate = Decimal(str(data["rates"][home_currency]))
    return {
        "rate": rate,                       # invoice_currency -> home_currency
        "rate_base": invoice_currency,
        "rate_quote": home_currency,
        "source": "finexly",
        "as_of": data["timestamp"],         # store the source timestamp
        "locked_at": int(time.time()),      # when WE locked it
    }

def home_value(amount_invoice_ccy, rate):
    """Convert an invoice-currency amount into home currency."""
    return (Decimal(str(amount_invoice_ccy)) * rate).quantize(
        Decimal("0.01"), rounding=ROUND_HALF_UP
    )

Le détail crucial est que lock_invoice_rate s'exécute une seule fois, à la création de la facture, et son résultat est écrit dans l'enregistrement de la facture. Pour les préoccupations de production comme la mise en cache, les nouvelles tentatives et la gestion élégante des réponses 429, suivez les modèles de notre guide de mise en cache et de gestion des erreurs — vous ne voulez pas qu'un incident transitoire de l'API bloque l'émission des factures.

Stocker le taux de change avec la facture

Comme le taux est immuable par facture, stockez-le sur la facture, et non dans une table partagée de « taux courant » que vous pourriez écraser. Un schéma minimal ressemble à ceci :

CREATE TABLE invoices (
  id              BIGSERIAL PRIMARY KEY,
  issue_date      DATE        NOT NULL,
  invoice_ccy     CHAR(3)     NOT NULL,   -- what the customer is billed in
  home_ccy        CHAR(3)     NOT NULL,   -- your functional currency
  total_invoice   NUMERIC(18,2) NOT NULL, -- total in invoice_ccy
  fx_rate         NUMERIC(18,8) NOT NULL, -- invoice_ccy -> home_ccy, LOCKED
  fx_source       TEXT        NOT NULL,   -- e.g. 'finexly'
  fx_as_of        TIMESTAMPTZ NOT NULL,   -- the rate's source timestamp
  total_home      NUMERIC(18,2) NOT NULL  -- total_invoice * fx_rate, at issue
);

Trois choses rendent ce schéma propice à l'audit. D'abord, fx_rate utilise huit décimales — les taux de change ont besoin de bien plus de précision que les deux décimales d'un montant monétaire, et tronquer trop tôt introduit une dérive d'arrondi. Ensuite, fx_as_of enregistre d'où vient le chiffre et quand, afin que tout auditeur puisse le reproduire à partir des données historiques. Enfin, total_home est calculé et stocké au moment de l'émission, de sorte qu'un rapport exécuté six mois plus tard n'a jamais à deviner.

Pour la transparence envers le client, imprimez le taux figé sur la facture elle-même : le montant dû, la devise, le taux utilisé et la date à laquelle il s'est appliqué. C'est une bonne pratique largement recommandée précisément parce qu'elle lève l'ambiguïté lorsque le paiement arrive à un taux différent.

Factures rétroactives : utilisez des taux historiques, pas ceux d'aujourd'hui

Tôt ou tard, vous émettrez une facture datée dans le passé — une correction, une saisie tardive ou un contrat spécifiant une date d'effet antérieure. Utiliser le taux d'aujourd'hui pour une facture de mars est tout simplement faux et échouera à un audit. Récupérez plutôt le taux de la date réelle de la facture depuis un point de terminaison historique :

def lock_historical_rate(home_currency, invoice_currency, invoice_date):
    """invoice_date as 'YYYY-MM-DD'. Returns the locked rate for a
    backdated or corrected invoice."""
    resp = requests.get("https://api.finexly.com/v1/historical", params={
        "date": invoice_date,
        "base": invoice_currency,
        "symbols": home_currency,
        "access_key": API_KEY,
    }, timeout=10)
    resp.raise_for_status()
    data = resp.json()
    rate = Decimal(str(data["rates"][home_currency]))
    return {"rate": rate, "as_of": invoice_date, "source": "finexly"}

La règle est identique au cas en direct — figer une fois, stocker pour toujours — mais la date que vous interrogez est la date d'émission de la facture, pas le jour courant. Pour un traitement plus approfondi du travail avec des taux datés, voir le guide de l'API de taux de change historiques.

Arrondi et précision, faits correctement

Les bugs liés à l'argent sont presque toujours des bugs d'arrondi. Deux règles vous évitent les ennuis.

N'utilisez jamais de virgule flottante pour l'argent. 0.1 + 0.2 n'est pas 0.3 en arithmétique à virgule flottante, et ces minuscules erreurs s'accumulent d'une ligne de facture à l'autre. Utilisez un type décimal : Decimal en Python, BigDecimal en Java, decimal en C#, ou une représentation en centimes entiers en JavaScript.

Décidez où l'arrondi se produit. Arrondissez le taux à pleine précision (8+ décimales), mais arrondissez les montants à l'unité mineure de la devise — deux décimales pour l'USD ou l'EUR, zéro décimale pour le JPY ou le KRW, trois pour certaines autres. Une erreur fréquente consiste à coder en dur deux décimales et à émettre une facture de ¥1,234.56, ce qui n'est pas un montant valide en yens. Déterminez le nombre de décimales à partir de la devise, en utilisant les données d'unité mineure de la norme ISO 4217.

Pour les factures à lignes de détail, préférez arrondir chaque ligne puis additionner, et rapprochez du total arrondi afin que les lignes imprimées correspondent au total imprimé. Quelle que soit la convention choisie, appliquez-la de manière cohérente dans la facturation, les paiements et les rapports.

Comptabiliser le gain et la perte de change au moment du paiement

C'est ici que le taux figé porte ses fruits. Lorsque le client paie, vous convertissez ce qui a réellement atterri sur votre compte bancaire vers votre devise locale au taux de la date de paiement. L'écart entre cela et la valeur locale de la date de facture est un gain ou une perte de change réalisé.

// Amounts kept as Decimal-like strings; use a money library in production.
function realizedFxGainLoss(invoice, paymentRate) {
  // invoice.totalInvoice: amount billed, in the invoice currency
  // invoice.fxRate:       LOCKED rate at issue (invoice_ccy -> home_ccy)
  // paymentRate:          rate on the day the payment settled

  const homeAtIssue   = invoice.totalInvoice * invoice.fxRate;
  const homeAtPayment = invoice.totalInvoice * paymentRate;

  const gainLoss = homeAtPayment - homeAtIssue;
  return {
    homeAtIssue:   round2(homeAtIssue),
    homeAtPayment: round2(homeAtPayment),
    fxGainLoss:    round2(gainLoss),        // > 0 gain, < 0 loss
  };
}

function round2(n) { return Math.round(n * 100) / 100; }

Vous récupérez paymentRate de la même manière que vous avez figé le taux de la facture — un appel latest à la date de règlement, ou un appel historical si vous rapprochez a posteriori. Passez fxGainLoss dans un compte dédié « gain/perte de change ». Cette seule écriture est ce qui garde votre comptabilité équilibrée quand le marché bouge entre l'émission et le paiement, et c'est exactement le travail de rapprochement que la facturation multidevise manuelle rate. Les entreprises qui intègrent cela dans des pipelines automatisés peuvent s'appuyer sur la même infrastructure de taux décrite dans notre guide de facturation SaaS multidevise.

Avoirs, remboursements et factures récurrentes

Trois cas limites complètent un système intègre :

  • Les avoirs et les remboursements doivent contrepasser la facture d'origine à son taux figé d'origine — et non au taux courant. Un remboursement est un dénouement de la transaction initiale, alors réutilisez le fx_rate de la facture que vous créditez. Tout écart résiduel à la date réelle du remboursement devient une autre petite écriture de gain/perte de change.
  • Les factures récurrentes obtiennent chacune leur propre taux figé à leur propre date d'émission. Un abonnement de 12 mois facturé mensuellement produit douze factures avec douze taux. Ne figez pas un taux unique pour l'année sauf si le contrat le fixe explicitement.
  • Les taux fixés par contrat priment parfois sur le marché — certains contrats d'entreprise spécifient un taux fixe pour une période. Prévoyez un champ de surcharge manuelle, mais stockez-le avec les mêmes métadonnées d'audit pour qu'il reste reproductible.

Foire aux questions

Quel taux de change dois-je utiliser sur une facture ? Utilisez le taux au comptant en vigueur à la date d'émission de la facture, puis figez-le. Les US GAAP comme les IFRS exigent d'enregistrer les transactions en devise étrangère au taux de la date de transaction, et la date de facture est cette date. Ne le recalculez pas lorsque le client consulte ou paie la facture.

Dois-je stocker le taux de change ou seulement le montant converti ? Stockez les deux — plus la source et l'horodatage du taux. Ne conserver que le total converti rend impossible l'audit ou le calcul correct du gain/perte de change plus tard. Le taux, l'horodatage « au » et la source réunis permettent à quiconque de reproduire le chiffre.

Comment gérer une facture datée dans le passé ? Interrogez un taux de change historique pour la date d'émission réelle plutôt que d'utiliser celui d'aujourd'hui. La règle figer une fois, stocker pour toujours est la même ; seule change la date que vous consultez.

Qu'est-ce qui cause un gain ou une perte de change sur une facture ? Le mouvement du marché entre la date de facture et la date de paiement. Votre comptabilité a enregistré la créance au taux de la date de facture, mais la trésorerie arrive valorisée au taux de la date de paiement. L'écart est un gain ou une perte de change réalisé et se comptabilise dans un compte dédié du grand livre.

Ai-je besoin d'une API de devises payante pour construire une facturation multidevise ? Vous pouvez commencer avec une formule gratuite. L'API de taux de change gratuite de Finexly couvre les taux en direct et historiques pour les volumes de démarrage, et vous ne passez à une offre supérieure qu'à mesure que votre débit de factures augmente.

Pour commencer

La facturation multidevise se résume à une discipline : figez le taux à la date de facture, stockez-le avec des métadonnées d'audit complètes et rapprochez l'écart au paiement. Faites cela, et la facturation internationale cesse d'être un branle-bas de fin de trimestre.

Prêt à le construire ? Obtenez votre clé API Finexly gratuite — sans carte bancaire. Commencez avec des taux en direct et historiques pour plus de 170 devises sur la formule gratuite, et montez en puissance à mesure que votre volume de factures grandit.

Vlado Grigirov

Senior Currency Markets Analyst & Financial Strategist

Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...

View full profile →

Partager cet article