Comment tout s'articule
- Créez des clés et ajoutez vos sites dans la console.
- Pour les épreuves d'entraînement, collez l'extrait dans votre page.
- Pour vos propres tests, votre serveur lance un passage et reçoit une adresse de lancement.
- Votre page l'ouvre, le candidat passe le test et le résultat vous parvient par webhook ou par l'API.
Clés
pk_test_pk_live_- Les clés publiables vont dans vos pages web. Elles n'ouvrent que des épreuves d'entraînement, sur les sites que vous avez indiqués.
sk_test_sk_live_- Les clés serveur agissent pour votre organisation. Gardez-les sur votre serveur et ne les envoyez jamais à un navigateur.
Les clés de test marchent tout de suite et ne sont pas décomptées de votre offre. Les clés live demandent que votre compte soit approuvé.
Épreuves d'entraînement
Ajoutez le script une fois, puis placez une épreuve où vous voulez. Le cadre s'ajuste tout seul à son contenu.
<div id="gb-test"></div>
<script src="https://www.supergb.com/cbt/js/embed/v1.js"></script>
<script>
GreenBridge.mount("#gb-test", { key: "pk_live_...", paper: "PAPER_ID" });
</script>
L'épreuve est l'identifiant affiché dans le générateur d'extrait de votre console. Ajoutez mode: "exam" pour des conditions d'examen chronométrées.
Vos propres tests
Rédigez vos tests dans la console, sous Tests, et ouvrez-les. Quand un candidat est prêt, votre serveur lance un passage :
curl -X POST https://www.supergb.com/cbt/partner-api/v1/sessions \
-H "Authorization: Bearer $GREEN_BRIDGE_KEY" \
-H "Content-Type: application/json" \
-d '{"test_id": "TEST_ID", "language": "fr", "candidate": {"id": "learner-42", "name": "Ada Obi", "email": "ada@example.com"}}'
candidate.id est votre propre identifiant pour la personne, 128 caractères au plus. Le nom et l'e-mail sont facultatifs ; nous ne gardons que ce que vous envoyez.
language est facultatif : l'un de de, en, es, fr, yo, ig, ha, nl, pt, sw. Les boutons, le minuteur et les messages du passage s'affichent dans cette langue ; vos questions restent telles que vous les avez écrites. Sans ce champ, le passage est en anglais.
La réponse contient une adresse de lancement utilisable une seule fois, dans les 10 minutes. Ouvrez-la dans votre page :
HTTP/1.1 201 Created
{
"attempt_id": "att_...",
"launch_token": "lt_...",
"launch_url": "https://www.supergb.com/cbt/fr/embed/v1/test?launch=lt_...",
"launch_expires_at": "2026-10-23T09:10:00Z",
"live": true,
"language": "fr"
}
<div id="gb-test"></div>
<script src="https://www.supergb.com/cbt/js/embed/v1.js"></script>
<script>
GreenBridge.mountTest("#gb-test", {
launchUrl: "LAUNCH_URL_FROM_YOUR_SERVER",
onEvent: function (event) {
if (event.type === "submitted") {
showThanks(event.detail.attempt_id);
}
}
});
</script>
Une fois ouvert, un passage dure jusqu'à 24 heures et une actualisation le reprend. Chaque candidat passe chaque test une fois.
Pour lister vos tests et leurs identifiants :
curl https://www.supergb.com/cbt/partner-api/v1/tests -H "Authorization: Bearer $GREEN_BRIDGE_KEY"
Messages du cadre
onEvent reçoit ces messages, et seulement depuis notre cadre :
| Événement | Signification |
|---|---|
ready | La page est chargée. |
resize | La hauteur du contenu a changé. Le cadre suit tout seul. |
completed | Une épreuve d'entraînement a été corrigée. detail contient score et max_score. |
submitted | Un test a été soumis. detail contient attempt_id. Récupérez le résultat depuis votre serveur, pas depuis le navigateur. |
Résultats
Passages soumis, du plus récent au plus ancien, 50 par page. Filtrez par test_id, candidate_id ou les deux.
curl "https://www.supergb.com/cbt/partner-api/v1/attempts?test_id=TEST_ID&page=0" -H "Authorization: Bearer $GREEN_BRIDGE_KEY"
curl https://www.supergb.com/cbt/partner-api/v1/attempts/ATTEMPT_ID -H "Authorization: Bearer $GREEN_BRIDGE_KEY"
Un passage ressemble à ceci. questions est inclus à partir de l'offre Growth.
{
"id": "att_...",
"test_id": "TEST_ID",
"candidate_id": "learner-42",
"live": true,
"language": "fr",
"started_at": "2026-10-23T09:02:11Z",
"submitted_at": "2026-10-23T09:41:57Z",
"integrity_events": 0,
"score": 34.0,
"max_score": 40.0,
"percent": 85.0,
"grading_status": "fully_graded",
"questions": [
{"question_id": "q1", "type": "multiple_choice_question", "score": 1.0, "max_score": 1.0}
]
}
grading_status vaut fully_graded quand plus rien n'est à corriger à la main, sinon pending_manual_review ou pending_transcription.
Webhooks
Ajoutez jusqu'à 5 adresses https dans votre console. Chaque événement est envoyé en POST signé et renvoyé pendant 3 jours jusqu'à ce que votre serveur réponde par un statut 2xx.
| Événement | Signification |
|---|---|
attempt.started | Le candidat a ouvert le passage. |
attempt.submitted | Le candidat a soumis. |
attempt.graded | Toutes les notes sont définitives. Renvoyé à chaque changement de note. |
attempt.integrity_flagged | Le candidat a quitté le test ou tenté de copier ou coller 3 fois. |
ping | Un événement de test envoyé depuis votre console. |
POST /hooks/green-bridge
Content-Type: application/json
Green-Bridge-Event: attempt.graded
Green-Bridge-Delivery: whd_...
Green-Bridge-Signature: t=1792834917,v1=5f0c...
{
"id": "evt_graded_att_..._1",
"type": "attempt.graded",
"created_at": "2026-10-23T10:21:57Z",
"data": { "id": "att_...", "candidate_id": "learner-42", "score": 34.0, "max_score": 40.0, "grading_status": "fully_graded" }
}
L'identifiant d'un événement ne change jamais : vous pouvez ignorer sans risque un événement déjà traité.
Vérifier la signature
Calculez le HMAC-SHA256 de t, d'un point et du corps brut avec votre secret de signature, puis comparez-le à v1. Refusez un horodatage de plus de cinq minutes.
Node.js
const crypto = require("crypto");
function isFromGreenBridge(header, rawBody, secret) {
const parts = Object.fromEntries(header.split(",").map(part => part.split("=")));
if (!parts.t || !parts.v1 || Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) {
return false;
}
const expected = crypto.createHmac("sha256", secret).update(parts.t + "." + rawBody).digest("hex");
return expected.length === parts.v1.length
&& crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
Python
import hashlib, hmac, time
def is_from_green_bridge(header, raw_body, secret):
parts = dict(part.split("=", 1) for part in header.split(","))
if "t" not in parts or abs(time.time() - int(parts["t"])) > 300:
return False
signed = parts["t"].encode() + b"." + raw_body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))
Erreurs
Les erreurs reviennent en JSON avec un code stable :
HTTP/1.1 404 Not Found
{"error": {"code": "test_not_found"}}
| Code | HTTP | Signification |
|---|---|---|
invalid_key |
401 | La clé est absente, inconnue ou révoquée. |
partner_suspended |
403 | Votre compte est suspendu. Contactez-nous. |
live_keys_need_approval |
403 | Les clés live fonctionnent une fois votre compte approuvé. |
not_on_plan |
403 | Votre offre ne comprend pas cette fonction. |
test_not_found |
404 | Aucun de vos tests ne porte cet identifiant. |
attempt_not_found |
404 | Aucun de vos passages ne porte cet identifiant. |
candidate_not_found |
404 | Vous n'avez aucun candidat avec cet identifiant. |
test_not_open |
409 | Le test n'est pas encore ouvert, ou il est fermé. |
already_submitted |
409 | Ce candidat a déjà soumis ce test. |
invalid_request |
400 | Un champ manque ou n'a pas la forme attendue. |
monthly_limit_reached |
429 | Le quota du mois est épuisé. Les clés de test fonctionnent toujours. |
internal_error |
500 | Un problème est survenu de notre côté. Réessayez. |
Limites et données
- Jusqu'à 300 requêtes par minute pour chaque clé serveur. Au-delà, la réponse est 429 sans contenu ; attendez une minute et réessayez.
- Les passages live et la correction par IA sont décomptés du quota mensuel de votre offre. Les passages lancés avec une clé de test ne sont pas comptés.
Vos données
Ce que nous conservons sur vos tests et vos candidats, pendant combien de temps, et comment le récupérer.
- Tests et vos questions
- Conservés jusqu'à ce que vous les supprimiez ou fermiez votre compte.
- Candidats
- L'identifiant que vous envoyez, ainsi qu'un nom et un e-mail seulement si vous les envoyez. Conservés un an après la dernière apparition du candidat.
- Passages et résultats
- Réponses, enregistrements, notes et événements d'intégrité. Conservés un an après le début du passage, puis effacés.
- Épreuves d'entraînement
- Conservées un an, uniquement pour compter votre consommation. Le score arrive dans votre page avec l'événement completed.
- Livraisons de webhooks
- Conservées 30 jours, dans le journal des livraisons de votre console.
- Consommation de l'API
- Décomptes quotidiens par clé, conservés 400 jours, sur l'écran Consommation de votre console.
Récupérez les résultats à tout moment avec GET /attempts. Avec les offres Growth et Institution, vous pouvez aussi télécharger les résultats de chaque test au format CSV depuis le menu du test dans votre console : une ligne par passage avec la note de chaque question, et la réponse du candidat aux questions que vous avez rédigées. Les questions de la banque Green Bridge n'affichent que leurs notes.
Pour effacer un candidat plus tôt :
curl -X POST https://www.supergb.com/cbt/partner-api/v1/candidates/erase \
-H "Authorization: Bearer $GREEN_BRIDGE_KEY" \
-H "Content-Type: application/json" \
-d '{"candidate_id": "learner-42"}'
Un résultat qu'un candidat enregistre dans son propre compte Green Bridge lui appartient dès lors. Effacer le candidat ou fermer votre compte ne le supprime pas.
Le propriétaire de votre compte peut le fermer dans Sites web et clés. Les clés et les webhooks s'arrêtent aussitôt et tout ce qui précède est effacé dans la journée, alors téléchargez d'abord ce dont vous avez besoin.
Besoin de quelque chose que les offres ne couvrent pas ? Utilisez Nous contacter sur l'écran Offre de votre console.