# Enregistrer un événement de transaction

> Enregistre un événement de transaction de store pour un profil. Adapty Mail utilise les événements de transaction pour placer
> les profils dans des flows basés sur les achats — l'`event_type` correspond à des flows tels que renouvellement annulé,
> problème de facturation, expiré et remboursé — ainsi que pour l'attribution des revenus.
>
> Envoyez ces événements lorsque vous gérez des achats, des renouvellements et des annulations. Seul le
> flow **jamais acheté** fonctionne sans eux.

## OpenAPI

```yaml
/api-specs/adapty-mail-api.yaml post /api/v1/profile/transaction-event/save/
openapi: 3.1.0
info:
  title: Adapty Mail API
  version: 1.0.0
  description: |
    L'API Adapty Mail vous permet d'envoyer des profils utilisateur et des événements de transaction à Adapty Mail directement
    depuis votre serveur, sans faire transiter les données par le SDK Adapty.

    Utilisez-la pour :

    - Ajouter des abonnés lorsque vous n'avez pas encore de base dans Adapty Mail.
    - Réutiliser la base d'abonnés de vos autres applications.
    - Alimenter Adapty Mail en mode serveur à serveur, avec votre backend comme source de vérité.

    Un profil avec une adresse e-mail suffit pour le flow **never purchased**. Tous les autres flows
    (renewal cancelled, billing issue, expired, refunded) sont pilotés par l'historique d'achats, donc ces
    profils ont également besoin d'événements de transaction pour être placés dans le bon flow.

    Pour un guide étape par étape, consultez [Envoyer des e-mails et des transactions via l'API Adapty Mail](/docs/mail-send-data-via-api).
servers:
  - url: https://api-mail.adapty.io
    description: Serveur de production
paths:
  /api/v1/profile/transaction-event/save/:
    post:
      summary: Enregistrer un événement de transaction
      description: |
        Enregistre un événement de transaction de store pour un profil. Adapty Mail utilise les événements de transaction pour placer
        les profils dans des flows basés sur les achats — l'`event_type` correspond à des flows tels que renouvellement annulé,
        problème de facturation, expiré et remboursé — ainsi que pour l'attribution des revenus.

        Envoyez ces événements lorsque vous gérez des achats, des renouvellements et des annulations. Seul le
        flow **jamais acheté** fonctionne sans eux.
      operationId: saveTransactionEvent
      security:
        - apikeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TransactionEventDTO"
            examples:
              basic:
                summary: A new monthly subscription purchase
                value:
                  event_type: subscription_started
                  event_id: evt_abc123
                  event_datetime: "2026-06-10T14:20:05Z"
                  external_profile_id: user_12345
                  store: app_store
                  store_product_id: premium_monthly
                  store_transaction_id: "1000000123456789"
                  store_original_transaction_id: "1000000123456789"
                  purchased_at: "2026-06-10T14:20:00Z"
                  originally_purchased_at: "2026-06-10T14:20:00Z"
                  price_usd: "9.99"
                  expires_at: "2026-07-10T14:20:00Z"
      responses:
        "200":
          description: Événement de transaction enregistré avec succès. Le corps de la réponse est un objet vide.
          content:
            application/json:
              schema:
                type: object
              examples:
                default:
                  value: {}
        "400":
          description: Échec de la validation — un champ obligatoire est manquant ou invalide. `field_name` indique le champ concerné.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Errors"
              examples:
                default:
                  value:
                    errors:
                      - message: Field required
                        error_code: base_error
                        status_code: 400
                        field_name: event_type
        "403":
          description: Clé API secrète manquante ou invalide.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Errors"
              examples:
                default:
                  value:
                    errors:
                      - message: Secret key doesn't exist
                        error_code: secret_key_does_not_exist_error
                        status_code: 403
                        field_name: null
components:
  schemas:
    TransactionEventDTO:
      type: object
      required:
        - event_type
        - event_id
        - event_datetime
        - external_profile_id
        - store
        - store_product_id
        - store_transaction_id
        - store_original_transaction_id
        - purchased_at
        - originally_purchased_at
      properties:
        event_type:
          $ref: "#/components/schemas/TransactionEventType"
        event_id:
          type: string
          description: Identifiant unique de cet événement, géré par votre système. Utilisez-le pour garantir l'idempotence des événements.
        event_datetime:
          type: string
          format: date-time
          description: Date et heure d'enregistrement de l'événement, au format ISO 8601.
        external_profile_id:
          type: string
          description: |
            Le même `external_profile_id` stable que vous envoyez lors de l'enregistrement du profil. Associe la
            transaction au bon profil.

            Vous pouvez envoyer une transaction avant que le profil n'existe. Adapty Mail conserve l'événement
            sans association et le lie au profil lors du prochain enregistrement portant le même identifiant.
        customer_user_id:
          type: string
          description: |
            L'identifiant de l'utilisateur dans votre propre système. Adapty Mail l'utilise pour retrouver le profil lorsque
            `external_profile_id` ne correspond à aucun profil. Il n'est pas stocké sur l'événement.
        email:
          type: string
          format: email
          description: |
            L'adresse e-mail de l'acheteur. Adapty Mail l'utilise pour retrouver le profil lorsqu'aucun
            identifiant ne correspond. Elle n'est pas stockée sur l'événement.
        store:
          type: string
          description: Le store dont provient la transaction, par exemple `app_store`, `play_store` ou `stripe`.
        store_product_id:
          type: string
          description: Identifiant du produit acheté dans le store.
        store_transaction_id:
          type: string
          description: Identifiant de cette transaction dans le store.
        store_original_transaction_id:
          type: string
          description: Identifiant de la première transaction dans la chaîne d'abonnement. Pour le premier achat, il est égal à `store_transaction_id`.
        purchased_at:
          type: string
          format: date-time
          description: Date et heure de cette transaction, au format ISO 8601.
        originally_purchased_at:
          type: string
          format: date-time
          description: Date et heure du premier achat de l'abonnement, au format ISO 8601.
        price_usd:
          type: string
          description: Le montant de la transaction en USD, sous forme de chaîne décimale (par exemple, `"9.99"`).
        expires_at:
          type: string
          format: date-time
          description: Date et heure d'expiration de l'abonnement, au format ISO 8601. À omettre pour les achats uniques.
        offer:
          $ref: "#/components/schemas/Offer"
    Errors:
      type: object
      description: Réponse d'erreur standard. Chaque échec renvoie un statut 4XX avec cette structure.
      properties:
        errors:
          type: array
          items:
            type: object
            properties:
              message:
                type: string
                description: Description de l'erreur lisible par un humain.
              error_code:
                type: string
                description: Identifiant d'erreur lisible par une machine.
              status_code:
                type: integer
                description: Code de statut HTTP pour cette erreur.
              field_name:
                type: string
                description: Le champ de la requête à l'origine de l'erreur, ou `null` si l'erreur n'est pas liée à un champ spécifique.
    TransactionEventType:
      type: string
      description: Le type d'événement de transaction. Les flux basés sur les achats sont déclenchés par ces valeurs.
      enum:
        - subscription_started
        - subscription_renewed
        - subscription_renewal_cancelled
        - subscription_renewal_reactivated
        - billing_issue_detected
        - entered_grace_period
        - subscription_refunded
        - subscription_expired
        - non_subscription_purchase
        - non_subscription_purchase_refunded
    Offer:
      type: object
      description: Détails d'une offre promotionnelle ou d'une offre de lancement appliquée à la transaction.
      required:
        - category
        - offer_type
      properties:
        category:
          $ref: "#/components/schemas/OfferCategory"
        offer_type:
          $ref: "#/components/schemas/OfferType"
        offer_id:
          type: string
          description: Identifiant de l'offre dans le store, le cas échéant.
    OfferCategory:
      type: string
      enum:
        - introductory
        - promotional
        - offer_code
        - win_back
    OfferType:
      type: string
      enum:
        - free_trial
        - pay_as_you_go
        - pay_up_front
  securitySchemes:
    apikeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: |
        Authentifiez chaque requête avec votre clé API secrète Adapty Mail, envoyée en tant qu'en-tête **Authorization**
        avec la valeur `Bearer {your_secret_api_key}`, par exemple, `Bearer secret_live_...`.

        Vous trouverez cette clé dans Adapty Mail sous **Settings**. La clé est spécifique au projet — elle identifie le
        projet auquel les données appartiennent, ainsi les endpoints de profil et de transaction ne nécessitent pas d'ID de projet.
```
