> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.client-p.pylote.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Whitelist et tracking

> Whitelister vos recruteurs (indispensable pour les contacter) et tracker les consultations de profils (obligation contractuelle)

Deux obligations partenaires, de nature différente :

|               | Whitelist recruteurs                            | Tracking consultations          |
| ------------- | ----------------------------------------------- | ------------------------------- |
| **Nature**    | Indispensable au bon fonctionnement             | **Engagement contractuel**      |
| **Endpoint**  | `POST /partners/whitelist`                      | `POST /partners/events`         |
| **Fréquence** | Une fois par recruteur                          | À chaque consultation de profil |
| **Si absent** | Le recruteur ne peut pas contacter le freelance | Suspension de l'accès API       |

## 1. Whitelist : indispensable pour le contact recruteur-freelance

### Pourquoi c'est indispensable

Pylote protège l'identité des freelances : leur email réel n'est **jamais** exposé. Tous les profils retournés par `GET /freelances` ont un email proxy en `@freelance.pylote.io`.

Pour que le proxy fonctionne dans les deux sens, **le recruteur doit lui aussi avoir un email proxy**. Pylote en génère un quand vous le whitelistez : `lutessa.marieg@recruiter.pylote.io`.

C'est ce couple d'emails proxy qui permet :

* Au recruteur d'**envoyer un mail au freelance** (relayé par Pylote)
* Au freelance de **répondre** (relayé dans l'autre sens)
* À Pylote de **mesurer les interactions** dans le dashboard du freelance

<Warning>
  Sans whitelist, le recruteur ne peut tout simplement **pas joindre** les freelances Pylote. Aucun message n'arrivera à destination, l'email proxy n'existe pas.

  Whitelistez **chaque recruteur de votre plateforme** dès qu'il accède à des profils Pylote.
</Warning>

### Premier setup : whitelister tous vos recruteurs en une fois

<Tip>
  **À l'onboarding**, vous avez probablement déjà des dizaines (voire des centaines) de recruteurs sur votre plateforme. Plutôt que de faire N appels unitaires, utilisez `POST /partners/whitelist/batch` qui en accepte jusqu'à 500 par appel.
</Tip>

```bash theme={null}
curl -X POST "https://client-p.pylote.io/partners/whitelist/batch" \
  -H "x-api-key: votre-cle-partenaire" \
  -H "Content-Type: application/json" \
  -d '{
    "recruiters": [
      { "recruiterEmail": "marie.gilles@lutessa.com",  "firstname": "Marie",  "lastname": "Gilles",  "company": "Lutessa" },
      { "recruiterEmail": "paul.durand@tmc-europe.com", "firstname": "Paul",  "lastname": "Durand",  "company": "TMC Europe" }
    ]
  }'
```

**Réponse** (succès partiel possible — un recruteur en erreur ne fait pas échouer les autres) :

```json theme={null}
{
  "results": [
    { "recruiterEmail": "marie.gilles@lutessa.com",   "whitelistedEmail": "lutessa.marieg@recruiter.pylote.io" },
    { "recruiterEmail": "paul.durand@tmc-europe.com", "whitelistedEmail": "tmceurope.pauld@recruiter.pylote.io" }
  ]
}
```

### Au fil de l'eau : whitelister un nouveau recruteur

Pour chaque nouveau recruteur ajouté ensuite à votre plateforme, l'endpoint unitaire :

```bash theme={null}
curl -X POST "https://client-p.pylote.io/partners/whitelist" \
  -H "x-api-key: votre-cle-partenaire" \
  -H "Content-Type: application/json" \
  -d '{
    "recruiterEmail": "marie.gilles@lutessa.com",
    "firstname": "Marie",
    "lastname": "Gilles",
    "company": "Lutessa"
  }'
```

**Réponse :**

```json theme={null}
{
  "whitelistedEmail": "lutessa.marieg@recruiter.pylote.io"
}
```

<Warning>
  Le champ `company` doit être l'entreprise **du recruteur** (ex : "Lutessa"), pas la vôtre (ex : "Agrega"). C'est ce nom qui apparaît dans le dashboard du freelance.
</Warning>

## 2. Tracking : obligation contractuelle

### Pourquoi c'est obligatoire

Pylote offre aux freelances une fonctionnalité de **visibilité** : ils voient en temps réel quelles entreprises consultent leur profil, avec quels mots-clés et quelles actions.

C'est une **feature premium** et un levier de conversion majeur pour Pylote. Sans le tracking des partenaires, les freelances ne voient rien des consultations passant par votre plateforme - ce qui dégrade l'expérience produit et la valeur de Pylote.

<Warning>
  Le tracking est un **engagement contractuel**. Tout partenaire utilisant l'API Pylote s'engage à remonter chaque interaction recruteur via `POST /partners/events`.

  Le non-respect peut entraîner la suspension de l'accès API.
</Warning>

### Ce que voit le freelance

Quand un recruteur de Lutessa consulte un profil via Agrega, le freelance voit dans son dashboard :

```
Lutessa via Agrega - a consulté votre profil - il y a 2h
Lutessa via Agrega - a téléchargé votre CV - il y a 1h
```

### Events à tracker

Chaque interaction recruteur-freelance doit générer un appel à `POST /partners/events`.

| Action           | Quand l'envoyer                                | Obligatoire |
| ---------------- | ---------------------------------------------- | ----------- |
| `profile_view`   | Le recruteur ouvre la fiche du freelance       | **Oui**     |
| `click_cv`       | Le recruteur clique sur le lien CV             | **Oui**     |
| `click_linkedin` | Le recruteur clique sur le lien LinkedIn       | **Oui**     |
| `click_phone`    | Le recruteur clique sur le téléphone           | Oui         |
| `click_email`    | Le recruteur clique sur l'email                | Oui         |
| `add_favorite`   | Le recruteur ajoute le freelance à ses favoris | Oui         |

<Note>
  Au minimum, `profile_view`, `click_cv` et `click_linkedin` doivent être trackés. Les events `click_phone`, `click_email` et `add_favorite` sont également attendus si ces actions sont disponibles sur votre plateforme.
</Note>

### Envoyer un event

```bash theme={null}
curl -X POST "https://client-p.pylote.io/partners/events" \
  -H "x-api-key: votre-cle-partenaire" \
  -H "Content-Type: application/json" \
  -d '{
    "recruiterEmail": "marie.gilles@lutessa.com",
    "freelanceId": "bc1d49cf-1cc7-4afe-92aa-0ebd545fcd12",
    "action": "profile_view"
  }'
```

**Réponse :**

```json theme={null}
{ "status": "ok" }
```

| Champ            | Description                                                                                                     |
| ---------------- | --------------------------------------------------------------------------------------------------------------- |
| `recruiterEmail` | Email réel du recruteur (doit être dans la whitelist)                                                           |
| `freelanceId`    | Champ `meta.id` du JSON Resume retourné par `GET /freelances`                                                   |
| `action`         | Type d'interaction (`profile_view`, `click_cv`, `click_linkedin`, `click_phone`, `click_email`, `add_favorite`) |

### Exemple d'implémentation (Node.js)

```javascript theme={null}
async function trackProfileView(recruiterEmail, freelanceId) {
  await axios.post(
    `https://client-p.pylote.io/partners/events`,
    {
      recruiterEmail,
      freelanceId,
      action: 'profile_view'
    },
    {
      headers: {
        'x-api-key': process.env.PYLOTE_PARTNER_KEY,
        'Content-Type': 'application/json'
      }
    }
  );
}

// Dans votre handler d'affichage de profil :
app.get('/freelance/:id', async (req, res) => {
  const freelance = await getFreelanceFromDB(req.params.id);
  const recruiter = req.user;

  // Tracker AVANT d'afficher le profil
  await trackProfileView(recruiter.email, freelance.pyloteId);

  res.render('freelance-profile', { freelance });
});
```

## Flow complet

```mermaid theme={null}
sequenceDiagram
    participant R as Recruteur
    participant P as Partenaire
    participant API as Pylote API
    participant F as Freelance (extension)

    Note over P,API: 1. Whitelist (une fois par recruteur)
    P->>API: POST /partners/whitelist
    Note right of P: {recruiterEmail, firstname, lastname, company}
    API-->>P: {whitelistedEmail: "lutessa.marieg@recruiter.pylote.io"}

    Note over P,API: 2. Sync (périodique)
    P->>API: GET /freelances?modifiedTime=...
    API-->>P: [{meta: {id: "abc123"}, basics: {email: "...@freelance.pylote.io"}}]

    Note over R,F: 3. Usage quotidien
    R->>P: Ouvre la fiche d'un freelance
    P->>API: POST /partners/events {action: "profile_view"}
    API-->>P: {status: "ok"}
    API->>F: Dashboard : "Lutessa via Agrega"

    R->>P: Contacte le freelance
    P->>API: Email via proxy recruiter.pylote.io <-> freelance.pylote.io
    API->>F: Mail relayé au freelance
```

## Obligations de suppression

En plus du tracking, vous devez **supprimer les profils deleted** de votre base dans un **délai de 30 jours** suivant la réception du statut de suppression.

Quand `GET /freelances` retourne un profil avec `meta.status: "deleted"` :

1. Supprimez le profil de votre base de données
2. Supprimez toutes les données associées (CV caché, notes, etc.)
3. Ne conservez que l'ID pour éviter de ré-importer le profil

<Warning>
  Le délai de **30 jours** est contractuel. Passé ce délai, Pylote se réserve le droit de suspendre l'accès API.
</Warning>

Les statuts de suppression sont :

* `account_deleted` - le freelance a supprimé son compte
* `account_banned` - compte banni par Pylote
* `account_excluded` - compte exclu
* `account_invisible` - profil rendu invisible

<Info>
  Utilisez la route `GET /freelances/deleted-freelances` pour récupérer la liste complète des profils à supprimer si vous avez manqué des synchronisations.
</Info>

## Destruction des données en cas de résiliation

En cas de résiliation du contrat de partenariat (quelle qu'en soit la cause) :

1. Votre Clé API sera **révoquée** à la date d'effet de la résiliation
2. Vous devez **cesser toute utilisation** de l'API immédiatement
3. Vous devez **détruire toutes les données** issues de l'API stockées dans vos systèmes

<Note>
  Exception : les données déjà intégrées dans les profils de vos clients recruteurs et traitées sous leur propre responsabilité ne sont pas concernées par cette obligation de destruction.
</Note>
