# Valider un achat Paddle

> Valide un achat à l'aide du jeton Paddle fourni en utilisant les identifiants Paddle dans les paramètres de votre application dans l'Adapty Dashboard.
> Si l'achat est valide, l'historique des transactions est importé depuis Paddle vers le profil dans Adapty avec le customer_user_id spécifié.
> Si aucun profil avec ce customer_user_id n'existait auparavant, il sera créé.

## OpenAPI

```yaml
/api-specs/adapty-api.yaml post /api/v2/server-side-api/purchase/paddle/token/validate/
openapi: 3.1.0
info:
  title: API côté serveur Adapty
  version: 1.0.0
servers:
  - url: https://api.adapty.io
    description: Serveur de production
paths:
  /api/v2/server-side-api/purchase/paddle/token/validate/:
    post:
      summary: Valider un achat Paddle
      description: |
        Valide un achat à l'aide du jeton Paddle fourni en utilisant les identifiants Paddle dans les paramètres de votre application dans l'Adapty Dashboard.
        Si l'achat est valide, l'historique des transactions est importé depuis Paddle vers le profil dans Adapty avec le customer_user_id spécifié.
        Si aucun profil avec ce customer_user_id n'existait auparavant, il sera créé.
      operationId: validatePaddlePurchase
      tags:
        - Paddle
      security:
        - apikeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaddleValidationRequest"
            example:
              customer_user_id: <YOUR_CUSTOMER_USER_ID>
              paddle_token: live_7d279f61a3339fed520f7cd8c08
      responses:
        "200":
          description: Achat validé avec succès
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProfileResponse"
              example:
                data:
                  app_id: 14c3d623-2f3a-455a-aa86-ef83dff6913b
                  profile_id: 3286abd3-48b0-4e9c-a5f6-ac0a006804a6
                  customer_user_id: Jane.doe@example.com
                  total_revenue_usd: 0
                  segment_hash: 8f45947bad31ab0c
                  timestamp: 1736436751469
                  custom_attributes:
                    - key: favourite_sport
                      value: yoga
                  access_levels: []
                  subscriptions:
                    - purchase_id: 5a7ab471-2299-45f7-ad69-1d395c1256e3
                      store: app_store
                      store_product_id: 1year.premium
                      store_base_plan_id: null
                      store_transaction_id: "30002109551456"
                      store_original_transaction_id: "30002109551456"
                      purchased_at: "2022-10-12T09:42:50+00:00"
                      environment: Production
                      is_refund: false
                      is_consumable: false
                  non_subscriptions: []
        "400":
          description: Requête incorrecte
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                no_products_found:
                  summary: Aucun produit trouvé
                  value:
                    errors:
                      - No products found
                    error_code: no_products_found
                    status_code: 400
                paddle_api_key_not_found:
                  summary: Clé API Paddle introuvable
                  value:
                    errors:
                      - Paddle API key not found
                    error_code: paddle_api_key_not_found
                    status_code: 400
                invalid_paddle_credentials_or_purchase_not_found:
                  summary: Identifiants Paddle invalides ou achat introuvable
                  value:
                    errors:
                      - Invalid Paddle credentials or purchase not found
                    error_code: invalid_paddle_credentials_or_purchase_not_found
                    status_code: 400
        "401":
          description: Non autorisé
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              example:
                errors:
                  - Invalid API key
                error_code: unauthorized
                status_code: 401
        "500":
          description: Erreur interne du serveur
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
components:
  schemas:
    PaddleValidationRequest:
      type: object
      properties:
        customer_user_id:
          type: string
          description: L'identifiant de votre utilisateur dans votre système
        paddle_token:
          type: string
          description: |
            Jeton d'un objet Paddle représentant un achat unique.
            Peut être soit un identifiant de transaction (txn_...) soit un identifiant d'abonnement (sub_...)
      required:
        - customer_user_id
        - paddle_token
    ProfileResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/Profile"
      required:
        - data
    ErrorResponse:
      type: object
      properties:
        errors:
          type: array
          items:
            type: object
            properties:
              source:
                type: string
                nullable: true
                description: Source de l'erreur
              errors:
                type: array
                items:
                  type: string
                description: Tableau de messages d'erreur
        error_code:
          type: string
          description: Nom court de l'erreur
        status_code:
          type: integer
          description: Code de statut HTTP
      required:
        - errors
        - error_code
        - status_code
    Profile:
      type: object
      properties:
        app_id:
          type: string
          format: uuid
          description: L'identifiant interne de votre application
        profile_id:
          type: string
          format: uuid
          description: Identifiant de profil Adapty
        customer_user_id:
          type: string
          nullable: true
          description: L'identifiant de votre utilisateur dans votre système
        total_revenue_usd:
          type: number
          format: float
          description: Valeur décimale représentant le chiffre d'affaires total en USD généré par le profil
        segment_hash:
          type: string
          description: Paramètre interne
        timestamp:
          type: integer
          format: int64
          description: Temps de réponse en millisecondes, nécessaire pour résoudre une condition de concurrence
        custom_attributes:
          type: array
          items:
            $ref: "#/components/schemas/CustomAttribute"
          description: Maximum de 30 attributs personnalisés autorisés pour le profil
        access_levels:
          type: array
          items:
            $ref: "#/components/schemas/AccessLevel"
          description: Tableau d'objets de niveau d'accès. Tableau vide si le client n'a aucun niveau d'accès
        subscriptions:
          type: array
          items:
            $ref: "#/components/schemas/Subscription"
          description: Tableau d'objets d'abonnement. Tableau vide si le client n'a aucun abonnement
        non_subscriptions:
          type: array
          items:
            $ref: "#/components/schemas/NonSubscription"
          description: Tableau d'objets hors abonnement. Tableau vide si le client n'a aucun achat
      required:
        - app_id
        - profile_id
        - customer_user_id
        - total_revenue_usd
        - segment_hash
        - timestamp
        - custom_attributes
        - access_levels
        - subscriptions
        - non_subscriptions
    CustomAttribute:
      type: object
      properties:
        key:
          type: string
          maxLength: 30
          description: La clé doit être une chaîne de caractères d'au plus 30 caractères. Seuls les lettres, chiffres, tirets, points et underscores sont autorisés
        value:
          oneOf:
            - type: string
            - type: number
          description: La valeur de l'attribut doit comporter au plus 50 caractères. Seules les chaînes de caractères et les décimaux sont autorisés comme valeurs
      required:
        - key
        - value
    AccessLevel:
      type: object
      properties:
        access_level_id:
          type: string
          description: Identifiant du niveau d'accès
        store:
          type: string
          description: Store où le niveau d'accès a été acheté
        store_product_id:
          type: string
          description: Identifiant du produit dans le store
        store_base_plan_id:
          type: string
          nullable: true
          description: Identifiant du plan de base dans le store
        store_transaction_id:
          type: string
          description: Identifiant de transaction dans le store
        store_original_transaction_id:
          type: string
          description: Identifiant de transaction originale dans le store
        offer:
          allOf:
            - $ref: "#/components/schemas/OfferDTO"
          nullable: true
          description: Détails de l'offre, si une offre promotionnelle ou de lancement a été appliquée
        starts_at:
          type: string
          format: date-time
          nullable: true
          description: Quand le niveau d'accès commence
        purchased_at:
          type: string
          format: date-time
          description: Quand le niveau d'accès a été acheté
        originally_purchased_at:
          type: string
          format: date-time
          description: Quand le niveau d'accès a été acheté initialement
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: Quand le niveau d'accès expire
        renewal_cancelled_at:
          type: string
          format: date-time
          nullable: true
          description: Quand le renouvellement a été annulé
        billing_issue_detected_at:
          type: string
          format: date-time
          nullable: true
          description: Quand un problème de facturation a été détecté
        is_in_grace_period:
          type: boolean
          description: Si le niveau d'accès est en délai de grâce
        cancellation_reason:
          type: string
          nullable: true
          description: Raison de l'annulation
    Subscription:
      type: object
      properties:
        store:
          type: string
          description: Store où l'abonnement a été acheté
        store_product_id:
          type: string
          description: Identifiant du produit dans le store
        store_base_plan_id:
          type: string
          nullable: true
          description: Identifiant du plan de base dans le store
        store_transaction_id:
          type: string
          description: Identifiant de transaction dans le store
        store_original_transaction_id:
          type: string
          description: Identifiant de transaction originale dans le store
        offer:
          allOf:
            - $ref: "#/components/schemas/OfferDTO"
          nullable: true
          description: Détails de l'offre, si une offre promotionnelle ou de lancement a été appliquée
        environment:
          type: string
          description: Environnement (Sandbox, Production)
        purchased_at:
          type: string
          format: date-time
          description: Quand l'abonnement a été acheté
        originally_purchased_at:
          type: string
          format: date-time
          description: Quand l'abonnement a été acheté initialement
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: Quand l'abonnement expire
        renewal_cancelled_at:
          type: string
          format: date-time
          nullable: true
          description: Quand le renouvellement a été annulé
        billing_issue_detected_at:
          type: string
          format: date-time
          nullable: true
          description: Quand un problème de facturation a été détecté
        is_in_grace_period:
          type: boolean
          description: Si l'abonnement est en délai de grâce
        cancellation_reason:
          type: string
          nullable: true
          description: Raison de l'annulation
    NonSubscription:
      type: object
      properties:
        purchase_id:
          type: string
          format: uuid
          description: Identifiant unique de l'achat
        store:
          type: string
          description: Store où l'achat a été effectué
        store_product_id:
          type: string
          description: Identifiant du produit dans le store
        store_base_plan_id:
          type: string
          nullable: true
          description: Identifiant du plan de base dans le store
        store_transaction_id:
          type: string
          description: Identifiant de transaction dans le store
        store_original_transaction_id:
          type: string
          description: Identifiant de transaction originale dans le store
        purchased_at:
          type: string
          format: date-time
          description: Quand l'achat a été effectué
        environment:
          type: string
          description: Environnement (Sandbox, Production)
        is_refund:
          type: boolean
          description: Si cet achat est un remboursement
        is_consumable:
          type: boolean
          description: Si cet achat est un consommable
    OfferDTO:
      type: object
      properties:
        category:
          type: string
          enum:
            - introductory
            - promotional
            - offer_code
            - win_back
          description: Catégorie de l'offre
        type:
          type: string
          enum:
            - free_trial
            - pay_as_you_go
            - pay_up_front
          description: Type d'offre
        id:
          type: string
          nullable: true
          description: Identifiant de l'offre
      required:
        - category
        - type
  securitySchemes:
    apikeyAuth:
      type: apiKey
      name: Authorization
      in: header
      default: Api-Key {Your secret API key}
      description: |
        Les requêtes API doivent être authentifiées par votre clé API secrète via l'en-tête **Authorization** 
        avec la valeur `Api-Key {your_secret_api_key}`, par exemple, 
        `Api-Key secret_live_...`. Retrouvez cette clé dans l'Adapty Dashboard -> 
        **App Settings** -> onglet **General** -> section **API keys**.
```
