GoodDoctor

API GoodDoctor

Une API REST claire pour gérer les médecins.

GoodDoctor est une API de style Stripe pour l'ERP hospitalier. Écritures idempotentes, pagination par curseur, journal d'événements et webhooks signés, avec la même forme de ressource prévisible sur chaque endpoint.

Construite sur quelques idées simples

Apprenez ces six concepts une fois et chaque endpoint se comporte comme vous l'attendez.

Authentification par jeton

Échangez un email et un mot de passe sur /v1/auth/login contre un JWT à courte durée de vie, puis envoyez-le comme jeton Bearer à chaque requête.

Écritures idempotentes

Passez une Idempotency-Key sur les requêtes de création. Une nouvelle tentative avec la même clé renvoie le résultat d'origine au lieu de le dupliquer.

Pagination par curseur

Les endpoints de liste renvoient les pages les plus récentes d'abord. Parcourez-les avec limit et starting_after, has_more vous dit quand vous arrêter.

Événements

Chaque changement d'état est enregistré comme un événement que vous pouvez lister et rejouer via /v1/events, pour une piste d'audit complète.

Webhooks signés

Enregistrez des endpoints pour recevoir les événements en temps réel. Les livraisons sont signées et réessayées avec un délai progressif jusqu'à acquittement.

Ressources prévisibles

Des formes de ressources de style Stripe : identifiants stables, champ object et horodatages Unix. Snake_case en entrée, snake_case en sortie.

Démarrage

Trois étapes, de vos identifiants à votre premier médecin créé.

  1. 01

    Obtenir un jeton

    Envoyez vos identifiants en POST sur /v1/auth/login et lisez access_token dans la réponse.

  2. 02

    Appeler l'API

    Joignez le jeton dans l'en-tête Authorization: Bearer à chaque requête vers /v1/doctors et les autres ressources.

  3. 03

    Écouter les événements

    Enregistrez un endpoint de webhook, ou interrogez /v1/events, pour réagir aux changements en temps réel.

Exemples par endpoint

Chaque endpoint, avec un exemple prêt à copier en TypeScript, Java (Spring Boot) et Python.

POST/v1/auth/login

S'authentifier

Échangez vos identifiants contre un jeton Bearer à courte durée de vie.

const res = await fetch("http://localhost:8080/v1/auth/login", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    email: "admin@hospital.cm",
    password: "changeme123",
  }),
});

const { access_token } = await res.json();
POST/v1/doctors

Créer un médecin

Création idempotente : réessayez avec la même Idempotency-Key sans créer de doublon.

const res = await fetch("http://localhost:8080/v1/doctors", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${token}`,
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: JSON.stringify({
    first_name: "Amina",
    last_name: "Okafor",
    gender: "FEMALE",
    type: "SPECIALISTE",
    specialisations: ["CARDIOLOGY"],
    email: "amina@hospital.cm",
  }),
});

const doctor = await res.json();
GET/v1/doctors

Lister les médecins

Pagination par curseur : utilisez limit et starting_after, has_more indique s'il reste des pages.

const res = await fetch(
  "http://localhost:8080/v1/doctors?limit=10",
  { headers: { Authorization: `Bearer ${token}` } },
);

const { data, has_more } = await res.json();
GET/v1/doctors/{id}

Récupérer un médecin

Lit une seule ressource médecin par son identifiant.

const id = "doc_123";

const res = await fetch(
  `http://localhost:8080/v1/doctors/${id}`,
  { headers: { Authorization: `Bearer ${token}` } },
);

const doctor = await res.json();
PATCH/v1/doctors/{id}

Mettre à jour un médecin

Mise à jour partielle : envoyez uniquement les champs à modifier.

const id = "doc_123";

const res = await fetch(
  `http://localhost:8080/v1/doctors/${id}`,
  {
    method: "PATCH",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({ phone: "+237 690 00 00 00" }),
  },
);

const doctor = await res.json();
DELETE/v1/doctors/{id}

Supprimer un médecin

Renvoie un accusé de suppression { id, object, deleted }.

const id = "doc_123";

const res = await fetch(
  `http://localhost:8080/v1/doctors/${id}`,
  {
    method: "DELETE",
    headers: { Authorization: `Bearer ${token}` },
  },
);

const { deleted } = await res.json();
GET/v1/events

Lister les événements

Parcourez le journal d'audit de tous les changements d'état.

const res = await fetch(
  "http://localhost:8080/v1/events?limit=20",
  { headers: { Authorization: `Bearer ${token}` } },
);

const { data } = await res.json();
POST/v1/webhook_endpoints

Enregistrer un webhook

Le secret de signature n'est renvoyé qu'une seule fois, à la création.

const res = await fetch(
  "http://localhost:8080/v1/webhook_endpoints",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({
      url: "https://example.com/webhooks",
      enabled_events: "*",
    }),
  },
);

const { signing_secret } = await res.json();

Référence des endpoints

Le cœur de l'API. Tous les chemins sont relatifs à votre URL de base.

POST/v1/auth/login
POST/v1/doctors
GET/v1/doctors
GET/v1/doctors/{id}
PATCH/v1/doctors/{id}
DELETE/v1/doctors/{id}
GET/v1/events
POST/v1/webhook_endpoints

Prêt à intégrer ?

Obtenez un jeton, envoyez votre première requête et configurez un webhook. Une question ou un besoin d'accès ? Écrivez-nous.