Contexte
Historiquement, lorsqu'une entreprise s'internationalisait, elle affichait souvent partout la même devise - en général le dollar US, parfois l'euro. Les clients résidant dans des pays utilisant une autre devise payaient en USD ou en EUR, puis se voyaient facturer des frais de conversion supplémentaires par leur banque. Cela pèse sur les taux de conversion, les clients ne sachant pas exactement combien ils seront facturés une fois ces frais ajoutés.
Des plateformes comme Stripe permettent aujourd'hui de proposer aux clients un prix dans leur devise locale, puis de le reconvertir vers votre devise opérationnelle. On parle alors de presentment currency (la devise dans laquelle paie le client) et de settlement currency (la devise dans laquelle vous recevez réellement les fonds). Stripe convertit normalement entre les deux en utilisant des taux mid-market, augmentés d'une petite marge.
Le défi qui en découle, c'est de savoir précisément combien on va recevoir dans sa devise « maison ». Les taux de change fluctuent en permanence : on peut estimer la conversion, mais en pratique on se retrouve souvent face à des écarts comptables liés à des estimations supérieures ou inférieures au montant qui finit par arriver sur le compte bancaire.
L'API FX Quotes de Stripe est précisément conçue pour supprimer cette incertitude.
Ce qu'est l'API FX Quotes
Dans sa forme la plus simple, l'API permet de demander un devis pour la conversion d'une devise vers une autre. Les taux retournés sont garantis pour une durée définie. On peut attacher ce devis à un PaymentIntent, à un Transfer, ou à tout objet supporté, et Stripe garantit que la conversion se fera à ce taux tant que le devis est actif.
C'est un changement de logique délibéré : on passe de « on convertira au taux qui sera en vigueur au moment du règlement » à « voici le taux qui sera utilisé, point final ». Cette prévisibilité est la principale promesse de valeur de l'API.
Pourquoi c'est utile
Quiconque travaille avec plusieurs devises finit par découvrir à quel point les taux de change peuvent être glissants. De petits mouvements introduisent du bruit dans le rapprochement, rognent les marges, ou font atterrir des transferts un peu à côté du montant prévu. Imaginez que vous estimiez aujourd'hui un prix converti à 94,29 € pour un client, mais que le taux bouge avant la capture, et que le client soit finalement facturé 96,02 €. Ou imaginez un compte connecté qui attend 20 € mais qui en reçoit 19,85 € après règlement. Vu individuellement, c'est faible. À l'échelle, cela génère du support et du frottement de rapprochement.
C'est une douleur parfois supportable quand on convertit ses propres revenus. Cela l'est beaucoup moins quand :
- vous voulez afficher au client un prix final dans sa devise locale, ou
- vous opérez une plateforme dans laquelle les comptes connectés s'attendent à recevoir des montants exacts, et non approximatifs.
L'API FX Quotes vous donne une base prévisible. Au lieu d'espérer que la conversion tombe juste, vous savez exactement comment Stripe va la traiter.
Une note sur le sens de la conversion
Un détail important qui surprend beaucoup de monde au premier abord : la conversion de devise n'est pas symétrique. Si un devis vous indique que 2 GBP donnent 1 EUR, vous ne pouvez pas l'inverser et supposer que 1 EUR donnera 2 GBP dans l'autre sens. Le change réel comprend des taux à l'achat et à la vente, et l'API Stripe en tient compte.
Si vous avez besoin des deux sens, demandez deux devis. Plus simplement : demandez toujours le devis dans le sens dans lequel vous comptez l'utiliser.
Exemple de base : utiliser FX Quotes avec un PaymentIntent
À l'international, un besoin classique consiste à afficher un prix dans la devise locale du client, même si le compte Stripe par défaut est dans une autre devise. Imaginons qu'on opère en GBP mais qu'on veuille afficher le prix en euros.
Étape 1 : demander un devis
curl https://api.stripe.com/v1/fx_quotes \
-u "sk_test_123:" \
-H "Stripe-Version: 2025-08-27.basil; fx_quote_preview=v1" \
-d "to_currency"=gbp \
-d "from_currencies[]"=eur \
-d "lock_duration"=day
Dans le cadre d'un paiement, to_currency est typiquement la devise de règlement du compte Stripe, tandis que from_currencies[] contient les devises dans lesquelles paient les clients. La requête renvoie une réponse contenant un taux de conversion verrouillé et l'ID du devis (fxq_xxxxxx).
{
"id": "fxq_xxx",
"object": "fx_quote",
"lock_duration": "day",
"lock_status": "active",
"rates": {
"eur": {
"exchange_rate": 0.853682,
"rate_details": {
"base_rate": 0.872885,
"duration_premium": 0.002,
"fx_fee_rate": 0.02
}
}
},
"to_currency": "gbp",
"usage": { "type": "payment" }
}
Le paramètre exchange_rate inclut les frais Stripe de conversion, alors que base_rate les exclut. Si l'on veut que le client supporte l'intégralité du coût de la conversion, on divise le prix cible (100 £) par exchange_rate (0,853682) et on facture 117,14 €. Si l'entreprise absorbe le coût du change, on divise par base_rate (0,872885), et on facture 114,56 €.
| Cas d'usage | Valeur à utiliser |
|---|---|
| Le client supporte les frais de change Stripe | exchange_rate |
| L'entreprise absorbe les frais de change | base_rate |
Étape 2 : attacher le devis à un PaymentIntent
curl https://api.stripe.com/v1/payment_intents \
-u "sk_test_123:" \
-H "Stripe-Version: 2025-08-27.basil; fx_quote_preview=v1" \
-d "amount"=11714 \
-d "currency"=eur \
-d "fx_quote"=fxq_xxxxxx
Le PaymentIntent présenté au client final pour 117,14 € arrivera, une fois payé, sous forme de 100 £ sur notre compte Stripe. On supprime ainsi toute incertitude, tant côté facturation client que côté encaissement.
FX Quotes avec Stripe Connect
En multi-devise avec Stripe Connect, les écarts de change peuvent devenir particulièrement douloureux. Une plateforme peut opérer dans une devise et ses comptes connectés dans une autre, et de petits mouvements de change génèrent rapidement beaucoup de bruit opérationnel.
Deux scénarios FX courants apparaissent avec Connect :
- Application fees : on facture le client final dans une devise, mais la commission de la plateforme doit être collectée dans une autre.
- Transferts entre la plateforme et les comptes connectés : on peut avoir besoin d'envoyer des fonds à un compte connecté dans sa devise locale, alors que notre solde est dans une autre. La précision compte ici - créateurs, restaurants ou marchands attendent des paiements exacts.
La mécanique pour les application fees est la même que pour les PaymentIntents ci-dessus, on ne s'y attardera pas. Le cas le plus intéressant est le transfert, où la plateforme doit déplacer des fonds depuis son propre solde vers un compte connecté dans une autre devise.
Exemple : garantir qu'un compte connecté reçoive exactement 20 €
Imaginons que nous soyons une plateforme de livraison de repas qui propose une promotion de 20 % de réduction. Un client commande pour 100 € de nourriture et paie 80 € à notre plateforme. Les 80 € arrivent sur la plateforme ; les 20 € restants dus au restaurant doivent être complétés depuis le solde propre de la plateforme. Si la plateforme opère en GBP et le restaurant en EUR, il faut transférer exactement 20 € depuis notre solde GBP.
Demander le devis (dans le bon sens)
curl https://api.stripe.com/v1/fx_quotes \
-u "sk_test_123:" \
-H "Stripe-Version: 2025-08-27.basil; fx_quote_preview=v1" \
-d to_currency=eur \
-d "from_currencies[]"=gbp \
-d lock_duration=five_minutes \
-d "usage[type]"=transfer \
-d "usage[transfer][destination]"="{{CONNECTED_ACCOUNT_ID}}"
Comme nous voulons que le compte connecté soit servi en intégralité, la plateforme absorbe les frais. On utilise base_rate dans le calcul. 20 € ÷ 1,14587 = 17,45 £.
Créer le transfert avec ce devis
curl https://api.stripe.com/v1/transfers \
-u "sk_test_123:" \
-H "Stripe-Version: 2025-08-27.basil; fx_quote_preview=v1" \
-d amount=1745 \
-d currency=gbp \
-d destination="{{CONNECTED_ACCOUNT_ID}}" \
-d fx_quote=fxq_xxx
Stripe débite 17,45 £ du solde de la plateforme et garantit que le compte connecté recevra exactement 20 €. Pas de surprise au rapprochement, pas de versement correctif, plus de devinettes.
Combien de temps le devis est-il valide ?
Par défaut, le devis renvoie le taux courant du marché. Le paramètre lock_duration contrôle la durée pendant laquelle le devis est valide - 5 minutes, une heure ou une journée. Des durées plus longues sont possibles sur demande, sous réserve d'accord de Stripe. Stripe applique des frais plus élevés pour réserver le devis - le champ duration_premium reflète ce coût.
Le devis peut quand même expirer dans cet intervalle. Un devis longue durée pour les paiements a un seuil de 3,5 %, et pour les transferts un seuil de 1 %. Si le taux dévie au-delà du seuil, le devis est invalidé et lock_status passe à expired. Le webhook fx_quote.expired est alors déclenché.
La prévisibilité l'emporte sur l'à-peu-près
La conversion de devises est l'un de ces sujets qui paraissent simples, mais qui glissent silencieusement des incohérences un peu partout. L'API FX Quotes de Stripe apporte un niveau de prévisibilité bienvenu. Plutôt que de traiter le change comme une cible mouvante, on le traite comme une valeur connue : un devis avec des bornes, une expiration et un résultat garanti.
Si vous tarifez dans plusieurs devises, si vous encaissez en multi-devise, ou si vous opérez une plateforme dont les transferts doivent tomber juste, l'API FX Quotes vous donne un cadre bien plus fiable que d'espérer le bon taux au moment de la capture.