# SDK serveur Python

URL: https://traqio.app/fr/docs/sdks/python
Last updated: 2026-10-16

Signalez inscriptions et achats depuis un backend Python avec le paquet traqio, et rattachez chacun à son clic publicitaire. Django, Flask, FastAPI.

`traqio` est le SDK Traqio pour les backends Python — la moitié serveur du SDK web de Traqio. La conversion qui compte sur un site — une inscription, un abonnement, un achat — a lieu sur votre backend, là où l’id utilisateur est connu. Ce paquet la signale avec le **trackID**, le click id de la publicité que [@traqio/web](https://traqio.app/fr/docs/sdks/web) a gardé en stockage first-party depuis la page d’arrivée, et Traqio crédite la campagne qui a amené l’utilisateur — [de façon déterministe](https://traqio.app/fr/docs/concepts/web-attribution), par l’id de ce clic. Bibliothèque standard uniquement ; Django, Flask, FastAPI ou tout autre framework.

## Prérequis

- Python 3.9 ou plus. Aucune dépendance ; typé (`py.typed`).
- Une **clé serveur** pour le produit (`tq_sk_…`). Ni la clé SDK de l’app ni une clé web ne fonctionnent ici.
- [@traqio/web](https://traqio.app/fr/docs/sdks/web) sur le site, et des publicités qui pointent vers des [liens de tracking](https://traqio.app/fr/docs/concepts/tracking-links) avec une destination site web — c’est ainsi que le trackID arrive jusqu’à votre formulaire d’inscription.

## Mise en place

### Créer une clé serveur

Dans la console, ouvrez **Intégrations → SDK** et créez une **clé serveur**. Elle n’est affichée qu’une fois : placez-la dans l’environnement du backend, jamais dans le code ni dans une page. Traqio n’en garde qu’une empreinte ; une clé perdue est remplacée par une nouvelle, et l’ancienne révoquée.

.env:
```bash
TRAQIO_SECRET_KEY=tq_sk_...
```

### Installer le paquet

```bash
pip install traqio
```

Tant que le paquet n’est pas sur PyPI, installez le wheel que nous vous envoyons :

```bash
# the file you received, committed inside the backend's repository
pip install ./vendor/traqio-0.1.0-py3-none-any.whl
```

### Créer le client

```python
import os
from traqio import Traqio

# One client per process. The key comes from the server's environment, never from code.
traqio = Traqio(os.environ["TRAQIO_SECRET_KEY"])
```

Le client ne garde aucune connexion ouverte : un par processus suffit. Il refuse une clé web (`tq_web_…`).

### Signaler l’inscription avec son trackID

Appelez `signup()` une fois, là où le compte est créé. @traqio/web écrit le trackID dans le cookie `traq_click` sur votre propre domaine : le navigateur l’envoie donc avec la requête d’inscription.

Django:
```python
from traqio import TraqioError, track_id_from_request

def signup(request):
    user = User.objects.create_user(...)
    try:
        traqio.signup(str(user.pk), track_id_from_request(request))
    except TraqioError as error:
        logger.warning("traqio: %s", error)  # never fail the sign-up itself
    return redirect("/welcome")
```

Flask:
```python
from flask import request
from traqio import track_id_from_request

@app.post("/signup")
def signup():
    user = create_user(request.form)
    traqio.signup(str(user.id), track_id_from_request(request))
    return redirect("/welcome")
```

FastAPI:
```python
from fastapi import BackgroundTasks, Request
from traqio import track_id_from_request

@app.post("/signup")
async def signup(request: Request, background: BackgroundTasks):
    user = await create_user(await request.json())
    # The client is synchronous: a background task runs it in a thread, after the response.
    background.add_task(traqio.signup, str(user.id), track_id_from_request(request))
    return {"id": user.id}
```

Si le backend est sur un autre domaine que le site, le cookie ne lui parvient pas : envoyez plutôt `Traqio.getTrackId()` depuis le navigateur avec le formulaire. L’inscription est le moment où l’utilisateur est **acquis** ; le dernier clic qui la précède, dans votre [fenêtre d’attribution](https://traqio.app/fr/docs/concepts/attribution-windows), reçoit le crédit.

### Suivre les conversions

```python
traqio.track(
    str(user.pk),
    "purchase",
    value=49,
    currency="EUR",
    transaction_id=payment_intent.id,  # one payment, one row — whoever reports it
    store="stripe",
)
```

Les conversions suivent l’utilisateur : elles sont créditées à la campagne qui l’a acquis.

## Ce que dit la réponse

```python
result = traqio.signup(str(user.pk), track_id)

result.track_id                 # "matched" | "unknown" | "expired" | "claimed" | "refused" | None
result.acquired                 # True: the sign-up is recorded
result.attribution.network      # "meta", "tiktok"… or "organic"
result.attribution.campaign_id  # the campaign that brought the user
```

| track_id | Signification |
| --- | --- |
| matched | Le clic appartient désormais à cet utilisateur. Une nouvelle tentative répond de nouveau matched. |
| unknown | Aucun clic de ce produit n’a cet id — une faute de frappe, le lien d’un autre produit, ou une valeur que @traqio/web n’a pas écrite. |
| expired | Le clic est plus ancien que la fenêtre d’attribution du produit. |
| claimed | Un autre utilisateur, ou une installation d’app, possède déjà ce clic. Un clic crédite une seule identité. |
| refused | Le clic a échoué à une règle anti-fraude (il est passé par un réseau d’anonymisation). Il est compté, jamais crédité. |

## Ce qu’il fait aujourd’hui, et ce qu’il ne fait pas

|  | Aujourd’hui |
| --- | --- |
| Rattacher une inscription à son clic, et dire qui a été crédité | Oui — dans la réponse |
| Enregistrer les achats avec valeur, devise et id de paiement, dédoublonnés | Oui |
| Laisser intacts les installations, revenus et ROAS de vos apps | Oui — jamais rattachés à une installation d’app |
| Afficher les conversions web dans les rapports de la console | Oui — par campagne, à côté des installations |
| Envoyer les conversions web à Meta ou TikTok | Pas encore |

Les conversions envoyées ici apparaissent dans **Événements en direct**, marquées comme non rapprochées d’une installation — c’est normal pour un site web. Une inscription créditée à une campagne est comptée dans le rapport ROAS comme une conversion web de cette campagne, à côté de ses installations, et la réponse de chaque appel vous donne l’attribution tout de suite.

## Erreurs et nouvelles tentatives

Une erreur réseau, un timeout, un `429` ou un `5xx` est retenté — deux fois par défaut, avec le même corps, donc rien n’est compté deux fois. Un `4xx` (clé erronée ou révoquée, payload invalide) n’est pas retenté. Les deux se terminent par une `TraqioError` :

```python
from traqio import TraqioError

try:
    traqio.signup(str(user.pk), track_id)
except TraqioError as error:
    # error.status: 401 = wrong or revoked key, 400 = invalid payload, None = network
    logger.warning("traqio: %s (status %s)", error, error.status)
```

> **Signalez après votre propre écriture** Appelez Traqio une fois le compte ou le paiement enregistré, et ne laissez jamais une erreur Traqio le faire échouer.

## Référence de l’API

Traqio(…):
```python
Traqio(
    secret_key,            # the server key, tq_sk_… — required
    endpoint="https://api.traqio.app",
    timeout=10.0,          # seconds per attempt
    max_retries=2,         # after a network error, a 429 or a 5xx
    transport=None,        # a custom transport (proxies, tests)
)
```

| Méthode | Ce qu’elle fait |
| --- | --- |
| signup(user_id, track_id=None, events=()) | Signale l’inscription — l’acquisition — avec son trackID. La première est conservée. |
| track(user_id, name, *, value, currency, transaction_id, store, event_id, track_id) | Enregistre une conversion d’un utilisateur connu. |
| send(user_id, *, track_id, signup, events) | L’appel brut derrière les deux, pour plusieurs événements à la fois. |
| track_id_from_request(request) | Le trackID tiré d’une requête Django, Flask ou Starlette, ou None. |
| track_id_from_cookie_header(header) | La même chose, depuis un en-tête Cookie brut. |

> **Niveau de preuve** Testé sur Python 3.9 et 3.11, transport HTTP réel compris, et exécuté de bout en bout contre une API Traqio en fonctionnement : une inscription portant un trackID est revenue matched avec sa campagne, un clic inconnu a reçu unknown, une clé erronée a été refusée. Pas encore exécuté dans le backend de production d’un client.

## Questions fréquentes

**Existe-t-il un client asynchrone ?**
Pas aujourd’hui : le client est synchrone et n’utilise que la bibliothèque standard. Dans FastAPI ou Starlette, confiez l’appel à une tâche d’arrière-plan, qui l’exécute dans un thread après la réponse — la page montre comment.

**Quels frameworks peuvent lire le trackID ?**
track_id_from_request lit les requêtes Django (l’en-tête Cookie), Flask et Starlette / FastAPI (leurs cookies), et tout objet doté d’un mapping headers. Il renvoie None quand le visiteur ne vient pas d’une publicité.

**Et si le visiteur ne vient pas d’une publicité ?**
Passez None. L’inscription est quand même enregistrée, et l’utilisateur est organique : aucune campagne n’est créditée.

**Une nouvelle tentative compte-t-elle un achat deux fois ?**
Non. Chaque appel génère ses ids d’événement une seule fois et renvoie exactement le même corps, et un achat est aussi identifié par son transaction_id : le même paiement signalé deux fois est stocké une fois.
