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

# SDK Dart / Flutter

> Installez et utilisez le SDK Dart LigdiCash dans vos applications Flutter iOS et Android.

Le SDK Dart LigdiCash est conçu pour Flutter. Il utilise les conventions Dart — named parameters, enums, `Future<>` — et s'intègre naturellement dans vos widgets et services.

## Installation

Ajoutez la dépendance dans votre `pubspec.yaml` :

```yaml pubspec.yaml theme={null}
dependencies:
  ligdicash: ^1.0.2
```

Puis installez :

```bash theme={null}
flutter pub get
```

**Prérequis :** Dart SDK ≥ 3.4.1 / Flutter ≥ 3.x.

## Initialisation

```dart Dart theme={null}
import 'package:ligdicash/ligdicash.dart';

final client = Ligdicash(
  apikey: '{API_KEY}',
  authToken: '{AUTH_TOKEN}',
  platform: PlatformType.live,
);
```

Obtenez votre `apikey` et votre `authToken` depuis le [dashboard LigdiCash](https://dashboard.ligdicash.com) en créant un projet API. Stockez-les dans vos variables d'environnement, jamais en dur dans le code Flutter.

***

## Payin avec redirection

Le client est redirigé vers la page de paiement hébergée par LigdiCash dans une WebView. C'est le flux recommandé sur mobile.

```dart Dart theme={null}
// 1. Créer la facture
final invoice = client.Invoice(
  currency: 'xof',
  description: 'Commande #ORD-20240512',
  customerFirstname: 'Amadou',
  customerLastname: 'Ouédraogo',
  customerEmail: 'amadou@exemple.com',
  storeName: 'MaSuperBoutique',
  storeWebsiteUrl: 'https://masuperboutique.com',
);

// 2. Ajouter les articles
invoice.addItem(
  name: 'Chemise kente',
  description: 'Taille M',
  quantity: 2,
  unitPrice: 15000,
);
invoice.addItem(
  name: 'Frais de livraison',
  description: '',
  quantity: 1,
  unitPrice: 1500,
);

// 3. Lancer le paiement
final response = await invoice.payWithRedirection(
  returnUrl: 'https://masuperboutique.com/commande/succes',
  cancelUrl: 'https://masuperboutique.com/commande/annulation',
  callbackUrl: 'https://backend.masuperboutique.com/ligdicash/callback',
  customData: {'transaction_id': 'ORD-20240512'},
);

// 4. Ouvrir la WebView avec l'URL de paiement
final paymentUrl = response.responseText;
```

<Warning>
  Sur Flutter, ouvrez `paymentUrl` dans une **WebView native** (package `webview_flutter`). Ne jamais l'afficher dans un `WebView` basé sur iframe HTML — LigdiCash le bloque.
</Warning>

<Tip>
  Détectez l'URL de retour (`returnUrl` / `cancelUrl`) dans le callback `onNavigationRequest` de la WebView pour la fermer automatiquement et reprendre le flux de l'application.
</Tip>

<Tip>
  Laissez toujours `customer` absent dans le payin avec redirection. Si vous passez un numéro, LigdiCash filtre la page de paiement pour ne montrer que les opérateurs de ce numéro.
</Tip>

***

## Payin sans redirection

Le client paie directement depuis votre interface Flutter. Vous devez collecter son numéro de téléphone et, selon l'opérateur, son code OTP.

```dart Dart theme={null}
// 1. Créer la facture
final invoice = client.Invoice(
  currency: 'xof',
  description: 'Commande #ORD-20240512',
  customerFirstname: 'Amadou',
  customerLastname: 'Ouédraogo',
  customerEmail: 'amadou@exemple.com',
  storeName: 'MaSuperBoutique',
  storeWebsiteUrl: 'https://masuperboutique.com',
);
invoice.addItem(
  name: 'Chemise kente',
  description: 'Taille M',
  quantity: 2,
  unitPrice: 15000,
);

// 2. Lancer le paiement (avec OTP fourni par le client)
final response = await invoice.payWithoutRedirection(
  otp: '123456',            // Code OTP saisi par le client
  customer: '22670123456',  // Numéro du client, sans + ni espaces
  callbackUrl: 'https://backend.masuperboutique.com/ligdicash/callback',
  customData: {'transaction_id': 'ORD-20240512'},
);

// 3. Stocker le token pour vérification ultérieure
final token = response.token;
```

<Note>
  Le mode OTP varie selon l'opérateur. Par exemple, pour un opérateur en mode USSD, le client génère son OTP sur son téléphone **avant** que vous ne soumetttiez. Pour un opérateur en mode approbation (ex. Moov Africa), envoyez `otp: ''` — le client approuve directement sur son application. Consultez la [page de l'opérateur](/api-paiement/payin-sans-redirect/introduction) concerné.
</Note>

***

## Payout

Envoyez de l'argent vers un client — remboursement, gain, salaire.

### Vers le wallet LigdiCash du client

```dart Dart theme={null}
final withdrawal = client.Withdrawal(
  amount: 5000,
  description: 'Remboursement commande ORD-20240510',
  customer: '22670123456',
);

final response = await withdrawal.send(
  type: WithdrawalType.client,
  toWallet: false,  // false = virement automatique vers le mobile money lié
  callbackUrl: 'https://backend.masuperboutique.com/ligdicash/callback-payout',
  customData: {'transaction_id': 'REFUND-20240512'},
);

final token = response.token;
```

### Directement vers le mobile money

```dart Dart theme={null}
final response = await withdrawal.send(
  type: WithdrawalType.merchant,  // Payout direct, sans wallet intermédiaire
  callbackUrl: 'https://backend.masuperboutique.com/ligdicash/callback-payout',
  customData: {'transaction_id': 'PAY-20240512'},
);
```

<Note>
  `WithdrawalType.client` utilise `POST /pay/v01/withdrawal/create` (via wallet LigdiCash). `WithdrawalType.merchant` utilise `POST /pay/v01/straight/payout` (mobile money direct, plus lent). Voir [Payout — Introduction](/api-paiement/payout/introduction).
</Note>

***

## Vérification de statut

Appelez `getTransaction` avec le token stocké à la **création** (pas le token du callback, qui est différent).

```dart Dart theme={null}
final token = 'eyJ0eXAiOiJ...';  // Token retourné lors de la création

// Payin
final transaction = await client.getTransaction(
  token: token,
  type: TransactionType.payin,
);

// Payout client (withdrawal/create)
// final transaction = await client.getTransaction(
//   token: token,
//   type: TransactionType.clientPayout,
// );

if (transaction.status == 'completed') {
  // Livrer la commande / valider le paiement
} else if (transaction.status == 'pending') {
  // Paiement en cours — relancer dans quelques secondes
} else {
  // Paiement échoué ou annulé
}
```

**Valeurs de `TransactionType` :**

| Valeur                         | Endpoint vérifié                         |
| ------------------------------ | ---------------------------------------- |
| `TransactionType.payin`        | `GET /redirect/checkout-invoice/confirm` |
| `TransactionType.clientPayout` | `GET /withdrawal/confirm`                |

**Champs disponibles sur `transaction` :**

| Propriété      | Type                   | Description                                   |
| -------------- | ---------------------- | --------------------------------------------- |
| `status`       | `String`               | `"completed"`, `"pending"`, `"cancelled"`     |
| `responseCode` | `String`               | `"00"` succès, `"01"` échec                   |
| `amount`       | `double`               | Montant de la transaction                     |
| `operatorId`   | `String`               | Identifiant de l'opérateur                    |
| `operatorName` | `String`               | Nom de l'opérateur                            |
| `customer`     | `String`               | Numéro du client                              |
| `token`        | `String`               | Token de la transaction                       |
| `customData`   | `Map<String, dynamic>` | Données personnalisées envoyées à la création |

<Warning>
  Ne livrez jamais une commande uniquement sur la base d'un callback entrant. Appelez toujours `getTransaction` avec le token stocké à la création pour confirmer le statut côté serveur LigdiCash. Voir [Sécurisation du callback](/api-paiement/callback/securisation).
</Warning>

***

## Gestion des erreurs

```dart Dart theme={null}
try {
  final response = await invoice.payWithRedirection(
    returnUrl: 'https://masuperboutique.com/succes',
    cancelUrl: 'https://masuperboutique.com/annulation',
    callbackUrl: 'https://backend.masuperboutique.com/callback',
    customData: {'transaction_id': 'ORD-20240512'},
  );

  if (response.responseCode != '00') {
    // Erreur retournée par l'API — consultez response.wiki
    debugPrint('Erreur API: ${response.responseText}');
  }
} catch (e) {
  // Erreur réseau ou exception inattendue
  debugPrint('Erreur: $e');
}
```

<Note>
  Vérifiez `response.responseCode` après chaque appel : `"00"` indique un succès, `"01"` une erreur. En cas d'erreur, consultez `response.wiki` pour obtenir l'URL de détail des sous-codes.
</Note>

***

## Liens utiles

* [Guide — Intégration mobile Flutter](/guides/quickstart-mobile)
* [Payin avec redirection — Integration mobile](/api-paiement/payin-redirect/integration-mobile)
* [Payout — Introduction](/api-paiement/payout/introduction)
* [Sécurisation du callback](/api-paiement/callback/securisation)
* [Pattern transaction\_id](/concepts/transaction-id-pattern)
* [Dépôt GitHub ligdicash-dart](https://github.com/Ligdicash/ligdicash-dart)
