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

# Créer une transaction

> Enregistrez une demande de paiement mobile money et récupérez les références à conserver.

Cette opération enregistre une demande de paiement pour le compte authentifié et renvoie les références à conserver. Elle ne prend en charge que `Ipay-Payment-Type: mobile` (mobile money) ; les autres moyens de paiement passent par les [liens de paiement](/api-reference/liens-de-paiement/creer-un-lien). La liste des moyens est dans [Reversement et frais](/guides/reversement#frais-par-moyen-de-paiement).

<Warning>
  Le statut renvoyé à la création n'est pas définitif. Vérifiez toujours le statut final côté serveur, avec [Consulter une transaction](/api-reference/transactions/consulter-un-paiement) ou via les [webhooks](/guides/webhooks), avant de livrer une commande.
</Warning>

* **Compte validé.** Le compte doit être validé pour l'environnement ciblé, sinon l'API répond `403` sans créer de transaction.
* **Environnements.** Sandbox et Live sont deux comptes distincts, avec des clés distinctes : une clé Sandbox utilisée avec `Ipay-Target-Environment: live` est refusée, et inversement. Voir [Authentification](/api-reference/authentification).
* **`transaction_id`.** C'est votre propre référence de commande, unique pour votre compte. Vous la retrouverez sous le nom `external_reference`, et elle est acceptée comme identifiant par [Consulter une transaction](/api-reference/transactions/consulter-un-paiement).
* **Montant minimum.** `25` XOF en Live pour `mobile`. Le minimum diffère en Sandbox : voir [Sandbox et tests](/guides/sandbox-et-tests).
* **Références à conserver.** `reference` est l'identifiant iMoney Encaissement de la transaction, accepté par les opérations de consultation. `public_reference` est la référence affichable à votre client.

## Doublons et idempotence

Il n'existe pas d'en-tête de clé d'idempotence. La création applique une détection de doublon **au niveau applicatif** sur `external_reference`, c'est-à-dire sur le `transaction_id` que vous envoyez. **En Live**, un second appel avec la même valeur reçoit `422` (`{"status": "failed", "message": "External Reference Not Valid"}`) et ne crée pas de seconde transaction. **En Sandbox, la forme de la réponse à un doublon n'est pas garantie identique** à celle du Live : à confirmer auprès du support avant d'en faire une assertion de test automatisé.

<Warning>
  Cette détection n'est pas garantie sous appels concurrents : deux requêtes envoyées au même instant avec le même `transaction_id` peuvent toutes les deux réussir. Générez un `transaction_id` unique par tentative, et vérifiez le statut avec [Consulter une transaction](/api-reference/transactions/consulter-un-paiement) avant de retenter une transaction dont vous n'avez pas reçu la réponse.
</Warning>

## Limites

Aucune limite de débit n'est documentée pour cette opération : à confirmer auprès du support avant un envoi massif. Les messages d'erreur communs à toutes les opérations sont regroupés dans [Erreurs](/api-reference/erreurs).


## OpenAPI

````yaml openapi.yaml POST /payments
openapi: 3.1.0
info:
  title: iPayMoney Merchant API
  version: 1.0.0
  description: >-
    Contrats marchands v1 vérifiés contre les routes, contrôleurs et services
    Rails. Les contrats partenaires et les routes v2 non opérationnelles ne font
    pas partie de cette spécification publique. Les liens de paiement doivent
    utiliser des références aléatoires privées.
servers:
  - url: https://i-pay.money/api/v1
    description: Sandbox ou Live selon les en-têtes et la clé utilisée
security: []
tags:
  - name: Payments
    description: Création et suivi des transactions marchandes
  - name: Payment links
    description: Liens de paiement hébergés
paths:
  /payments:
    post:
      tags:
        - Payments
      summary: Créer une transaction
      parameters:
        - $ref: '#/components/parameters/TargetEnvironment'
        - $ref: '#/components/parameters/PaymentType'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentRequest'
            examples:
              sandboxMobile:
                summary: Transaction mobile Sandbox réussie
                value:
                  amount: 1000
                  country: NE
                  currency: XOF
                  msisdn: '40410000000'
                  transaction_id: ORDER-SANDBOX-001
                  customer_name: Client Test
      responses:
        '200':
          description: >-
            Transaction enregistrée. Le statut final doit être vérifié
            séparément.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentCreateResponse'
        '400':
          description: >-
            En-tête ou paramètre d'authentification invalide, ou corps de la
            requête invalide (champ manquant ou valeur hors contrainte).
          x-verified: >-
            Note interne de vérification (non destinée à la documentation
            publique). Détecté par `ApiAuthService#authenticate`
            (app/services/api_auth_service.rb:20-26) ou
            `Live::PaymentService#request_payment`
            (app/services/live/payment_service.rb). Messages exacts vérifiés le
            2026-09-16.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missingHeaderParams:
                  summary: En-tête d'authentification manquant
                  value:
                    message: 'Bad Request: Missing params'
                notAllowedEnvironment:
                  summary: Ipay-Target-Environment non autorisé
                  value:
                    message: 'Bad Request: Not Allowed Environment'
                notAllowedPaymentType:
                  summary: Ipay-Payment-Type non autorisé
                  value:
                    message: 'Bad Request: Not Allowed Payment Type'
                missingAuthenticationKey:
                  summary: Authorization Bearer manquant ou mal formé
                  value:
                    message: 'Bad Request: Missing Authentication Key'
                missingBodyParams:
                  summary: >-
                    Champ requis manquant dans le corps (amount, country,
                    currency, msisdn, transaction_id ou customer_name)
                  value:
                    message: 'Bad Request: Missing Body Params'
                countryNotAllowed:
                  summary: country différent de NE ou BJ
                  value:
                    message: 'Bad Request: Country Not Allowed'
                currencyNotAllowed:
                  summary: currency différente de XOF
                  value:
                    message: 'Bad Request: Currency Not Allowed'
                amountNotValid:
                  summary: >-
                    amount sous le minimum applicable (25 XOF en Live, 50 XOF en
                    Sandbox)
                  value:
                    message: 'Bad Request: Amount Not Valid'
                incorrectMsisdn:
                  summary: msisdn au format invalide pour la méthode
                  value:
                    message: 'Bad Request: Incorrect MSISDN'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '406':
          $ref: '#/components/responses/NotAcceptable'
        '422':
          description: >-
            Référence externe (`transaction_id`) déjà utilisée pour ce compte :
            détection de doublon appliquée au niveau applicatif, non garantie
            sous appels concurrents — l'API n'expose aucune clé d'idempotence.
            Ce code couvre aussi un paiement invalide pour une autre raison de
            validation.
          x-verified: >-
            Note interne de vérification (non destinée à la documentation
            publique). Voir `Live::PaymentService#error_response`,
            app/services/live/payment_service.rb:994-1005.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                duplicateExternalReference:
                  summary: transaction_id déjà utilisé pour ce compte
                  value:
                    status: failed
                    message: External Reference Not Valid
      security:
        - bearerAuth: []
components:
  parameters:
    TargetEnvironment:
      name: Ipay-Target-Environment
      in: header
      required: true
      schema:
        type: string
        enum:
          - sandbox
          - live
    PaymentType:
      name: Ipay-Payment-Type
      in: header
      required: true
      description: >-
        Méthode de paiement. `POST /payments` ne prend en charge que `mobile`
        (mobile money). Les autres moyens de paiement (carte bancaire et autres
        canaux) ne s'utilisent pas ici : ils sont disponibles via les liens de
        paiement (`POST /external_payments`). Liste complète : [moyens de
        paiement](/guides/reversement#frais-par-moyen-de-paiement).
      x-verified: >-
        Note interne de vérification (non destinée à la documentation publique).
        Décision de périmètre : seule la valeur `mobile` est documentée pour
        `POST /payments` ; les autres valeurs traitées par
        `Live::PaymentService` restent acceptées par l'API mais relèvent du
        parcours « lien de paiement ». `external_payment` est réservé à `POST
        /external_payments` (paramètre dédié de cette opération).
      schema:
        type: string
        const: mobile
        example: mobile
  schemas:
    PaymentRequest:
      type: object
      description: >-
        Corps requis pour créer un paiement mobile money (`Ipay-Payment-Type:
        mobile`). Le montant minimum est de 25 XOF (50 XOF en Sandbox). En
        dessous, l'API répond 400 `Bad Request: Amount Not Valid`. Pour les
        autres moyens de paiement, utilisez les liens de paiement.
      x-verified: >-
        Note interne de vérification (non destinée à la documentation publique).
        Corps requis par `Live::PaymentService#request_payment`
        (app/services/live/payment_service.rb). Seuil `mobile` ≥ 25 vérifié le
        2026-09-16 (`verify_mobile_amount_value`). Les seuils des autres types
        ne sont plus documentés ici (périmètre réduit à `mobile`).
      required:
        - amount
        - country
        - currency
        - msisdn
        - transaction_id
        - customer_name
      properties:
        amount:
          type: integer
          minimum: 25
          example: 1000
          description: >-
            Montant à débiter, en XOF (entier). Minimum : 25 XOF en Live, 50 XOF
            en Sandbox.
        country:
          type: string
          enum:
            - NE
            - BJ
          example: NE
        currency:
          type: string
          const: XOF
        msisdn:
          type: string
          example: '40410000000'
        transaction_id:
          type: string
          description: Référence unique dans le compte
        customer_name:
          type: string
    PaymentCreateResponse:
      type: object
      required:
        - status
        - reference
        - public_reference
      properties:
        status:
          type: string
          example: succeeded
        reference:
          type: string
        public_reference:
          type: string
        meta_data:
          type: object
          additionalProperties: true
    Error:
      type: object
      properties:
        message:
          type: string
        status:
          type: string
          description: >-
            Présent uniquement sur certains échecs applicatifs, ex. paiement
            dupliqué sur `POST /payments` où `status` vaut toujours `failed`.
            Absent des autres erreurs de ce contrat (ex. 404 `Payment Not
            Found`, erreurs d'en-tête/authentification).
          x-verified: >-
            Note interne de vérification (non destinée à la documentation
            publique). Voir `Live::PaymentService#error_response`
            (app/services/live/payment_service.rb:994-1005).
          example: failed
  responses:
    Unauthorized:
      description: Clé invalide
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Compte ou environnement indisponible
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotAcceptable:
      description: Content-Type différent de application/json
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: Clé secrète du compte Sandbox ou Live

````