{
  "openapi": "3.0.3",
  "info": {
    "title": "API partenaire Instafuel",
    "version": "1.0.0",
    "description": "API machine des apporteurs d'affaires Instafuel.\n\nInstafuel est une plateforme ivoirienne de paiement carburant : les entreprises\nrèglent les pleins de leur flotte dans n'importe quelle station, quel que soit le\nmarketeur, via un wallet interne appelé **Fuelz**.\n\nUn **apporteur d'affaires** gère un portefeuille d'entreprises clientes. Cette API\nlui permet de piloter ce portefeuille depuis son propre système : lire les\ntransactions et les soldes, enrôler de nouvelles entreprises, provisionner les\ncomptes de ses clients et déclarer les versements qui alimentent leurs wallets.\n\n## Authentification\n\nToutes les requêtes portent une clé API dans l'en-tête `Authorization` :\n\n```\nAuthorization: Bearer ifp_live_a1b2c3…\n```\n\nLes clés sont créées depuis le portail partenaire. Le secret n'est affiché\n**qu'une seule fois**, à la création : il n'est pas stocké en clair et ne peut pas\nêtre relu. Perdu, il se remplace par une nouvelle clé.\n\nDeux environnements, distingués par le préfixe : `ifp_live_` et `ifp_test_`.\n\n## Portefeuille\n\nUne clé ne voit **que** les entreprises du portefeuille de son apporteur. Une\nentreprise hors portefeuille est **introuvable** (`404`), jamais « interdite » —\nl'API ne confirme pas l'existence de ressources qui ne vous concernent pas.\n\n## Droits\n\nChaque clé porte une liste de **scopes**. Une route dont le scope manque répond\n`403 PAPI_SCOPE_MISSING` en nommant le droit requis. Les scopes disponibles pour\nvotre compte sont plafonnés par Instafuel : `GET /v1/papi/me` vous dit à tout\nmoment ce que porte la clé utilisée.\n\n## Conventions\n\n- **Montants** : entiers en FCFA, jamais de flottant. 1 Fuelz = 1 FCFA.\n- **Dates** : chaînes ISO 8601 en UTC (`2026-08-31T14:03:00.000Z`).\n- **Succès** : `{ \"data\": … }`, plus `\"pagination\"` sur les listes.\n- **Erreurs** : `{ \"error\": { \"code\": \"CODE_STABLE\", \"message\": \"…\" } }`. Branchez\n  votre logique sur `code`, qui est stable ; `message` est en français et peut\n  évoluer.\n- **Pagination** : `?page=1&perPage=20`, `perPage` plafonné à 100.\n- **Idempotence** : toute écriture exige l'en-tête `X-Idempotency-Key`. Rejouée à\n  l'identique dans les 24 h, la requête renvoie la première réponse\n  (`X-Idempotent-Replay: true`) au lieu de créer un doublon. Avec un corps\n  différent, `409 IDEMPOTENCY_CONFLICT`.\n- **Débit** : limite par minute et par clé. Les réponses portent\n  `X-RateLimit-Limit`, `X-RateLimit-Remaining` et `X-RateLimit-Reset`.\n\n## Ce que l'API ne fait pas\n\n- **Créer une entreprise directement.** `POST /companies` ouvre une demande\n  d'approbation et répond `202`. Un opérateur Instafuel valide. Créer une personne\n  morale ouvre un wallet et une relation contractuelle : ce n'est pas un geste\n  automatisable par un tiers.\n- **Créditer un wallet.** `POST /companies/{id}/wallet/credit` **déclare** un\n  versement et répond `202`. Le solde ne bouge qu'après vérification de\n  l'encaissement par Instafuel.\n- **Notifier par webhook.** Aucun webhook n'existe à ce jour. Interrogez les\n  ressources concernées.\n",
    "contact": {
      "name": "Support partenaires Instafuel"
    },
    "license": {
      "name": "Propriétaire"
    }
  },
  "tags": [
    {
      "name": "Identité",
      "description": "Qui est cette clé, et que porte-t-elle."
    },
    {
      "name": "Entreprises",
      "description": "Le portefeuille — lecture, enrôlement, mise à jour."
    },
    {
      "name": "Comptes",
      "description": "Comptes web des entreprises clientes (pilotage de flotte)."
    },
    {
      "name": "Wallet",
      "description": "Soldes Fuelz, écritures et déclarations de versement."
    },
    {
      "name": "Transactions",
      "description": "Pleins réglés via Instafuel."
    },
    {
      "name": "Chauffeurs",
      "description": "Portefeuilles chauffeurs des entreprises du portefeuille."
    },
    {
      "name": "Alertes",
      "description": "Anomalies détectées sur les entreprises du portefeuille."
    },
    {
      "name": "Rapports",
      "description": "Agrégats du portefeuille."
    }
  ],
  "security": [
    {
      "PartnerApiKey": []
    }
  ],
  "paths": {
    "/v1/papi/me": {
      "get": {
        "tags": [
          "Identité"
        ],
        "operationId": "getKeyIdentity",
        "summary": "Identité de la clé",
        "description": "Renvoie l'apporteur associé à la clé, ses plafonds, et les droits que porte la\nclé utilisée. **Aucun scope requis** — c'est le premier appel à faire, et le\nmoyen de diagnostiquer un `403` de scope sans ouvrir un ticket.\n",
        "responses": {
          "200": {
            "description": "Identité de la clé",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/KeyIdentity"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "`FEATURE_DISABLED` — l'API partenaire n'est pas ouverte sur cette\nplateforme, ou `RESELLER_NOT_FOUND` si le compte apporteur a disparu\nentre la validation de la clé et la lecture.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/companies": {
      "get": {
        "tags": [
          "Entreprises"
        ],
        "operationId": "listCompanies",
        "summary": "Lister les entreprises du portefeuille",
        "description": "Scope requis : `COMPANIES_READ`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "search",
            "in": "query",
            "description": "Filtre sur le nom, insensible à la casse.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ACTIVE",
                "INACTIVE"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste paginée",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Company"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Entreprises"
        ],
        "operationId": "requestCompanyCreation",
        "summary": "Demander l'enrôlement d'une entreprise",
        "description": "Scope requis : `COMPANIES_WRITE`.\n\n**Répond `202`, pas `201`.** Aucune entreprise n'existe à l'issue de cet appel :\nune demande d'approbation est ouverte, qu'un opérateur Instafuel doit valider.\nLa demande expire au bout de 7 jours.\n\n`rccm` et `nif` sont obligatoires : sans immatriculation, la même entreprise\nréelle pourrait être enrôlée deux fois, avec deux wallets distincts.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyCreateRequest"
              },
              "example": {
                "name": "Transports Kouassi SARL",
                "email": "contact@kouassi.ci",
                "phoneNumber": "+2250700000099",
                "rccm": "CI-ABJ-2024-B-1234",
                "nif": "NIF-99887766",
                "headquartersAddress": "Zone 4C, Abidjan"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Demande enregistrée, en attente de validation Instafuel",
            "headers": {
              "X-Idempotent-Replay": {
                "$ref": "#/components/headers/IdempotentReplay"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ApprovalPending"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Doublon. `COMPANY_ALREADY_EXISTS` si une entreprise porte déjà ce nom, ce\nRCCM ou ce NIF ; `COMPANY_REQUEST_ALREADY_PENDING` si une demande est déjà\nen cours pour cette immatriculation ; `IDEMPOTENCY_CONFLICT` si la clé\nd'idempotence a servi avec un autre contenu.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/companies/{companyId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Entreprises"
        ],
        "operationId": "getCompany",
        "summary": "Lire une entreprise",
        "description": "Scope requis : `COMPANIES_READ`.",
        "responses": {
          "200": {
            "description": "Entreprise",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Company"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Entreprises"
        ],
        "operationId": "updateCompany",
        "summary": "Mettre à jour une entreprise",
        "description": "Scope requis : `COMPANIES_WRITE`.\n\nModification **partielle** : seuls les champs fournis sont écrits. Les champs\nacceptés sont `name`, `email`, `phoneNumber`, `rccm`, `nif` et\n`headquartersAddress` — tout autre champ est ignoré.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyUpdateRequest"
              },
              "example": {
                "phoneNumber": "+2250700000100",
                "headquartersAddress": "Cocody Riviera 3, Abidjan"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Entreprise mise à jour",
            "headers": {
              "X-Idempotent-Replay": {
                "$ref": "#/components/headers/IdempotentReplay"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Company"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/companies/{companyId}/users": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Comptes"
        ],
        "operationId": "listCompanyUsers",
        "summary": "Lister les comptes web d'une entreprise",
        "description": "Scope requis : `USERS_READ`.\n\nSeuls les comptes de pilotage de flotte (`FLEET_ADMINISTRATOR`, `DAF`) sont\nrenvoyés. Les chauffeurs relèvent de `GET /v1/papi/drivers`.\n",
        "responses": {
          "200": {
            "description": "Comptes de l'entreprise",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CompanyUser"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Comptes"
        ],
        "operationId": "createCompanyUser",
        "summary": "Créer un compte web chez une entreprise cliente",
        "description": "Scope requis : `USERS_WRITE`.\n\nLe compte reçoit un courriel d'activation contenant un lien à usage unique,\nvalable 72 h. Aucun mot de passe ne transite par l'API.\n\n**Les coordonnées doivent être celles de l'entreprise cliente.** Un email ou un\ntéléphone appartenant à un compte apporteur est refusé en\n`422 RESELLER_SELF_ASSIGNMENT` : un compte client donne accès à la surface de\ngestion de flotte de cette entreprise, qui n'est pas votre périmètre.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyUserCreateRequest"
              },
              "example": {
                "name": "Aminata Traoré",
                "email": "a.traore@kouassi.ci",
                "phoneNumber": "+2250700000123",
                "role": "DAF"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Compte créé, courriel d'activation envoyé",
            "headers": {
              "X-Idempotent-Replay": {
                "$ref": "#/components/headers/IdempotentReplay"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CompanyUser"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`EMAIL_ALREADY_EXISTS` ou `PHONE_ALREADY_EXISTS`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "`RESELLER_SELF_ASSIGNMENT` (coordonnées d'un compte apporteur),\n`RESELLER_USER_QUOTA_EXCEEDED` (plafond de comptes atteint),\n`ROLE_NOT_ALLOWED`, ou `VALIDATION_ERROR`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/companies/{companyId}/users/{userId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        },
        {
          "name": "userId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "patch": {
        "tags": [
          "Comptes"
        ],
        "operationId": "updateCompanyUser",
        "summary": "Mettre à jour un compte web",
        "description": "Scope requis : `USERS_WRITE`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompanyUserUpdateRequest"
              },
              "example": {
                "status": "INACTIVE"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Compte mis à jour",
            "headers": {
              "X-Idempotent-Replay": {
                "$ref": "#/components/headers/IdempotentReplay"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CompanyUser"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/companies/{companyId}/wallet": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Wallet"
        ],
        "operationId": "getCompanyWallet",
        "summary": "Solde du wallet d'une entreprise",
        "description": "Scope requis : `WALLET_READ`.\n\n`availableFcfa` = `balanceFcfa` − `heldFcfa`. Le montant retenu correspond aux\npleins pré-autorisés dont le volume réel n'est pas encore confirmé.\n",
        "responses": {
          "200": {
            "description": "Wallet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Wallet"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/companies/{companyId}/wallet/ledger": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "get": {
        "tags": [
          "Wallet"
        ],
        "operationId": "listLedgerEntries",
        "summary": "Écritures du wallet",
        "description": "Scope requis : `LEDGER_READ`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "$ref": "#/components/parameters/From"
          },
          {
            "$ref": "#/components/parameters/To"
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "CREDIT",
                "DEBIT",
                "REFUND",
                "HOLD",
                "RELEASE",
                "ADJUSTMENT"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Écritures paginées, de la plus récente à la plus ancienne",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LedgerEntry"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/companies/{companyId}/wallet/credit/proof": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "post": {
        "tags": [
          "Wallet"
        ],
        "operationId": "uploadCreditProof",
        "summary": "Téléverser une preuve de versement",
        "description": "Scope requis : `CREDIT_REQUEST_WRITE`.\n\n**Étape préalable obligatoire à toute demande de crédit** : celle-ci exige les\nidentifiants renvoyés ici. Jusqu'à 3 fichiers, 10 Mo chacun.\n\nSeul endpoint de l'API en `multipart/form-data`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  }
                },
                "required": [
                  "files"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Preuves enregistrées",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CreditProof"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`PROOF_NO_FILE` — aucun fichier reçu sous le champ `files`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "description": "`PROOF_TOO_LARGE` — fichier au-delà de 10 Mo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/companies/{companyId}/wallet/credit": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CompanyId"
        }
      ],
      "post": {
        "tags": [
          "Wallet"
        ],
        "operationId": "requestWalletCredit",
        "summary": "Déclarer un versement à créditer",
        "description": "Scope requis : `CREDIT_REQUEST_WRITE`.\n\n**Répond `202`, pas `200` : rien n'est crédité.** Vous déclarez qu'un versement\na eu lieu ; seul Instafuel constate l'encaissement et approuve. Le solde ne\nbouge qu'ensuite. La demande expire au bout de 7 jours.\n\nUne preuve est **obligatoire** — téléversez-la d'abord via\n`POST …/wallet/credit/proof` et reprenez les identifiants obtenus dans\n`proofIds`.\n\n`clientReference` est votre référence de versement (numéro de virement,\nidentifiant Mobile Money). Elle est préfixée côté serveur par votre identifiant\nd'apporteur, ce qui vous évite toute collision avec un autre partenaire.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreditRequestBody"
              },
              "example": {
                "amountFcfa": 2500000,
                "source": "BANK_TRANSFER",
                "clientReference": "VIR-2026-0831-004",
                "proofIds": [
                  "8f14e45f-ceea-467a-9f57-4f1f0e4d1a2b"
                ],
                "note": "Virement reçu le 31/08 sur le compte SGCI"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Déclaration enregistrée, en attente de validation Instafuel",
            "headers": {
              "X-Idempotent-Replay": {
                "$ref": "#/components/headers/IdempotentReplay"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ApprovalPending"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`PROOF_REQUIRED`, `WALLET_BLOCKED` ou `IDEMPOTENCY_KEY_MISSING`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`RESELLER_CREDIT_DISABLED` — le crédit wallet n'est pas ouvert sur votre\ncompte — ou `PAPI_SCOPE_MISSING`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "description": "`RESELLER_CREDIT_CAP_EXCEEDED` (plafond par opération),\n`RESELLER_DAILY_CAP_EXCEEDED` (plafond journalier, demandes en attente\ncomprises), ou `VALIDATION_ERROR`.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/wallets": {
      "get": {
        "tags": [
          "Wallet"
        ],
        "operationId": "listWallets",
        "summary": "Soldes de tout le portefeuille",
        "description": "Scope requis : `WALLET_READ`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ],
        "responses": {
          "200": {
            "description": "Wallets paginés",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Wallet"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/credit-requests": {
      "get": {
        "tags": [
          "Wallet"
        ],
        "operationId": "listCreditRequests",
        "summary": "Suivre vos déclarations de versement",
        "description": "Scope requis : `WALLET_READ` — suivre l'état de ses demandes est une lecture.\n\nNe renvoie que les demandes émises par votre organisation.\n",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING_APPROVAL",
                "APPROVED",
                "REJECTED",
                "EXPIRED"
              ]
            }
          },
          {
            "name": "companyId",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Demandes, de la plus récente à la plus ancienne",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CreditRequest"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/credit-requests/{requestId}": {
      "parameters": [
        {
          "name": "requestId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Wallet"
        ],
        "operationId": "getCreditRequest",
        "summary": "Lire une déclaration de versement",
        "description": "Scope requis : `WALLET_READ`.",
        "responses": {
          "200": {
            "description": "Demande",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/CreditRequest"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/transactions": {
      "get": {
        "tags": [
          "Transactions"
        ],
        "operationId": "listTransactions",
        "summary": "Lister les pleins du portefeuille",
        "description": "Scope requis : `TRANSACTIONS_READ`.\n\n`status` accepte plusieurs valeurs séparées par des virgules.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "companyId",
            "in": "query",
            "description": "Restreint à une entreprise du portefeuille. Hors portefeuille, `404`.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "status",
            "in": "query",
            "example": "CONFIRMED,CANCELED",
            "schema": {
              "type": "string"
            }
          },
          {
            "$ref": "#/components/parameters/From"
          },
          {
            "$ref": "#/components/parameters/To"
          }
        ],
        "responses": {
          "200": {
            "description": "Transactions paginées",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Transaction"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/transactions/{transactionId}": {
      "parameters": [
        {
          "name": "transactionId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "tags": [
          "Transactions"
        ],
        "operationId": "getTransaction",
        "summary": "Lire un plein",
        "description": "Scope requis : `TRANSACTIONS_READ`.",
        "responses": {
          "200": {
            "description": "Transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Transaction"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/drivers": {
      "get": {
        "tags": [
          "Chauffeurs"
        ],
        "operationId": "listDriverWallets",
        "summary": "Portefeuilles chauffeurs",
        "description": "Scope requis : `DRIVERS_READ`.\n\nRenvoie les soldes chauffeurs des entreprises du portefeuille. Contient des\ndonnées personnelles (nom, téléphone) : ce scope se demande en conscience.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "companyId",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "ACTIVE",
                "FROZEN",
                "CLOSED"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Portefeuilles chauffeurs paginés",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DriverWallet"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/alerts": {
      "get": {
        "tags": [
          "Alertes"
        ],
        "operationId": "listAlerts",
        "summary": "Alertes des entreprises du portefeuille",
        "description": "Scope requis : `ALERTS_READ`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "companyId",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "OPEN",
                "ACKNOWLEDGED",
                "DISMISSED",
                "RESOLVED"
              ]
            }
          },
          {
            "name": "severity",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "INFO",
                "WARNING",
                "CRITICAL"
              ]
            }
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Alertes paginées",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Alert"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/papi/reports/portfolio-summary": {
      "get": {
        "tags": [
          "Rapports"
        ],
        "operationId": "getPortfolioSummary",
        "summary": "Synthèse du portefeuille",
        "description": "Scope requis : `REPORTS_READ`.\n\nAgrégats sur une période — 30 derniers jours par défaut. Ne comptabilise que\nles transactions confirmées.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/From"
          },
          {
            "$ref": "#/components/parameters/To"
          }
        ],
        "responses": {
          "200": {
            "description": "Synthèse",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/PortfolioSummary"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "PartnerApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Clé API partenaire : `Authorization: Bearer ifp_live_…`.\n\nLe secret n'est affiché qu'à la création de la clé et n'est jamais relisible.\nUne clé compromise se révoque depuis le portail partenaire, avec effet immédiat.\n"
      }
    },
    "parameters": {
      "CompanyId": {
        "name": "companyId",
        "in": "path",
        "required": true,
        "description": "Identifiant d'une entreprise de votre portefeuille.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PerPage": {
        "name": "perPage",
        "in": "query",
        "description": "Plafonné à 100.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 20
        }
      },
      "From": {
        "name": "from",
        "in": "query",
        "description": "Borne inférieure, date ISO 8601.",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "To": {
        "name": "to",
        "in": "query",
        "description": "Borne supérieure, date ISO 8601.",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "IdempotencyKey": {
        "name": "X-Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Valeur unique par opération — un UUID convient. Rejouée à l'identique dans les\n24 h, la requête renvoie la première réponse au lieu de créer un doublon.\n",
        "schema": {
          "type": "string",
          "maxLength": 200
        }
      }
    },
    "headers": {
      "RateLimitLimit": {
        "description": "Requêtes autorisées sur la fenêtre courante, pour cette clé.",
        "schema": {
          "type": "integer",
          "example": 600
        }
      },
      "RateLimitRemaining": {
        "description": "Requêtes restantes sur la fenêtre courante.",
        "schema": {
          "type": "integer",
          "example": 583
        }
      },
      "RateLimitReset": {
        "description": "Horodatage Unix (secondes) de la remise à zéro du compteur.",
        "schema": {
          "type": "integer",
          "example": 1788171600
        }
      },
      "IdempotentReplay": {
        "description": "Présent et valant `true` quand la réponse est le rejeu d'une requête déjà\ntraitée : rien n'a été créé ni modifié par cet appel-ci.\n",
        "schema": {
          "type": "string",
          "enum": [
            "true"
          ],
          "example": "true"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Requête malformée — `INVALID_PATH_PARAM` (identifiant de chemin non entier),\n`INVALID_QUERY_PARAM` (filtre mal formé : entier ou date ISO 8601 attendus),\n`IDEMPOTENCY_KEY_MISSING` (en-tête `X-Idempotency-Key` absent sur une écriture).\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Clé absente, invalide, révoquée ou expirée — `PAPI_KEY_MISSING`,\n`PAPI_KEY_INVALID`, `PAPI_KEY_REVOKED`, `PAPI_KEY_EXPIRED`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "PAPI_KEY_INVALID",
                "message": "Clé API invalide."
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "`PAPI_SCOPE_MISSING` (la clé ne porte pas le droit requis),\n`PAPI_NOT_ENABLED` (accès API non activé sur votre compte),\n`PAPI_IP_FORBIDDEN` (adresse non autorisée pour cette clé),\n`RESELLER_INACTIVE` (compte apporteur inactif).\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "PAPI_SCOPE_MISSING",
                "message": "Cette clé ne porte pas le scope TRANSACTIONS_READ."
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Ressource introuvable — ou hors de votre portefeuille : l'API ne distingue pas\nles deux cas, et ne confirme donc jamais l'existence d'une ressource qui ne\nvous concerne pas.\n\nDeux autres causes portent le même statut : `FEATURE_DISABLED`, quand l'API\npartenaire n'est pas ouverte sur cette plateforme — tant qu'elle ne l'est pas,\nelle n'existe pas ; et `ENDPOINT_NOT_FOUND`, sur une URL qui n'existe pas.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Conflit — doublon métier ou clé d'idempotence réutilisée avec un autre contenu",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Corps invalide — `details` nomme les champs fautifs",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "VALIDATION_ERROR",
                "message": "Données invalides",
                "details": [
                  {
                    "field": "rccm",
                    "messages": [
                      "Le RCCM est obligatoire pour immatriculer une entreprise"
                    ]
                  }
                ]
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Limite de débit dépassée. Les en-têtes `X-RateLimit-Limit`,\n`X-RateLimit-Remaining` et `X-RateLimit-Reset` (epoch en secondes) indiquent\nquand réessayer.\n\nCes trois en-têtes accompagnent **toutes** les réponses de l'API, pas seulement\ncelle-ci : c'est ce qui vous permet de ralentir avant d'être coupé.\n",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "`INTERNAL_ERROR` — incident côté Instafuel. Le message ne porte jamais de détail\ntechnique. Réessayez avec un délai croissant, **en réutilisant la même clé\nd'idempotence** s'il s'agissait d'une écriture : c'est ce qui garantit qu'une\nopération éventuellement passée avant l'erreur ne sera pas exécutée deux fois.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": {
                "code": "INTERNAL_ERROR",
                "message": "Erreur interne"
              }
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "description": "Identifiant stable — branchez votre logique dessus."
              },
              "message": {
                "type": "string",
                "description": "Explication en français, susceptible d'évoluer."
              },
              "details": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "field": {
                      "type": "string"
                    },
                    "messages": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "error"
        ]
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "example": 1
          },
          "perPage": {
            "type": "integer",
            "example": 20
          },
          "total": {
            "type": "integer",
            "example": 137
          },
          "totalPages": {
            "type": "integer",
            "example": 7
          }
        }
      },
      "KeyIdentity": {
        "type": "object",
        "properties": {
          "reseller": {
            "type": "object",
            "properties": {
              "id": {
                "type": "integer",
                "example": 12
              },
              "ref": {
                "type": "string",
                "nullable": true,
                "example": "RSL-4A21C0FE"
              },
              "name": {
                "type": "string",
                "example": "Kouassi Partners"
              },
              "status": {
                "type": "string",
                "enum": [
                  "ACTIVE",
                  "INACTIVE"
                ]
              },
              "companiesCount": {
                "type": "integer",
                "example": 14
              },
              "walletCredit": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "type": "boolean"
                  },
                  "perOperationCapFcfa": {
                    "type": "integer",
                    "nullable": true,
                    "example": 5000000
                  },
                  "dailyCapFcfa": {
                    "type": "integer",
                    "nullable": true,
                    "example": 20000000
                  }
                }
              },
              "quotas": {
                "type": "object",
                "properties": {
                  "maxCompanies": {
                    "type": "integer",
                    "nullable": true
                  },
                  "maxUsersPerCompany": {
                    "type": "integer",
                    "nullable": true
                  }
                }
              }
            }
          },
          "key": {
            "type": "object",
            "properties": {
              "ref": {
                "type": "string",
                "example": "PAK-91B0C2D3"
              },
              "prefix": {
                "type": "string",
                "example": "ifp_live_9c1"
              },
              "environment": {
                "type": "string",
                "enum": [
                  "LIVE",
                  "TEST"
                ]
              },
              "scopes": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Scope"
                }
              },
              "rateLimitPerMin": {
                "type": "integer",
                "example": 60
              }
            }
          }
        }
      },
      "Scope": {
        "type": "string",
        "description": "Droit porté par une clé.",
        "enum": [
          "COMPANIES_READ",
          "COMPANIES_WRITE",
          "USERS_READ",
          "USERS_WRITE",
          "WALLET_READ",
          "LEDGER_READ",
          "TRANSACTIONS_READ",
          "DRIVERS_READ",
          "ALERTS_READ",
          "REPORTS_READ",
          "CREDIT_REQUEST_WRITE"
        ]
      },
      "Company": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "example": 4832
          },
          "ref": {
            "type": "string",
            "nullable": true,
            "example": "ENT-B14E77A3"
          },
          "name": {
            "type": "string",
            "example": "Transports Kouassi SARL"
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "INACTIVE"
            ]
          },
          "email": {
            "type": "string",
            "nullable": true,
            "example": "contact@kouassi.ci"
          },
          "phoneNumber": {
            "type": "string",
            "nullable": true,
            "example": "+2250700000099"
          },
          "rccm": {
            "type": "string",
            "nullable": true,
            "example": "CI-ABJ-2024-B-1234"
          },
          "nif": {
            "type": "string",
            "nullable": true,
            "example": "NIF-99887766"
          },
          "headquartersAddress": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CompanyCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "email",
          "phoneNumber",
          "rccm",
          "nif"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 150
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phoneNumber": {
            "type": "string",
            "maxLength": 30
          },
          "rccm": {
            "type": "string",
            "maxLength": 64,
            "description": "Registre du commerce. Normalisé en majuscules avant contrôle d'unicité."
          },
          "nif": {
            "type": "string",
            "maxLength": 64,
            "description": "Identifiant fiscal. Normalisé en majuscules avant contrôle d'unicité."
          },
          "headquartersAddress": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "CompanyUpdateRequest": {
        "type": "object",
        "description": "Tous les champs sont facultatifs ; seuls ceux fournis sont modifiés.",
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phoneNumber": {
            "type": "string",
            "maxLength": 32
          },
          "rccm": {
            "type": "string",
            "maxLength": 64
          },
          "nif": {
            "type": "string",
            "maxLength": 64
          },
          "headquartersAddress": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "CompanyUser": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "example": 981
          },
          "ref": {
            "type": "string",
            "nullable": true,
            "example": "USR-2C77A10B"
          },
          "name": {
            "type": "string",
            "example": "Aminata Traoré"
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "phoneNumber": {
            "type": "string",
            "nullable": true
          },
          "role": {
            "type": "string",
            "enum": [
              "FLEET_ADMINISTRATOR",
              "DAF"
            ]
          },
          "companyId": {
            "type": "integer",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "INACTIVE",
              "SUSPENDED",
              "ARCHIVED"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CompanyUserCreateRequest": {
        "type": "object",
        "required": [
          "name",
          "email",
          "phoneNumber",
          "role"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 150
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Sert à l'authentification et reçoit le lien d'activation."
          },
          "phoneNumber": {
            "type": "string",
            "maxLength": 30
          },
          "role": {
            "type": "string",
            "enum": [
              "FLEET_ADMINISTRATOR",
              "DAF"
            ]
          },
          "language": {
            "type": "string",
            "enum": [
              "FR",
              "EN"
            ]
          }
        }
      },
      "CompanyUserUpdateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phoneNumber": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "FLEET_ADMINISTRATOR",
              "DAF"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "INACTIVE",
              "SUSPENDED"
            ]
          }
        }
      },
      "Wallet": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "example": 55
          },
          "ref": {
            "type": "string",
            "nullable": true,
            "example": "WAL-7C0DE118"
          },
          "companyId": {
            "type": "integer",
            "example": 4832
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "BLOCKED"
            ]
          },
          "balanceFcfa": {
            "type": "integer",
            "example": 13942000
          },
          "heldFcfa": {
            "type": "integer",
            "description": "Montant retenu par des pleins pré-autorisés non encore confirmés.",
            "example": 120000
          },
          "availableFcfa": {
            "type": "integer",
            "example": 13822000
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "LedgerEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "ref": {
            "type": "string",
            "nullable": true,
            "example": "LED-3F19B7C2"
          },
          "type": {
            "type": "string",
            "enum": [
              "CREDIT",
              "DEBIT",
              "REFUND",
              "HOLD",
              "RELEASE",
              "ADJUSTMENT"
            ]
          },
          "amountFcfa": {
            "type": "integer",
            "example": 2500000
          },
          "balanceAfterFcfa": {
            "type": "integer",
            "example": 13942000
          },
          "source": {
            "type": "string",
            "nullable": true,
            "enum": [
              "BANK_TRANSFER",
              "MOBILE_MONEY",
              "CASH_DEPOSIT",
              "CHEQUE",
              "ADJUSTMENT",
              null
            ]
          },
          "reference": {
            "type": "string",
            "nullable": true,
            "description": "Référence du versement, préfixée par votre identifiant d'apporteur.",
            "example": "RS-12-VIR-2026-0831-004"
          },
          "transactionId": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Transaction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "ref": {
            "type": "string",
            "nullable": true,
            "example": "TRX-88C4A1D0"
          },
          "status": {
            "type": "string",
            "enum": [
              "CREATED",
              "PREAUTHORIZED",
              "VALIDATED",
              "CONFIRMED",
              "CANCELED",
              "EXPIRED",
              "FAILED",
              "REFUNDED"
            ]
          },
          "companyId": {
            "type": "integer"
          },
          "amountFcfa": {
            "type": "integer",
            "example": 45000
          },
          "fuelType": {
            "type": "string",
            "example": "DIESEL"
          },
          "unitPriceFcfa": {
            "type": "integer",
            "example": 875
          },
          "liters": {
            "type": "object",
            "properties": {
              "estimate": {
                "type": "number",
                "nullable": true,
                "example": 51.43
              },
              "actual": {
                "type": "number",
                "nullable": true,
                "description": "Volume réellement servi. Reste `null` tant qu'il n'est pas saisi en station.",
                "example": 51.2
              }
            }
          },
          "selfService": {
            "type": "boolean",
            "description": "Transaction conduite par le chauffeur seul, sans validation d'un pompiste."
          },
          "station": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string",
                "example": "Total Marcory"
              }
            }
          },
          "driver": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "vehicle": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "integer"
              },
              "registration": {
                "type": "string",
                "example": "815KJ01"
              }
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "confirmedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "canceledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "DriverWallet": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "ref": {
            "type": "string",
            "nullable": true
          },
          "companyId": {
            "type": "integer"
          },
          "driver": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "integer"
              },
              "name": {
                "type": "string"
              },
              "phoneNumber": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "FROZEN",
              "CLOSED"
            ]
          },
          "balanceFcfa": {
            "type": "integer"
          },
          "heldFcfa": {
            "type": "integer"
          },
          "availableFcfa": {
            "type": "integer"
          },
          "lastCreditAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "lastDebitAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "Alert": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "companyId": {
            "type": "integer",
            "nullable": true
          },
          "type": {
            "type": "string",
            "example": "WALLET_LOW_BALANCE"
          },
          "severity": {
            "type": "string",
            "enum": [
              "INFO",
              "WARNING",
              "CRITICAL"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "OPEN",
              "ACKNOWLEDGED",
              "DISMISSED",
              "RESOLVED"
            ]
          },
          "title": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "triggeredAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "acknowledgedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "resolvedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CreditRequestBody": {
        "type": "object",
        "required": [
          "amountFcfa",
          "source",
          "clientReference",
          "proofIds"
        ],
        "properties": {
          "amountFcfa": {
            "type": "integer",
            "minimum": 1,
            "example": 2500000
          },
          "source": {
            "type": "string",
            "description": "Nature réelle du versement constaté.",
            "enum": [
              "BANK_TRANSFER",
              "MOBILE_MONEY",
              "CASH_DEPOSIT",
              "CHEQUE"
            ]
          },
          "clientReference": {
            "type": "string",
            "maxLength": 100,
            "description": "Votre référence de versement. Préfixée côté serveur, sans collision possible avec un autre partenaire."
          },
          "proofIds": {
            "type": "array",
            "maxItems": 3,
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Identifiants renvoyés par `POST …/wallet/credit/proof`."
          },
          "note": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "CreditRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING_APPROVAL",
              "APPROVED",
              "REJECTED",
              "EXPIRED"
            ]
          },
          "companyId": {
            "type": "integer",
            "nullable": true
          },
          "amountFcfa": {
            "type": "integer",
            "nullable": true
          },
          "source": {
            "type": "string",
            "nullable": true
          },
          "clientReference": {
            "type": "string",
            "nullable": true
          },
          "requestedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "decidedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "rejectedReason": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CreditProof": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "fileName": {
            "type": "string",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "nullable": true
          },
          "sizeBytes": {
            "type": "integer",
            "nullable": true
          }
        }
      },
      "ApprovalPending": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "APPROVAL_PENDING"
          },
          "approvalId": {
            "type": "string",
            "format": "uuid"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "PortfolioSummary": {
        "type": "object",
        "properties": {
          "period": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "format": "date-time"
              },
              "to": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "totals": {
            "type": "object",
            "properties": {
              "companies": {
                "type": "integer"
              },
              "activeCompanies": {
                "type": "integer"
              },
              "transactions": {
                "type": "integer"
              },
              "amountFcfa": {
                "type": "integer"
              },
              "walletBalanceFcfa": {
                "type": "integer"
              },
              "walletHeldFcfa": {
                "type": "integer"
              }
            }
          },
          "companies": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "ref": {
                  "type": "string",
                  "nullable": true
                },
                "name": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "ACTIVE",
                    "INACTIVE"
                  ]
                },
                "transactions": {
                  "type": "integer"
                },
                "amountFcfa": {
                  "type": "integer"
                },
                "walletBalanceFcfa": {
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "https://instafuel-backend-staging.up.railway.app"
    }
  ]
}
