API REST
API DoctAuth
L'API indique si une adresse email a été certifiée par un professionnel de santé authentifié avec sa carte CPS ou son e-CPS, et renvoie son identité professionnelle. Elle permet aussi d'inviter un praticien à certifier son adresse, de veiller des adresses, de télécharger le filtre des adresses certifiées, d'obtenir une signature électronique au nom d'un praticien authentifié (et de la vérifier), et, pour les éditeurs qui en ont l'accès, de lire son coffre de chiffrement ou de demander à un correspondant d'activer le chiffrement.
Chaque requête porte trois en-têtes :
X-DoctAuth-Key: l'identifiant public de votre clé.X-DoctAuth-Timestamp: l'heure en secondes Unix. Un écart de plus de 5 minutes est refusé.X-DoctAuth-Signature:v1=suivi du HMAC-SHA256 en hexadécimal, calculé avec votre secret.
La chaîne signée assemble ces quatre éléments, séparés par un retour à la ligne :
timestamp
POST (ou GET, en majuscules)
/api/v1/lookup (chemin complet, sans le domaine)
sha256 hexadécimal du corps exact envoyé ("" pour un GET)Fonction d'appel signé
Les exemples des autres onglets utilisent cette fonction.
import { createHash, createHmac } from "node:crypto";
const KEY_ID = "dak_..."; // identifiant de la clé
const SECRET = "das_..."; // secret, à garder côté serveur
/** Appel signé à l'API DoctAuth. body = chaîne exacte envoyée ("" pour un GET). */
export async function doctauth(method, path, body = "") {
const timestamp = Math.floor(Date.now() / 1000).toString();
const bodyHash = createHash("sha256").update(body).digest("hex");
const signed = [timestamp, method, path, bodyHash].join("\n");
const signature = "v1=" + createHmac("sha256", SECRET).update(signed).digest("hex");
const res = await fetch("https://doctauth.fr" + path, {
method,
headers: {
"Content-Type": "application/json",
"X-DoctAuth-Key": KEY_ID,
"X-DoctAuth-Timestamp": timestamp,
"X-DoctAuth-Signature": signature,
},
body: method === "GET" ? undefined : body,
});
return res.json();
}Erreurs communes
401: en-têtes manquants, clé inconnue ou révoquée, signature invalide, horodatage trop ancien, ou requête rejouée (replayed_request: la signature de tout appel autre queGET, doncPOSTcommeDELETE /watch, ne sert qu'une fois pendant dix minutes).403: compte éditeur suspendu ou non validé.400: corps JSON invalide.429:rate_limited, limite de débit atteinte. La réponse porte l'en-têteRetry-After(secondes) et le même délai dansretryAfterSeconds. Voir l'onglet Clés de test et limites.