⚙️Interconnexion avec les logiciels existants

Schéma général d'interconnexion

Documentation technique de l'API

Authentification

Tous les agents peuvent utiliser l'API. Les requêtes faites sur l'API sont authentifiées grâce à des tokens d'accès associés à chaque agent. Chaque action faite via l'API est donc attribuable à un agent.

http --json POST 'https://www.rdv-solidarites.fr/api/v1/auth/sign_in' \
  email='martine@demo.rdv-solidarites.fr' password='123456'

En cas de succès d'authentification, la réponse à cette requête contiendra dans le corps le détail de l'agent, et dans les headers les token d'accès à l'API. Par exemple :

HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Download-Options: noopen
X-Permitted-Cross-Domain-Policies: none
Referrer-Policy: strict-origin-when-cross-origin
Content-Type: application/json; charset=utf-8
access-token: SFYBngO55ImjD1HOcv-ivQ< token-type: Bearer
client: Z6EihQAY9NWsZByfZ47i_Q< expiry: 1605600758
uid: martine@demo.rdv-solidarites.fr
ETag: W/"0fe52663d6745c922160384e13afe1e1"
Cache-Control: max-age=0, private, must-revalidate
X-Meta-Request-Version: 0.7.2
X-Request-Id: 291fab6a-043b-4b9c-b4b9-3c7fc9c9453a
X-Runtime: 0.194743< Transfer-Encoding: chunked
* Connection #0 to host rdv-solidarites.fr left intact
{
  "data": {
    "id":1,
    "deleted_at":null,
    "email":"martine@demo.rdv-solidarites.fr",
    "provider":"email",
    "service_id":1,
    "role":"admin",
    "last_name":"VALIDAY",
    "first_name":"Martine",
    "uid":"martine@demo.rdv-solidarites.fr",
    "email_original":null,
    "allow_password_change":false
  }
}
* Closing connection 0

Les 3 headers essentiels pour l'authentification sont les suivants :

access-token: SFYBngO55ImjD1HOcv-ivQ
client: Z6EihQAY9NWsZByfZ47i_Q
uid: martine@demo.rdv-solidarites.fr
  • access-token : c'est le jeton d'accès qui vous a été attribué. Il a une durée de vie de 24h, après ça il vous faudra reproduire cette procédure pour en récupérer un nouveau.

  • client : un identifiant unique associé à l'appareil depuis lequel vous avez effectué la requête

  • uid : l'identifiant de l'agent dans l'API, égal à l'email de l'agent.

Ces 3 headers doivent être transmis avec chacune de vos requêtes successives à l'API, peu importe la méthode HTTP.

L'API répondra avec un statut 401 si ces identifiants sont invalides.

Format

L'API supporte uniquement le format JSON. Toutes les réponses envoyées par l'API contiendront le header Content-Type: application/json et leur contenu est présent dans le body dans un format JSON à désérialiser

Création et invitations des bénéficiaires

Cet endpoint permet de créer des allocataires sur RDV-Insertion (ce qui crée automatiquement un utilisateur correspondant sur RDV-Solidarités) et de les inviter à prendre RDV par SMS, mail ou les 2 en fonction des attributs envoyés dans la requête.

La création et l'invitation des bénéficiaires se fera de manière asynchrone.

Route

POST https://www.rdv-insertion.fr/api/v1/organisations/:rdv_solidarites_organisation_id/users/create_and_invite_many

⚠ Attention: Le nom de domaine pour la création/invitation des bénéficiaires est rdv-insertion.fr et non rdv-solidarites.fr comme pour l'authentification.

Paramètres de l'URL

  • rdv_solidarites_organisation_id: L'ID de l'organisation sur RDV-Solidarités pour laquelle on veut créer les bénéficiaires et les invitations. Cet ID apparaît dans l'URL de la page index de l'organisation sur RDV-Solidarités:

Dans cet exemple l'ID de l'organsation est le 294.

Paramètres dans le body de la requête

Le body de la requête en JSON contiendra les attributs suivants.

  • users: ARRAY[USER_ATTRIBUTES] : Tableau d'objets comprenant les attributs ci-dessous. La taille maximum de ce tableau sera de 25.

    • first_name: STRING (requis): Prénom du bénéficiaire

    • last_name: STRING (requis): Nom du bénéficiaire

    • title: STRING (requis): Civilité du bénéficaire. Valeurs possibles: monsieur, madame.

    • affiliation_number: STRING (requis) : Numéro d'allocataire du bénéficaire.

    • role: STRING (requis) : Le rôle de la personne au sein du dossier de demande RSA. Valeurs possibles: demandeur, conjoint.

    • email: STRING (optionnel) : L'email du bénéficiaire. S'il n'est pas présent l'invitation par email ne sera pas envoyée.

    • phone_number: STRING (optionnel) : Le numéro de téléphone du bénéficiaire. S'il n'est pas présent l'invitation par SMS ne sera pas envoyée.

    • birth_date: STRING (optionnel) : Date de naissance du bénéficiaire au format DD/MM/YYYY

    • nir (optionnel) : NIR

    • pole_emploi_id (optionnel) : numéro d'identification Pole emploi

    • rights_opening_date: STRING (optionnel): Date de notification que l'allocataire est bénéficiaire du RSA (= date de réception du 1er flux bénéficiaire quotidien qui montre que l'allocataire est un nouvel entrant). Au format DD/MM/YYYY.

    • address: STRING (optionnel) : L'addresse de l'utilisateur. Cette addresse comprend le code postal et la ville.

    • birth_name : STRING (optionnel) : Le nom de naissance du bénéficiaire

    • department_internal_id: STRING (optionnel) : ID interne de la personne au sein du système d'information du département (cela peut être l'ID lié à l'éditeur comme l'ID de IODAS par exemple). Cet ID est nécessaire si l'on veut que RDV-Insertion notifie de la prise/annulation de RDV sur une API côté département ou éditeur.

    • invitation: OBJECT (optionnel): Contient les informations ci-dessous liés à l'invitation à prendre rdv:

      (Dans cet exemple le rdv_solidarites_lieu_id est 1263)

      • motif_category_name: STRING: Le nom de la catégorie de motif pour laquelle on veut inviter l'allocataire. Il peut ne pas être précisé si l'organisation ne peut inviter que sur une seule catégorie. Ces valeurs sont visibles sur la page de votre organisation RDV-Insertion sur RDV-Insertion:

Exemple de body

{
    "users": [
        {
            "first_name": "Didier",
            "last_name": "Drogba",
            "title": "monsieur",
            "affiliation_number": "10492394",
            "role": "demandeur",
            "email": "didier@drogba.com",
            "phone_number": "0777889911",
            "birth_date": "11/03/1978",
            "rights_opening_date": "11/11/2021",
            "address": "13 rue de la République 13001 MARSEILLE",
            "department_internal_id": "11111444",
            "invitation" : {
                "rdv_solidarites_lieu_id": 3330,
                "motif_category_name": "RSA orientation"
            }
        },
        {
            "first_name": "Dimitri",
            "last_name": "Payet",
            "title": "monsieur",
            "affiliation_number": "12322131",
            "role": "conjoint",
            "email": "dimitri@payet.com",
            "phone_number": "0655443322",
            "birth_date": "29/03/1987",
            "rights_opening_date": "15/11/2021",
            "address": "5 Avenue du Moulin des Baux, 13260 Cassis",
            "department_internal_id": "22221111",
            "invitation": {
                "rdv_solidarites_lieu_id": 3339,
                "motif_category_name": "RSA orientation"
            }
        }
    ]
}

Réponse

Lors de l'envoi, nous allons vérifier que pour chaque bénéficiaire les attributs requis sont présents et que tous les attributs passés sont au bon format (email, téléphone etc). Si c'est le cas la requête sera un succès. Cela ne veut pas dire que la création et l'invitation des allocataires et l'invitation ont été un succès car ces actions se feront de manière asynchrone.

En cas de succès

Si la requête est un succès (voir conditions plus haut), nous répondrons avec un statut 200 et un body en JSON notifiant le succès de la requête:

{ 
    "success": true
}

En cas d'échec

Si la requête est un échec (voir conditions plus haut), nous répondrons avec un statut 422 et un body en JSON contenant les erreurs de la requête, avec pour chaque entrée les erreurs correspondantes:

{
    "success": false,
    "errors": [
        { 
           "Entrée 7 - valeur_du_department_internal_id_si_présent": {
               "title": ["Civilité doit être rempli(e)"],
               "email": ["Email n'est pas valide"] 
            },
        },
        {
            "Entrée 12 - valeur_du_department_internal_id_si_présent": {
                "last_name": ["Nom doit être rempli(e)"],
                "phone_number": ["Numéro de téléphone n'est pas valide"]
            }
        }
    ]
}

À noter que si l'ID de l'organisation passé dans l'URL ne correspond pas à l'ID d'une organisation en base, l'API répond avec le statut 404.

Notifications asynchrones

Lors du processus asynchrone de création et des invitations des allocataires des erreurs peuvent avoir lieu, bien que la réponse à la requête ait été un succès. Il faut alors notifier l'organisation de ces échecs.

En cas de problèmes à la création de l'allocataire

En cas d'échec de la création de l'utilisateur, un mail sera envoyé à la personne ayant fait la requête avec l'identité de l'utilisateur en question et les erreurs associées à sa création.

En cas de problèmes à l'invitation de l'allocataire

S'il y a un problème lors de l'invitation d'un allocataire, l'organisation ne sera pas notifiée directement. Par contre elle pourra voir facilement les personnes qui n'ont pas été invitées sur la page de l'organisation dans RDV-Insertion et tous les récupérer en filtrant sur le statut "Non invité":

Elle pourra alors les inviter en cliquant sur les coches sur chaque format d'invitation:

Diagramme de séquence

Documentation technique des webhooks

Contexte

Lorsqu'un rdv est créé, modifié ou supprimé sur RDV-Solidarités, RDV-Insertion reçoit un webhook avec les données liées au rdv. RDV-Insertion va alors formatter ces données pour y ajouter quelques éléments avant de les envoyer vers l'endpoint dédié du département.

Payload de la requête

La requête aura toujours la même forme quelque soit l'évènement lié à son envoi, seul les valeurs des champs changent. Le payload aura alors avoir la forme suivante:

{
  "data": {
    "id": 313,
    "address": "Route de Brest, Quimper, 29000",
    "agents": [
      {
        "id": 7,
        "email": "amine.dhobb@beta.gouv.fr",
        "first_name": "Amine",
        "last_name": "DHOBB"
      }
    ],
    "cancelled_at": null,
    "collectif": false,
    "context": null,
    "created_by": "user",
    "deleted_at": null,
    "duration_in_min": 30,
    "ends_at": "2023-03-03 09:30:00 +0100",
    "lieu": {
      "id": 10,
      "address": "Route de Brest, Quimper, 29000",
      "name": "Quimper centre",
      "organisation_id": 30,
      "phone_number": "0193939393",
      "single_use": false
    },
    "max_participants_count": null,
    "motif": {
      "id": 35,
      "bookable_publicly": true,
      "category": "rsa_orientation",
      "collectif": false,
      "deleted_at": null,
      "follow_up": false,
      "location_type": "public_office",
      "motif_category": {
        "id": 1,
        "name": "RSA orientation",
        "short_name": "rsa_orientation"
      },
      "name": "RDV Orientation RSA",
      "organisation_id": 30,
      "service_id": 4
    },
    "name": null,
    "organisation": {
      "id": 30,
      "email": null,
      "name": "Conseil départemental du Finistère",
      "phone_number": null
    },
    "starts_at": "2023-03-03 09:00:00 +0100",
    "status": "unknown",
    "users": [
      {
        "id": 420,
        "address": "20 avenue de Ségur 75007 Paris",
        "address_details": null,
        "affiliation_number": "OJSQOJCQS",
        "birth_date": null,
        "birth_name": null,
        "caisse_affiliation": null,
        "case_number": null,
        "created_at": "2023-03-01 15:01:56 +0100",
        "email": "didierdrogba@gmail.com",
        "family_situation": null,
        "first_name": "Didier",
        "invitation_accepted_at": null,
        "invitation_created_at": "2023-03-01 15:02:05 +0100",
        "last_name": "Drogba",
        "logement": null,
        "notes": null,
        "notify_by_email": true,
        "notify_by_sms": true,
        "number_of_children": null,
        "phone_number": "0606070708",
        "phone_number_formatted": "+33606070708",
        "responsible": null,
        "responsible_id": null,
        "user_profiles": null,
        "department_internal_id": "NCQSNCJQSN",
        "title": "monsieur"
      }
    ],
    "users_count": 1,
    "uuid": "a76b5eb0-a057-4a1f-99b1-f1fb8bd84f01"
  },
  "meta": {
    "model": "Rdv",
    "event": "created",
    "timestamp": "2023-03-01 15:03:04 +0100"
  }
}

Les attributs notables sont les suivants:

  • event : STRING : évenement ayant déclenché l'envoi de la requête. Valeurs possibles: created, updated ou destroyed.

  • duration_in_min: INTEGER : Durée du rendez-vous en minutes

  • cancelled_at: STRING : Au format AAAA-MM-JJ HH:MM:SS UTCOFFSET. Moment où le rdv a été annulé. Il est nul si le rdv n'a pas été annulé.

  • created_by: STRING : indique qui de l'usager ou de l'agent a créé le rdv. Valeurs possbiles: user ou agent.

  • starts_at : STRING : Au format AAAA-MM-JJ HH:MM:SS UTCOFFSET . Moment où le rdv est fixé.

  • collectif: BOOLEAN : indique s'il s'agit d'un rdv collectif ou non

  • status : STRING : Le statut du rdv. Valeurs possibles:

    1. unknown: état lors de la création de rdv. Il reste dans cet état tant que le statut du rdv n'a pas été renseigné par l'agent.

    2. seen: Lorsque l'agent marque le rdv comme ayant été "honoré".

    3. excused: Lorsque l'agent clique sur "Annulé à l'initiative de l'usager" ou lorsque l'usager annule son rdv depuis son espace RDV-Solidarités. Ça signifie que l'usager a notifié son absence au préalable.

    4. revoked: Lorsque l'agent clique sur "Annulé à l'initiative du service.

    5. noshow: Lorsque l'agent clique sur "Absence non excusée" pour signifier une absence de l'allocataire.

  • users: ARRAY[USER_ATTRIBUTES] : Tableau des bénéficiaires pour qui le rdv a été pris. Les attributs envoyés sont id (ID de l'allocataire sur RDV-Insertion) first_name, last_name, title, affiliation_number, role, email, phone_number, birth_date, department_internal_id (voir leurs définitions au dessus)

  • agents: ARRAY[AGENT_ATTRIBUTES] : Tableau des bénéficiaires avec qui le rdv a été pris. En général ce tableau ne comprend qu'un seul bénéficiaire. Les attributs envoyés sont l'email, first_name et last_name.

  • organisation: OBJET[ORGANISATION_ATTRIBUTES] : les attributs de l'organisation dans laquelle a lieu le rdv. Ces attributs sont l'id, l'email, le name et le phone_number.

  • lieu: OBJET[LIEU_ATTRIBUTES] : les attributs du lieu dans lequel se fait le rdv. Si le rdv est téléphonique il n'y a pas de lieu associé. On envoie notamment son id, son address, son phone_number et son name.

  • motif: OBJET[MOTIF_ATTRIBUTES] : les attributs du motifs du rdv. On y retrouve notamment:

    • name : STRING : nom du motif

    • location_type : STRING : indique si le motif est sur place, par téléphone ou à domicile. Valeurs possibles: public_office, phone, home

    • motif_category: OBJET[MOTIF_CATEGORY_ATTRIBUTES] : La catégorie du motif en question. On y retrouve son name et son short_name

  • participations: ARRAY[PARTICIPATION_ATTRIBUTES] : renvoie les participations au rdv. C'est particulièrement utile pour les rdvs collectif, où chaque user a son propre status de participation au rdv.

Headers

Principe

Un header de signature sera inclus dans la requête qui permettra de vérifier que la requête vient bien de RDV-Insertion. Il comprendra un JWT dont la signature sera créée à l'aide d'une clé secrète partagée entre nos applications. La fonction de hachage utilisée est SHA-256. Le payload de ce JWT comprendra l'id (id), l'adresse (address) et la date de début du rdv (starts_at). Le token aura un temps d'expiration de 10 minutes après sa création.

JWT Header

L'entête du token définit l'algorithme de hashage (HS256) et le type de jeton (JWT). On y précisera le timestamp d'expiration du token (now + 10 * 60).

    {
        "alg": "HS256",
        "typ": "JWT",
        "exp": 1651068687
    }

JWT Payload

Voici donc le payload pris en compte dans notre JWT (par rapport à l'exemple précédent):

    {
        "id": 313,
        "address":"Route de Brest, Quimper, 29000",
        "starts_at": "2023-03-03 09:00:00 +0100"
    }

Envoi

Il sera envoyé dans un header Authorization sous la forme Bearer mon-jwt.

Si on schématise on aura donc dans notre header Authorization en reprenant l'exemple de webhook précédent:

Bearer base64UrlEncode({ "alg": "HS256", "typ": "JWT", "exp": now + 10 * 60 }) + "." + base64UrlEncode({"id": 2989, "address": "Avenue de Ségur, Paris, 75015", "starts_at": "2022-04-21 10:30:00 +0200"}) + "." + base64UrlEncode(HMAC256(base64UrlEncode({ "alg": "HS256", "typ": "JWT", exp: now + 10 * 60 }) + "." + base64UrlEncode({"id": 2989, "address": "Avenue de Ségur, Paris, 75015", "starts_at": "2022-04-21 10:30:00 +0200"})))

.

Last updated