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

# Créer une vente

> Soumet une vente SOCODE, VIRUNGA ou TV. La réponse dit seulement si la vente est prise ; son issue arrive par le rappel, ou par `GET /v1/ventes/{uuid}`.

Un refus métier répond HTTP 200 avec `REJETEE`. Un HTTP 5xx ou un délai dépassé n'est jamais un échec : renvoyez la même vente avec le même `uuid`.

Portée de la clé : `ventes:ecrire`.



## OpenAPI

````yaml openapi/v1.json POST /v1/ventes
openapi: 3.1.0
info:
  title: API Umeme pour les intégrateurs
  version: 1.0.0
  description: >-
    Contrat de l'API Umeme pour les intégrateurs : vendre de l'électricité
    prépayée et des abonnements TV depuis le portefeuille de votre revendeur.
servers:
  - url: https://sandbox.umeme.app
    description: Sandbox d'intégration
  - url: https://api.umeme.app
    description: Production
security:
  - cle: []
tags:
  - name: Ventes
  - name: Compteurs
  - name: Portefeuille
  - name: Outils
paths:
  /v1/ventes:
    post:
      tags:
        - Ventes
      summary: Créer une vente
      description: >-
        Soumet une vente SOCODE, VIRUNGA ou TV. La réponse dit seulement si la
        vente est prise ; son issue arrive par le rappel, ou par `GET
        /v1/ventes/{uuid}`.


        Un refus métier répond HTTP 200 avec `REJETEE`. Un HTTP 5xx ou un délai
        dépassé n'est jamais un échec : renvoyez la même vente avec le même
        `uuid`.


        Portée de la clé : `ventes:ecrire`.
      operationId: creerVente
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NouvelleVente'
            examples:
              socode:
                summary: Vente SOCODE au compteur de test 00
                value:
                  uuid: 94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb
                  compte: SOCODE
                  reference: '09900000000'
                  montant: 5
      responses:
        '200':
          description: >-
            La demande est traitée : acceptée, rejetée ou reconnue comme
            doublon.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VenteSoumise'
              examples:
                acceptee:
                  summary: ACCEPTEE
                  value:
                    uuid: 94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb
                    statut: ACCEPTEE
                    creeLe: '2026-11-07T08:26:44Z'
                rejetee:
                  summary: REJETEE
                  value:
                    uuid: 94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb
                    statut: REJETEE
                    motifRejet:
                      code: SOLDE_INSUFFISANT
                      message: Le solde du portefeuille ne couvre pas cette vente.
                doublon:
                  summary: DOUBLON_IGNORE
                  value:
                    uuid: 94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb
                    statut: DOUBLON_IGNORE
                    creeLe: '2026-11-07T08:26:44Z'
        '401':
          $ref: '#/components/responses/NonAuthentifie'
        '403':
          $ref: '#/components/responses/Interdit'
        '409':
          description: Cet `uuid` désigne déjà une autre vente.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Erreur'
              example:
                code: UUID_REUTILISE
                message: Cet uuid désigne déjà une autre vente.
        '429':
          $ref: '#/components/responses/TropDeRequetes'
      x-codeSamples:
        - lang: bash
          label: cURL
          source: |-
            curl -X POST "$UMEME_BASE_URL/ventes" \
              -H "Authorization: Bearer $UMEME_CLE" \
              -H "Content-Type: application/json" \
              -d '{
                "uuid": "94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb",
                "compte": "SOCODE",
                "reference": "09900000000",
                "montant": 5
              }'
        - lang: javascript
          label: Node.js · fetch
          source: |-
            // Node.js 18 et plus : fetch est intégré.
            const baseUrl = process.env.UMEME_BASE_URL;

            const corps = {
              uuid: "94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb",
              compte: "SOCODE",
              reference: "09900000000",
              montant: 5,
            };

            const reponse = await fetch(`${baseUrl}/ventes`, {
              method: "POST",
              headers: {
                Authorization: `Bearer ${process.env.UMEME_CLE}`,
                "Content-Type": "application/json",
              },
              body: JSON.stringify(corps),
            });
            const donnees = await reponse.json();
        - lang: javascript
          label: Node.js · Axios
          source: |-
            // npm install axios
            import axios from "axios";

            const umeme = axios.create({
              baseURL: process.env.UMEME_BASE_URL,
              headers: { Authorization: `Bearer ${process.env.UMEME_CLE}` },
              timeout: 30000,
            });

            const corps = {
              uuid: "94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb",
              compte: "SOCODE",
              reference: "09900000000",
              montant: 5,
            };

            const { data } = await umeme.post("/ventes", corps);
        - lang: python
          label: Python
          source: |-
            import os

            import requests

            BASE_URL = os.environ["UMEME_BASE_URL"]
            ENTETES = {"Authorization": f"Bearer {os.environ['UMEME_CLE']}"}

            corps = {
                "uuid": "94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb",
                "compte": "SOCODE",
                "reference": "09900000000",
                "montant": 5,
            }

            reponse = requests.post(
                f"{BASE_URL}/ventes",
                headers=ENTETES,
                json=corps,
                timeout=30,
            )
            donnees = reponse.json()
        - lang: php
          label: PHP
          source: |-
            // composer require guzzlehttp/guzzle
            $client = new GuzzleHttp\Client([
                'base_uri' => getenv('UMEME_BASE_URL') . '/',
                'headers' => ['Authorization' => 'Bearer ' . getenv('UMEME_CLE')],
                'timeout' => 30,
            ]);

            $corps = [
                'uuid' => '94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb',
                'compte' => 'SOCODE',
                'reference' => '09900000000',
                'montant' => 5,
            ];

            $reponse = $client->post('ventes', [
                'json' => $corps,
            ]);
            $donnees = json_decode($reponse->getBody(), true);
        - lang: java
          label: Java
          source: >-
            // Java 15 et plus : java.net.http et blocs de texte.

            var baseUrl = System.getenv("UMEME_BASE_URL");

            var client = HttpClient.newHttpClient();


            var corps = """
                {
                  "uuid": "94a223fe-fb34-47f2-aaa5-b80c4bf8a8eb",
                  "compte": "SOCODE",
                  "reference": "09900000000",
                  "montant": 5
                }
                """;

            var requete = HttpRequest.newBuilder(URI.create(baseUrl +
            "/ventes"))
                .header("Authorization", "Bearer " + System.getenv("UMEME_CLE"))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(corps))
                .build();

            var reponse = client.send(requete,
            HttpResponse.BodyHandlers.ofString());
components:
  schemas:
    NouvelleVente:
      type: object
      required:
        - uuid
        - compte
        - reference
        - montant
      properties:
        uuid:
          type: string
          format: uuid
          description: >-
            Identifiant que vous générez et enregistrez avant l'appel. Le même
            `uuid` avec la même vente rend `DOUBLON_IGNORE` ; avec une autre
            vente, une erreur 409 `UUID_REUTILISE`.
        compte:
          $ref: '#/components/schemas/Compte'
        reference:
          type: string
          description: >-
            Compteur à 11 chiffres pour SOCODE et VIRUNGA, référence
            d'abonnement pour TV. Dans la sandbox, les compteurs de test
            choisissent l'issue.
        montant:
          type: number
          minimum: 0.5
          maximum: 5000
          description: >-
            En dollars, de 0,50 à 5 000, deux décimales au plus. Débité du
            portefeuille à l'acceptation, remboursé si la vente échoue.
        telClient:
          type: string
          pattern: ^243[0-9]{9}$
          description: >-
            Téléphone du client en RDC, au format `243…`. Il reçoit le jeton par
            SMS.
        metadonnees:
          type: object
          additionalProperties: true
          description: >-
            Vos propres données, rendues telles quelles par la consultation et
            le rappel.
    VenteSoumise:
      type: object
      required:
        - uuid
        - statut
      properties:
        uuid:
          type: string
          format: uuid
          description: L'identifiant envoyé.
        statut:
          type: string
          enum:
            - ACCEPTEE
            - REJETEE
            - DOUBLON_IGNORE
          description: >-
            Ce qu'il advient de la demande. L'issue de la vente, elle, suit les
            statuts `EN_COURS`, `EN_RECONCILIATION`, `REUSSIE` ou `ECHOUEE`.
        creeLe:
          type: string
          format: date-time
          description: Heure d'acceptation, en UTC.
        motifRejet:
          type: object
          description: Présent si la vente est `REJETEE`. Rien n'a été débité.
          required:
            - code
            - message
          properties:
            code:
              $ref: '#/components/schemas/CodeRejet'
            message:
              type: string
              description: En français, pour vos journaux. Il peut changer.
    Erreur:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: 'Stable : il ne se renomme jamais. C''est lui que votre code compare.'
        message:
          type: string
          description: En français, pour vos journaux. Il peut changer.
    Compte:
      type: string
      enum:
        - SOCODE
        - VIRUNGA
        - TV
      description: Ce que l'on vend, et chez quel fournisseur.
    CodeRejet:
      type: string
      enum:
        - SOLDE_INSUFFISANT
        - LIMITE_JOUR_ATTEINTE
        - MONTANT_HORS_LIMITES
        - MONTANT_SOUS_MINIMUM
        - REFERENCE_INVALIDE
        - COMPTEUR_INCONNU
        - COMPTEUR_BLOQUE
        - COMPTEUR_DE_TEST
        - SERVICE_INDISPONIBLE
        - COMPTE_NON_AUTORISE
  responses:
    NonAuthentifie:
      description: >-
        Clé absente, inconnue, révoquée, ou de l'autre environnement :
        `CLE_INVALIDE`, `CLE_REVOQUEE`, `CLE_MAUVAIS_ENVIRONNEMENT`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Erreur'
          example:
            code: CLE_INVALIDE
            message: La clé est absente ou inconnue.
    Interdit:
      description: >-
        Adresse hors de votre liste d'IP autorisées, ou accès suspendu :
        `IP_NON_AUTORISEE`, `INTEGRATEUR_SUSPENDU`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Erreur'
          example:
            code: IP_NON_AUTORISEE
            message: Cette adresse n'est pas dans votre liste d'IP autorisées.
    TropDeRequetes:
      description: >-
        Plus de 10 requêtes par seconde pour cette clé. Attendez le nombre de
        secondes de l'en-tête `Retry-After`.
      headers:
        Retry-After:
          description: Secondes à attendre avant de réessayer.
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Erreur'
          example:
            code: TROP_DE_REQUETES
            message: 'Trop de requêtes : réessayez dans 1 seconde.'
  securitySchemes:
    cle:
      type: http
      scheme: bearer
      description: >-
        Votre clé d'API : `umeme_test_…` dans la sandbox, `umeme_live_…` en
        production.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.