> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sezzle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Ios

Ce guide vous explique comment intégrer le SDK iOS Sezzle dans votre application. À la fin, votre application affichera les messages promotionnels Sezzle sur les pages produits et lancera le paiement Sezzle.

### Prérequis

* Cible de déploiement iOS 15.0+
* Swift 5.9+
* Un compte marchand Sezzle avec votre <a href="https://dashboard.sezzle.com/merchant/settings/apikeys" target="_blank">Clé API publique</a>
* Un serveur backend pour capturer les paiements après le paiement

<Tip>
  Un exemple d'application fonctionnel est inclus dans le dépôt du SDK à <a href="https://github.com/sezzle/sezzle-merchant-sdk-ios/tree/main/Example" target="_blank">Example/SezzleCheckoutExample</a>. Il illustre toutes les variantes de widget et les deux modes de paiement.
</Tip>

## 1. Installation

<Tabs>
  <Tab title="Swift Package Manager">
    1. Dans Xcode, allez à **File > Add Package Dependencies**
    2. Saisissez l'URL du dépôt :

    ```
    https://github.com/sezzle/sezzle-merchant-sdk-ios.git
    ```

    3. Sélectionnez **Up to Next Major Version** à partir de la dernière version
    4. Ajoutez `SezzleMerchantSDK` à votre cible
  </Tab>

  <Tab title="CocoaPods">
    Ajoutez à votre `Podfile` :

    ```ruby theme={"system"}
    pod 'SezzleMerchantSDK'
    ```

    Puis exécutez :

    ```bash theme={"system"}
    pod install
    ```
  </Tab>
</Tabs>

**Requirements:** iOS 15.0+, Swift 5.9+

## 2. Configuration

Initialisez le SDK une fois au démarrage de l'application dans votre `AppDelegate` :

```swift theme={"system"}
import SezzleMerchantSDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        SezzleSDK.shared.configure(
            publicKey: "sz_pub_your_key_here",
            environment: .production  // use .sandbox for testing
        )
        return true
    }
}
```

| Paramètre     | Type                | Défaut        | Description                                                 |
| ------------- | ------------------- | ------------- | ----------------------------------------------------------- |
| `publicKey`   | `String`            | Requis        | Votre clé API publique Sezzle                               |
| `environment` | `SezzleEnvironment` | `.production` | `.sandbox` pour les tests, `.production` pour la production |

<Warning>
  N'incluez jamais votre **clé privée** API dans l'application. Le SDK utilise uniquement la clé publique. Utilisez votre clé privée côté serveur pour capturer les paiements.
</Warning>

## 3. Messages promotionnels

Ajoutez un `SezzlePromotionalView` à votre page produit pour afficher la tarification en versements :

```swift theme={"system"}
import SezzleMerchantSDK

let promoView = SezzlePromotionalView(
    amountInCents: 9999,  // $99.99
    presentingFrom: self   // UIViewController for modal presentation
)
view.addSubview(promoView)
```

Le widget affiche automatiquement le message correct en fonction du prix et se met à jour lorsque vous appelez :

```swift theme={"system"}
promoView.update(amountInCents: 14999)  // price changed to $149.99
```

<Frame caption="Widgets promotionnels à différents niveaux de prix">
  <img src="https://mintcdn.com/sezzle/klJ95KzsWuUWpHvl/images/docs/guides/mobile/ios-product-page-light.png?fit=max&auto=format&n=klJ95KzsWuUWpHvl&q=85&s=00fc0f3d1283f897c0dbf172c327e093" alt="iOS Widgets" width="1206" height="2622" data-path="images/docs/guides/mobile/ios-product-page-light.png" />
</Frame>

### Tous les paramètres

```swift theme={"system"}
SezzlePromotionalView(
    amountInCents: Int,
    currency: String = "USD",
    style: SezzlePromotionalStyle = .light,
    widgetConfig: SezzleWidgetConfig = .default,
    presentingFrom viewController: UIViewController
)
```

| Paramètre        | Type                     | Défaut     | Description                                                    |
| ---------------- | ------------------------ | ---------- | -------------------------------------------------------------- |
| `amountInCents`  | `Int`                    | Requis     | Prix du produit en centimes (ex. : 4999 = 49,99 \$)            |
| `currency`       | `String`                 | `"USD"`    | Code de devise ISO 4217 (ex. : `"USD"`, `"CAD"`)               |
| `style`          | `SezzlePromotionalStyle` | `.light`   | `.light` pour les fonds clairs, `.dark` pour les fonds sombres |
| `widgetConfig`   | `SezzleWidgetConfig`     | `.default` | Contrôle les seuils de tarification et le paiement en 5 fois   |
| `presentingFrom` | `UIViewController`       | Requis     | Contrôleur de vue pour présenter la fenêtre d'information      |

<Tip>
  Le widget détecte automatiquement le mode sombre et change de style via `traitCollectionDidChange`. Si vous souhaitez forcer un style spécifique, passez `.light` ou `.dark` explicitement.
</Tip>

### Configuration du widget

Tous les paramètres de configuration sont **optionnels** — le widget fonctionne immédiatement avec des valeurs par défaut sensées :

| Paramètre            | Défaut              | Description                                                                                         |
| -------------------- | ------------------- | --------------------------------------------------------------------------------------------------- |
| `minPriceInCents`    | `3500` (35 \$)      | Prix minimum pour afficher le widget                                                                |
| `maxPriceInCents`    | `250000` (2 500 \$) | Prix maximum pour les paiements à court terme (PI4/PI5)                                             |
| `enablePayIn5`       | `true`              | Afficher « 5 paiements » pour les prix égaux ou supérieurs au seuil PI5                             |
| `pi5MinPriceInCents` | `5000` (50 \$)      | Seuil de prix pour le paiement en 5 fois                                                            |
| `longTermConfig`     | `nil` (désactivé)   | Activer les paiements mensuels à long terme — définissez sur un `SezzleLongTermConfig` pour activer |

Pour personnaliser, ne passez que les valeurs que vous souhaitez remplacer :

```swift theme={"system"}
let config = SezzleWidgetConfig(
    longTermConfig: SezzleLongTermConfig(
        minPriceInCents: 25_000  // $250+ shows monthly payments
    )
)

let promoView = SezzlePromotionalView(
    amountInCents: 79900,
    widgetConfig: config,
    presentingFrom: self
)
```

### Texte promotionnel personnalisé

Si vous avez besoin d'un contrôle total sur l'interface utilisateur, utilisez `SezzlePromoDataHandler` pour obtenir un `NSAttributedString` stylisé avec le logo Sezzle intégré :

```swift theme={"system"}
SezzlePromoDataHandler.getMessage(amountInCents: 9999) { attributedString in
    myLabel.attributedText = attributedString
}
```

## 4. Paiement

### Construire l'objet de paiement

```swift theme={"system"}
let checkout = SezzleCheckout(
    customer: SezzleCustomer(
        email: "customer@example.com",
        firstName: "Jane",
        lastName: "Doe",
        phone: "+15551234567",
        billingAddress: SezzleAddress(
            street: "123 Main St",
            city: "Minneapolis",
            state: "MN",
            postalCode: "55401",
            countryCode: "US"
        )
    ),
    order: SezzleOrder(
        referenceId: "order-12345",
        description: "Wireless Earbuds",
        amount: SezzleAmount(amountInCents: 4599, currency: "USD"),
        items: [
            SezzleItem(
                name: "Wireless Earbuds",
                sku: "WE-001",
                quantity: 1,
                price: SezzleAmount(amountInCents: 3999, currency: "USD")
            )
        ],
        taxAmount: SezzleAmount(amountInCents: 350, currency: "USD"),
        shippingAmount: SezzleAmount(amountInCents: 250, currency: "USD")
    )
)
```

#### Champs client

| Champ             | Requis | Description                                    |
| ----------------- | ------ | ---------------------------------------------- |
| `email`           | Oui    | Adresse e-mail du client                       |
| `firstName`       | Non    | Prénom du client                               |
| `lastName`        | Non    | Nom de famille du client                       |
| `phone`           | Non    | Numéro de téléphone du client                  |
| `dob`             | Non    | Date de naissance (`"YYYY-MM-DD"`)             |
| `billingAddress`  | Non    | Adresse de facturation (`SezzleAddress`)       |
| `shippingAddress` | Non    | Adresse de livraison (`SezzleAddress`)         |
| `tokenize`        | Non    | Tokeniser le client pour les commandes futures |

#### Champs de commande

| Champ                      | Requis | Description                                                                                                                                                                                   |
| -------------------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `referenceId`              | Oui    | Votre identifiant de commande/référence interne                                                                                                                                               |
| `description`              | Non    | Description de la commande                                                                                                                                                                    |
| `amount`                   | Oui    | Montant total de la commande en centimes + devise                                                                                                                                             |
| `intent`                   | Non    | [`.auth`](/fr/docs/api/core/sessions/postv2session#body-order-intent) (par défaut, capture ultérieure depuis votre backend) ou `.capture` (capture automatique à la finalisation du paiement) |
| `items`                    | Non    | Détails des articles de la commande                                                                                                                                                           |
| `discounts`                | Non    | Articles de remise (`[SezzleDiscount]`)                                                                                                                                                       |
| `taxAmount`                | Non    | Détail du montant des taxes                                                                                                                                                                   |
| `shippingAmount`           | Non    | Détail du montant de la livraison                                                                                                                                                             |
| `metadata`                 | Non    | Paires clé-valeur personnalisées. Le SDK inclut automatiquement `_sdk_platform`, `_sdk_version`, `_device_model`, et `_os_version` — évitez d'utiliser des clés préfixées par `_`.            |
| `locale`                   | Non    | Langue du paiement (`.enUS`, `.enCA`, `.frCA`)                                                                                                                                                |
| `checkoutFinancingOptions` | Non    | Restreindre à des plans spécifiques : `.fourPayBiweekly`, `.fourPayMonthly`, `.sixPayMonthly`. Optionnel — omettez pour laisser Sezzle afficher tous les plans éligibles.                     |

#### Champs d'adresse (`SezzleAddress`)

| Champ         | Description                  |
| ------------- | ---------------------------- |
| `name`        | Nom complet                  |
| `street`      | Ligne 1 de l'adresse postale |
| `street2`     | Ligne 2 de l'adresse postale |
| `city`        | Ville                        |
| `state`       | État ou province             |
| `postalCode`  | Code postal                  |
| `countryCode` | Code pays ISO (ex. : `"US"`) |
| `phone`       | Numéro de téléphone          |

### Démarrer le paiement

```swift theme={"system"}
SezzleSDK.shared.startCheckout(
    checkout,
    from: self,            // presenting UIViewController
    delegate: self,        // SezzleCheckoutDelegate
    mode: .systemBrowser   // or .webView
)
```

### Gérer le résultat

Conformez-vous à `SezzleCheckoutDelegate` :

```swift theme={"system"}
extension ProductViewController: SezzleCheckoutDelegate {

    func checkoutDidComplete(result: SezzleCheckoutResult) {
        // For this flow, `result.orderUUID` is populated.
        // (For the server-driven flow, see Section 8.)
        if let orderUUID = result.orderUUID {
            // Send orderUUID to your backend to capture payment
            // POST /v2/order/{orderUUID}/capture
            print("Order completed: \(orderUUID)")
        }
    }

    func checkoutDidCancel() {
        // Customer closed checkout without completing
        print("Checkout cancelled")
    }

    func checkoutDidFail(error: SezzleError) {
        // Handle the error
        switch error {
        case .networkError(let underlying):
            print("Network error: \(underlying)")
        case .apiError(let statusCode, let message):
            print("API error \(statusCode): \(message)")
        case .browserDismissed:
            print("Browser dismissed")
        case .notConfigured:
            print("SDK not configured")
        case .invalidResponse:
            print("Invalid response")
        }
    }
}
```

<Note>
  Après `checkoutDidComplete`, envoyez `result.orderUUID` vers votre serveur backend. Votre serveur doit appeler `POST /v2/order/{orderUUID}/capture` en utilisant votre **privée** clé API pour capturer le paiement. Consultez l' [Orders API](/fr/docs/api/core/orders/postv2capturebyorder) pour plus de détails.
</Note>

## 5. Mode WebView

Par défaut, le paiement s'ouvre dans `ASWebAuthenticationSession` (navigateur système). Pour garder l'utilisateur dans votre application, utilisez le mode WebView :

```swift theme={"system"}
SezzleSDK.shared.startCheckout(
    checkout,
    from: self,
    delegate: self,
    mode: .webView
)
```

<Tabs>
  <Tab title="Navigateur système (par défaut)">
    <Frame>
      <img src="https://mintcdn.com/sezzle/klJ95KzsWuUWpHvl/images/docs/guides/mobile/ios-system-browser-checkout.png?fit=max&auto=format&n=klJ95KzsWuUWpHvl&q=85&s=afe3f023e26e05c3ac879c3ef4bbd009" alt="System Browser" width="1206" height="2622" data-path="images/docs/guides/mobile/ios-system-browser-checkout.png" />
    </Frame>
  </Tab>

  <Tab title="WebView">
    <Frame>
      <img src="https://mintcdn.com/sezzle/klJ95KzsWuUWpHvl/images/docs/guides/mobile/ios-webview-checkout.png?fit=max&auto=format&n=klJ95KzsWuUWpHvl&q=85&s=4a5606d37ee85f0616ced7ba1ff440a8" alt="WebView" width="1206" height="2622" data-path="images/docs/guides/mobile/ios-webview-checkout.png" />
    </Frame>
  </Tab>
</Tabs>

| Mode             | Avantages                                        | Inconvénients                                                      |
| ---------------- | ------------------------------------------------ | ------------------------------------------------------------------ |
| `.systemBrowser` | Sécurisé, partage les cookies Safari, recommandé | Bref changement de contexte                                        |
| `.webView`       | Reste dans l'application                         | Pas de partage de cookies, l'utilisateur se connecte à chaque fois |

### Appareils multi-utilisateurs — effacement de la session Sezzle à la déconnexion

Le `WKWebsiteDataStore.default()` est un store persistant unique à l'échelle de l'application, hérité par chaque WebView avec la configuration par défaut. Les cookies définis lors du paiement `.webView` d'un utilisateur (jetons d'authentification, identifiants de session) persistent entre les utilisateurs sur le même appareil — ainsi, si votre application prend en charge plusieurs utilisateurs (par exemple, un flux de déconnexion/connexion sur un appareil partagé), la première tentative BNPL de l'utilisateur suivant peut reprendre la session Sezzle de l'utilisateur précédent et exposer son état (refus de limite de crédit, etc.) au mauvais client.

À partir de `1.2.2`, appelez `SezzleSDK.shared.clearWebViewData()` depuis votre **flux de déconnexion** pour effacer les cookies et le stockage Web de Sezzle avant que l'utilisateur suivant ne se connecte :

```swift theme={"system"}
func onUserLogout() {
    // ...clear your own session state...
    SezzleSDK.shared.clearWebViewData()
}

// Or with a completion handler if you need to know when it's done:
SezzleSDK.shared.clearWebViewData {
    // safe to start a new Sezzle checkout as a different user now
}
```

L'effacement est limité aux domaines propres à Sezzle — vos autres cookies et stockage Web ne sont pas affectés. Peut être appelé de manière répétée en toute sécurité ; peut être appelé en toute sécurité même si aucun paiement Sezzle n'a jamais été effectué. L'opération est asynchrone ; le gestionnaire de complétion optionnel se déclenche sur l'acteur principal.

`.systemBrowser` le mode partage les cookies avec Safari via `ASWebAuthenticationSession` et n'est pas affecté — si vos utilisateurs ont besoin de les effacer, ils doivent le faire directement dans Safari.

## 6. Mode sombre

Le SDK s'adapte automatiquement au paramètre d'apparence de l'appareil. Le widget promotionnel, la modale d'acomptes et la modale de paiement prennent tous en charge le mode sombre.

<Tabs>
  <Tab title="Clair">
    <Frame>
      <img src="https://mintcdn.com/sezzle/klJ95KzsWuUWpHvl/images/docs/guides/mobile/ios-product-page-light.png?fit=max&auto=format&n=klJ95KzsWuUWpHvl&q=85&s=00fc0f3d1283f897c0dbf172c327e093" alt="Light Mode" width="1206" height="2622" data-path="images/docs/guides/mobile/ios-product-page-light.png" />
    </Frame>
  </Tab>

  <Tab title="Sombre">
    <Frame>
      <img src="https://mintcdn.com/sezzle/klJ95KzsWuUWpHvl/images/docs/guides/mobile/ios-product-page-dark.png?fit=max&auto=format&n=klJ95KzsWuUWpHvl&q=85&s=ad32c685164f0e32c29528a325bbf47e" alt="Dark Mode" width="1206" height="2622" data-path="images/docs/guides/mobile/ios-product-page-dark.png" />
    </Frame>
  </Tab>
</Tabs>

Si vous avez besoin de forcer un style spécifique (par exemple, votre application ne suit pas le paramètre système) :

```swift theme={"system"}
let promoView = SezzlePromotionalView(
    amountInCents: 9999,
    style: .dark,  // force dark style
    presentingFrom: self
)
```

## 7. Gestion des erreurs

Toutes les erreurs sont transmises via `SezzleCheckoutDelegate.checkoutDidFail(error:)` :

| Erreur                           | Quand                                              | Action suggérée                          |
| -------------------------------- | -------------------------------------------------- | ---------------------------------------- |
| `.notConfigured`                 | `SezzleSDK.shared.configure()` n'a pas été appelé  | Appeler `configure()` dans `AppDelegate` |
| `.networkError`                  | Pas d'internet, délai d'attente dépassé, échec DNS | Afficher une option de réessai           |
| `.apiError(statusCode, message)` | L'API Sezzle a retourné une erreur                 | Vérifier le code de statut et le message |
| `.browserDismissed`              | L'utilisateur a fermé le navigateur/WebView        | Retourner à la page produit              |
| `.invalidResponse`               | Format de réponse inattendu                        | Contacter le support Sezzle              |

## 8. Intégration pilotée par le serveur

Pour les marchands plus importants qui préfèrent une intégration entièrement pilotée par le serveur — sans clé publique sur l'appareil, le backend gérant la création de session, la capture et les remboursements — utilisez la surcharge alternative `startCheckout` introduite dans `1.2.0`.

### Fonctionnement

Votre backend crée la session de paiement via [`POST /v2/session`](/fr/docs/api/core/sessions/postv2session) avec des URLs de rappel choisies par le marchand, puis transmet `order.checkout_url` ainsi que ces URLs à l'application. Le SDK ouvre l'URL, intercepte la navigation vers vos URLs de rappel, et rapporte le résultat via `SezzleCheckoutDelegate.checkoutDidComplete(result:)` avec l'URL de rappel complète — vous pouvez ainsi encoder votre propre état dans la chaîne de requête et le récupérer à la complétion.

```mermaid theme={"system"}
sequenceDiagram
    participant App as Merchant App
    participant Backend as Merchant Backend
    participant SDK as Sezzle SDK
    participant API as Sezzle API

    App->>Backend: 1. Request checkout
    Backend->>API: 2. POST /v2/session (with merchant callback URLs)
    API-->>Backend: order.uuid + order.checkout_url
    Backend-->>App: 3. checkout_url + callback URLs
    App->>SDK: 4. startCheckout(checkoutURL:completeURL:cancelURL:…)
    SDK-->>App: 5. checkoutDidComplete(result.callbackURL)
    App->>Backend: 6. Map callback URL state → orderUUID
    Backend->>API: 7. Capture payment
```

### Étape 1 — Le backend crée la session

Choisissez les URLs de rappel que vous souhaitez — un schéma personnalisé comme `yourapp-sezzle://...` ou des liens profonds HTTPS. Vous pouvez encoder l'état dans la chaîne de requête (par exemple `yourapp-sezzle://done?orderRef=12345`) et le récupérer depuis le rappel du SDK.

Persister `order.uuid` côté serveur ; l'application n'a besoin que de `order.checkout_url` ainsi que des deux URLs de rappel.

<Warning>
  **Ne pas mettre de PII, de jetons d'authentification, ni quoi que ce soit de sensible dans la chaîne de requête de l'URL de rappel.** L'URL de rappel est rendue dans le navigateur et peut être journalisée. Utilisez des références opaques (un `orderRef` aléatoire mappé côté serveur) — jamais l'e-mail, le téléphone, les données de paiement ou les jetons de session du client.

  Les schémas d'URL personnalisés ne sont pas non plus **exclusifs** — une autre application installée sur l'appareil peut enregistrer le même schéma et intercepter le rappel. Pour une sécurité maximale en production, utilisez les **Universal Links** (liens profonds HTTPS vérifiés) avec le mode `.webView` — ils sont liés à un domaine que vous contrôlez, de sorte que d'autres applications ne peuvent pas les revendiquer.
</Warning>

### Étape 2 — L'application présente le paiement

```swift theme={"system"}
SezzleSDK.shared.startCheckout(
    checkoutURL: URL(string: checkoutURL)!,                              // from order.checkout_url (String → URL)
    completeURL: URL(string: "yourapp-sezzle://checkout/done")!,         // matches your server's complete_url.href
    cancelURL:   URL(string: "yourapp-sezzle://checkout/cancelled")!,    // matches your server's cancel_url.href
    from: self,
    delegate: self,
    mode: .webView   // or .systemBrowser
)
```

`SezzleSDK.shared.configure(publicKey:)` est **non** requis pour ce flux — il n'y a rien à authentifier pour le SDK.

### Étape 3 — Lire le résultat

```swift theme={"system"}
func checkoutDidComplete(result: SezzleCheckoutResult) {
    guard let callbackURL = result.callbackURL else { return }
    let orderRef = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false)?
        .queryItems?
        .first(where: { $0.name == "orderRef" })?
        .value
    // Look up orderRef in your backend, then call /v2/order/{order.uuid}/capture
}
```

### Notes

* **`ASWebAuthenticationSession` nécessite un schéma d'URL personnalisé** pour le rappel (paramètre `callbackURLScheme:`). Les rappels HTTPS ne sont pas acceptés par l'API de session d'authentification. Pour les liens profonds basés sur HTTPS (par exemple, pris en charge par Universal Links), utilisez le mode `.webView` — il intercepte la navigation directement via `WKNavigationDelegate` et fonctionne avec n'importe quel schéma.
* **Faites correspondre vos URLs.** Quelles que soient les URLs que votre backend a transmises en tant que `complete_url.href` / `cancel_url.href`, transmettez les mêmes URLs à `startCheckout`. Le SDK effectue la correspondance sur le schéma + l'hôte + le chemin ; les paramètres de requête de l'URL entrante sont lus par vous.
* **`order.uuid` réside sur votre serveur.** Il n'est pas dans le `checkout_url` et n'est pas renvoyé — votre backend le possède déjà depuis la réponse de création de session.

## 9. Tests

Utilisez l'environnement sandbox pour les tests :

```swift theme={"system"}
SezzleSDK.shared.configure(
    publicKey: "sz_pub_your_sandbox_key",
    environment: .sandbox
)
```

Utilisez les [données de test](/fr/docs/api/test-cards) pour effectuer des paiements de test en sandbox.

<Warning>
  Passez à `.production` et à votre clé publique de production avant de publier sur l'App Store.
</Warning>
