# API Mobilic - documentation

Mobilic est un outil numérique dont le but est de simplifier et d'améliorer le suivi du temps de travail dans le transport routier.

Le coeur de Mobilic est une API qui permet aux applications métier de transmettre et de lire simplement les données relatives au temps de travail. La présente documentation détaille les grands principes ainsi que le fonctionnement de cette API.

{% embed url="<https://youtu.be/8EcIlThBlSY>" %}
Découvrez le processus d'interfaçage avec Mobilic
{% endembed %}

{% hint style="info" %}
Le protocole OAuth n'est plus recommandé. Pour plus d'information, voir [Authentification](/guides/authentification)
{% endhint %}

## Architecture globale

L'API Mobilic est vouée à être utilisée par 3 types d'acteurs :

* les applications métier des travailleurs mobiles, plutôt sur support mobile ou embarqué, qui vont alimenter l'API en données
* les applications métier des exploitants des entreprises de transport, susceptibles de consommer la donnée à différentes fins (pré-paie, gestion RH, analyse des coûts, ...)
* les outils numériques des corps de contrôle, qui vont se servir des données comme base de contrôle

![](/files/Vu1dpAkSiUQjzrU5Eq6Q)

## Notre brochure&#x20;

{% file src="/files/MlGX0vYr3IuLc5ozBYi8" %}


# Philosophie de l'API

Dans ses grandes lignes l'API Mobilic est un simple système d'enregistrement des activités, dans un esprit très proche de celui du tachygraphe.

L'API agrège pour chaque travailleur mobile la succession de ses activités à partir des informations transmises par les applications métier. Ces dernières peuvent en retour demander à accéder à tout ou partie de la série temporelle.

## Activité

Le concept d'activité est central. Il est caractérisé par :

* l'identité du travailleur mobile qui effectue l'activité
* l'horodatage de début
* l'horodatage de fin
* la nature (déplacement, travail en dehors du véhicule)

Ainsi une activité peut être vue comme une période de la journée d'un travailleur mobile associée à un type de travail. Les temps de repos sont déduits comme étant les creux entre les différentes périodes. L'historique des activités pour un travailleur donné est suffisant pour recalculer les temps de travail (et de repos) agrégés à différentes échelles et ainsi vérifier le respect de la réglementation.

## Mission

La mission permet de regrouper des activités d'un même travailleur ou de travailleurs différents. C'est une notion qui n'a pas d'impact sur la mesure du temps de travail et le contrôle de la réglementation, entièrement basés sur l'activité.

Le concept est plutôt orienté vers les besoins des exploitants :

* pour calculer le temps total réel d'un "chantier", et donc le coût réel, et l'opposer au prix facturé
* pour rendre compte de la notion d'équipe
* pour valider d'un bloc le temps de travail plutôt que activité par activité

## Temps réel

Il existe deux manières d'enregistrer les activités :

1. l'approche en temps réel qui repose sur des événements de changement d'activité. La durée d'une activité n'est déterminée qu'a posteriori, au moment du prochain changement d'activité.
2. l'enregistrement en différé où les activités sont renseignées avec leurs durées, à la manière d'un emploi du temps (ex. : j'ai travaillé de 9h à 12h, de 14h à 17h et entre les deux j'étais en pause).

L'API Mobilic permet de faire les deux mais privilégie fortement l'approche temps réel. La seconde approche est pensée principalement comme un outil de corrections ponctuelles. Dans le mode "temps réel" l'API tient soigneusement compte de l'heure de réception par le serveur des événements, tout en permettant à l'appelant de préciser la véritable heure métier (très utile lorsque les événements ne peuvent pas être soumis tout de suite, pour des raisons de connectivité par exemple).

Ce fonctionnement vise à garantir les avantages suivants :

* en enregistrant les changements d'activité dès qu'ils se produisent on réduit fortement l'imprécision dans la mesure du temps de travail par rapport à une déclaration a posteriori
* le risque de falsification est également atténué

Pour comprendre plus en détail le fonctionnement de l'approche en temps réel voir [Enregistrement des activités](/guides/enregistrement-des-activites).

## Rattachement des salariés <a href="#rattachement-des-salaries" id="rattachement-des-salaries"></a>

Les comptes utilisateurs sont liés à la personne titulaire du compte, indépendamment de son entreprise ou de son métier (travailleur mobile ou gestionnaire). Ainsi une personne qui change d'entreprise garde quand même un seul et même compte.

L'appartenance (variable dans le temps) d'une personne à une entreprise est représentée par un rattachement. Un compte peut avoir plusieurs rattachements dans le temps, au fur et à mesure que la personne passe d'une entreprise à l'autre.

Un compte peut également être rattaché simultanément à plusieurs entreprises, pour répondre au cas fréquent de sociétés sœurs qui peuvent occasionnellement mutualiser leurs travailleurs.

{% hint style="info" %}
Par défaut le temps de travail enregistré par un compte travailleur mobile sera associé à l'entreprise à laquelle il est rattaché au moment de l'activité. Si il y a plusieurs rattachements simultanés le rattachement principal (unique) prévaut en l'absence de précision supplémentaire.
{% endhint %}

Pour des raisons de sécurité le rattachement d'une personne à une entreprise doit être approuvé à la fois par l'entreprise et par le salarié. Cela se fait dans l'ordre suivant :

1. L'entreprise (c'est-à-dire un utilisateur Mobilic qui a les droits d'administration de cette entreprise) effectue une demande de rattachement du salarié par API, en précisant une date de début du rattachement (et optionnellement une date de fin)
2. La demande de rattachement est enregistrée mais reste inactive tant qu'elle n'a pas été approuvée par le salarié
3. Le compte salarié approuve par API la demande de rattachement. Les anciens rattachements sont éventuellement terminés si besoin.


# Conditions d'interfaçage

L'interfaçage avec l'API Mobilic et l'utilisation du code source sont libres à condition de respecter certaines conditions.

## **Interfaçage avec l'API**

Mobilic étant un outil développé par le ministère chargé des Transports, nous vous demanderons de respecter les conditions suivantes au moment de l'interfaçage :

* Nous contacter avant tout interfaçage, afin que nous validions avec vous l'usage prévu et que nous vous transmettions les informations techniques nécessaires ;
* Pour obtenir les accès à la production, remplir la demande d'habilitation à l'API Mobilic disponible sur le lien suivant : <https://datapass.api.gouv.fr/formulaires/api-mobilic/demande/nouveau> ;&#x20;
* Respecter les conditions générales d'utilisation (disponibles sur : <https://mobilic.beta.gouv.fr/>) ;
* Devenir partenaire de Mobilic : <https://mobilic.beta.gouv.fr/partners> ;
* Communiquer sur l’interfaçage en suivant les instructions de notre kit de communication disponible ci-dessous.

{% file src="/files/qBP0BaTLf0CAMssXN7Po" %}

## Utilisation du code source

Le code source de Mobilic est ouvert (licence MIT : <https://spdx.org/licenses/MIT.html>) et peut donc être réutilisé librement.&#x20;

Cependant, dans la mesure où il a été réalisé par l’Etat dans le cadre de ses missions de service public, le code de Mobilic revêt, conformément aux dispositions de l’article L. 300-2 du code des relations entre le public et l’administration (CRPA), le caractère de document administratif.

Ainsi, pour utiliser le code source, il est nécessaire de respecter les conditions suivantes :

* S'interfacer avec Mobilic
* Communiquer sur l'interfaçage en suivant les instructions du kit de communication


# Processus d'interfaçage

Mobilic étant un outil réglementaire, nous privilégions un échange avec les logiciels souhaitant s'interfacer afin de les aider à construire leur workflow.

## Processus à suivre pour vous interfacer avec Mobilic :&#x20;

1. Prise de contact avec l'équipe Mobilic par mail en écrivant à : <interfacage@beta.gouv.fr>.
2. Organisation d'un premier rendez-vous en visioconférence entre vous et l'équipe Mobilic pour  comprendre votre besoin, vous informer sur les [contraintes d'intégration](/workflow-a-respecter), et répondre à vos questions réglementaires et techniques.
3. A la suite du rendez-vous, l'équipe Mobilic vous créera un accès au bac à sable.
4. Quand vous aurez fini votre développement, nous programmerons une seconde visioconférence pour valider avec vous le workflow.
5. Une fois le workflow et la [demande d'habilitation](https://datapass.api.gouv.fr/formulaires/api-mobilic/demande/nouveau) validés, vous aurez accès à l'environnement de production.

Durant l'ensemble du processus d'interfaçage, nous nous tiendrons à votre disposition pour répondre à toutes vos questions réglementaires ou techniques. N'hésitez pas à nous écrire !


# Workflow à respecter

Mobilic étant un outil réglementaire, nous vous demanderons de respecter le workflow suivant pour éviter tout problème à vos clients en cas de contrôle.

## Intégration côté salarié :&#x20;

#### Privilégier la saisie en temps réel :&#x20;

**Les temps de travail doivent être envoyés en temps réel** en distinguant bien les différents types d'activité (déplacement, autre tâche et pause).

#### Prendre en compte les données obligatoires :

* Lieu de prise de service
* Immatriculation du véhicule utilisé&#x20;
* Kilométrage du véhicule au moment de la prise de service &#x20;
* Lieu de fin de service
* Kilométrage du véhicule au moment de la fin de service

## Intégration côté salarié et/ou gestionnaire :

#### Prévoir un processus de modification et de validation des temps saisis :&#x20;

Une fois son temps de travail saisi, le salarié doit pouvoir le modifier et/ou le valider. Ensuite, ce sera au gestionnaire de pouvoir modifier et/ou valider ces temps.

Il est important de noter qu'une validation automatique a été mise en place dans Mobilic :&#x20;

* Validation côté salarié : 24 heures après le lancement de la journée ;
* Validation côté gestionnaire : 2 jours ouvrés après la validation du salarié.

#### Permettre le contrôle dans votre application :&#x20;

Le QR code de contrôle Mobilic doit être intégré dans votre outil afin d'éviter au salarié d'avoir à se connecter sur Mobilic lors d'un contrôle en bord de route.

#### Prendre en compte le consentement des utilisateurs :

Chaque utilisateur possède un compte Mobilic qui le suit tout au long de sa carrière. Un compte Mobilic devra donc être créé de manière individuelle par les utilisateurs. De plus, ces derniers devront être informés du fait que le logiciel qu'ils utilisent est interfacé avec Mobilic.

#### **Informer les clients de la nécessité de créer un compte sur Mobilic**

Il est nécessaire de démontrer par tout moyen que vous informez vos clients de la nécessité de : &#x20;

* créer un compte Mobilic pour leur entreprise et pour chaque salarié ;
* effectuer la procédure de rattachement entre leur compte et votre logiciel.

Cela vous est demandé car il arrive que des entreprises pensent être en conformité avec la réglementation en utilisant un logiciel interfacé avec Mobilic, mais sans avoir créé de compte ni effectué la procédure de rattachement avec le logiciel. En cas de contrôle, ces entreprises peuvent donc être verbalisées car les données de leur entreprise ne sont pas reçues dans Mobilic.

###


# Changelog

Historique des évolutions majeures de l'API Mobilic.

## 23/03/2026

Évolution de la génération des exports d'activités au format Excel. La génération des fichiers applique certaines règles en fonction de la période et du nombre de salariés sélectionnés. Ces règles ont un impact direct sur le nombre de fichiers générés et la répartition des données. Pour en savoir plus, la documentation est disponible [ici](https://developers.mobilic.beta.gouv.fr/~/revisions/6xhv0OjpCY5SLhsbD8Ha/exports)

## 09/12/2025

### **Paramètre `nbWorkers` obligatoire pour `softwareRegistration`**

Le paramètre `nbWorkers` est désormais **obligatoire** lors de l'enregistrement d'une nouvelle entreprise via la mutation `softwareRegistration` utilisée par les partenaires API.

**Pourquoi ce changement ?**

Lorsqu'une entreprise est créée via l'API partenaire sans renseigner le nombre de salariés, Mobilic ne dispose pas de cette information essentielle pour **calculer le certificat de l'entreprise**. Ce paramètre est donc maintenant requis pour garantir l'éligibilité au certificat dès l'inscription.

**Impact :**

* **Nouvelles inscriptions** : Le paramètre `nbWorkers` est requis
* **Entreprises existantes** : Aucun impact immédiat. Les entreprises déjà inscrites conservent leur configuration actuelle, mais peuvent mettre à jour cette information pour bénéficier du calcul de certificat

**Exemple d'inscription d'une nouvelle entreprise :**

```graphql
  mutation {
    company {
      softwareRegistration(
        clientId: 123
        usualName: "Mon Entreprise"
        siren: "123456789"
        nbWorkers: 10
      ) {
        id
      }
    }
  }
```

Validation :

* nbWorkers doit être un entier strictement supérieur à 0
* Une erreur sera retournée si le paramètre est absent, égal à 0, ou négatif

***

Mise à jour du nombre de salariés pour une entreprise existante

Pour les entreprises déjà inscrites qui n'ont pas de nombre de salariés renseigné, utilisez la mutation updateCompanyDetails afin de permettre le calcul du certificat :

```graphql
  mutation {
    company {
      updateCompanyDetails(
        companyId: 123
        newNbWorkers: 15
      ) {
        id
        name
      }
    }
  }
```

Cette mutation nécessite d'être administrateur de l'entreprise concernée.

## 07/07/2025 <a href="#id-17032021" id="id-17032021"></a>

### Validation automatique des missions

Nouvelle fonctionnalité : Les missions sont désormais automatiquement validées selon les délais suivants :

* Validation salarié : 1 jour après la première activité ;
* Validation gestionnaire : 2 jours ouvrés après la validation salarié

**Modification des missions auto-validées gestionnaire :**

\
Les gestionnaires peuvent modifier leurs missions automatiquement validées via l'API en utilisant la mutation ValidateMission avec le paramètre justification :

```graphql
 mutation ValidateMission(
    $missionId: Int!
    $usersIds: [Int]!
    $justification: OverValidationJustificationEnum
    $activityId: Int!
    $startTime: TimeStamp
    $endTime: TimeStamp
    $removeEndTime: Boolean
    $context: GenericScalar
  ) {
    activities {
      validateMission(
        missionId: $missionId
        usersIds: $usersIds
        justification: $justification # Obligatoire après auto-validation
        activityItems: [
          {
            edit: {
              activityId: $activityId
              startTime: $startTime
              endTime: $endTime
              removeEndTime: $removeEndTime
              context: $context
            }
          }
        ]
      ) {
        id
      }
    }
  }
```

Valeurs de justification disponibles :

* "personal" : Raisons personnelles
* "professional" : Raisons professionnelles
* "time\_off" : Congé

\
**Important :** Cette possibilité de modification n'existe que pour les validations automatiques gestionnaire. Les validations manuelles restent définitives et non modifiables.

## 16/06/2025 <a href="#id-17032021" id="id-17032021"></a>

Modification du comportement de la mutation `syncEmployment` , désormais le courriel de l'utilisateur retourné en réponse ne peux plus être masqué afin de rattacher plus facilement ceux qui avaient déjà un compte Mobilic aux editeurs tiers de logiciel.

## 21/05/2025 <a href="#id-17032021" id="id-17032021"></a>

Correction de la mutation `cancelMission` qui renvoyait une erreur lorsque la dernière activité de la mission n'avait pas de date de fin.

## 01/04/2025 <a href="#id-17032021" id="id-17032021"></a>

Correction du comportement de la mutation `syncEmployment` qui renvoyait dans certains cas un email "null" (lorsque l'utilisateur existait déjà, était déjà rattaché à l'entreprise et qu'il s'agissait du premier gestionnaire).

## 10/02/2025 <a href="#id-17032021" id="id-17032021"></a>

Ajout du champ `gender` pour un `User`

## 05/12/2024 <a href="#id-17032021" id="id-17032021"></a>

Le type `String` a été remplacé par le type `Email` pour les champs suivants :

* `Mutations/auth/login` → champ `email`
* `Mutations/employments/create_employment` → champ `mail`
* `Mutations/employments/batch_create_worker_employments` → champ `mails`

Exemple de changement à effectuer pour la mutation `login` :&#x20;

```graphql
mutation login($email: String!, $password: String!) {
  auth {
    login(email: $email, password: $password) {
      accessToken
      refreshToken
    }
  }
}
```

devient&#x20;

```graphql
mutation login($email: Email!, $password: String!) {
  auth {
    login(email: $email, password: $password) {
      accessToken
      refreshToken
    }
  }
}
```

***

The type `String` was replace by the type `Email` for the following fields:

* `Mutations/auth/login` → field `email`
* `Mutations/employments/create_employment` → field `mail`
* `Mutations/employments/batch_create_worker_employments` → field `mails`

Example of change you may have to do for the `login` mutation :&#x20;

```graphql
mutation login($email: String!, $password: String!) {
  auth {
    login(email: $email, password: $password) {
      accessToken
      refreshToken
    }
  }
}
```

become&#x20;

```graphql
mutation login($email: Email!, $password: String!) {
  auth {
    login(email: $email, password: $password) {
      accessToken
      refreshToken
    }
  }
}
```

## 02/10/2024 <a href="#id-17032021" id="id-17032021"></a>

* `CompanyOutput` dispose maintenant d'un champ `CurrentUsers` qui retourne une liste de `User` qui a travaillé ou travaille pour cette entreprise

## 12/08/2024 <a href="#id-17032021" id="id-17032021"></a>

* le endpoint `/companies/download_activity_report` envoie un email (ou plusieurs s'il y a trop de données) au gestionnaire qui fait l'appel, plutôt que de télécharger le fichier.

## 08/07/2024 <a href="#id-17032021" id="id-17032021"></a>

* La mutation `updateCompanyName` est renommée `updateCompanyDetails` et permet de mettre à jour le nom, le numéro de téléphone ainsi que le type d'activité de l'entreprise. On peut préciser si l'on souhaite appliquer le type d'activité aux salariés
* Une mutation `ChangePhoneNumber` permet de mettre à jour le numéro de téléphone d'un utilisateur
* Une mutation `ChangeEmployeeBusinessType` permet de modifier le type d'activité d'un salarié rattaché
* Une nouvelle route `POST` `/controllers/download_control_c1b` permet de télécharger le fichier C1B d'un contrôle
* Les objets `User` et `Company` ont un champ `phoneNumber`
* Les objets `Company` et `Employment` possèdent un champ `Business` (`BusinessType`, `TransportType`)
*

## 03/04/2024 <a href="#id-17032021" id="id-17032021"></a>

* Dans la mutation `logLocation`, il n'est plus autorisé de renseigner `kilometerReading` pour une mission sans véhicule

## 11/03/2024 <a href="#id-17032021" id="id-17032021"></a>

* Ajout d'un `ActivityType` : `OFF` qui correspond à une absence (congé, repos, formation, etc.)
* Ajout de la mutation `logHoliday` permettant de créer une mission avec une activité de type `OFF` et de la valider directement. [Cliquer ici pour voir la documentation pour créer une absence](/guides/enregistrement-des-activites#creation-dune-absence)
* Amélioration des performances (à l'aide de dataloaders)

## 13/02/2024 <a href="#id-17032021" id="id-17032021"></a>

* Suppression du paramètre `missionsDeleted` sur `User` remplacé par :&#x20;
* Ajout de l'attribut `include_deleted_missions` sur `missions` de `User`
* Correction de la mutation `syncEmployment` avec un utilisateur déjà lié plusieurs fois à l'entreprise

## 15/01/2024 <a href="#id-17032021" id="id-17032021"></a>

* Ajout du paramètre `missionsDeleted` sur `Company` et `User` (même format que `missions`)
* Ajout des paramètres `deletedAt` et `deletedBy` sur `missionsDeleted`

## 18/12/2023 <a href="#id-17032021" id="id-17032021"></a>

* Correction de la mutation **`activities.validateMission`** : il était (encore) possible pour un gestionnaire d'éditer et valider la mission d'un salarié qui ne l'avait pas encore validé, ceci n'est plus possible. À noter qu'il y a [3 exceptions à cette règle documentées ici](https://faq.mobilic.beta.gouv.fr/usages-et-fonctionnement-de-mobilic-gestionnaire/suivi-et-validation-du-temps-de-travail#en-tant-que-gestionnaire-je-peux-uniquement-modifier-et-valider-les-missions-validees-par-les-salari).

## 02/10/2023 <a href="#id-17032021" id="id-17032021"></a>

**Création d'une mutation `mutations.updateCompanyName`**

Permet de modifier le nom usuel d'une entreprise en envoyant le `new_name` et le `company_id`

## 14/09/2023 <a href="#id-17032021" id="id-17032021"></a>

* Ajout du paramètre `employee_version` dans l'export C1B (`POST /companies/generate_tachograph_files`)

## 31/07/2023 <a href="#id-17032021" id="id-17032021"></a>

* Correction de la mutation `syncEmployment` lorsqu'un email renseigné correspond à un utilisateur ayant déjà un compte Mobilic
* Pour l'environnement sandbox : les emails envoyés en masse (relance et/ou alerte) ne seront plus envoyés

## &#x20;07/02/2023 <a href="#id-17032021" id="id-17032021"></a>

**Création d'une mutation `account.resetPasswordConnected`**

Cette mutation permet de modifier le mot de passe d'un utilisateur directement en envoyant le `user_id` et le nouveau `password` . La requête ne fonctionne que pour l'utilisateur connecté.

**Modification des mutations relatives aux nouveaux mot de passe** `ResetPasswordConnected,` `ResetPassword` et `UserSignUp`

Elles acceptent désormais un argument password de type Password, et non un String

## 07/12/2022 <a href="#id-17032021" id="id-17032021"></a>

**Modification de la mutation `activities.validateMission`**\
Remplacement de l'attribut d'input userId par une liste usersIds, afin de pouvoir valider les missions en équipe en une fois en fournissant une liste de salariés.\
La valeur de retour de cette mutation est maintenant de type Mission

**Modification de la mutation `activities.logActivity`**\
Une activité peut être renseignée sur une mission via cette mutation uniquement si l'utilisateur qui fait l'appel a créé la mission, ou si cette activité le concerne.

**Modification de la mutation `activities.editActivity`**\
Une activité ne peut être modifié que par son créateur, ou par l'utilisateur concerné par l'activité.\
\
Suite aux 2 modifications ci dessus, pour modifier une mission avant validation gestionnaire, il faut utiliser l'attribut *activity\_items* de la mutation **`activities.validateMission`**<br>

## 17/10/2022 <a href="#id-17032021" id="id-17032021"></a>

**Correctif**\
Possibilité de rajouter un véhicule qui aurait été supprimé dans l'interface gestionnaire

## 16/08/2022 <a href="#id-17032021" id="id-17032021"></a>

**Création d'une mutation `activities.cancelMission`**\
Permet d'annuler toutes les activités pour un salarié et une mission donnés.

## 01/08/2022 <a href="#id-17032021" id="id-17032021"></a>

**Création d'une query `BulkActivity`**\
Permet d'envoyer une liste d'ajouts/modifications/annulations d'activités et de valider leur faisabilité. Les changements potentiels ne sont pas sauvegardés en base.

**Modification de la query `ValidateMission`**\
Ajout d'un argument `activity_items` représentant une liste d'ajouts/modifications/annulations d'activités à jouer avant la validation de la mission.\
Ajout d'un argument `expenditures_cancel_ids` représentant une liste de frais à supprimer avant la validation.\
Ajout d'un argument `expenditures_inputs` représentant une liste de frais à ajouter avant la validation.

## 20/06/2022 <a href="#id-17032021" id="id-17032021"></a>

**Il est désormais impossible pour un gestionnaire de détacher son propre compte de son entreprise.**

## 23/05/2022 <a href="#id-17032021" id="id-17032021"></a>

**Modification du format de l'onglet "Détails" des exports Excel.**

**Modification cosmétique du PDF d'export mensuel**

## 10/05/2022 <a href="#id-17032021" id="id-17032021"></a>

**Possibilité d'exporter les activités au format Excel dans un ZIP avec un fichier par employé**

* Rajout de l'attribut `one_file_by_employee` dans la route `/companies/download_activity_report` (False par défaut)

**Modification du format de l'onglet "Activités" des exports Excel.**

## 05/04/2022 <a href="#id-17032021" id="id-17032021"></a>

#### Possibilité de donner / retirer les droits administrateurs d'un utilisateur <a href="#ajout-des-lieux-de-debut-et-prise-de-service" id="ajout-des-lieux-de-debut-et-prise-de-service"></a>

* Rajout de la mutation `employments.changeEmployeeRole`

## 20/03/2022 <a href="#id-17032021" id="id-17032021"></a>

#### Rajout du temps de liaison comme type d'activité <a href="#ajout-des-lieux-de-debut-et-prise-de-service" id="ajout-des-lieux-de-debut-et-prise-de-service"></a>

* Possibilité d'enregistrer une activité de type "transfer" qui correspond au temps de liaison

**Possibilité de ne récupérer les données d'une liste d'entreprises spécifiques pour un utilisateur donné.**

* ajout du champs `company_ids` sur la query `admin_companies`

## 05/10/2021 <a href="#id-17032021" id="id-17032021"></a>

#### Possibilité d'enregistrer des frais par jour sur des missions de plusieurs jours. <a href="#ajout-des-lieux-de-debut-et-prise-de-service" id="ajout-des-lieux-de-debut-et-prise-de-service"></a>

* ajout du champs `spending_date` sur l'entité `Expenditure` représentant la date du frais.

## 17/03/2021 <a href="#id-17032021" id="id-17032021"></a>

#### Ajout des lieux de début et prise de service <a href="#ajout-des-lieux-de-debut-et-prise-de-service" id="ajout-des-lieux-de-debut-et-prise-de-service"></a>

* ajout de l'entité `BaseAddress` représentant une adresse postale.
* ajout de la mutation `activities.logLocation` pour enregistrer un lieu de début ou fin de mission.
* ajout des champs `startLocation` et `endLocation` sur l'entité `Mission`.

## 02/02/2021 <a href="#id-02022021" id="id-02022021"></a>

* une mission ne peut plus être validée par un gestionnaire tant qu'elle n'est pas encore terminée par le salarié.
* le salarié est mainetnant notifié par mail lorsque le gestionnaire valide avec modifications une mission.

## 19/01/2021 <a href="#id-19012021" id="id-19012021"></a>

#### Ajout des observations <a href="#ajout-des-observations" id="ajout-des-observations"></a>

* nouvelle entité `Comment` représentant une observation faite par un utilisateur à propos d'une mission.
* ajout d'un champ `comments` sur l'entité `Mission`.

#### Autres <a href="#autres" id="autres"></a>

* ajout d'un paramètre `onlyNonValidatedMissions` du champ `Company.missions`, qui permet de ne récupérer que les missions en attente de validation par un gestionnaire.

## 04/12/2020 <a href="#id-04122020" id="id-04122020"></a>

#### Ajout de champs <a href="#ajout-de-champs" id="ajout-de-champs"></a>

* ajout d'un champ `serviceDuration` sur l'entité `WorkDay`, donnant directement l'amplitude de la journée de travail (en secondes).
* ajout d'un champ `totalWorkDuration` sur l'entité `WorkDay`, donnant directement le temps de travail de la journée (en secondes).

## 12/11/2020 <a href="#id-12112020" id="id-12112020"></a>

#### Simplification des types en sortie <a href="#simplification-des-types-en-sortie" id="simplification-des-types-en-sortie"></a>

* harmonisation des opérations qui ne retournent aucun résultat via la création d'un type `Void`.
* l'opération `logActivity` retourne maintenant uniquement l'activité créée (et non plus la liste des activités de la mission).
* l'opération `editActivity` retourne maintenant uniquement l'activité modifiée (et non plus la liste des activités de la mission).
* l'opération `cancelActivity` ne retourne plus la liste des activités de la mission.
* l'opération `logExpenditure` retourne maintenant uniquement le frais créé (et non plus la liste de tous les frais de la mission).
* l'opération `cancelExpenditure` ne retourne plus la liste des frais de la mission.

## 29/10/2020 <a href="#id-29102020" id="id-29102020"></a>

#### Ajout de champs <a href="#ajout-de-champs-1" id="ajout-de-champs-1"></a>

* ajout d'un champ `adminedCompanies` sur l'entité `User`, permettant de récupérer la liste des entreprises sur lesquelles l'utilisateur a des droits de gestion.
* ajout d'un champ `workDays` sur l'entité `Company`, pour récupérer les journées de travail des salariés de l'entreprise
* ajout d'un champ `missions` sur l'entité `Company`, pour récupérer les missions de l'entreprise.
* ajout d'un champ `endTime` sur l'entité `Activity`, indiquant la date et l'heure de fin (si renseignées).
* ajout d'un champ `lastUpdateTime` sur l'entité `Activity`, indiquant la date et l'heure de dernière modification.
* ajout d'une opération `mission (id: Int)` de type `query` pour accéder aux informations d'une mission.

#### Changement de la logique d'enregistrement <a href="#changement-de-la-logique-denregistrement" id="changement-de-la-logique-denregistrement"></a>

* distinction entre [deux modes d'enregistrement](/guides/enregistrement-des-activites#enregistrement-dune-activite) : le mode tachygraphe (enregistrement d'un changement d'activité) et le mode classique (enregistrement d'une période d'activité). L'opération `logActivity` prend désormais un paramètre `switch` permettant de préciser le mode.
* les identifiants (id) des activités sont maintenant "persistants".

#### Limitation du volume de sortie <a href="#limitation-du-volume-de-sortie" id="limitation-du-volume-de-sortie"></a>

* ajout de paramètres pour [restreindre la période d'historique récupérée](/guides/consultation-du-temps-de-travail#choix-de-la-periode-dhistorique-recuperee) (pour un utilisateur ou une entreprise).

#### Divers <a href="#divers" id="divers"></a>

* gestion des erreurs par des [codes erreurs](/guides/gestion-des-erreurs#codes-erreurs).
* simplification du format d'entrée pour les horodatages : passage d'un format en millisecondes à un format en secondes.
* les horodatages de début et de fin d'activité sont désormais arrondis à la minute (inférieure).
* les jetons d'accès OAuth ont été rendus permanents (jusqu'à révocation par l'utilisateur) : il n'y a plus de date d'expiration.


# API Reference

La documentation technique de l'API est accessible depuis la [console](https://mobilic.beta.gouv.fr/developers/playground) (dans l'onglet **Docs** à droite).


# Effectuer une requête à l'API

L'API Mobilic est un service web (basé sur le protocole HTTP) qui utilise le standard GraphQL.

## GraphQL

Contrairement aux architectures de type REST où le verbe HTTP et l'URI vont caractériser l'opération, toutes les requêtes à l'API GraphQL partageront le même verbe HTTP `POST` et le même URI.

{% hint style="info" %}
Cet URI unique dépend de l'environnement :&#x20;

* <https://api.mobilic.beta.gouv.fr/graphql> pour l'environnement de production
* <https://api.sandbox.mobilic.beta.gouv.fr/graphql> pour l'environnement bac à sable
  {% endhint %}

Le détail de l'opération sera précisé dans le corps JSON de la requête.

## Exemple simple <a href="#exemple-simple" id="exemple-simple"></a>

Toutes les actions réalisables sur l'API nécessitent d'avoir [créé un compte Mobilic](/guides/inscription-et-rattachement-des-salaries), et presque toutes requièrent d'être [authentifié](/guides/authentification).

Pour cet exemple basique, nous allons prendre une opération qui affiche l'email, le nom, et l'identifiant Mobilic de l'utilistateur, à l'aide de l'opération `me`

Le corps de la requête, au format JSON, doit contenir un champ `query` qui précise l'opération. La valeur de ce champ `query` est pour l'opération `me`:

```graphql
query {
    me {
        id
        lastName
        email
    }
}
```

Pour constituer le corps JSON de la requête, il suffit de mettre le texte de l'opération dans une chaîne de caractères, en échappant les guillemets à l'aide d'un anti-slash et en remplaçant les sauts de ligne par  :

```json
{
    \"query\": \"query {\n me {\n id\n lastName\n email\n }\n }\"
}
```

{% hint style="info" %}
Cette requête nécessite d'être authentifié, il faut donc rajouter les header HTTP d'authentification [décrit dans cette page](/guides/authentification#utilisation-des-jetons).
{% endhint %}

Pour soumettre la requête à l'API il est possible d'utiliser :

* la [console](https://mobilic.beta.gouv.fr/developers/playground) pour une expérience interactive. Voir le [guide de la console](/guides/utiliser-la-console).
* n'importe quelle librairie HTTP (`curl`, `requests` en `python`, ...)

### Via cURL <a href="#via-curl" id="via-curl"></a>

Il suffit de constituer le corps JSON de la requête à partir du champ `query`.

```bash
curl \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {access_token}" \
  -H "X-CLIENT-ID: {client_id}" \
  --data "{ \"query\": \"query {\n me {\n id\n lastName\n email\n }\n }\"}" \
  https://api.sandbox.mobilic.beta.gouv.fr/graphql
```

Pour plus d'informations sur la manière d'écrire des opérations GraphQL vous pouvez consulter notre [guide sur les opérations GraphQL](/guides/syntaxe-des-operations-graphql).


# Authentification

Pour des raisons de sécurité et de traçabilité la plupart des actions effectuables sur l'API nécessitent d'être authentifié.

## Jetons d'accès <a href="#jetons-dacces" id="jetons-dacces"></a>

L'API Mobilic utilise une authentification par jeton d'accès : les requêtes dites authentifiées sont celles qui comportent un jeton valide.

### Jeton et autorisation <a href="#jwt-et-autorisation" id="jwt-et-autorisation"></a>

Les jetons utilisés sont des jetons générés par l'API.

Lorsque une requête authentifiée parvient à l'API, celle-ci vérifie la validité du jeton. Si le jeton est valide, l'API considérera que la requête provient de l'utilisateur dont l'identité est associée au jeton.

L'API déterminera ensuite si l'utilisateur est bien autorisé à effectuer l'opération demandée avant de procéder à celle-ci.

### Différents type de jeton

Il existe 2 types de jetons d'accès :

* Les jetons liés à un compte utilisateur : ils permettent de faire des requêtes au nom d'un utilisateur, pour toutes les sociétés dans lesquelles il serait rattaché.
* Les jetons liés à un rattachement "Compte utilisateur / Société" : ils permettent de faire des requêtes au nom d'un utilisateur uniquement pour la société correspondante.

Ces deux types de jetons permettent d'effectuer les même requêtes, mais ont des méthodes de récupération différentes. Afin de voir celle qui convient le mieux à votre cas d'usage, vous pouvez voir leur méthode de récupération, ou contacter l'équipe Mobilic pour obtenir des conseils.

{% content-ref url="/pages/KTOyKMJNSUK6WcYe7oKW" %}
[Jetons liés à un Utilisateur](/guides/authentification/jetons-lies-a-un-utilisateur)
{% endcontent-ref %}

{% content-ref url="/pages/hmXaVMjGlusciaqLwwlg" %}
[Jetons liés à un Rattachement](/guides/authentification/jetons-lies-a-un-rattachement)
{% endcontent-ref %}

## Utilisation des jetons

#### Jetons liés à un utilisateur

Il convient de rajouter les deux header HTTP à vos requêtes :

| Nom           | Valeur                                     |
| ------------- | ------------------------------------------ |
| X-CLIENT-ID   | Le client\_id fournir par l'équipe Mobilic |
| Authorization | Bearer `<jeton_utilisateur>`               |

#### Jeton lié à un rattachement

| Nom                | Valeur                                     |
| ------------------ | ------------------------------------------ |
| X-CLIENT-ID        | Le client\_id fournir par l'équipe Mobilic |
| X-EMPLOYMENT-TOKEN | `<jeton_rattachement>`                     |


# Jetons liés à un Utilisateur

## Prérequis

Le `client` qui souhaite récupérer manuellement les jetons Utilisateur doit préalablement enregistrer son application auprès de l'API Mobilic.

Pour cela il faut envoyer un email à l'adresse <mobilic@beta.gouv.fr> en précisant les informations suivantes :

* environnement demandé (production ou bac à sable)
* nom de l'application

En retour, le client recevra alors un identifiant `client_id`

## Génération du jeton

Une fois le `client_id` reçu, il convient de le transmettre à l'utilisateur (gestionnaire ou salarié), qui pourra alors suivre la [procédure de génération manuelle de clé API](https://faq.mobilic.beta.gouv.fr/je-suis-salarie/autoriser-lacces-a-un-logiciel-tiers#comment-generer-un-cle-api).&#x20;

L'utilisateur peut alors vous transmettre le jeton généré.

Ce jeton vous permettra d'effectuer les appels API en étant authentifié en tant que l'utilisateur qui a généré le jeton.


# Jetons liés à un Rattachement

## Prérequis

Le `client` qui souhaite pouvoir récupérer des jetons liés à un rattachement afin d'effectuer des opérations pour le compte de ses utilisateurs doit préalablement enregistrer son application auprès de l'API Mobilic.

Pour cela il faut envoyer un email à l'adresse <mobilic@beta.gouv.fr> en précisant les informations suivantes :

* environnement demandé (production ou bac à sable)
* nom de l'application

Le client recevra alors un `client_id` et une `api_key.`

## Endpoint /protected

Le endpoint /protected vous permettra de faire des requêtes spécifiques à la création d'entreprise, au rattachement de salariés et à la récupération de jetons de rattachement.

#### Uri

* <https://api.mobilic.beta.gouv.fr/protected> pour l'environnement de production
* <https://api.sandbox.mobilic.beta.gouv.fr/protected> pour l'environnement bac à sable

#### HTTP Header

Deux Header HTTP sont à rajouter lorsque vous utilisez ce endpoint :

* X-API-KEY : mettre l'`api_key` fourni par l'équipe Mobilic
* X-CLIENT-ID : mettre le `client_id` fourni par l'équipe Mobilic

##

## Récupération des jetons

**Etape 1** : Votre logiciel doit d'abord être relié à la société correspondante.

{% content-ref url="/pages/PGhLo1uJSbWhgqCWHZOL" %}
[Liaison de votre logiciel à une société](/guides/authentification/jetons-lies-a-un-rattachement/liaison-de-votre-logiciel-a-une-societe)
{% endcontent-ref %}

**Etape 2** : Vous devez ensuite envoyer des demandes d'ouverture d'accès aux salariés

{% content-ref url="/pages/B41HJ8dc9z4meKbhWsiw" %}
[Rattachement  des employés à la société](/guides/authentification/jetons-lies-a-un-rattachement/rattachement-des-employes-a-la-societe)
{% endcontent-ref %}

**Etape 3** : Récupération des jetons d'accès

{% content-ref url="/pages/c9rtfa3xGdnXyQHpjduk" %}
[Récupération des jetons liés à un rattachement](/guides/authentification/jetons-lies-a-un-rattachement/recuperation-des-jetons-lies-a-un-rattachement)
{% endcontent-ref %}

#### [Exemple de workflow](/guides/authentification/jetons-lies-a-un-rattachement/exemple-de-workflow)<br>


# Liaison de votre logiciel à une société

## Cas d'une société déjà existante dans Mobilic

Vous pouvez communiquer votre `client_id` à un gestionnaire de cette société. Il pourra alors le rentrer dans sa console gestionnaire dans Mobilic :&#x20;

<figure><img src="/files/l9X6cjqDPLRyV4zmQLqX" alt=""><figcaption></figcaption></figure>

## Cas d'une société non existante dans Mobilic

Vous pouvez créer une société dans Mobilic et y être automatiquement lié, en faisant un appel API au endpoint [/protected](/guides/authentification/jetons-lies-a-un-rattachement#endpoint-protected) :

```graphql
mutation {
    company{
    softwareRegistration(
        clientId: 156432124,
        usualName: "Nom de la société",
        siren: "110068012",
        siret: "12234567005",
        nbWorkers: 10
      ){
        id
        name
    }
  }
}
```

Le paramètre `nbWorkers` est obligatoire et correspond au nombre de salariés de l'entreprise. Cette information est nécessaire pour permettre le calcul du certificat Mobilic. La valeur doit être un entier strictement supérieur à 0.

## Contraintes métier importantes

#### Restriction SIREN/SIRET

**⚠️ Contrainte métier** : Une entreprise ne peut pas être enregistrée à la fois de façon **globale** (représentant tous ses établissements) ET par **établissements spécifiques** (avec des SIRETs distincts).

**Explication**

Dans Mobilic, une entreprise peut être enregistrée selon deux modes :

1. **Mode global** : L'entreprise représente l'ensemble de ses établissements (aucun SIRET spécifique)
2. **Mode établissements** : L'entreprise est enregistrée pour des établissements spécifiques (avec SIRETs)

Ces deux modes sont **mutuellement exclusifs** pour un même SIREN.

**Cas d'erreur :**&#x20;

La mutation `softwareRegistration` échouera si :

* Une entreprise existe déjà en **mode global** pour le SIREN donné
* ET vous tentez de créer un établissement **spécifique** avec un SIRET

**Exemple complet**

**1. Création initiale en mode global (réussit)** :

```graphql
mutation {
    company {
        softwareRegistration(
            clientId: 156432124,
            usualName: "Société Globale",
            siren: "110068012",
            nbWorkers: 10
            # ← Pas de SIRET = mode global
        ) {
            id
            name
        }
    }
}
```

2. Tentative de création d'établissement spécifique (échoue) : <br>

```graphql
mutation {
      company {
          softwareRegistration(
              clientId: 156432124,
              usualName: "Établissement spécifique",
              siren: "110068012",
              siret: "11006801200123",  # ← SIRET spécifique
              nbWorkers: 10
          ) {
              id
              name
          }
      }
  }
```

Réponse d'erreur :&#x20;

```json
{
    "errors": [{
      "message": "Company already registered globally for this SIREN (representing all establishments). Cannot create 
  SIRET-specific establishments.",
      "locations": [{"line": 4, "column": 15}],
      "path": ["company", "softwareRegistration"],
      "extensions": {
        "code": "SIREN_ALREADY_SIGNED_UP"
      }
    }],
    "data": {
      "company": {
        "softwareRegistration": null
      }
   
```

### Solutions recommandées

Choisir une approche cohérente dès le départ :

Option 1 : **Approche globale**

* Créez l'entreprise sans SIRET pour représenter tous les établissements
* Idéal pour les entreprises avec gestion centralisée

Option 2 : **Approche par établissements**

* Créez directement chaque établissement avec son SIRET spécifique
* Idéal pour les entreprises avec gestion décentralisée par établissement

⚠️ Important : Une fois le mode choisi pour un SIREN, il ne peut plus être modifié. Planifiez votre stratégie d'enregistrement en fonction de vos besoins métier.


# Rattachement  des employés à la société

Une fois que le logiciel est relié à la société, il est possible d'effectuer des requêtes API afin de solliciter les employés à accorder au logiciel les droits d'accès à leur compte Mobilic.

Pour cela, il faut faire un appel au endpoint [/protected](/guides/authentification/jetons-lies-a-un-rattachement#endpoint-protected) avec la liste des employés que l'on souhaite rattacher :

```graphql
mutation {
    company{
        syncEmployment(companyId: 58, employees: [
                 {firstName:"Prénom_test1",
                  lastName:"Nom_test1",
                  email:"email-salarie1@gmail.com"},
                 {firstName:"Prénom_test2",
                  lastName:"Nom_test2",
                  email:"email-salarie2@gmail.com"}]){
            id
            email
            user{
                firstName
                lastName
            }
        }
    }
}
```

Les salariés concernés recevront un email leur demandant d'[autoriser votre logiciel à accéder à leur compte.](https://faq.mobilic.beta.gouv.fr/je-suis-salarie/autoriser-lacces-a-un-logiciel-tiers#comment-donner-acces-a-mon-compte-mobilic-a-un-editeur-tiers)

Si vous avez déjà envoyé une demande de rattachement à un salarié, il n'en recevra pas de nouvelles, sauf si sa précédente demande est expirée (Au bout de 7 jours).

Vous recevrez en retour la liste de tous les salariés ayant été invités à rejoindre l'entreprise et à vous ouvrir leur accès.


# Récupération des jetons liés à un rattachement

Une fois qu'un salarié a validé votre demande d'ouverture d'accès, vous pourrez récupérer le token liés à son compte en faisant une requête sur le endpoint [/protected](/guides/authentification/jetons-lies-a-un-rattachement#endpoint-protected) :

<pre class="language-graphql"><code class="lang-graphql"><strong>query {
</strong>    employmentToken(employmentId: 73, clientId: 156432124){
        accessToken
        employment{
            id
            email
            user {
                id
            }
        }
    }
}
</code></pre>

***Paramètres d'entrée :***

* *clientId* : fourni par l'équipe Mobilic lors de l'inscription de votre logiciel dans Mobilic.
* *employmentId* : identifiant récupérer dans le champ id de la requête `syncEmployment`

Le champ accessToken et le userId renvoyés vous permettront de faire des requêtes au nom de l'utilisateur concerné.


# Exemple de workflow

### Récupération de la liste des utilisateurs d'une entreprise

#### Étape 1 : Récupération de la Liste des Utilisateurs

Pour obtenir la liste des utilisateurs d'une entreprise, utilisez la requête GraphQL **company**. Cette requête n'est pas protégée, mais nécessite un jeton de rattachement dans l'en-tête.

**Requête GraphQL**

```graphql
query {
    company(id: Int!) {
        name
        users {
            id
            firstName
            lastName
            email
        }
    }
}
```

**En-têtes Requis**

```graphql
{
    "X-CLIENT-ID": "Votre Id donné par Mobilic",
    "X-EMPLOYMENT-TOKEN": "access_token récupéré avec la requête employmentToken"
}
```

#### Étape 2 : Récupération du Jeton d'Accès

Pour obtenir un jeton d'accès, utilisez la mutation protégée **employmentToken**. Vous pouvez créer un utilisateur avec la mutation **syncEmployment**  qui vous retournera un **employementId**.

**Mutation GraphQL pour Créer un Utilisateur**

```graphql
mutation {
    company {
        syncEmployment(companyId: id!, employees: [
            {
                lastName: "user_exemple",
                email: "user_exemple@email.com"
            }
        ]) {
            id
        }
    }
}
```

**En-têtes Requis**

```graphql
{
    "X-CLIENT-ID": "votre client id",
    "X-API-KEY": "votre api key"
}
```

#### Étape 3 : Récupération du Jeton de Rattachement

Utilisez l'ID obtenu à l'étape précédente pour récupérer le jeton de rattachement avec la mutation **employmentToken**.

**Mutation GraphQL pour Récupérer le Jeton**

```graphql
query {
    employmentToken(employmentId: id, clientId: "Votre Client Id") {
        accessToken
    }
}
```

**En-têtes Requis**

```graphql
{
    "X-CLIENT-ID": "votre client id",
    "X-API-KEY": "votre api key"
}
```

#### Résultat

En réponse, vous obtiendrez un **accessToken** que vous utiliserez dans l'en-tête de la requête **company de l'étape 1** pour accéder à la liste des utilisateurs de l'entreprise cliente.


# Syntaxe des opérations GraphQL

Nous avons déjà vu comment [construire à partir d'une opération une requête à l'API GraphQL](/guides/effectuer-une-requete-a-lapi). Nous allons maintenant détailler l'écriture d'une opération.

{% hint style="info" %}
Cette page donne un aperçu très condensé du langage de requêtes GraphQL. Pour des informations plus détaillées vous pouvez consulter la [documentation officielle](https://graphql.org/).
{% endhint %}

Une opération est constituée des éléments suivants :

1. le type de l'opération, toujours précisé en premier
2. l'identifiant de l'opération, c'est-à-dire son chemin dans le graphe des opérations
3. les variables d'opération et leurs valeurs
4. le schéma de la réponse, qui permet de sélectionner le niveau d'informations retournées par l'API.

{% hint style="info" %}
La distinction entre 2 et 4 n'existe pas vraiment dans GraphQL, une opération étant vue comme la sélection d'un certain champ dans le graphe entier des opérations.
{% endhint %}

Nous nous servirons de l'opération de `logActivity` pour illustrer chacun de ces constituants :

```graphql
mutation {
    activities {
        logActivity(userId: 222408790, missionId: 500, type: "work", startTime: 1616281275) {
            id
        }
    }
}
```

## Type d'opération <a href="#type-doperation" id="type-doperation"></a>

L'API Mobilic utilise deux types d'opération définis par le standard GraphQL :

* `query` pour toutes les opérations de lecture qui ne modifient pas l'état du système
* `mutation` pour toutes les opérations qui vont modifier l'état du système (création, édition, suppression)

L'opération de `logActivity` crée une nouvelle activité pour un utilisateur, elle est logiquement une `mutation`.

## Identifiant de l'opération <a href="#identifiant-de-loperation" id="identifiant-de-loperation"></a>

L'opération de `logactivity` a été regroupée avec les autres opérations relatives aux activités. Son chemin complet dans les opérations de mutation est `activities -> logActivity`.

## Variables d'opération <a href="#variables-doperation" id="variables-doperation"></a>

Elles sont précisées entre parenthèses à côté de l'opération concernée. Dans le cas de l'opération de `logActivity` il y a quatre variables, `userId`, `missionId`, `startTime` et `type`.

{% hint style="info" %}
Une opération GraphQL peut très bien inclure des variables à plusieurs niveaux de "nesting".
{% endhint %}

La syntaxe GraphQL permet de définir les variables dans l'opération mais de préciser leurs valeurs en dehors. Par exemple l'opération de `login` peut s'écrire :

```graphql
mutation($type: String!, $startTime: TimeStamp!, $missionId: Int!, $userId: Int) {
  activities {
    logActivity(type: $type, startTime: $startTime, missionId: $missionId, userId: $userId) {
      id
    }
  }
}
```

{% hint style="info" %}
Il est important de noter que :

* les variables sont déclarées juste après le type de l'opération.
* une variable est toujours précédée d'un `$`
  {% endhint %}

Le corps JSON de la requête HTTP doit alors contenir un champ `variables` qui définit pour chaque variable la valeur à injecter :

```json
{
  "query": "mutation logActivity($type: String!, $startTime: TimeStamp!, $missionId: Int!, $userId: Int) {\n  activities {\n logActivity(\n type: $type\n startTime: $startTime\n missionId: $missionId\n userId: $userId\n ) {\n id}}\n}\n"
  "variables": { "type": "work", "startTime": 1616281275, "missionId": 500, "userId": 222408790}
}
```

## Schéma de la réponse <a href="#schema-de-la-reponse" id="schema-de-la-reponse"></a>

C'est une fonctionnalité très puissante de GraphQL : la possibilité de personnaliser la réponse de l'API parmi le graphe des objets.

Par exemple pour l'opération de `logActivity` on peut ne demander en retour que l'identifiant de l'activité créée :

```graphql
mutation {
    activities {
        logActivity(userId: 222408790, missionId: 500, type: "work", startTime: 1616281275) {
            id
        }
    }
}
```

Le corps de la réponse sera au format JSON, et **suivra le schéma de la requête**, comme défini dans les [spécifications GraphQL](https://spec.graphql.org/June2018/#sec-Response-Format). Dans l'exemple précédent le JSON de retour contiendra un champ `data` (toujours présent dans le cas d'une requête sans erreurs), contenant un champ `auth` qui contient lui-même un champ `login` et ainsi de suite :

```json
{
  "data": {
    "activities": {
      "logActivity": {
        "id": 1608
      }
    }
  }
}
```

Ce fonctionnement prend tout son sens pour les objets complexes avec un fort niveau d'imbrication : par exemple une entreprise, auxquels sont rattachés des utilisateurs, qui effectuent des missions, qui elles-mêmes regroupent plusieurs activités. En fonction de ses besoins l'appelant est libre de récupérer un graphe d'objets plus ou moins profond.


# Gestion des erreurs

## Convention GraphQL

[Les spécifications GraphQL](https://spec.graphql.org/June2018/#sec-Response-Format) précisent le format général de retour des erreurs : lorsque une requête cause une ou plusieurs erreurs la réponse JSON contiendra un champ `errors`, qui sera une liste non vide des erreurs recontrées.

Si la requête a donné lieu à une exécution la réponse contiendra également un champ `data`, comme dans le cas d'une requête sans erreurs.

On peut distinguer 3 types d'erreurs :

* les erreurs de syntaxe
* les erreurs de schéma
* les erreurs applicatives, qui arrivent pendant l'exécution de la requête

Les erreurs de syntaxe et les erreurs de schéma bloquent l'exécution de la requête : la réponse ne contiendra pas de champ `data`.

## Erreurs de syntaxe <a href="#erreurs-de-syntaxe" id="erreurs-de-syntaxe"></a>

Les erreurs de syntaxe recouvrent toutes les erreurs qui empêchent le parser GraphQL d'interpréter la requête. Le code HTTP de la réponse sera toujours `400`.

On y trouve par exemple les erreurs dans la constitution du JSON :

```http
POST /api/graphql HTTP/1.1
Host: sandbox.mobilic.beta.gouv.fr
Content-Type: application/json

{"Mauvais JSON"}
```

qui donnera cette réponse :

```http
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "errors": [
    {
      "message":"POST body sent invalid JSON."
    }
  ]
{
```

Il y a également les erreurs de syntaxe GraphQL :

```http
POST /api/graphql HTTP/1.1
Host: sandbox.mobilic.beta.gouv.fr
Content-Type: application/json

{
  "query": "wrongKeyword"
}
```

Réponse :

```http
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json

{
  "errors": [
    {
      "message":"Syntax Error GraphQL (1:1) Unexpected Name \"wrongKeyword\"\n\n1: wrongKeyword\n   ^\n",
      "locations": [
        {
          "line":1,
          "column":1
        }
      ]
    }
  ]
}
```

{% hint style="info" %}
Dans la [console](https://mobilic.beta.gouv.fr/developers/docs/playground) les erreurs de syntaxe sont détectées en direct et empêchent la requête d'être soumise à l'API.
{% endhint %}

## Erreurs de schéma <a href="#erreurs-de-schema" id="erreurs-de-schema"></a>

Les erreurs de schéma concernent les requêtes syntaxiquement correctes mais qui ne respectent pas le schéma des opérations.

Comme la syntaxe est correcte nous ne montrons dans la suite que l'opération GraphQL plutôt que de montrer tout le corps de la requête HTTP. Pour rappel le passage de l'opération GraphQL à la requête `POST` HTTP est expliqué [ici](/guides/effectuer-une-requete-a-lapi#exemple-simple).

Comme pour les erreurs de syntaxe le code HTTP de la réponse est `400`.

Exemple

```graphql
query {
  wrongOperation {
    someField
  }
}
```

Réponse

```json
{
  "errors": [
    {
      "message": "Cannot query field \"wrongOperation\" on type \"Queries\".",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ]
    }
  ]
}
```

### Erreurs de validation des variables <a href="#erreurs-de-validation-des-variables" id="erreurs-de-validation-des-variables"></a>

Les erreurs de type sur les variables d'opération sont également considérées comme des erreurs de schéma et donnent lieu aux mêmes réponses.

Exemple

```graphql
query {
  user(id: "pas un entier") {
    firstName
  }
}
```

Réponse

```json
{
  "errors": [
    {
      "message": "Argument \"id\" has invalid value \"pas un entier\".\nExpected type \"Int\", found \"pas un entier\".",
      "locations": [
        {
          "line": 2,
          "column": 12
        }
      ]
    }
  ]
}
```

{% hint style="warning" %}
Dans la [console](https://mobilic.beta.gouv.fr/developers/docs/playground) la réponse retournée par l'API à une requête qui cause une erreur de schéma se retrouve à l'affichage encapsulée dans un champ supplémentaire `error`.
{% endhint %}

## Erreurs applicatives <a href="#erreurs-applicatives" id="erreurs-applicatives"></a>

Les erreurs applicatives désignent toutes les erreurs qui arrivent lors de l'exécution de la requête.

Le code HTTP de la réponse est `200` pour ce type d'erreurs.

### Résultats partiels <a href="#resultats-partiels" id="resultats-partiels"></a>

Lorsque des erreurs arrivent à l'exécution la réponse comporte également un champ `data`, qui peut contenir des résultats partiels, en fonction des endroits où sont apparues les erreurs.

Exemple

```graphql
query {
  company(id: 1) {
    id
    name
    missions {
      id
    }
  }
}
```

Réponse

```json
{
  "errors": [
    {
      "message": "Unauthorized access to field 'missions' of company object. Actor must be company admin.",
      "locations": [
        {
          "line": 5,
          "column": 5
        }
      ],
      "path": ["company", "missions"],
      "extensions": {
        "code": "AUTHORIZATION_ERROR"
      }
    }
  ],
  "data": {
    "company": {
      "id": 8,
      "name": "Mobilic Team",
      "missions": null
    }
  }
}
```

Dans le cas ci-dessus la réponse a retourné des résultats partiels car une partie de l'opération n'a pas déclenché d'erreur. Pour les parties qui causent des erreurs le champ correspondant dans la réponse aura toujours la valeur `null`.

### Codes erreurs <a href="#codes-erreurs" id="codes-erreurs"></a>

Chaque erreur applicative comprend un code, situé dans le champ `extensions.code` de l'erreur. Ces codes servent à classer les erreurs. Voici la liste des codes :&#x20;

#### Erreurs d'authentification et de sécurité

| Code                           | Description                                                                              | Sévérité |
| ------------------------------ | ---------------------------------------------------------------------------------------- | -------- |
| `AUTHENTICATION_ERROR`         | Données d'authentification manquantes ou invalides (token expiré, clé API invalide)      | Critique |
| `AUTHORIZATION_ERROR`          | Permissions insuffisantes pour accéder à la ressource ou effectuer l'opération           | Haute    |
| `INVALID_TOKEN`                | Token d'invitation invalide pour le rattachement à une entreprise                        | Haute    |
| `BLOCKED_ACCOUNT_ERROR`        | Le compte utilisateur est bloqué                                                         | Haute    |
| `BAD_PASSWORD_ERROR`           | Mot de passe incorrect lors de la connexion                                              | Moyenne  |
| `ACTIVATION_EMAIL_DELAY_ERROR` | Délai minimum entre deux envois d'email d'activation non respecté (protection anti-spam) | Basse    |
| `UNSUPPORTED_ALGORITHM_ERROR`  | Algorithme de cryptographie non supporté                                                 | Haute    |

#### Erreurs d'intégration SSO

| Code                                                | Description                                           | Sévérité |
| --------------------------------------------------- | ----------------------------------------------------- | -------- |
| `FRANCE_CONNECT_ERROR`                              | Erreur lors de l'authentification via FranceConnect   | Haute    |
| `FRANCE_CONNECT_V2_ERROR`                           | Erreur spécifique à FranceConnect v2                  | Haute    |
| `AGENT_CONNECT_ERROR`                               | Erreur lors de l'authentification via AgentConnect    | Haute    |
| `AGENT_CONNECT_ORGANIZATIONAL_UNIT_NOT_FOUND_ERROR` | Unité organisationnelle non trouvée dans AgentConnect | Moyenne  |

#### Erreurs de validation des données

| Code                  | Description                                                                                     | Sévérité |
| --------------------- | ----------------------------------------------------------------------------------------------- | -------- |
| `INVALID_INPUTS`      | Valeurs incorrectes pour les variables de l'opération GraphQL                                   | Basse    |
| `BAD_REQUEST`         | Requête HTTP invalide (erreur 400)                                                              | Moyenne  |
| `BAD_GRAPHQL_REQUEST` | Requête GraphQL mal formée ou ne respectant pas le schéma                                       | Moyenne  |
| `INVALID_RESOURCE`    | Impossible d'effectuer l'opération demandée sur cet objet (ressource dans un état incompatible) | Moyenne  |

#### Erreurs métier - Entreprises

| Code                          | Description                                               | Sévérité |
| ----------------------------- | --------------------------------------------------------- | -------- |
| `SIRET_ALREADY_SIGNED_UP`     | Ce SIRET est déjà inscrit sur Mobilic                     | Moyenne  |
| `SIREN_ALREADY_SIGNED_UP`     | Ce SIREN est déjà inscrit sur Mobilic                     | Moyenne  |
| `COMPANY_HAS_CEASED_ACTIVITY` | L'entreprise a cessé son activité selon les données INSEE | Moyenne  |

#### Erreurs métier - Missions et activités

| Code                      | Description                                                                                   | Sévérité |
| ------------------------- | --------------------------------------------------------------------------------------------- | -------- |
| `OVERLAPPING_MISSIONS`    | Chevauchement temporel de deux missions pour un même travailleur mobile                       | Moyenne  |
| `OVERLAPPING_ACTIVITIES`  | Chevauchement temporel de deux activités pour un même travailleur mobile                      | Moyenne  |
| `MISSION_ALREADY_ENDED`   | Tentative de modification d'une mission déjà terminée pour le travailleur                     | Moyenne  |
| `INVALID_ACTIVITY_SWITCH` | Échec de l'enregistrement en mode tachygraphe en raison d'entrées chronologiques incohérentes | Basse    |
| `DUPLICATE_EXPENDITURES`  | Tentative d'enregistrement de frais déjà existants sur une mission                            | Basse    |

#### Erreurs métier - Emplois et rattachements

| Code                      | Description                                                                      | Sévérité |
| ------------------------- | -------------------------------------------------------------------------------- | -------- |
| `OVERLAPPING_EMPLOYMENTS` | Chevauchement temporel de deux rattachements entreprise pour un même salarié     | Moyenne  |
| `NO_PRIMARY_EMPLOYMENT`   | Absence de rattachement principal (requis pour créer un rattachement secondaire) | Moyenne  |

#### Erreurs système

| Code                    | Description                                         | Sévérité |
| ----------------------- | --------------------------------------------------- | -------- |
| `INTERNAL_ERROR`        | Erreur interne côté serveur Mobilic                 | Critique |
| `INTERNAL_SERVER_ERROR` | Erreur serveur interne (variante d'INTERNAL\_ERROR) | Critique |

#### Guide de sévérité

* **Critique** : Nécessite une intervention immédiate, bloque toute utilisation
* **Haute** : Impact important sur les fonctionnalités, investigation rapide requise
* **Moyenne** : Erreur métier à corriger, ne bloque pas l'utilisation générale
* **Basse** : Information ou avertissement, peut être traité ultérieurement


# Utiliser la console

La console est une interface graphique simple mais efficace pour découvrir et requêter l'API Mobilic.

La console est accessible depuis le lien suivant :

<https://mobilic.beta.gouv.fr/developers/playground>

## Présentation <a href="#presentation" id="presentation"></a>

La console est constituée de 4 parties :

* l'éditeur de requêtes qui occupe l'essentiel de la partie gauche. C'est ici que sont écrites les [opérations](/guides/syntaxe-des-operations-graphql).
* les réponses retournées par l'API sur la moitié droite
* le tiroir de documentation qui détaille les actions de l'API, ouvrable depuis le bouton situé tout à gauche
* l'éditeur d'en-têtes de requêtes + variables d'opération situé en bas à gauche

## Authentification <a href="#authentification" id="authentification"></a>

La plupart des requêtes à l'API nécessitent d'être [authentifié via un jeton d'accès](/guides/authentification).

Exemple de rajout d'un jeton lié à un rattachement :

```json
{
  "X-CLIENT-ID": 156432124,
  "X-EMPLOYMENT-TOKEN": "06dd5a1a9f9552876c79251dcccd7bbdb7cd5c098b72"
}
```

Exemple de rajout d'un jeton lié à un utilisateur :

```json
{
  "X-CLIENT-ID": 156432124,
  "Authorization" : "Bearer 1234-fefdsfds-1484-fsdfsd-489"
}
```

## Exemple simple <a href="#exemple-simple" id="exemple-simple"></a>

Reprenons l'exemple de l'action de `login` détaillé [ici](/guides/effectuer-une-requete-a-lapi#exemple-simple).

Dans l'éditeur de requêtes il n'y a pas besoin de constituer le corps JSON de la requête HTTP, il suffit simplement d'y écrire l'[opération GraphQL](/guides/syntaxe-des-operations-graphql).

![Opération de création d'activité dans la console](/files/VxUos0ruDGo7k9rFoNeg)

Puis il suffit de soumettre la requête en cliquant sur le bouton du milieu, en ayant préalablement renseigné les header HTTP d'authentification.

## Editer les variables d'opération <a href="#editer-les-variables-doperation" id="editer-les-variables-doperation"></a>

Il est possible d'utiliser des [variables d'opération](/guides/syntaxe-des-operations-graphql#variables-doperation) à l'aide de l'éditeur de variables en bas à gauche.


# Enregistrement des activités

L'enregistrement des activités constitue le principal flux entrant de données de l'API Mobilic.

Nous allons détailler ici les différentes opérations qui permettent de réaliser ces enregistrements.

## Prérequis

Toutes les opérations explicitées ci-après nécessitent l'authentification d'un compte "activé" :&#x20;

* à la suite de l'inscription, l'utilisateur doit confirmer son adresse email pour activer son compte
* tant que son compte n'est pas actif, les opérations ci-dessous ne seront pas disponibles

{% hint style="info" %}
Pour en savoir plus sur le parcours utilisateur, vous pouvez consulter les notices d'utilisation des [travailleurs mobiles](https://mobilic.beta.gouv.fr/resources/driver) et des [gestionnaires](https://mobilic.beta.gouv.fr/resources/admin)
{% endhint %}

Pour savoir si un compte utilisateur est actif, l'opération suivante permet de récupérer les paramètres `hasActivatedEmail` et `hasConfirmedEmail` :&#x20;

```graphql
query user {
  user(id: XXXXX) {
    hasConfirmedEmail
    hasActivatedEmail
  }
}
```

Ceux-ci doivent correspondre à `true`.

## Opérations <a href="#operations" id="operations"></a>

### Récupérer les entreprises sur lesquelles un salarié peut créer une mission <a href="#creation-dune-nouvelle-mission" id="creation-dune-nouvelle-mission"></a>

Pour pouvoir récupérer les id des entreprises sur lesquelles un salarié peut renseigner du temps de travail, l'opération suivante peut être utilisée :

```graphql
query user {
  user(id: XXXXX) {
    currentEmployments {
      company {
        name
        id
      }
    }
  }
}
```

### Création d'une nouvelle mission <a href="#creation-dune-nouvelle-mission" id="creation-dune-nouvelle-mission"></a>

Avant d'enregistrer les activités il est indispensable de créer une mission à laquelle seront rattachées les activités.

L'opération de création de la mission est la suivante :

```graphql
mutation {
    activities {
        createMission(name: "XXX", "companyId: YYY) {
            id
            name
        }
    }
}
```

Il y a deux variables, optionnelles toutes les deux :

* `name`
* `companyId`, qui permet de préciser l'entreprise associée à la mission dans le cas où l'auteur est rattaché à plusieurs entreprises.

{% hint style="info" %}
Si une entreprise est donnée via `companyId` il faut que l'auteur y soit rattaché, soit en tant que gestionnaire soit en tant que travailleur. Dans le cas où aucune entreprise n'est précisée la mission est associée à l'entreprise de rattachement principale de l'auteur.
{% endhint %}

La création de la mission ne déclenche pas le démarrage du chrono de temps de travail : les deux moments sont séparés. Cela permet par exemple à l'exploitant de planifier et de créer à l'avance les missions dans son logiciel métier, qui pourrait ensuite les enregistrer dans l'interface dédiée aux travailleurs mobiles pour leur permettre de renseigner le temps de travail de chaque mission le moment venu.

### Enregistrement d'une activité <a href="#enregistrement-dune-activite" id="enregistrement-dune-activite"></a>

L'enegistrement d'une activité se fait au moyen de l'opération `logActivity`.

C'est l'opération principale.

```graphql
mutation(
  $type: ActivityTypeEnum!
  $startTime: TimeStamp!
  $endTime: TimeStamp
  $switch: Boolean
  $userId: Int
  $context: GenericScalar
  $missionId: Int!
) {
  activities {
    logActivity(
      type: $type
      startTime: $startTime
      missionId: $missionId
      endTime: $endTime
      switch: $switch
      context: $context
      userId: $userId
    ) {
      id
      type
      startTime
    }
  }
}
```

Elle prend en arguments :

* `type`, la nature de la nouvelle activité (déplacement, travail, accompagnement)
* `startTime`, l'heure de début d'activité
* `missionId`, la mission pour laquelle est effectuée l'activité
* `endTime`, l'heure de fin d'activité (optionnelle)
* `switch`, indique si le mode d'enregistrement tachygraphe est activé (optionnel, par défaut oui)
* `userId`, le travailleur mobile pour lequel enregistrer l'activité (optionnel, par défaut c'est l'utilisateur authentifié)
* `context`, des données libres qui seront rattachées à l'activité

{% hint style="info" %}
Par défaut l'activité est enregistrée pour l'utilisateur qui effectue l'opération (l'utilisateur authentifié avec le jeton). Afin de faciliter l'usage de l'API il est possible d'enregistrer des activités pour un autre utilisateur, en utilisant le champ `userId`.
{% endhint %}

#### **Mode d'enregistrement tachygraphe**

L'API Mobilic privilègie une saisie en temps réel des activités, dans laquelle les évènements de changement d'activité sont transmis à l'API. L'heure de fin d'une activité n'est déterminée qu'au moment du changement d'activité suivant.

En conséquence l'opération `logActivity` a deux modes de fonctionnement :

* le mode "tachygraphe", correspondant au principe ci-dessus (`switch: true`). L'API enregistre les **changements d'activité**.
* un mode plus classique où les activités sont saisies a posteriori avec leur heure de fin éventuelle (`switch: false`). L'API enregistre directement **les activités**.

Plus précisément le mode "tachygraphe" fonctionne de la manière suivante :

* la variable `startTime` correspond à l'heure de changement d'activité. Au moment de l'opération l'utilisateur ne peut pas avoir d'activité enregistrée après cette heure. En d'autres termes le changement d'activité n'est possible que **pendant ou après la dernière activité**.
* l'opération **n'accepte pas d'heure de fin** (`endTime`)
* si la dernière activité de l'utilisateur n'est pas terminée **l'opération met fin à la dernière activité à l'heure** `startTime`.
* l'opération crée une **nouvelle activité démarrant à** `startTime` **et sans date de fin**.

Par opposition le mode d'enregistrement classique se contente de créer une nouvelle période d'activité pour l'utilisateur, en vérifiant simplement qu'il n'y a pas de chevauchement avec son historique. Il peut notamment être utilisé pour intercaler une nouvelle activité parmi les activités passées (ce que le mode tachygraphe ne permet pas de faire).

### Mise à jour d'une activité <a href="#mise-a-jour-dune-activite" id="mise-a-jour-dune-activite"></a>

L'opération de correction ou de modification d'une activité est `editActivity`. Seule la période d'une activité est modifiable (pas le type de travail, ni la mission ni le travailleur concernés)

```graphql
mutation(
  $activityId: Int!
  $startTime: TimeStamp
  $endTime: TimeStamp
  $removeEndTime: Boolean
  $context
) {
  activities {
    editActivity(
      activityId: $activityId
      startTime: $startTime
      endTime: $endTime
      removeEndTime: $removeEndTime
      context: $context
    ) {
      id
      type
      startTime
    }
  }
}
```

Elle prend en arguments :

* `activityId`, l'identifiant de l'activité à modifier
* `startTime`, la nouvelle heure de début (optionnelle, si elle a été modifiée)
* `endTime`, la nouvelle heure de fin (optionnelle, si elle a été modifiée)
* `removeEndTime`, indique si la fin de l'activité doit être annulée (optionnel et incompatible avec `endTime`). Utile si l'activité a été terminée par erreur.
* `context`, des données libres qui seront rattachées à l'évènement de modification.

### Annulation d'une activité <a href="#annulation-dune-activite" id="annulation-dune-activite"></a>

L'opération d'annulation d'une activité est `cancelActivity`. Elle permet de supprimer l'activité de l'historique de l'utilisateur.

```graphql
mutation(
  $activityId: Int!
  $context
) {
  activities {
    cancelActivity(
      activityId: $activityId
      context: $context
    ) {
       success
    }
  }
}
```

### Fin de mission <a href="#fin-de-mission" id="fin-de-mission"></a>

L'opération signale la fin de la mission pour le travailleur mobile.

```graphql
mutation(
  $missionId: Int!
  $endTime: TimeStamp!
  $userId: Int
  $context: GenericScalar
) {
  activities {
    endMission(
      missionId: $missionId
      endTime: $endTime
      userId: $userId
      context: $context
    ) {
      id
      name
    }
  }
}
```

Les arguments de l'opération ont la même fonction que pour l'enregistrement d'une activité. Dans le cas où la dernière activité de l'utilisateur n'est pas terminée l'opération y met fin à l'heure `endTime`.

### Création d'une absence

La création d'une absence est plus simple grace à l'opération `logHoliday`. Elle permet de créer une mission avec une activité de type `OFF` et de la valider en un seul appel.

```graphql
mutation (
    $companyId: Int!
    $userId: Int
    $startTime: TimeStamp!
    $endTime: TimeStamp!
    $title: String!
) {
    activities{
        logHoliday(
            companyId: $companyId
            userId: $userId
            startTime: $startTime
            endTime: $endTime
            title: $title
        ) {
            id
        }
    }
}
```

Elle prend en arguments :&#x20;

* `comment`, le motif de l'absence (optionel)
* `companyId`, l'identifiant de l'entreprise pour laquelle l'absence est enregistrée
* `endTime`, l'heure de fin de l'absence
* `startTime`, l'heure de début de l'absence
* `title`, l'intitulé de l'absence
* `userId`, l'identifiant du salarié concerné par l'absence (optionnel, par défaut c'est l'auteur de l'opération)

## Exemples <a href="#exemples" id="exemples"></a>

Nous allons illustrer l'utilisation et le rôle des opérations précédentes à travers l'exemple d'une journée de travail classique.

### Début de journée <a href="#debut-de-journee" id="debut-de-journee"></a>

La première action à effectuer consiste à créer une mission.

```graphql
mutation {
  activities {
    createMission(name: "Journée test", companyId: 1) {
      id
      name
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "createMission": {
        "id": 18,
        "name": "Journée test"
      }
    }
  }
}
```

#### **Lieu de début de mission**

Une fois la mission créée, on peut renseigner le lieu de début de mission, et le kilométrage du véhicule.

Ces informations sont obligatoires.

```graphql
mutation {
  activities {
    logLocation(missionId: 18, type: "mission_start_location", manualAddress: "10 avenue de la République 75011", kilometerReading: 5500) {
      id
      name
    }
  }
}
```

Pour plus d'information sur le renseignement des lieux d'une mission, se référer à la page suivante :

{% content-ref url="/pages/4SLtn48D8QhvBeWD7Xw1" %}
[Enregistrement des lieux de début et de fin de mission](/guides/enregistrement-des-lieux-de-debut-et-de-fin-de-mission)
{% endcontent-ref %}

#### **Première activité**

On peut ensuite enregistrer le démarrage de la première activité de la mission.

```graphql
mutation {
  activities {
    # 9h00
    logActivity(missionId: 18, type: "drive", startTime: 1577869200) {
      id
      type
      startTime
      endTime
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "logActivity": {
        "id": 193,
        "type": "drive",
        "startTime": 1577869200,
        "endTime": null
      }
    }
  }
}
```

En mode tachygraphe l'activité n'a pas d'heure de fin au moment de son enregistrement. Tant que l'API ne reçoit pas un nouvel évènement de changement ou de fin d'activité le chronomètre continue de tourner.

#### **Deuxième activité**

L'enregistrement du changement d'activité se fait de manière identique à l'enregistrement précédent, c'est-à-dire en mode tachygraphe.

```graphql
mutation {
  activities {
    # 11h00
    logActivity(missionId: 18, type: "work", startTime: 1577876400) {
      id
      type
      startTime
      endTime
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "logActivity": {
        "id": 194,
        "type": "work",
        "startTime": 1577876400,
        "endTime": null
      }
    }
  }
}
```

Le changement d'activité a créé une nouvelle activité débutant à 11h (et sans heure de fin) et a mis fin à l'activité précédente à cette même heure.

### Pause <a href="#pause" id="pause"></a>

Pour indiquer la fin d'une activité sans démarrage immédiat d'une autre activité, il suffit d'éditer la date de fin de l'activité.

```graphql
mutation {
  activities {
    # 12h30
    editActivity(activityId: 194, endTime: 1577881800) {
      id
      type
      startTime
      endTime
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "editActivity": {
        "id": 194,
        "type": "work",
        "startTime": 1577876400,
        "endTime": 1577881800
      }
    }
  }
}
```

### Fin de journée <a href="#fin-de-journee" id="fin-de-journee"></a>

**Troisième activité**

Une fois la pause terminée l'enregistrement des activités peut reprendre, toujours en mode tachygraphe.

```graphql
mutation {
  activities {
    # 14h00
    logActivity(missionId: 18, type: "work", startTime: 1577887200) {
      id
      type
      startTime
      endTime
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "logActivity": {
        "id": 195,
        "type": "work",
        "startTime": 1577887200,
        "endTime": null
      }
    }
  }
}
```

Lors du décompte du temps de travail sur la journée, les périodes de creux entre deux activités seront automatiquement décomptées comme du temps de pause.

#### **Quatrième activité**

```graphql
mutation {
  activities {
    # 15h30
    logActivity(missionId: 18, type: "drive", startTime: 1577892600) {
      id
      type
      startTime
      endTime
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "logActivity": {
        "id": 196,
        "type": "drive",
        "startTime": 1577892600,
        "endTime": null
      }
    }
  }
}
```

#### **Lieu de fin de mission**

On termine la journée en renseignant le lieu de fin de mission, et le nouveau kilométrage du véhicule.

Ces informations sont obligatoires.

```graphql
mutation {
  activities {
    logLocation(missionId: 18, type: "mission_end_location", manualAddress: "25 avenue de la République 75011", kilometerReading: 5550) {
      id
      name
    }
  }
}
```

Pour plus d'information sur le renseignement des lieux d'une mission, se référer à la page suivante :

{% content-ref url="/pages/4SLtn48D8QhvBeWD7Xw1" %}
[Enregistrement des lieux de début et de fin de mission](/guides/enregistrement-des-lieux-de-debut-et-de-fin-de-mission)
{% endcontent-ref %}

#### **Fin de mission**

Pour terminer la mission il suffit d'effectuer l'opération `endMission` en passant la date de fin de l'activité en cours.

```graphql
mutation {
  activities {
    # 17h
    endMission(missionId: 18, endTime: 1577898000) {
      id
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "endMission": {
        "id": 18
      }
    }
  }
}
```

### Corrections éventuelles <a href="#corrections-eventuelles" id="corrections-eventuelles"></a>

Le travailleur mobile s'aperçoit de quelques erreurs et oublis dans sa saisie intiale.

#### **Oubli de redémarrer après la pause**

La vraie heure de reprise d'activité après la pause du midi est 13h30 mais l'utilisateur n'a enregistré la reprise qu'à 14h. Pour corriger cela il lui suffit d'indiquer que l'activité de reprise a en fait démarré une demi-heure plus tôt.

```graphql
mutation {
  activities {
    # 13h30
    editActivity(activityId: 195, startTime: 1577885400) {
      id
      type
      startTime
      endTime
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "editActivity": {
        "id": 195,
        "type": "work",
        "startTime": 1577885400,
        "endTime": 1577892600
      }
    }
  }
}
```

**Correction de la fin d'une activité**

Le travailleur mobile a signalé trop tôt la fin de mission. Il souhaite décaler la date de fin de 17h à 17h30.

```graphql
mutation {
  activities {
    # 17h30
    editActivity(activityId: 196, endTime: 1577899800) {
      id
      type
      startTime
      endTime
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "editActivity": {
        "id": 196,
        "type": "work",
        "startTime": 1577892600,
        "endTime": 1577899800
      }
    }
  }
}
```

**Rajout d'une activité a posteriori**

Le travailleur mobile souhaite ajouter une activité qui s'est déroulée de 8h à 9h. Il lui suffit d'enregistrer une activité en mode classique.

```graphql
mutation {
  activities {
    # 8h - 9h
    logActivity(
      missionId: 18
      type: "work"
      startTime: 1577865600
      endTime: 1577869200
      switch: false
    ) {
      id
      type
      startTime
      endTime
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "logActivity": {
        "id": 197,
        "type": "work",
        "startTime": 1577865600,
        "endTime": 1577869200
      }
    }
  }
}
```

#### **Validation de la mission**

Pour valider la mission il suffit d'effectuer l'opération `validateMission`.

```graphql
mutation {
  activities {
    validateMission(missionId: 18, usersIds: [1577898000]) {
      id
    }
  }
}
```

Réponse

```json
{
  "data": {
    "activities": {
      "validateMission": {
        "id": 18
      }
    }
  }
}
```

<br>


# Enregistrement des lieux de début et de fin de mission

Il existe trois façons différentes de renseigner les lieux de début et de fin de mission.

Ces lieux doivent obligatoirement être renseignés au début et à la fin des missions.

### Renseigner une adresse manuelle

```graphql
mutation {
  activities {
    logLocation(missionId: 18,
                type: "mission_start_location",
                manualAddress: "10 avenue de la République 75011",
                kilometerReading: 5500) {
      id
      name
    }
  }
}
```

###

### Renseigner une adresse préenregistrée

Il est possible de préenregistrer des adressses au sein d'une société, pour présenter au salarié une liste prédéfinie d'adresses si celles ci sont fréquemment utilisées. Par exemple pour y renseigner des entrepôts.

Il vous suffit alors de renseigner l'identifiant de l'adresse dans la requête `logLocation`

```graphql
mutation {
  activities {
    logLocation(missionId: 18,
                type: "mission_start_location",
                companyKnownAddressId: 16,
                kilometerReading: 5500) {
      id
      name
    }
  }
}
```

### Renseigner une adresse au format GeoJSON

Il est possible de renseigner une adresse au format GeoJSON, tel que renvoyé par l'API [api.adresse](https://adresse.data.gouv.fr/) par exemple.

L'adresse est alors à renseigner dans le champ `geoApiData`.

```graphql
mutation {
  activities {
    logLocation(missionId: 18,
                type: "mission_start_location",
                geoApiData: {"type":"Feature","geometry":{"type":"Point","coordinates":[2.35273,48.847202]},"properties":{"label":"41 Rue du Cardinal Lemoine 75005 Paris","score":0.9999999844012717,"housenumber":"41","id":"75105_1545_00041","name":"41 Rue du Cardinal Lemoine","postcode":"75005","citycode":"75105","x":652499.34,"y":6860989.97,"city":"Paris","district":"Paris 5e Arrondissement","context":"75, Paris, Île-de-France","type":"housenumber","importance":0.71867,"street":"Rue du Cardinal Lemoine","distance":6}},
                kilometerReading: 5500) {
      id
      name
    }
  }
}
```


# Consultation du temps de travail

Les données de temps de travail enregistrées dans l'API Mobilic peuvent être consultées par les utilisateurs concernés.

L'API met à disposition trois opérations de consultation :

* pour une mission
* pour un travailleur mobile
* pour une entreprise

## Consultation des données d'une mission <a href="#consultation-des-donnees-dune-mission" id="consultation-des-donnees-dune-mission"></a>

{% hint style="info" %}
L'accès aux données de temps de travail d'une mission n'est autorisée que pour les membres de l'entreprise concernée par la mission.
{% endhint %}

```graphql
query {
    mission(id: Int!) {
        name
        activities {
            id
            type
            startTime
            endTime
            userId
        }
        expenditures {
            id
            type
            userId
        }
    }
}
```

La requête retourne la liste des activités associées à la mission (concernant éventuellement plusieurs utilisateurs).

## Consultation des données pour un travailleur mobile <a href="#consultation-des-donnees-pour-un-travailleur-mobile" id="consultation-des-donnees-pour-un-travailleur-mobile"></a>

{% hint style="info" %}
L'accès complet aux données de temps de travail n'est autorisé que pour les gestionnaires de l'entreprise ou pour l'utilisateur lui-même.
{% endhint %}

```graphql
query {
    user(id: Int!) {
        firstName
        lastName
        missions {
            edges {
                node {
                    name
                    activities {
                        id
                        type
                        startTime
                        endTime
                        userId
                    }
                    expenditures {
                        id
                        type
                        userId
                    }
                }
            }
        }
    }
}
```

Dans l'exemple ci-dessus, sous réserve d'un niveau d'autorisation adapté, l'API retournera la liste des missions sur lesquelles le travailleur a enregistré du temps de travail.

Si l'on souhaite uniquement récupérer les activités sans avoir un regroupement par missions, il est possible de requêter directement le champ `activities` :

```graphql
query {
    user(id: Int!) {
        firstName
        lastName
        activities {
            edges {
                node {
                    id
                    type
                    startTime
                    endTime
                    userId
                    missionId
                }
            }
        }
    }
}
```

Il est également possible de récupérer le temps de travail déjà calculé par journée.

```graphql
query {
    user(id: Int!) {
        firstName
        lastName
        workDays {
            edges {
                node {
                    startTime
                    endTime
                    activityDurations
                }
            }
        }
    }
}
```

## Consultation des données entreprise <a href="#consultation-des-donnees-entreprise" id="consultation-des-donnees-entreprise"></a>

Cette opération permet d'accéder à toutes les données de temps de travail propres à l'entreprise, c'est-à-dire toutes les missions qui ont été réalisées par des salariés de l'entreprise.

{% hint style="info" %}
L'accès complet à toutes les missions nécessite d'être rattaché en tant que gestionnaire à l'entreprise.
{% endhint %}

```graphql
query {
    company(id: Int!) {
        name
        missions {
            edges {
                node {
                    id
                    name
                    activities {
                        id
                        type
                        startTime
                        endTime
                        userId
                    }
                    expenditures {
                        id
                        type
                        userId
                    }
                }
            }
        }
    }
}
```

Il est également possible de récupérer la liste des membres actuels de l'entreprise.

```graphql
query {
    company(id: Int!) {
        name
        users {
            id
            firstName
            lastName
        }
    }
}
```

A l'instar de la consultation des données d'un travailleur mobile il est possible de récupérer le temps de travail déjà agrégé par journée.

```graphql
query {
    company(id: Int!) {
        name
        workDays {
            edges {
                node {
                    userId
                    startTime
                    endTime
                    activityDurations
                }
            }
        }
    }
}
```

### Cas d'une gestion multi-sociétés <a href="#cas-dune-gestion-multi-societes" id="cas-dune-gestion-multi-societes"></a>

Il est possible de récupérer en une seule requête la liste de toutes les entreprises sur lesquelles l'utilisateur a un droit de gestion, via le champ `adminedCompanies`.

```graphql
query {
  me {
    adminedCompanies {
      name
      workDays {
        edges {
          node {
            userId
            startTime
            endTime
            activityDurations
          }
        }
      }
    }
  }
}
```

## Choix de la période d'historique récupérée <a href="#choix-de-la-periode-dhistorique-recuperee" id="choix-de-la-periode-dhistorique-recuperee"></a>

Les trois champs permettant de récupérer des données de temps de travail prennent des arguments optionnels pour restreindre la période d'historique :

* le champ `activities(fromTime: TimeStamp, untilTime: TimeStamp)` au niveau d'un travailleur mobile
* le champ `missions(fromTime: TimeStamp, untilTime: TimeStamp)` au niveau d'un travailleur mobile ou d'une entreprise
* le champ `workDays(fromDate: Date, untilDate: Date)` au niveau d'un travailleur mobile ou d'une entreprise

```graphql
query {
    user(id: Int!) {
        firstName
        lastName
        activities(fromTime: 1577869200, untilTime: 1578081600) {
            edges {
                node {
                    # toutes les activités qui ont eu lien (au moins en partie) entre le 01/01/2020 9h et le 03/01/2020 20h
                    id
                    type
                    startTime
                    endTime
                    userId
                    missionId
                }
            }
        }
    }
}
```

```graphql
query {
    user(id: Int!) {
        firstName
        lastName
        missions(fromTime: 1577869200) {
            # toutes les missions pour lesquelles le travailleur mobile a du temps de travail après le 01/01/2020 9h
            edges {
                node {
                    name
                    activities {
                        id
                        type
                        startTime
                        endTime
                        userId
                    }
                    expenditures {
                        id
                        type
                        userId
                    }
                }
            }
        }
    }
}
```

```graphql
query {
  me {
    adminedCompanies {
      name
      workDays(fromDate: "2020-01-01") {
        edges {
          node {
            # toutes les journées de travail des entreprises concernées à partir du 01/01/2020
            userId
            startTime
            endTime
            activityDurations
          }
        }
      }
    }
  }
}
```

Sur les champs de l'entreprise il existe également un paramètre `limit` qui définit un nombre maximal de missions retournées, en plus du filtre sur les dates. Les missions les plus récentes (dans la période sélectionnée) seront renvoyées.


# QR code à présenter lors d'un contrôle

Lorsque le salarié est contrôlé, il doit présenter un QR code généré par l'API Mobilic. Pour obtenir la chaîne de caractère servant à générer ce QR Code, un endpoint POST a été mis en place.

## API REST

```
POST /control/generate-user-read-token
Content-Type: application/json

{}
```

### Authentification

Afin de pouvoir utiliser cette API, vous devez être authentifié : [Authentification](/guides/authentification).

Le QR code généré sera celui de l'utilisateur authentifié. Le contrôleur aura alors accès aux informations de cet utilisateur.

### Réponse

En cas de succès, l'API retourne deux champs au format JSON :&#x20;

```json
{
    "controlToken":"frefr5e6f45614564yhFRFDSFS.tGDGDFgDFGd4g565dg65dgdGDGDFGD.eZFEZfdsQY-c646s",
    "token":"46sE-itIeK39_fre6f456e44641n65yh4ngn"
}

```

### Construction du QR Code à partir de la réponse

la chaîne de caractère qui doit être mise sous forme de QR code est de la forme suivante :

<https://mobilic.beta.gouv.fr/control/user-history?token=_token\\_recupéré\\&ts=timestamp\\_actuel_\\&controlToken=_control\\_token\\_récupéré>\_


# Inscription et rattachement des salariés

L'accès aux services de l'API Mobilic nécessite de disposer d'un compte.

## Création de compte via l'interface Mobilic <a href="#creation-de-compte" id="creation-de-compte"></a>

L'inscription se fait sur le site Mobilic, depuis les liens suivants

* [https://mobilic.beta.gouv.fr/signup/admin](https://mobilic.beta.gouv.fr/logout?next=/signup/admin) pour créer des comptes correspondant à de vrais utilisateurs sur l'environnement de production
* [https://sandbox.mobilic.beta.gouv.fr/signup/admin](https://sandbox.mobilic.beta.gouv.fr/logout?next=/signup/admin) pour créer des comptes de test sur l'environnement bac à sable

Il y a 3 étapes à l'inscription :

1. le gestionnaire crée son compte individuel et inscrit son entreprise (depuis les liens ci-dessus).
2. le gestionnaire invite ses salariés en renseignant leurs adresses email depuis son espace entreprise.
3. le salarié crée son compte individuel en suivant les instructions contenues dans l'email d'invitation.

## Création de compte par API <a href="#creation-de-compte" id="creation-de-compte"></a>

Se référer à la page dédiée :

{% content-ref url="/pages/B41HJ8dc9z4meKbhWsiw" %}
[Rattachement  des employés à la société](/guides/authentification/jetons-lies-a-un-rattachement/rattachement-des-employes-a-la-societe)
{% endcontent-ref %}

## Rattachement des salariés <a href="#rattachement-des-salaries" id="rattachement-des-salaries"></a>

Les comptes utilisateurs sont liés à la personne titulaire du compte, indépendamment de son entreprise ou de son métier (travailleur mobile ou gestionnaire). Ainsi une personne qui change d'entreprise garde quand même un seul et même compte.

L'appartenance (variable dans le temps) d'une personne à une entreprise est représentée par un rattachement. Un compte peut avoir plusieurs rattachements dans le temps, au fur et à mesure que la personne passe d'une entreprise à l'autre.

Un compte peut également être rattaché simultanément à plusieurs entreprises, pour répondre au cas fréquent de sociétés soeurs qui peuvent occasionnellement mutualiser leurs travailleurs.

{% hint style="info" %}
Par défaut le temps de travail enregistré par un compte travailleur mobile sera associé à l'entreprise à laquelle il est rattaché au moment de l'activité. Si il y a plusieurs rattachements simultanés le rattachement principal (unique) prévaut en l'absence de précision supplémentaire.
{% endhint %}

Pour des raisons de sécurité le rattachement d'une personne à une entreprise doit être approuvé à la fois par l'entreprise et par le salarié. Cela se fait dans l'ordre suivant :

1. L'entreprise (c'est-à-dire un utilisateur Mobilic qui a les droits d'administration de cette entreprise) effectue une demande de rattachement du salarié par API, en précisant une date de début du rattachement (et optionnellement une date de fin)
2. La demande de rattachement est enregistrée mais reste inactive tant qu'elle n'a pas été approuvée par le salarié
3. Le compte salarié approuve par API la demande de rattachement. Les anciens rattachements sont éventuellement terminés si besoin.


# Auto-validations

Explication du fonctionnement des auto-validations et de l'impact sur l'API

Nous avons mis en place un système d'auto-validations ayant pour objectifs de valider les missions après un certain délai si cela n'a pas été fait par le salarié ou le gestionnaire :

* validation salarié **un jour ouvré** après le démarrage de la mission (moment où la première activité est ajoutée dans la mission pour un utilisateur)
* validation gestionnaire **deux jours ouvrés** après la validation salarié

L'auto-validation ne s'effectue qu'en cas d'oubli de validation dans le délai imparti.

L'objet `MissionValidation` contient un nouveau champ `is_auto` . De plus le champ `submitter` peut être null (car une auto-validation n'a pas de submitter).

```graphql
validations {
  id
  isAdmin
  isAuto     # NEW: true pour une auto-validation
  justification
  userId
  receptionTime
  missionId
  submitter { # peut être null
    id
    firstName
    lastName
  }
}
```

### Auto-validation salarié

Une auto-validation salarié est équivalente à une validation salarié classique, il n'est plus possible pour le salarié de modifier ou de valider la mission.

Si un salarié tente de valider une mission auto-validée une erreur sera retournée

```python
class MissionAlreadyAutoValidatedError(MobilicError):
    code = "MISSION_ALREADY_AUTO_VALIDATED"
    default_message = "This mission has already been automatically validated"
```

### Auto-validation gestionnaire

Un gestionnaire peut toujours modifier/valider une mission auto-validée à sa place, mais dans ce cas il est nécessaire d'ajouter un argument `justification` qui peut prendre un des valeurs suivantes :

* personal
* professional
* time\_off

```python
class OverValidationJustification(str, Enum):
    PERSONAL = "personal"
    PROFESSIONAL = "professional"
    TIME_OFF = "time_off"
    __description__ = """
Enumération des valeurs suivantes.
- "personal" : Raisons personnelles
- "professional" : Raisons professionnelles
- "time_off" : Congé
"""
```

mutation de validation gestionnaire :

```graphql
mutation validateMission(
    $missionId: Int!
    $usersIds: [Int]!
    $creationTime: TimeStamp
    $activityItems: [BulkActivityItem]
    $expendituresCancelIds: [Int]
    $expendituresInputs: [BulkExpenditureItem]
    $justification: OverValidationJustificationEnum # NEW: argument nécessaire si la mission a déja été auto-validée
  ) {
    activities {
      validateMission(
        missionId: $missionId
        usersIds: $usersIds
        creationTime: $creationTime
        activityItems: $activityItems
        expendituresCancelIds: $expendituresCancelIds
        expendituresInputs: $expendituresInputs
        justification: $justification # NEW: argument nécessaire si la mission a déja été auto-validée
      ) {
        ...FullMissionData
      }
    }
```


# Exports

## Endpoints d'exports

#### Vue d'ensemble

<table><thead><tr><th>Endpoint</th><th width="72">Méthode</th><th>Description</th><th>Authentification requise</th><th>Autorisation</th></tr></thead><tbody><tr><td><code>/companies/validate_export_params</code></td><td>POST</td><td>Prévisualise la stratégie d'export et le nombre de fichiers qui seront générés, sans lancer l'export</td><td>X-CLIENT-ID + X-EMPLOYMENT-TOKEN</td><td>Gestionnaire de l'entreprise</td></tr><tr><td><code>/companies/download_activity_report</code></td><td>POST</td><td>Lance la génération asynchrone des fichiers Excel de rapport d'activité (retourne 202)</td><td>X-CLIENT-ID + X-EMPLOYMENT-TOKEN</td><td>Gestionnaire de l'entreprise</td></tr><tr><td><code>/companies/generate_tachograph_files</code></td><td>POST</td><td>Génère et télécharge immédiatement une archive ZIP de fichiers C1B (chronotachygraphe)</td><td>X-CLIENT-ID + X-EMPLOYMENT-TOKEN</td><td>Gestionnaire de l'entreprise</td></tr></tbody></table>


# Export C1B

Génération de fichiers C1B contenant les données d'activité des salariés

## API REST

Pour exporter les données d'activité des salariés d'une entreprise au format C1B, utiliser l'API REST suivante :&#x20;

```
POST /companies/generate_tachograph_files
Content-Type: application/json

{
  "company_ids": [1],
  "user_ids": [100],
  "min_date": "2021-12-16",
  "max_date": "2022-02-14",
  "with_digital_signatures": false,Génération de fichiers C1B contenant les données d'activité des salariés
  "employee_version": false
}
```

### Authentification

Afin de pouvoir utiliser cette API, vous devez être authentifié : [Authentification](/guides/authentification).

### Requête

<table><thead><tr><th width="175">Champ</th><th width="284.48837209302326">Description</th><th width="178">Format</th><th>Obligatoire</th></tr></thead><tbody><tr><td><code>company_ids</code></td><td>Entreprises pour lesquelles on souhaite exporter les données</td><td>Liste d'identifiants d'entreprises</td><td>Oui</td></tr><tr><td><code>user_ids</code></td><td>Salariés pour lesquels on souhaite filtrer les données. Par défaut, on remonte les données pour tous les salariés</td><td>Liste d'identifiants de salariés</td><td>Non (par défaut: <code>[]</code>) </td></tr><tr><td><code>min_date</code></td><td>Date de début de la période souhaitée</td><td>Date au format "YYYY-MM-dd"</td><td>Non</td></tr><tr><td><code>max_date</code></td><td>Date de fin de la période souhaitée</td><td>Date au format "YYYY-MM-dd"</td><td>Non</td></tr><tr><td><code>with_digital_signatures</code></td><td>Permet d'ajouter des signatures numériques aux fichiers pour prouver leur intégrité</td><td>Booléen</td><td>Non (par défaut: <code>false</code>)</td></tr><tr><td><code>employee_version</code></td><td>Permet d'ajouter la version salarié correspondant aux fichiers</td><td>Booléen</td><td>Non (par défaut: <code>false</code>)</td></tr></tbody></table>

### Réponse

En cas de succès, l'API retourne un fichier ZIP :&#x20;

```
HTTP/1.1 200 OK
Content-Disposition: attachment; filename=fichiers_C1B.zip
Content-Type: application/zip
Content-Length: ...
```

### Cas d'erreurs

<table><thead><tr><th width="440">Description</th><th>HTTP Status</th></tr></thead><tbody><tr><td>Pas de token d'authentification</td><td>401 Unauthorized</td></tr><tr><td>Le token d'authentification ne correspond pas à une des entreprises renseignées</td><td>403 Forbidden</td></tr><tr><td>La requête est mal formée (le détail est dans le corps de la réponse)</td><td>404 Bad request</td></tr></tbody></table>


# Export Excel

Génération de fichiers Excel contenant les données d'activité des salariés

## API REST - Validation de l'export

Avant le téléchargement des fichiers d'activités, nous vous recommandons de valider les paramètres de l'export afin prévisualiser combien de fichier seront générés et comment les données seront réparties entre les fichiers. Pour la génération de ces fichiers, certaines règles s'appliquent en fonctions de la période et du nombre de salariés sélectionnés.

```
POST /companies/validate_export_params
Content-Type: application/json

{
  "company_ids": [1],
  "user_ids": [100],
  "min_date": "2021-12-16",
  "max_date": "2022-02-14",
  "one_file_by_employee": false,
  "detailed": false,
}
```

### **Règles de génération de fichiers (stratégies)**

<table><thead><tr><th width="241">Stratégie</th><th>Règle</th></tr></thead><tbody><tr><td>OVER_365_DAYS</td><td><p><em>Période de date ≥ 1 an</em> <br><strong>Génération</strong> : 1 fichier par année ET par salarié </p><p><strong>fichiers</strong> : &#x3C;nom_prenom>_YYYY ou &#x3C;nom_prenom>_YYYY_YYYY <br><strong>Tri</strong> : Alphabétique par nom de famille, puis chronologique Paramètre one_file_by_employee : ❌ Ignoré (toujours 1 fichier par salarié)</p></td></tr><tr><td>OVER_31_DAYS</td><td><p><em>Période > 31 jours (mais &#x3C; 365 jours)</em> <br><strong>Génération</strong> : Si ≤ 100 salariés : 1 fichier par mois Si > 100 salariés 1 fichier par mois ET par tranche de 100 salariés <strong>fichiers</strong> : YYYY-MM__YYYY (ex : 2024-03_mars_2024) </p><p><strong>Tri</strong> : Chronologique (grâce au préfixe YYYY-MM) Paramètre one_file_by_employee : ❌ Ignoré</p></td></tr><tr><td>OVER_100_USERS</td><td><p> <em>> 100 salariés (et période ≤ 31 jours)</em><br><strong>Génération</strong> : 1 fichier par tranche de 100 salariés </p><p><strong>Fichiers</strong> : batch_1, batch_2, etc. <br><strong>Tri</strong> : Alphabétique par nom de famille Paramètre one_file_by_employee : ❌ Ignoré</p></td></tr><tr><td>SINGLE_OR_CONSOLIDATED</td><td>≤ 100 salariés ET période ≤ 31 jours <br><strong>Génération</strong> : <br>one_file_by_employee = true -> 1 fichier par salarié Si one_file_by_employee = false (défaut) -> 1 fichier consolidé, <br><strong>le paramètre one_file_by_employee est Pris en compte</strong></td></tr></tbody></table>

### Authentification

Afin de pouvoir utiliser cette API, vous devez être authentifié : [Authentification](/guides/authentification).

### Requête

<table data-full-width="true"><thead><tr><th width="175">Champ</th><th width="284.48837209302326">Description</th><th width="178">Format</th><th>Obligatoire</th></tr></thead><tbody><tr><td><code>company_ids</code></td><td>Entreprises pour lesquelles on souhaite exporter les données</td><td>Liste d'identifiants d'entreprises</td><td>Oui</td></tr><tr><td><code>user_ids</code></td><td>Salariés pour lesquels on souhaite filtrer les données. Par défaut, on remonte les données pour tous les salariés</td><td>Liste d'identifiants de salariés</td><td>Non (par défaut: <code>[]</code>) </td></tr><tr><td><code>min_date</code></td><td>Date de début de la période souhaitée</td><td>Date au format "YYYY-MM-dd"</td><td>Non</td></tr><tr><td><code>max_date</code></td><td>Date de fin de la période souhaitée</td><td>Date au format "YYYY-MM-dd"</td><td>Non</td></tr><tr><td><pre><code>one_file_by_employee
</code></pre></td><td>Permet de spécifier si le fichier doit être unique pour chaque salarié ou en un seul fichier pour tous les salariés</td><td>Booléen</td><td>Non (par défaut: <code>false</code>)</td></tr><tr><td><code>detailed</code></td><td>Retourne le détail de chaque fichiers (chunks)</td><td>Booléen</td><td>Non  (défaut : <code>false</code>)</td></tr></tbody></table>

### Réponse

```
{
  "strategy": "string",
  "message": "string",
  "can_choose_consolidated": boolean,
  "num_chunks": integer,
  "chunks": [ ... ]  // Optionnel si detailed=true
}
```

#### Champs de la réponse

| Champ                     | Type      | Requis | Description                                                                                                                                                                 |
| ------------------------- | --------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `strategy`                | `string`  | Oui    | Identifiant de la stratégie de chunking appliquée. Valeurs possibles : `over_365_days`, `over_31_days`, `over_100_users`, `single_or_consolidated`                          |
| `message`                 | `string`  | Oui    | Message explicatif en français décrivant la stratégie appliquée et le nombre de fichiers attendus. À afficher directement à l'utilisateur.                                  |
| `can_choose_consolidated` | `boolean` | Oui    | Indique si le paramètre `one_file_by_employee` peut influencer le résultat. `true` uniquement pour la stratégie `single_or_consolidated`, `false` dans tous les autres cas. |
| `num_chunks`              | `integer` | Oui    | Nombre total de fichiers Excel qui seront générés lors de l'export.                                                                                                         |
| `chunks`                  | `array`   | Non    | Tableau contenant le détail de chaque chunk (fichier). Présent uniquement si le paramètre `detailed=true` est envoyé dans la requête.                                       |

#### Structure des objets dans `chunks` (si `detailed=true`)

| Champ         | Type                | Description                                                                                            |
| ------------- | ------------------- | ------------------------------------------------------------------------------------------------------ |
| `user_ids`    | `array[integer]`    | Liste des identifiants des salariés inclus dans ce fichier.                                            |
| `min_date`    | `string` (ISO 8601) | Date de début de la période couverte par ce fichier (format `YYYY-MM-DD`).                             |
| `max_date`    | `string` (ISO 8601) | Date de fin de la période couverte par ce fichier (format `YYYY-MM-DD`).                               |
| `file_suffix` | `string`            | Suffixe du nom de fichier qui sera généré (ex: `2026-01_janvier_2026`, `Martin_Jean_2024`, `batch_1`). |

## API REST - Téléchargement de l'export

Pour exporter les données d'activité des salariés d'une entreprise au format ZIP contenant plusieurs fichiers excel, utiliser l'API REST suivante :&#x20;

```
POST /companies/download_activity_report
Content-Type: application/json

{
  "company_ids": [1],
  "user_ids": [100],
  "min_date": "2021-12-16",
  "max_date": "2022-02-14",
  "one_file_by_employee": false
}
```

### Authentification

Afin de pouvoir utiliser cette API, vous devez être authentifié : [Authentification](/guides/authentification).

### Requête

<table data-full-width="true"><thead><tr><th width="175">Champ</th><th width="284.48837209302326">Description</th><th width="178">Format</th><th>Obligatoire</th></tr></thead><tbody><tr><td><code>company_ids</code></td><td>Entreprises pour lesquelles on souhaite exporter les données</td><td>Liste d'identifiants d'entreprises</td><td>Oui</td></tr><tr><td><code>user_ids</code></td><td>Salariés pour lesquels on souhaite filtrer les données. Par défaut, on remonte les données pour tous les salariés</td><td>Liste d'identifiants de salariés</td><td>Non (par défaut: <code>[]</code>) </td></tr><tr><td><code>min_date</code></td><td>Date de début de la période souhaitée</td><td>Date au format "YYYY-MM-dd"</td><td>Non</td></tr><tr><td><code>max_date</code></td><td>Date de fin de la période souhaitée</td><td>Date au format "YYYY-MM-dd"</td><td>Non</td></tr><tr><td><pre><code>one_file_by_employee
</code></pre></td><td>Permet de spécifier si le fichier doit être unique pour chaque salarié ou en un seul fichier pour tous les salariés</td><td>Booléen</td><td>Non (par défaut: <code>false</code>)</td></tr></tbody></table>

### Réponse

En cas de succès, l'API retourne un fichier ZIP :&#x20;

```
HTTP/1.1 200 OK
Content-Disposition: attachment; filename=fichiers_Excel.zip
Content-Type: application/zip
Content-Length: ...
```

### Cas d'erreurs

<table><thead><tr><th width="440">Description</th><th>HTTP Status</th></tr></thead><tbody><tr><td>Pas de token d'authentification</td><td>401 Unauthorized</td></tr><tr><td>Le token d'authentification ne correspond pas à une des entreprises renseignées</td><td>403 Forbidden</td></tr><tr><td>La requête est mal formée (le détail est dans le corps de la réponse)</td><td>404 Bad request</td></tr></tbody></table>


# Consultation des calculs de seuils réglementaires

Il est possible de consulter les résultats de calculs de seuils réglementaires pour un salarié

{% hint style="info" %}
L'accès aux données de calcul de seuils réglementaires n'est autorisé que pour les gestionnaires de l'entreprise ou pour l'utilisateur lui-même.
{% endhint %}

### Exemple d'appel à l'API

```graphql
query {
    user(id: Int!) {
      regulationComputationsByDay(fromDate: Date, toDate: Date) {
        day
        regulationComputations {
          submitterType
          regulationChecks(unit: "day" | "week") {
            type
            label
            description
            unit
            alert {
              extra
            }
          }
        }
      }
    }
  }
```

L'API renvoie une liste pour chaque jour contenant des calculs de seuils. Il est possible d'indiquer le jour de début et de fin du tableau grâce aux paramètres `fromDate` et `toDate`.

\
Chaque élement de la liste contient une liste de `RegulationComputation` représentant les calculs de seuils effectués pour le jour en question.

Un `RegulationComputation` possède

* un `submitterType` qui vaut `admin` ou `employee` . Ceci indique si le calcul a été effectué en prenant en compte la version salarié ou gestionnaire des activités.
* une liste de `regulationCheck` représentant les seuils règlementaires calculés pour la journée

Un `regulationCheck` possède

* un `type` pour identifier le seuil dépassé
* un `label`  correspondant au seuil dépassé
* une `description`
* une `unit` valant soit `day` ou `week` selon qu'il s'agisse d'une règle quotidienne ou hebdomadaire
* un objet `alert` qui est null s'il n'y a pas eu de dépassement de seuil pour la règle en question. S'il y a eu dépassement, l'objet sera non null et un champ `extra` contiendra un JSON avec des informations complémentaires relatives au dépassement

### Exemple de réponse

```graphql
user: {
  regulationComputationsByDay: [
    { 
      # le tableau contient une entrée par journée
      day: 2023-03-15,
      regulationComputations: [
        {
          day: 2023-03-15,
          # les calculs concernent les version salariés des données
          submitterType: employee, 
          regulationChecks: [
            {
              # identifiant de la règle vérifiée
              type: minimumDailyRest,
              label: Non-respect(s) du repos quotidien,
              description: La dur\u00e9e du repos quotidien ...,
              # indique si la règle est journalière ou hebdomadaire
              unit: day,
              # pas d'alerte relevée ici
              alert: null,
            },
            {
              type: maximumWorkDayTime,
              label: D\u00e9passement(s) de la dur\u00e9e maximale du travail quotidien,
              description: La dur\u00e9e du travail ...,
              unit: day,
              # un dépassement de seuil a été relevé
              alert: {
                # le champ extra contient des informations supplémentaires
                extra: {\night_work\: true, \max_time_in_hours\: 10},
              },
            },
            {
              type: maximumUninterruptedWorkTime,
              label: D\u00e9passement(s) de la dur\u00e9e maximale du travail ininterrompu,
              description: Lorsque le temps de travail ...,
              regulationRule: dailyRest,
              unit: day,
              # un dépassement de seuil a été relevé mais il n'y a pas d'informations supplémentaires
              alert: {
                extra: null,
              },
            },
            {
              # example de règle hebdomadaire
              type: maximumWorkedDaysInWeek,
              label: Non-respect(s) du repos hebdomadaire,
              description: Il est interdit de travailler plus ...,
              unit: week,
              alert: null,
            }         
          ],
        }
      ],
    }
  ],
}
```

### Explication des données "extra"

Le champ `extra` contient des informations différentes selon le type d'alerte

#### minimumDailyRest

* `min_daily_break_in_hours`  La durée du repos quotidien en heures à laquelle est soumise le salarié
* `breach_period_start` et `breach_period_end`  Le début et la fin de la période de 24h sur laquelle il a été constaté que le repos quotidien n'a pas été respecté
* `breach_period_max_break_in_seconds` La plus longue période de repos constaté sur cette période de 24h. Celle-ci est forcément inférieure à la durée légale du repos quotidien et c'est pourquoi une alerte a été levée
* `sanction_code` le code NATINF de la sanction liée à ce dépassement

**Exemple**

```
{
  min_daily_break_in_hours: 10,
  breach_period_start: 2023-02-18T05:10:00,
  breach_period_end: 2023-02-19T05:10:00,
  breach_period_max_break_in_seconds: 31380,
  sanction_code: NATINF 20525
}
# 10h de repos était nécessaire sur cette période de 24h 
# mais la plus longue pause a été de 8h 43m
```

#### maximumWorkDayTime

* `night_work` indique si le salarié est considéré comme travailleur de nuit dans le cadre du calcul du dépassement de seuil
* `max_work_range_in_hours` L'amplitude maximale du travail journalier en heures à laquelle est soumise le salarié. Cette valeur est différente pour un travailleur de nuit
* `work_range_in_seconds` La durée de l'amplitude du travail en secondes constatée qui a déclenché l'alerte. Cette durée est forcément supérieure à la durée maximale du travail journalier
* `work_range_start` et `work_range_end` Le début et la fin de la période sur laquelle le travail trop long a été constaté
* `sanction_code` le code NATINF de la sanction liée à ce dépassement

**Exemple**

```
{
  night_work: false, 
  max_work_range_in_hours: 12, 
  work_range_in_seconds: 46260, 
  work_range_start: 2022-12-12T06:59:00, 
  work_range_end: 2022-12-12T20:45:00, 
  sanction_code: NATINF 11292
}
# Amplitude maximale de 12h
# Amplitude constatée de 12h51m
```

#### minimumWorkDayBreak

* `work_range_start, work_range_end et` work\_range\_in\_seconds Début, fin et durée en secondes du temps de travail sur lequel le calcul se base. La durée du temps de travail influe sur le temps de pause nécessaire au salarié.
* `min_break_time_in_minutes` Temps de pause obligatoire en minutes auquel est soumis le salarié
* `total_break_time_in_seconds` Temps de pause constaté en secondes (ce temps est donc inférieur au temps de pause obligatoire)
* `sanction_code` la sanction liée à ce dépassement

**Exemple**

```
{
  total_break_time_in_seconds: 900.0,
  work_range_in_seconds: 30060,
  work_range_start: 2022-04-12T09:45:00,
  sanction_code: Sanction du Code du Travail,
  work_range_end: 2022-04-12T18:36:00,
  min_break_time_in_minutes: 30
}
# Pour une amplitude de 8h21m, 30 minutes de pause sont nécessaires
# Seulement 15 minutes de pause ont été constatées
```

#### maximumUninterruptedWorkTime

* `longest_uninterrupted_work_start` et `longest_uninterrupted_work_end` début et fin de la période de travail ininterrompu trop longue
* `longest_uninterrupted_work_in_seconds` durée en secondes du temps de travail ininterrompu trop long non conforme à la règlementation
* `max_uninterrupted_work_in_hours` durée en heures de la durée maximale de travail ininterrompu spécifiée par la règlementation
* `sanction_code` le code NATINF de la sanction liée à ce dépassement

**Exemple**

```
{
  max_uninterrupted_work_in_hours: 6,
  longest_uninterrupted_work_in_seconds: 22200.0,
  longest_uninterrupted_work_start: 2023-01-06T09:00:00,
  longest_uninterrupted_work_end: 2023-01-06T15:10:00,
  sanction_code: Sanction du Code du Travail
}
# Travail ininterrompu maximal: 6h
# 6h10m constaté
```

#### maximumWorkedDaysInWeek

* `max_nb_days_worked_by_week` nombre de jours travaillés par semaine maximum d'après la règlementation
* `min_weekly_break_in_hours` chaque semaine doit contenir au moins une pause consécutive d'une durée indiquée ici en heures
* `too_many_days` boolean indiquant si trop de jours travaillés ont été constatés dans la semaine
* `rest_duration_s` durée en secondes de la plus longue pause consécutive dans la semaine. Ce champ ne sera présent que si cette pause est insuffisante
* `sanction_code` le code NATINF de la sanction liée à ce dépassement

**Exemple**

```
{
  max_nb_days_worked_by_week: 6,
  min_weekly_break_in_hours: 34,
  too_many_days: false,
  rest_duration_s: 111240.0,
  sanction_code: NATINF 13152
}
# Plus longue pause de la semaine: 30h54m contre 34h règlementaires
```


# Certificat Mobilic

Il est possible, via un appel API, de savoir si une entreprise a obtenu le certificat Mobilic ([en savoir plus sur le certificat et sur les critères d'obtention](https://faq.mobilic.beta.gouv.fr/usages-et-fonctionnement-de-mobilic-gestionnaire/comment-obtenir-le-certificat-mobilic)).

Ce service est disponible pour les plateformes de mise en relation entre entreprises et particuliers, ou tout autre acteur regroupant les entreprises concernées par l'utilisation de Mobilic sur son site.

## Processus

Si vous souhaitez interroger notre API pour connaître l'état de certification d'une société dans Mobilic, contactez-nous pour obtenir une clé unique à l'adresse suivante : <interfacage@mobilic.beta.gouv.fr>.

Une fois que vous aurez récupéré la clé, vous pourrez interroger notre API, pour un SIREN donné, afin de savoir si une entreprise est certifiée ou non :&#x20;

### Exemple d'appel

```
HTTP POST : https://api.mobilic.beta.gouv.fr/companies/is_company_certified

Body : { "siren": "812773281"}

HEADER : X-MOBILIC-CERTIFICATION-KEY : "clé unique donnée par l'équipe Mobilic."
```

### Exemples de retour

Dans le cas où une entreprise a deux établissements certifiés dans Mobilic :

```json
[
    {
        "certification_attribution_date": "2023/01/01",
        "certification_expiration_date": "2023/06/30",
        "siren": "812773281",
        "siret": "00001"
    },
    {
        "certification_attribution_date": "2023/04/01",
        "certification_expiration_date": "2023/10/30",
        "siren": "812773281",
        "siret": "00002"
    }]

```

Dans le cas où une entreprise n'est pas certifiée dans Mobilic, n'est pas inscrite dans Mobilic ou a refusé de partager ses informations sur son certificat, l'API renvoie une liste vide :

```
[]
```

## Fréquence de mise à jour

Les certificats sont recalculés au début de chaque mois et sont valables pour un durée de 6 mois.

Il n'est donc pas nécessaire, ni recommandé, d'appeler notre API plusieurs fois par mois pour le même SIREN.


