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

# Créer un lien

> Crée un lien partageable : prix fixe, montant libre, plusieurs tarifs, panier ou inscription à un plan.

> [!TIP]
>
> Essayez avec une clé **sandbox** (`mp_sandbox_…`) : aucun argent réel ne bouge. Voir [Test et production](https://docs.mercy-pay.com/start/environments.md).

Un fichier envoyé par un payeur (champ `file`) n'accepte que les images et les PDF. Il reste privé : seuls les membres de votre boutique l'ouvrent, depuis le détail du lien dans le tableau de bord.

Voir [Créer un lien par l'API](https://docs.mercy-pay.com/payment-links/api-guide.md) pour des exemples de chaque mode de prix.


## OpenAPI

````yaml POST /api/v1/payment_links
openapi: 3.1.0
info:
  title: API Mercy Pay
  version: 1.0.0
  description: >-
    Encaissez par mobile money et par carte, facturez en récurrent et versez vos
    fonds. Les montants sont des entiers en unités mineures. Chaque réponse
    porte un en-tête `Request-Id`.
servers:
  - url: https://mercy-pay.com
    description: >-
      Production. La clé choisit l'environnement : `mp_sandbox_…` ou
      `mp_live_…`.
security:
  - bearerAuth: []
tags:
  - name: Compte
  - name: Sessions de paiement
  - name: Paiements
  - name: Remboursements
    description: Rendre un paiement au client, en entier.
  - name: Liens de paiement
  - name: Plans
  - name: Abonnements
  - name: Clients
  - name: Factures
  - name: Espace client
  - name: Soldes
  - name: Retraits
  - name: État des opérateurs
  - name: Événements
    description: Tout ce qui s'est passé sur le compte, envoyé ou non à un endpoint.
  - name: Endpoints de webhook
    description: Les URL de votre serveur qui reçoivent les événements.
paths:
  /api/v1/payment_links:
    post:
      tags:
        - Liens de paiement
      summary: Créer un lien
      description: >-
        Crée un lien partageable : prix fixe, montant libre, plusieurs tarifs,
        panier ou inscription à un plan.
      operationId: createPaymentLink
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
              properties:
                title:
                  type: string
                  description: Titre affiché au client
                  maxLength: 255
                description:
                  type: string
                  description: Description
                  maxLength: 500
                pricing_mode:
                  type: string
                  description: >-
                    Sans valeur : `fixed` si `amount` est fourni, sinon
                    `flexible`.
                  enum:
                    - fixed
                    - flexible
                    - options
                    - cart
                amount:
                  type: integer
                  description: Obligatoire en `fixed`. Prix en unités mineures.
                  minimum: 1
                  maximum: 1000000000
                minimum_amount:
                  type: integer
                  description: 'Montant libre : minimum accepté'
                  minimum: 1
                price_options:
                  type: array
                  description: Obligatoire en `options`. Un tarif par élément.
                  items:
                    type: object
                    required:
                      - label
                      - amount
                    properties:
                      id:
                        type: integer
                        description: À renvoyer pour modifier un tarif existant
                      label:
                        type: string
                        description: Nom du tarif
                        maxLength: 255
                      amount:
                        type: integer
                        description: Prix
                        minimum: 1
                items:
                  type: array
                  description: Obligatoire en `cart`. Un article par élément.
                  items:
                    type: object
                    required:
                      - name
                      - unit_amount
                    properties:
                      id:
                        type: integer
                        description: À renvoyer pour modifier un article existant
                      name:
                        type: string
                        description: Nom
                        maxLength: 255
                      description:
                        type: string
                        description: Description
                        maxLength: 500
                      unit_amount:
                        type: integer
                        description: Prix unitaire
                        minimum: 1
                      min_quantity:
                        type: integer
                        description: Quantité minimale
                        minimum: 1
                      max_quantity:
                        type: integer
                        description: Quantité maximale
                      variants:
                        type: array
                        items:
                          type: object
                          required:
                            - label
                          properties:
                            id:
                              type: integer
                              description: Identifiant
                            label:
                              type: string
                              description: Nom
                              maxLength: 255
                            unit_amount:
                              type: integer
                              description: Prix propre
                              minimum: 1
                custom_fields_schema:
                  type: array
                  items:
                    $ref: '#/components/schemas/CustomField'
                  description: >-
                    Champs à remplir par le payeur. Renvoyés sous
                    `custom_fields`.
                collect_phone:
                  type: boolean
                  description: Demande le téléphone du payeur
                collect_address:
                  type: boolean
                  description: Demande l'adresse du payeur
                after_payment_message:
                  type: string
                  description: Affiché après un paiement réussi
                  maxLength: 1000
                max_uses:
                  type: integer
                  description: Nombre de paiements au-delà duquel le lien s'arrête
                  minimum: 1
                expires_at:
                  type: string
                  description: Fin de validité, dans le futur
                  format: date-time
                success_url:
                  type: string
                  description: Retour après paiement réussi
                  format: uri
                  maxLength: 2048
                cancel_url:
                  type: string
                  description: Retour si le client abandonne
                  format: uri
                  maxLength: 2048
                active:
                  type: boolean
                  description: >-
                    `true` par défaut. `false` : le lien n'accepte plus de
                    paiement.
                metadata:
                  type:
                    - object
                    - 'null'
                  additionalProperties:
                    type:
                      - string
                      - 'null'
                    maxLength: 500
                  description: >-
                    Vos données libres, renvoyées telles quelles. 50 clés
                    maximum, valeurs de 500 caractères maximum.
                type:
                  type: string
                  description: >-
                    `one_time` par défaut, ou `recurring` pour inscrire à un
                    plan
                  enum:
                    - one_time
                    - recurring
                  default: one_time
                currency:
                  type: string
                  description: >-
                    Devise par défaut de votre compte si absente. Code devise
                    ISO 4217 de 3 lettres, par exemple `XAF`.
                  minLength: 3
                  maxLength: 3
                plan:
                  type: string
                  description: >-
                    Obligatoire en `recurring` : identifiant d'un plan actif
                    (`plan_…`)
            example:
              title: Formation Laravel
              pricing_mode: options
              price_options:
                - label: Solo
                  amount: 100000
                - label: Équipe de 5
                  amount: 400000
              custom_fields_schema:
                - id: company
                  type: text
                  label: Entreprise
                  required: true
              collect_phone: true
              max_uses: 30
      responses:
        '201':
          description: Lien créé
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/PaymentLink'
              example:
                data:
                  id: plink_2d8f4b6a1c3e4a5f9b7d8e0f2a4c6b18
                  object: payment_link
                  livemode: false
                  created: '2026-11-07T09:00:00+00:00'
                  type: one_time
                  pricing_mode: options
                  title: Formation Laravel
                  description: Deux jours en présentiel à Yaoundé
                  amount: null
                  minimum_amount: null
                  currency: XAF
                  price_options:
                    - id: 31
                      label: Solo
                      amount: 100000
                    - id: 32
                      label: Équipe de 5
                      amount: 400000
                  items: []
                  custom_fields:
                    - id: company
                      type: text
                      label: Entreprise
                      required: true
                  collect_phone: true
                  collect_address: false
                  after_payment_message: Merci, vous recevrez vos accès par e-mail.
                  is_active: true
                  max_uses: 30
                  uses_count: 12
                  views_count: 240
                  expires_at: null
                  archived_at: null
                  success_url: null
                  cancel_url: null
                  metadata:
                    course: laravel
                  url: https://mercy-pay.com/payer/k3j9x2pq
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/ValidationFailed'
        '429':
          $ref: '#/components/responses/RateLimited'
components:
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      schema:
        type: string
        maxLength: 255
      description: >-
        Une clé unique par opération : la rejouer pendant 24 heures renvoie la
        même réponse sans rien créer de plus. Voir
        [Idempotence](/developers/idempotency).
  schemas:
    CustomField:
      type: object
      required:
        - id
        - type
        - label
      properties:
        id:
          type: string
          description: 'Clé unique : lettres, chiffres, `_` et `-`. 64 caractères maximum.'
        type:
          type: string
          description: Type de champ
          enum:
            - text
            - select
            - multi_select
            - checkbox
            - file
        label:
          type: string
          description: Libellé affiché
        help_text:
          type:
            - string
            - 'null'
          description: Aide sous le champ
        required:
          type: boolean
          description: Champ obligatoire
        options:
          type: array
          items:
            type: string
          description: '`select` et `multi_select` : les choix, 50 maximum.'
        max_file_size_kb:
          type:
            - integer
            - 'null'
          description: >-
            `file` : taille maximale en Ko, 10240 au plus. Images et PDF
            uniquement.
    PaymentLink:
      type: object
      properties:
        id:
          type: string
          description: Identifiant du lien (`plink_…`)
        object:
          type: string
          const: payment_link
        livemode:
          type: boolean
          description: '`true` pour de l''argent réel (clé live), `false` en sandbox'
        created:
          type:
            - string
            - 'null'
          format: date-time
          description: Date de création, ISO 8601
        type:
          type: string
          description: '`one_time` (un paiement) ou `recurring` (inscription à un plan).'
          enum:
            - one_time
            - recurring
        pricing_mode:
          type: string
          description: >-
            `fixed`, `flexible` (montant libre), `options` (plusieurs tarifs) ou
            `cart` (panier). Toujours `fixed` pour un lien `recurring`.
          enum:
            - fixed
            - flexible
            - options
            - cart
        title:
          type: string
          description: Titre affiché au client
        description:
          type:
            - string
            - 'null'
          description: Description
        amount:
          type:
            - integer
            - 'null'
          description: Prix fixe, en unités mineures
        minimum_amount:
          type:
            - integer
            - 'null'
          description: 'Montant libre : minimum accepté'
        currency:
          type: string
          description: Devise du lien
        plan:
          type:
            - string
            - 'null'
          description: Plan d'un lien récurrent (`plan_…`), `null` sinon
        price_options:
          type: array
          items:
            $ref: '#/components/schemas/PriceOption'
        items:
          type: array
          items:
            $ref: '#/components/schemas/CartItem'
        custom_fields:
          type: array
          items:
            $ref: '#/components/schemas/CustomField'
        collect_phone:
          type: boolean
          description: Demande le téléphone du payeur
        collect_address:
          type: boolean
          description: Demande l'adresse du payeur
        after_payment_message:
          type:
            - string
            - 'null'
          description: Affiché après un paiement réussi
        is_active:
          type: boolean
          description: '`false` : le lien n''accepte plus de paiement'
        max_uses:
          type:
            - integer
            - 'null'
          description: >-
            Plafond de `uses_count`. Une session en cours réserve une place
            jusqu'à son expiration.
        uses_count:
          type: integer
          description: Paiements réussis, ou inscriptions pour un lien `recurring`
        views_count:
          type: integer
          description: Ouvertures de la page du lien
        expires_at:
          type:
            - string
            - 'null'
          format: date-time
          description: Fin de validité
        archived_at:
          type:
            - string
            - 'null'
          format: date-time
          description: Date d'archivage
        success_url:
          type:
            - string
            - 'null'
          description: Retour après paiement réussi
        cancel_url:
          type:
            - string
            - 'null'
          description: Retour si le client abandonne
        metadata:
          type:
            - object
            - 'null'
          additionalProperties: true
          description: Vos données libres. Voir [Metadata](/developers/metadata).
        url:
          type: string
          description: Page publique du lien, à partager
          format: uri
    PriceOption:
      type: object
      properties:
        id:
          type: integer
          description: Identifiant, à renvoyer pour modifier ce tarif
        label:
          type: string
          description: Nom du tarif
        amount:
          type: integer
          description: Prix en unités mineures
    CartItem:
      type: object
      properties:
        id:
          type: integer
          description: Identifiant, à renvoyer pour modifier cet article
        name:
          type: string
          description: Nom de l'article
        description:
          type:
            - string
            - 'null'
          description: Description
        unit_amount:
          type: integer
          description: Prix unitaire en unités mineures
        min_quantity:
          type:
            - integer
            - 'null'
          description: Quantité minimale
        max_quantity:
          type:
            - integer
            - 'null'
          description: Quantité maximale
        variants:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
                description: Identifiant
              label:
                type: string
                description: Nom de la variante
              unit_amount:
                type:
                  - integer
                  - 'null'
                description: Prix propre à la variante
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            type:
              type: string
              enum:
                - authentication_error
                - invalid_request_error
                - idempotency_error
                - payment_error
                - rate_limit_error
                - api_error
            code:
              type: string
              description: Code stable, à tester dans votre code
            message:
              type: string
              description: Explication en français, pour un humain
            param:
              type:
                - string
                - 'null'
              description: Le premier champ en cause
            doc_url:
              type: string
              description: Explication de ce code
            request_id:
              type: string
              description: >-
                Identifiant de la requête (`req_…`), aussi dans l'en-tête
                `Request-Id`
            errors:
              type: object
              additionalProperties:
                type: array
                items:
                  type: string
              description: Détail par champ refusé, sur une erreur `422`
      required:
        - error
  responses:
    Unauthorized:
      description: Clé absente, invalide ou révoquée
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: authentication_error
              code: api_key_invalid
              message: Clé API invalide.
              param: null
              doc_url: https://docs.mercy-pay.com/developers/errors#api_key_invalid
              request_id: req_01jc8x4m2v7t9qk3n5w6y8z0ab
    Forbidden:
      description: Compte suspendu, ou clé live avant l'approbation du KYC
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: authentication_error
              code: live_mode_requires_kyc
              message: Le mode live demande un KYC approuvé.
              param: null
              doc_url: >-
                https://docs.mercy-pay.com/developers/errors#live_mode_requires_kyc
              request_id: req_01jc8x4m2v7t9qk3n5w6y8z0ab
    Conflict:
      description: Conflit avec l'état de la ressource, ou clé d'idempotence réutilisée
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: invalid_request_error
              code: conflict
              message: 'Cette ressource est utilisée : archivez-la.'
              param: null
              doc_url: https://docs.mercy-pay.com/developers/errors#conflict
              request_id: req_01jc8x4m2v7t9qk3n5w6y8z0ab
    ValidationFailed:
      description: Données invalides, avec le détail dans `errors`
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: invalid_request_error
              code: validation_failed
              message: Le champ amount est obligatoire.
              param: amount
              doc_url: https://docs.mercy-pay.com/developers/errors#validation_failed
              request_id: req_01jc8x4m2v7t9qk3n5w6y8z0ab
              errors:
                amount:
                  - Le champ amount est obligatoire.
    RateLimited:
      description: Plus de 60 requêtes par minute avec cette clé
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              type: rate_limit_error
              code: rate_limited
              message: Trop de requêtes.
              param: null
              doc_url: https://docs.mercy-pay.com/developers/errors#rate_limited
              request_id: req_01jc8x4m2v7t9qk3n5w6y8z0ab
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Votre clé API. Utilisez une clé sandbox (`mp_sandbox_…`) pour essayer :
        aucun argent réel ne bouge.

````

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