Signature des requêtes
Chaque requête de la porte Brave est authentifiée par trois en-têtes. Le secret ne transite jamais sur le réseau : seule une empreinte HMAC est envoyée.
Schéma v2 (relecture sécurité n°2, 13/11/2026) : la clé de signature se dérive du secret en clair (
sha256("sig-v2|" + secret)) — l'empreinte du secret en base ne suffit plus à signer. La signature couvre la méthode, le chemin, l'horodatage et le corps. Le schéma v1 (empreinte « à plat » de la clé + hash du secret + horodatage) est rejeté (401), ainsi que l'ancienne dérivation d'empreinte pour les clés créées depuis la relecture n°2.Les trois en-têtes
- Name
X-Api-Key- Type
- string
- Description
Votre clé publique (ex.
VOTRE_CLE_API).
- Name
X-Timestamp- Type
- integer
- Description
Horodatage Unix de la requête, en secondes. Tolérance de ± 5 minutes.
- Name
X-Signature- Type
- string
- Description
HMAC-SHA256 hexadécimal (minuscules) du payload
MÉTHODE \n CHEMIN \n TIMESTAMP \n SHA256(CORPS).
Calcul de la signature
signingKey = sha256("sig-v2|" + secret) # le secret EN CLAIR, jamais envoyé
payload = MÉTHODE-en-majuscules + "\n"
+ chemin + "\n" # tel que reçu, query incluse
+ timestamp + "\n"
+ sha256(corps brut) # vide = chaîne vide
signature = HMAC-SHA256(payload, signingKey)
signingKeyse dérive de votre secret en clair (relecture sécurité n°2) : l'empreintesha256(secret)stockée en base ne permet PAS de recalculer la signature. Gardez le secret confidentiel.chemin: le chemin tel que la requête est envoyée, query string incluse si présente. Un paramètre de query ajouté, retiré ou modifié après signature invalide la requête.corps brut: l'empreinte porte sur le corps exactement tel qu'il part sur le réseau. Pour unGETsans corps, hashez la chaîne vide. Si vous modifiez le JSON après signature (même un espace), la signature ne vaut plus.- Le timestamp est en secondes (pas en millisecondes), base 10, sans padding.
- La signature est en hexadécimal minuscules (la casse de l'en-tête n'a pas d'importance côté vérification, mais une signature déjà utilisée est refusée : anti-rejeu).
- Une même signature ne peut pas être rejouée (anti-rejeu) : chaque requête doit porter un horodatage différent ou un corps différent.
Exemples de calcul
API_KEY="VOTRE_CLE_API" # votre clé publique
SECRET="VOTRE_SECRET" # votre secret — jamais envoyé sur le réseau
METHOD="GET"
PATH_="/v1/1000/ping" # chemin tel qu'envoyé, query incluse
BODY="" # corps brut exact (vide pour un GET sans corps)
SIGNING_KEY=$(printf '%s' "sig-v2|${SECRET}" | shasum -a 256 | cut -d' ' -f1)
BODY_HASH=$(printf '%s' "$BODY" | shasum -a 256 | cut -d' ' -f1)
TIMESTAMP=$(date +%s)
PAYLOAD=$(printf '%s\n%s\n%s\n%s' \
"$(printf '%s' "$METHOD" | tr '[:lower:]' '[:upper:]')" \
"$PATH_" "$TIMESTAMP" "$BODY_HASH")
SIGNATURE=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$SIGNING_KEY" | sed 's/^.*= //')
curl -s "https://partners.bravebooking.net${PATH_}" \
-H "X-Api-Key: $API_KEY" \
-H "X-Timestamp: $TIMESTAMP" \
-H "X-Signature: $SIGNATURE" \
-H "Accept: application/json"
Pièges fréquents
- Corps modifié après signature — tout changement du JSON (même un espace) change
sha256(corps)→ 401. Signez le corps exactement tel qu'il sera envoyé. - Query string oubliée —
pathinclut la query telle que partie : signez/v1/1000/bookings?from=…&to=…, pas seulement/v1/1000/bookings. - Méthode en minuscules — la méthode est normalisée en majuscules dans le payload (
getetGETdonnent la même signature). - Millisecondes au lieu de secondes — le timestamp est rejeté comme « trop ancien » (
401). - Horloge désynchronisée — synchronisez votre serveur (NTP) : la tolérance est de 5 minutes.
- Rejeu d'une requête — chaque signature n'est acceptée qu'une fois : dans un script, espacez les appels d'1 s (
sleep 1) ou faites varier le corps. - Ancien schéma v1 —
sha256(apiKey + secretHash + timestamp)est définitivement rejeté (401). - Ancienne dérivation d'empreinte —
sha256(sha256(secret) + "|brave-gateway-signing-v1")n'est plus acceptée pour les clés créées depuis la relecture n°2 : dérivez la clé desha256("sig-v2|" + secret).
Erreurs d'authentification
| Code | Signification |
|---|---|
401 missing_credentials | En-tête X-Api-Key, X-Timestamp ou X-Signature absent |
401 invalid_signature | Signature ne correspondant pas à la clé, au chemin, à la méthode ou au corps |
401 stale_timestamp | Horodatage hors de la fenêtre de 5 minutes |
429 | Trop d'échecs d'authentification depuis cette IP — réessayez après Retry-After secondes |
403 ip_not_allowed | IP source non présente dans la liste autorisée |
403 key_revoked | Clé révoquée, ou porte/format non activé pour cette clé |
Le détail des erreurs est sur la page Erreurs.