# Accepter des paiements pour des biens numériques sur iOS avec une page de paiement personnalisée Créez votre propre page de paiement personnalisée pour vendre des biens numériques et des abonnements dans l'application à l'aide de Payment Element. Pour les produits numériques, les contenus et les abonnements vendus aux États-Unis ou dans l’Espace économique européen (Elements), votre application iOS peut accepter Apple Pay à l’aide d’[Elements](https://docs.stripe.com/payments/elements.md). Si vous avez un nombre limité de produits et de prix, vous pouvez plutôt utiliser [Payment Links](https://docs.stripe.com/mobile/digital-goods/payment-links.md). Dans d’autres régions, votre application ne peut pas accepter Apple Pay pour les produits numériques, les contenus ou les abonnements. Ce guide décrit comment vendre un abonnement dans votre application en utilisant Elements pour rediriger vos clients vers votre propre page de paiement. Si vous avez déjà votre propre page de paiement qui utilise Elements, vous pouvez passer directement à l’étape [Configurer les liens universels](https://docs.stripe.com/mobile/digital-goods/custom-checkout.md#universal-links). > Si votre entreprise est nouvelle sur Stripe, traite un volume important de paiements et a des besoins d’intégration avancés, [contactez notre équipe commerciale](https://stripe.com/contact/sales) ## Ce que vous allez créer Si votre intégration utilise des [Accounts configurés par le client](https://docs.stripe.com/api/v2/core/accounts/create.md#v2_create_accounts-configuration-customer), remplacez les références `Customer` et événement dans les exemples de code par les références équivalentes de l’API Accounts v2. Pour plus d’informations, consultez la page [Représenter des clients avec des objets Account](https://docs.stripe.com/connect/use-accounts-as-customers.md). Ce guide vous explique comment : - Collectez des informations de paiement sur votre propre page de paiement avec [Elements](https://docs.stripe.com/payments/elements.md). - Modéliser vos abonnements avec des *produits* (Products represent what your business sells—whether that's a good or a service), des *tarifs* (Prices define how much and how often to charge for products. This includes how much the product costs, what currency to use, and the interval if the price is for subscriptions) et des *clients* (Customer objects represent customers of your business. They let you reuse payment methods and give you the ability to track multiple payments). - Utiliser les *liens universels* (Use Universal links on iOS and macOS to link directly to in-app content. They're standard HTTPS links, so the same URL works for your website and your app) pour rediriger directement vers votre application depuis Checkout. - Écouter des *webhooks* (A webhook is a real-time push notification sent to your application as a JSON payload through HTTPS requests) pour mettre à jour les abonnements de vos clients dans l’application. Ce guide ne traite que de la vente de biens numériques dans l’application. Si vous vendez l’un des éléments suivants, utilisez plutôt le [guide de paiement iOS natif](https://docs.stripe.com/payments/mobile.md) : - Produits physiques - Biens et services destinés à la consommation en dehors de votre application - Services en temps réel de personne à personne ## Configurer Stripe [Côté serveur] Tout d’abord, [inscrivez-vous](https://dashboard.stripe.com/register) pour créer un Compte Stripe. Ajoutez ensuite la bibliothèque d’API Stripe à votre back-end : #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` Installez ensuite l’interface de ligne de commande Stripe. L’interface de ligne de commande fournit les tests de [webhooks](https://docs.stripe.com/webhooks.md#test-webhook) requis, que vous pouvez exécuter pour créer vos produits et vos tarifs. Pour davantage d’options d’installation, consultez la page consacrée à l’[interface de ligne de commande Stripe](https://docs.stripe.com/stripe-cli.md). ## Créer des produits et tarifs Créez vos produits et leurs prix dans le Dashboard ou avec le CLI de Stripe. Cet exemple utilise un produit et un prix pour représenter un produit d’abonnement avec un prix mensuel de 9,99 USD. 1. Accédez à la page [Ajouter un produit](https://dashboard.stripe.com/test/products/create) et créez un produit d’abonnement à un tarif mensuel de 9,99 USD. 1. Après avoir créé le tarif, enregistrez l’ID du tarif pour pouvoir l’utiliser dans les étapes suivantes. Les ID de tarif sont similaires à : `price_G0FvDp6vZvdwRZ`. 1. Cliquez ensuite sur **Copier en mode production** pour dupliquer votre produit d’un [environnement de test vers le mode production](https://docs.stripe.com/keys.md#test-live-modes). ## Créer des clients [Côté serveur] Chaque fois que votre client accède à votre page de paiement, créez un objet Customer s’il n’en existe pas déjà un. Votre serveur doit gérer : - La création d’un client (s’il n’existe pas encore de client Stripe correspondant). - La création d’un abonnement à l’état `incomplete`. - Le renvoi de la clé secrète du client PaymentIntent au front-end. - Les webhooks afin que vous puissiez mettre à jour l’état de l’abonnement de votre client dans votre propre base de données. #### Node.js ```javascript // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. // Find your keys at https://dashboard.stripe.com/apikeys. const stripe = require('stripe')('<>'); // This assumes your app has an existing user database, which we'll call `myUserDB`. const user = myUserDB.getUser("jennyrosen"); if (!user.stripeCustomerID) { const customer = await stripe.customers.create({ name: user.name, email: user.email, }); // Set the user's Stripe Customer ID for later retrieval. user.stripeCustomerID = customer.id; } ``` > Veillez à conserver une association sur votre serveur entre le compte d’utilisateur et l’ID du client Stripe. Sans cela, vos clients ne pourront pas récupérer leurs achats. > > Si le client modifie son adresse e-mail sur la page de paiement, l’objet Customer se met à jour avec la nouvelle adresse. ## Créer un abonnement [Côté serveur] Lorsque vous créez un abonnement pour utiliser le Payment Element, vous transmettez généralement `payment_behavior: 'default_incomplete'`. Cela indique à Stripe de créer un abonnement à l’état `incomplete` et de générer un Payment Intent pour le paiement initial. > Conservez la valeur `subscription.id` dans votre base de données pour gérer les événements d’abonnement futurs, tels que les annulations, les mises à niveau et les passages à des offres inférieures. #### Node.js ```javascript // This example sets up an endpoint using the Express framework. const express = require('express'); const app = express(); // Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. const stripe = require('stripe')('<>'); app.post('/create-subscription', async (req, res) => { const { priceId, customerId } = req.body; // Create the subscription // setting payment_behavior to "default_incomplete" ensures we get a Payment Intent // that we can confirm on the client using the Payment Element const subscription = await stripe.subscriptions.create({ customer: customerId, items: [{ price: priceId }], payment_behavior: 'default_incomplete', expand: ['latest_invoice.payment_intent'], }); // Make sure you associate the subscription ID with the user in your database! myUserDB.addUserSubscription("jennyrosen", subscription.id); // Get the Payment Intent client secret const paymentIntent = subscription.latest_invoice.payment_intent; const clientSecret = paymentIntent.client_secret; return res.json({ subscriptionId: subscription.id, clientSecret: clientSecret, }); }); app.post('/login', async (req, res) => { // This assumes your app has an existing user database, which we'll call `myUserDB`. const token = myUserDB.login(req.body.login_details) res.json({token: token}) }); app.listen(4242, () => console.log(`Listening on port ${4242}!`)); ``` > Apple Pay est [activé par défaut](https://dashboard.stripe.com/settings/payment_methods) et s’affiche automatiquement dans le Payment Element lorsqu’un client utilise un appareil pris en charge et a enregistré au moins une carte dans son wallet. Vous pouvez accepter des moyens de paiement supplémentaires à l’aide de la propriété `payment_method_types`. Consultez la page [Aperçu des moyens de paiement](https://docs.stripe.com/payments/payment-methods/overview.md) pour en savoir plus. ## Configurer des liens universels Les liens universels permettent à votre page de paiement d’être profondément liée à votre application. Pour configurer un lien universel : - Ajoutez un fichier `apple-app-site-association` à votre domaine. - Ajoutez un droit de domaine associé à votre application. - Ajoutez une page de renvoi pour vos URL de redirection Checkout. #### Définissez les domaines associés Ajoutez un fichier à votre domaine sur `.well-known/apple-app-site-association` pour définir les URL que votre application peut gérer. Ajoutez l’ID d’application avec votre ID d’équipe que vous pourrez trouver sur la [page d’abonnement du portail développeur d’Apple](https://developer.apple.com/account). ```json { "applinks": { "apps": [], "details": [ { "appIDs": [ "A28BC3DEF9.com.example.MyApp1", "A28BC3DEF9.com.example.MyApp1-Debug" ], "components": [ { "/": "/checkout_redirect*", "comment": "Matches any URL whose path starts with /checkout_redirect" } ] } ] } } ``` Vous devez traiter le fichier avec le type MIME `application/json`. Utilisez `curl -I` pour confirmer le type de contenu. ```bash curl -I https://example.com/.well-known/apple-app-site-association ``` Pour en savoir plus, consultez la page d’Apple relative aux [domaines associés pris en charge](https://developer.apple.com/documentation/xcode/supporting-associated-domains). #### Ajouter un droit de domaine associé à votre application 1. Ouvrez le volet **Signatures et fonctionnalités** de la cible de votre application. 1. Cliquez sur **+ Fonctionnalité**, puis sélectionnez **Domaines associés**. 1. Ajoutez une entrée pour `applinks:example.com` à la liste Domaines associés. Pour en savoir davantage sur les liens universels, consultez la documentation d’Apple sur les [liens universels](https://developer.apple.com/ios/universal-links/). Bien qu’iOS intercepte les liens vers les URL définies dans votre fichier `apple-app-site-association`, il se peut que la redirection ne parvienne pas à ouvrir votre application. Créez une [page de renvoi](https://docs.stripe.com/payments/checkout/custom-success-page.md) vers les URL `success` et `cancel`. Par exemple, vous pouvez avoir une page `/checkout_redirect/success` et une page `/checkout_redirect/cancel`. ## Ouvrir Checkout dans Safari [Côté client] Ajoutez un bouton de paiement à votre application. Ce bouton ouvre votre page de paiement personnalisée dans Safari. ```swift import Foundation import SwiftUI import StoreKit struct BuySubscriptionsView: View { @EnvironmentObject var myBackend: MyBackend @State var paymentComplete = false var body: some View { // Check if payments are blocked by Parental Controls on this device. if !SKPaymentQueue.canMakePayments() { Text("Payments are disabled on this device.") } else { if paymentComplete { Text("Payment complete!") } else { Button { UIApplication.shared.open("https://example.com/checkout", options: [:], completionHandler: nil) } label: { Text("Subscribe") }.onOpenURL { url in // Handle the universal link from Checkout. if url.absoluteString.contains("success") { // The payment was completed. Show a success // page and fetch the latest customer entitlements // from your server. paymentComplete = true } } } } } } ``` ## Rediriger vers votre application [Côté serveur] Avec Elements, assurez-vous de [rediriger](https://docs.stripe.com/js/payment_intents/confirm_payment#confirm_payment_intent-options-confirmParams-return_url) les utilisateurs vers votre application (en utilisant le lien universel enregistré) une fois le paiement confirmé. ```javascript stripe.confirmPayment({ elements, confirmParams: { // Return URL where the customer should be redirected after the PaymentIntent is confirmed. return_url: 'https://example.com/checkout_redirect/success', }, }) .then(function(result) { if (result.error) { // Inform the customer that there was an error. } }); ``` ## Gérer le traitement des commandes [Côté serveur] Lorsque l’utilisateur effectue le paiement initial ou lorsque des paiements récurrents ultérieurs ont lieu, Stripe envoie des événements tels que : - `invoice.payment_succeeded` - `customer.subscription.updated` - `invoice.payment_failed` Écoutez ces événements dans votre endpoint de webhook. Par exemple : #### Node.js ```javascript app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => { const sig = req.headers['stripe-signature']; let event; try { event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET); } catch (err) { console.error('Webhook signature verification failed.', err.message); return res.sendStatus(400); } switch (event.type) { case 'invoice.payment_succeeded': { const invoice = event.data.object; // Mark subscription as active in your database // For example, invoice.subscription -> "sub_abc123" console.log('Payment succeeded'); break; } case 'invoice.payment_failed': { const invoice = event.data.object; console.log('Payment failed - notify the user to update their payment methods'); break; } case 'customer.subscription.updated': { const subscription = event.data.object; // For example, handle pause, cancellation, or other changes console.log(`Subscription updated: ${subscription.id}`); break; } default: console.log(`Unhandled event type ${event.type}`); } res.json({ received: true }); }); ``` Pour tester votre intégration, vous pouvez surveiller les événements dans le [Dashboard](https://dashboard.stripe.com/events) ou utiliser l’[interface de ligne de commande Stripe](https://docs.stripe.com/webhooks.md#test-webhook). Lorsque vous développez en mode production, configurez un endpoint de webhook et abonnez-vous aux types d’événements pertinents. Si vous ne connaissez pas votre clé `STRIPE_WEBHOOK_SECRET`, cliquez sur le [webhook](https://dashboard.stripe.com/webhooks) dans le Dashboard pour l’afficher. ### Tests Pour tester le bon fonctionnement de votre bouton de paiement, procédez comme suit : 1. Cliquez sur le bouton de paiement, qui vous redirige vers votre page de paiement avec le composant Payment Element de Stripe. 1. Saisissez le numéro de carte de test 4242 4242 4242 4242, un code CVC à trois chiffres, une date d’expiration et un code postal valide. 1. Appuyez sur **Payer**. 1. Le webhook `invoice.payment_succeeded` s’active et Stripe notifie votre serveur de la transaction. 1. Vous êtes redirigé(e) vers votre application. Si votre intégration ne fonctionne pas, consultez la section [Ressources de test supplémentaires](https://docs.stripe.com/mobile/digital-goods/custom-checkout.md#additional-testing-resources). ## Optional: Ressources de test supplémentaires Stripe met à votre disposition plusieurs cartes de test que vous pouvez utiliser pour vous assurer que votre intégration est prête à passer en production. Utilisez-les avec n’importe quels code CVC, code postal et date d’expiration future. | Numéro | Description | | ------------------- | ----------------------------------------------------------------------------------- | | 4242 4242 4242 4242 | Fait aboutir le paiement et le traite immédiatement. | | 4000 0000 0000 3220 | Effectue une authentification 3D Secure 2 pour que le paiement aboutisse. | | 4000 0000 0000 9995 | Échec systématique avec le code de refus de paiement `insufficient_funds`. | Pour obtenir la liste complète des cartes de test, consultez notre guide consacré aux [tests](https://docs.stripe.com/testing.md). ### Tester des liens universels Si votre lien universel ne vous renvoie pas vers votre application depuis Checkout, vérifiez que les logs `SharedWebCredentials` ne contiennent pas d’erreurs. 1. Ajouter un paramètre de débogage au droit de domaine associé 1. Ouvrez le volet **Signatures et fonctionnalités** de la cible de votre application. 1. Ajoutez le flag `?mode=developer` dans votre saisie pour votre domaine associé. *(Exemple : `applinks:example.com?mode=developer`)* 1. Passez l’appareil en mode développeur. 1. Exécutez une application de Xcode sur votre appareil pour activer le menu développeur. 1. Sur votre iPhone, ouvrez le volet **Réglages**, touchez **Développeur**, puis activez **Développement des domaines associés**. 1. Supprimez et désinstallez votre application. De cette manière, iOS récupérera à nouveau le fichier apple-app-site-association. 1. Finalisez le tunnel de paiement dans votre application. 1. Checkout vous redirige vers votre application. Si ce n’est pas le cas, lancez un diagnostic système. 1. Appuyez simultanément sur les boutons d’augmentation du volume, de réduction du volume et de marche/arrêt pendant 1 seconde, puis relâchez-les. Vous sentirez une courte vibration, mais aucun élément visuel ne s’affichera. 1. Patientez 5 minutes, puis accédez à **Paramètres > Confidentialité > Analyses et amélioration > Données d’analyse** et faites défiler jusqu’au dernier fichier de diagnostic système de la liste. 1. Touchez le bouton de partage pour envoyer le fichier avec AirDrop sur votre ordinateur. 1. Ouvrez l’archive du diagnostic système, puis le fichier `swcutil_show.txt` 1. Recherchez l’ID de votre application dans ce fichier. Vous verrez une section contenant des informations de débogage pour votre application, dont un message d’erreur, le cas échéant. ``` Service: applinks App ID: Y28TH9SHX7.com.stripe.FruitStore App Version: 1.0 App PI: { v = 0, t = 0x8, u = 0xc98, db = E335D78F-D49E-4F19-A150-F657E50DEDAE, {length = 8, bytes = 0x980c000000000000} } Domain: example.com?mode=developer User Approval: unspecified Site/Fmwk Approval: unspecified Flags: developer Last Checked: 2021-09-23 18:16:58 +0000 Next Check: 2021-09-23 21:21:34 +0000 Error: Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set. around line 1, column 0." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set. around line 1, column 0., NSJSONSerializationErrorIndex=0} Retries: 1 ``` ## See also - [Ajouter des réductions](https://docs.stripe.com/payments/checkout/discounts.md) - [Collecte des taxes](https://docs.stripe.com/payments/checkout/taxes.md) - [Collecter des numéros fiscaux](https://docs.stripe.com/tax/checkout/tax-ids.md) - [Personnaliser l’adaptation à votre marque](https://docs.stripe.com/payments/checkout/customization.md) - [Personnaliser votre page de confirmation de paiement](https://docs.stripe.com/payments/checkout/custom-success-page.md)