Partner-API, versie 1

Toetsen op uw eigen website

Toon onze oefentoetsen op uw pagina's of gebruik eigen toetsen: uw server start een afname, de kandidaat maakt die op uw pagina en het resultaat komt bij u terug.

API-adres
https://www.supergb.com/cbt/partner-api/v1

Hoe het samenhangt

  1. Maak sleutels aan en voeg uw websites toe in de console.
  2. Plak voor oefentoetsen het fragment in uw pagina.
  3. Voor eigen toetsen start uw server een afname en krijgt een startadres.
  4. Uw pagina opent dat, de kandidaat maakt de toets en het resultaat bereikt u via een webhook of de API.

Sleutels

pk_test_ pk_live_
Publiceerbare sleutels horen in uw webpagina's. Ze openen alleen oefentoetsen op de websites die u hebt opgegeven.
sk_test_ sk_live_
Serversleutels handelen namens uw organisatie. Bewaar ze op uw server en stuur ze nooit naar een browser.

Testsleutels werken meteen en tellen niet mee voor uw abonnement. Live-sleutels vragen een goedgekeurd account.

Oefentoetsen

Voeg het script één keer toe en plaats een toets waar u wilt. Het kader past zich zelf aan de inhoud aan.

<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>

De toets is de id uit de fragmentbouwer in uw console. Voeg mode: "exam" toe voor examenomstandigheden met tijdslimiet.

Uw eigen toetsen

Maak toetsen in de console onder Toetsen en zet ze open. Zodra een kandidaat klaar is, start uw server een afname:

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 is uw eigen id voor de persoon, maximaal 128 tekens. Naam en e-mail zijn optioneel; we bewaren alleen wat u stuurt.

language is optioneel: een van de, en, es, fr, yo, ig, ha, nl, pt, sw. Knoppen, timer en meldingen van de afname verschijnen in die taal; uw vragen blijven zoals u ze schreef. Zonder dit veld is de afname in het Engels.

Het antwoord bevat een startadres dat één keer werkt, binnen 10 minuten. Open het op uw pagina:

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>

Eenmaal geopend duurt een afname tot 24 uur en vernieuwen hervat hem. Elke kandidaat maakt elke toets één keer.

Zo vraagt u uw toetsen en hun id's op:

curl https://www.supergb.com/cbt/partner-api/v1/tests -H "Authorization: Bearer $GREEN_BRIDGE_KEY"

Berichten uit het kader

onEvent ontvangt deze berichten, en alleen uit ons kader:

GebeurtenisBetekenis
readyDe pagina is geladen.
resizeDe hoogte van de inhoud is veranderd. Het kader volgt vanzelf.
completedEen oefentoets is nagekeken. detail bevat score en max_score.
submittedEen toets is ingeleverd. detail bevat attempt_id. Haal het resultaat op via uw server, niet in de browser.

Resultaten

Ingeleverde afnames, nieuwste eerst, 50 per pagina. Filter op test_id, candidate_id of beide.

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"

Een afname ziet er zo uit. questions zit erbij vanaf het Growth-abonnement.

{
  "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 is fully_graded zodra er niets meer met de hand na te kijken is, anders pending_manual_review of pending_transcription.

Webhooks

Voeg tot 5 https-adressen toe in uw console. Elke gebeurtenis gaat als ondertekende POST en wordt 3 dagen opnieuw verstuurd tot uw server antwoordt met een 2xx-status.

GebeurtenisBetekenis
attempt.startedDe kandidaat heeft de afname geopend.
attempt.submittedDe kandidaat heeft ingeleverd.
attempt.gradedAlle cijfers staan vast. Opnieuw verstuurd telkens als een cijfer verandert.
attempt.integrity_flaggedDe kandidaat heeft de toets verlaten of 3 keer geprobeerd te kopiëren of te plakken.
pingEen testgebeurtenis vanuit uw 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" }
}

De id van een gebeurtenis verandert nooit, dus een gebeurtenis die u al hebt verwerkt kunt u gerust negeren.

De handtekening controleren

Bereken HMAC-SHA256 van t, een punt en de onbewerkte inhoud met uw ondertekeningsgeheim en vergelijk dat met v1. Weiger een tijdstempel ouder dan vijf minuten.

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", ""))

Fouten

Fouten komen terug als JSON met een vaste code:

HTTP/1.1 404 Not Found

{"error": {"code": "test_not_found"}}
Code HTTP Betekenis
invalid_key 401 De sleutel ontbreekt, is onbekend of ingetrokken.
partner_suspended 403 Uw account is geschorst. Neem contact met ons op.
live_keys_need_approval 403 Live-sleutels werken zodra uw account is goedgekeurd.
not_on_plan 403 Uw abonnement bevat dit niet.
test_not_found 404 Geen van uw toetsen heeft die id.
attempt_not_found 404 Geen van uw afnames heeft die id.
candidate_not_found 404 U hebt geen kandidaat met die id.
test_not_open 409 De toets is nog niet open of al gesloten.
already_submitted 409 Deze kandidaat heeft deze toets al ingeleverd.
invalid_request 400 Er ontbreekt een veld of het heeft niet de verwachte vorm.
monthly_limit_reached 429 Het tegoed van deze maand is op. Testsleutels werken nog.
internal_error 500 Er ging bij ons iets mis. Probeer het opnieuw.

Limieten en gegevens

  • Tot 300 verzoeken per minuut per serversleutel. Daarboven is het antwoord 429 zonder inhoud; wacht een minuut en probeer het opnieuw.
  • Live-afnames en AI-beoordeling tellen mee voor het maandtegoed van uw abonnement. Afnames gestart met een testsleutel tellen niet.

Uw gegevens

Wat we bewaren over uw toetsen en kandidaten, hoe lang, en hoe u het terugkrijgt.

Toetsen en uw vragen
Bewaard totdat u ze verwijdert of uw account opheft.
Kandidaten
De id die u stuurt, en een naam en e-mail alleen als u die stuurt. Bewaard tot een jaar nadat de kandidaat voor het laatst is gezien.
Afnames en resultaten
Antwoorden, opnames, punten en integriteitsgebeurtenissen. Bewaard tot een jaar na de start van de afname, daarna gewist.
Oefentoetsen
Een jaar bewaard, alleen om uw gebruik te tellen. De score bereikt uw pagina in de gebeurtenis completed.
Webhook-leveringen
30 dagen bewaard, in het leveringslogboek van uw console.
API-gebruik
Dagelijkse aantallen per sleutel, 400 dagen bewaard, op het scherm Gebruik van uw console.

Haal resultaten op elk moment op met GET /attempts. Met de abonnementen Growth en Institution kunt u de resultaten van elke toets ook als CSV downloaden via het menu van de toets in uw console: één regel per afname met de punten voor elke vraag, en het antwoord van de kandidaat op de vragen die u zelf hebt geschreven. Vragen uit de Green Bridge-vragenbank tonen alleen hun punten.

Zo wist u een kandidaat eerder:

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"}'

Een resultaat dat een kandidaat in zijn eigen Green Bridge-account opslaat, is vanaf dat moment van hem. Het wissen van de kandidaat of het opheffen van uw account verwijdert het niet.

De eigenaar van uw account kan het opheffen onder Websites en sleutels. Sleutels en webhooks stoppen meteen en alles hierboven wordt binnen een dag gewist, dus download eerst wat u nodig hebt.

De toezeggingen die hieraan ten grondslag liggen, staan in Partners en gegevensverwerking in onze Algemene Voorwaarden.

Iets nodig wat de abonnementen niet dekken? Gebruik Contact op het scherm Abonnement in uw console.