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

# Guide d'intégration rapide

> Intégrez l'API Remita en 5 étapes et effectuez votre première transaction mobile money.

## Prérequis

Avant de commencer, assurez-vous d'avoir :

* Vos credentials Remita : `username`, `password`, `apiKey`, `apiId`
* Un serveur HTTPS capable de recevoir les callbacks webhook
* Un UUID v4 généré côté serveur pour chaque transaction (`externalId`)

***

## Étape 1 — Obtenir un token d'accès

Appelez `POST /public/access_token` avec vos identifiants. Stockez le `access_token` et le `refresh_token` retournés.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.remita.cm/public/access_token \
    -H "Content-Type: application/json" \
    -d '{
      "username": "votre@email.com",
      "password": "votre_mot_de_passe"
    }'
  ```

  ```javascript JavaScript theme={null}
  async function getAccessToken(username, password) {
      const response = await fetch("https://api.remita.cm/public/access_token", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ username, password })
      });
      return await response.json();
  }
  ```

  ```python Python theme={null}
  import requests

  def get_access_token(username: str, password: str) -> dict:
      response = requests.post(
          "https://api.remita.cm/public/access_token",
          json={"username": username, "password": password}
      )
      response.raise_for_status()
      return response.json()

  token_data = get_access_token("votre@email.com", "votre_mot_de_passe")
  access_token = token_data["access_token"]
  refresh_token = token_data["refresh_token"]
  ```

  ```php PHP theme={null}
  <?php
  function getAccessToken(string $username, string $password): array {
      $ch = curl_init('https://api.remita.cm/public/access_token');
      curl_setopt_array($ch, [
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_POST           => true,
          CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
          CURLOPT_POSTFIELDS     => json_encode(compact('username', 'password')),
      ]);
      $body = curl_exec($ch);
      curl_close($ch);
      return json_decode($body, true);
  }

  $tokenData   = getAccessToken('votre@email.com', 'votre_mot_de_passe');
  $accessToken = $tokenData['access_token'];
  ```

  ```java Java theme={null}
  public void authenticate(String username, String password) throws Exception {
      String body = String.format(
          "{\"username\":\"%s\",\"password\":\"%s\"}", username, password
      );
      HttpClient client = HttpClient.newHttpClient();
      HttpRequest request = HttpRequest.newBuilder()
          .uri(URI.create("https://api.remita.cm/public/access_token"))
          .header("Content-Type", "application/json")
          .POST(HttpRequest.BodyPublishers.ofString(body))
          .build();
      HttpResponse<String> response = client.send(request,
          HttpResponse.BodyHandlers.ofString());
      System.out.println(response.body());
  }
  ```
</CodeGroup>

```json Réponse theme={null}
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600
}
```

<Tip>
  Le token expire après `expires_in` secondes. Appelez `POST /public/refresh_token` avec le `refreshToken` pour le renouveler sans redemander les identifiants.
</Tip>

***

## Étape 2 — Initier une collecte

Une **collecte** débite le compte mobile money d'un client et crédite votre compte Remita.

| Client           | `transferMethod` |
| ---------------- | ---------------- |
| Orange Money CM  | `OMCM`           |
| MTN Mobile Money | `MOMOCM`         |

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.remita.cm/api/v1/transaction/collect \
    -H "Content-Type: application/json" \
    -H "apiKey: YOUR_API_KEY" \
    -H "apiId: YOUR_API_ID" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
    -d '{
      "transferMethod": "OMCM",
      "customerName": "Jean Dupont",
      "externalId": "550e8400-e29b-41d4-a716-446655440000",
      "phoneNumber": "237690000000",
      "amount": 5000,
      "webhookUrl": "https://votre-serveur.com/remita/callback",
      "countryName": "CAMEROON"
    }'
  ```

  ```javascript JavaScript theme={null}
  async function initiateCollect(accessToken, apiKey, apiId) {
      const payload = {
          transferMethod: "OMCM",
          customerName: "Jean Dupont",
          externalId: crypto.randomUUID(),
          phoneNumber: "237690000000",
          amount: 5000,
          webhookUrl: "https://votre-serveur.com/remita/callback",
          countryName: "CAMEROON"
      };

      const response = await fetch("https://api.remita.cm/api/v1/transaction/collect", {
          method: "POST",
          headers: {
              "Content-Type": "application/json",
              "apiKey": apiKey,
              "apiId": apiId,
              "Authorization": `Bearer ${accessToken}`
          },
          body: JSON.stringify(payload)
      });
      return await response.json();
  }
  ```

  ```python Python theme={null}
  import requests, uuid

  def initiate_collect(access_token: str, api_key: str, api_id: str) -> dict:
      headers = {
          "Content-Type": "application/json",
          "apiKey": api_key,
          "apiId": api_id,
          "Authorization": f"Bearer {access_token}",
      }
      payload = {
          "transferMethod": "OMCM",
          "customerName": "Jean Dupont",
          "externalId": str(uuid.uuid4()),
          "phoneNumber": "237690000000",
          "amount": 5000,
          "webhookUrl": "https://votre-serveur.com/remita/callback",
          "countryName": "CAMEROON",
      }
      response = requests.post(
          "https://api.remita.cm/api/v1/transaction/collect",
          headers=headers, json=payload
      )
      response.raise_for_status()
      return response.json()
  ```

  ```php PHP theme={null}
  <?php
  function initiateCollect(string $accessToken, string $apiKey, string $apiId): array {
      $payload = [
          'transferMethod' => 'OMCM',
          'customerName'   => 'Jean Dupont',
          'externalId'     => sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
              mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
              mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
              mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
          ),
          'phoneNumber'    => '237690000000',
          'amount'         => 5000,
          'webhookUrl'     => 'https://votre-serveur.com/remita/callback',
          'countryName'    => 'CAMEROON',
      ];
      $ch = curl_init('https://api.remita.cm/api/v1/transaction/collect');
      curl_setopt_array($ch, [
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_POST           => true,
          CURLOPT_HTTPHEADER     => [
              'Content-Type: application/json',
              "apiKey: $apiKey", "apiId: $apiId",
              "Authorization: Bearer $accessToken",
          ],
          CURLOPT_POSTFIELDS => json_encode($payload),
      ]);
      $body = curl_exec($ch);
      curl_close($ch);
      return json_decode($body, true);
  }
  ```
</CodeGroup>

```json Réponse theme={null}
{
  "transactionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "externalId": "550e8400-e29b-41d4-a716-446655440000",
  "transferMethod": "OMCM",
  "customerName": "Jean Dupont",
  "customerPhone": "237690000000",
  "payToken": "abc123xyz",
  "amount": 5000,
  "feesSystem": 50,
  "feesApp": 25,
  "transactionStatus": "PENDING"
}
```

<Note>
  Conservez le `transactionId` — il est nécessaire pour vérifier le statut et traiter le webhook.
</Note>

***

## Étape 3 — Recevoir le résultat via webhook

Dès que la transaction atteint un état final (`SUCCESS` ou `FAILED`), Remita envoie un `POST` vers votre `webhookUrl`.

<CodeGroup>
  ```java Java (Spring Boot) theme={null}
  @RestController
  @RequestMapping("/remita")
  public class RemitaWebhookController {

      @PostMapping("/callback")
      public ResponseEntity<String> handleCallback(@RequestBody Map<String, Object> payload) {
          String transactionId = String.valueOf(payload.get("transactionId"));
          String externalId    = String.valueOf(payload.get("externalId"));
          String status        = String.valueOf(payload.get("status"));

          if ("SUCCESS".equals(status)) {
              System.out.println("Paiement reçu pour " + externalId);
              // Créditer le compte client, envoyer confirmation...
          } else if ("FAILED".equals(status)) {
              System.err.println("Paiement échoué pour " + externalId);
          }

          return ResponseEntity.ok("OK");
      }
  }
  ```

  ```python Python (FastAPI) theme={null}
  from fastapi import FastAPI, Request
  from fastapi.responses import PlainTextResponse

  app = FastAPI()

  @app.post("/remita/callback")
  async def remita_callback(request: Request):
      payload = await request.json()
      external_id = payload.get("externalId")
      status      = payload.get("status")

      if status == "SUCCESS":
          print(f"Paiement reçu — externalId: {external_id}")
      elif status == "FAILED":
          print(f"Paiement échoué — externalId: {external_id}")

      # IMPORTANT : toujours répondre 200 dans les 5 secondes
      return PlainTextResponse("OK", status_code=200)
  ```

  ```php PHP theme={null}
  <?php
  $payload = json_decode(file_get_contents('php://input'), true);
  if (!$payload) { http_response_code(400); exit; }

  $externalId = $payload['externalId'] ?? null;
  $status     = $payload['status']     ?? null;

  if ($status === 'SUCCESS') {
      error_log("Paiement reçu — externalId: $externalId");
  } elseif ($status === 'FAILED') {
      error_log("Paiement échoué — externalId: $externalId");
  }

  http_response_code(200);
  echo 'OK';
  ```

  ```javascript Node.js (Express) theme={null}
  app.post('/remita/callback', (req, res) => {
      const { transactionId, externalId, status, amount } = req.body;

      if (status === 'SUCCESS') {
          console.log(`Paiement reçu — externalId: ${externalId}, montant: ${amount}`);
      } else if (status === 'FAILED') {
          console.error(`Paiement échoué — externalId: ${externalId}`);
      }

      // Toujours répondre 200 dans les 5 secondes
      res.status(200).send('OK');
  });
  ```
</CodeGroup>

<Warning>
  Votre endpoint webhook doit retourner `HTTP 200` dans les **5 secondes**. Déléguez tout traitement lourd à une file de tâches et répondez immédiatement.
</Warning>

***

## Étape 4 — Vérifier le statut manuellement (polling)

Si vous n'avez pas reçu le webhook, vérifiez le statut avec le `transactionId` :

<CodeGroup>
  ```python Python theme={null}
  import requests, time

  def poll_transaction_status(
      transaction_id: str, access_token: str, api_key: str, api_id: str,
      max_attempts: int = 10, interval_seconds: int = 5
  ) -> str:
      headers = {
          "apiKey": api_key, "apiId": api_id,
          "Authorization": f"Bearer {access_token}",
      }
      for attempt in range(max_attempts):
          data = requests.post(
              "https://api.remita.cm/api/v1/transaction/transaction-status",
              headers=headers, params={"id": transaction_id}
          ).json()
          status = data.get("status")
          print(f"Tentative {attempt + 1} — Statut: {status}")
          if status in ("SUCCESS", "FAILED"):
              return status
          time.sleep(interval_seconds)
      return "TIMEOUT"
  ```

  ```javascript JavaScript theme={null}
  async function pollTransactionStatus(transactionId, accessToken, apiKey, apiId) {
      const headers = {
          "apiKey": apiKey, "apiId": apiId,
          "Authorization": `Bearer ${accessToken}`
      };
      for (let i = 0; i < 10; i++) {
          const res = await fetch(
              `https://api.remita.cm/api/v1/transaction/transaction-status?id=${transactionId}`,
              { method: "POST", headers }
          );
          const data = await res.json();
          if (["SUCCESS", "FAILED"].includes(data.status)) return data.status;
          await new Promise(r => setTimeout(r, 5000));
      }
      return "TIMEOUT";
  }
  ```
</CodeGroup>

***

## Étape 5 — Initier un dépôt (optionnel)

Un **dépôt** envoie de l'argent depuis votre compte Remita vers le compte mobile money d'un bénéficiaire. La structure est identique à la collecte :

```bash theme={null}
POST /api/v1/transaction/deposit
# Même corps que /collect — seul le sens du flux change
```

***

## Référence rapide

| Action                  | Méthode | Endpoint                                              |
| ----------------------- | ------- | ----------------------------------------------------- |
| Obtenir un token        | POST    | `/public/access_token`                                |
| Renouveler le token     | POST    | `/public/refresh_token`                               |
| Initier une collecte    | POST    | `/api/v1/transaction/collect`                         |
| Initier un dépôt        | POST    | `/api/v1/transaction/deposit`                         |
| Vérifier le statut      | POST    | `/api/v1/transaction/transaction-status?id=<id>`      |
| Valider une transaction | POST    | `/api/v1/transaction/validateTransaction`             |
| Rejeter une transaction | POST    | `/api/v1/transaction/rejectTransaction`               |
| Lister les transactions | GET     | `/api/v1/transaction/getByApplicationProduct`         |
| Consulter les soldes    | GET     | `/api/v1/transaction/getByApplicationProductBalances` |

***

## Checklist avant mise en production

<Check>Tokens stockés de manière sécurisée (jamais en clair dans le code ou les logs)</Check>
<Check>`apiKey` jamais exposée côté client (frontend / mobile)</Check>
<Check>`externalId` unique UUID v4 par transaction</Check>
<Check>`transferMethod` cohérent avec `countryName`</Check>
<Check>Endpoint webhook retournant `HTTP 200` en moins de 5 secondes</Check>
<Check>Gestion du renouvellement automatique du token (refresh)</Check>
<Check>Mécanisme de polling en fallback si webhook non reçu</Check>
<Check>Logs de toutes les transactions (`externalId`, `transactionId`, statut)</Check>
