Como tudo se encaixa
- Crie chaves e adicione os seus sites na consola.
- Para provas de treino, cole o excerto na sua página.
- Para os seus testes, o seu servidor inicia uma tentativa e recebe um endereço de início.
- A sua página abre-o, o candidato faz o teste e o resultado chega-lhe por webhook ou pela API.
Chaves
pk_test_pk_live_- As chaves publicáveis vão nas suas páginas web. Só abrem provas de treino nos sites que indicou.
sk_test_sk_live_- As chaves de servidor agem em nome da sua organização. Guarde-as no seu servidor e nunca as envie para um navegador.
As chaves de teste funcionam de imediato e não contam para o seu plano. As chaves live exigem que a sua conta esteja aprovada.
Provas de treino
Adicione o script uma vez e coloque uma prova onde quiser. A moldura ajusta-se sozinha ao conteúdo.
<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>
A prova é o id mostrado no gerador de excertos da sua consola. Acrescente mode: "exam" para condições de exame com tempo.
Os seus testes
Escreva testes na consola, em Testes, e abra-os. Quando um candidato estiver pronto, o seu servidor inicia uma tentativa:
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 é o seu próprio id para a pessoa, até 128 caracteres. O nome e o email são opcionais; só guardamos o que enviar.
language é opcional: um de de, en, es, fr, yo, ig, ha, nl, pt, sw. Os botões, o temporizador e as mensagens da tentativa aparecem nessa língua; as suas perguntas ficam como as escreveu. Sem este campo, a tentativa é em inglês.
A resposta traz um endereço de início que funciona uma vez, dentro de 10 minutos. Abra-o na sua página:
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>
Depois de aberta, uma tentativa dura até 24 horas e recarregar retoma-a. Cada candidato faz cada teste uma vez.
Para listar os seus testes e os respetivos ids:
curl https://www.supergb.com/cbt/partner-api/v1/tests -H "Authorization: Bearer $GREEN_BRIDGE_KEY"
Mensagens da moldura
onEvent recebe estas mensagens, e só da nossa moldura:
| Evento | Significado |
|---|---|
ready | A página carregou. |
resize | O conteúdo mudou de altura. A moldura acompanha sozinha. |
completed | Uma prova de treino foi corrigida. detail traz score e max_score. |
submitted | Um teste foi entregue. detail traz attempt_id. Obtenha o resultado a partir do seu servidor, não do navegador. |
Resultados
Tentativas entregues, da mais recente para a mais antiga, 50 por página. Filtre por test_id, candidate_id ou ambos.
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"
Uma tentativa tem este aspeto. questions está incluído a partir do plano 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 é fully_graded quando já não há nada para corrigir à mão; caso contrário, pending_manual_review ou pending_transcription.
Webhooks
Adicione até 5 endereços https na sua consola. Cada evento é enviado como POST assinado e repetido durante 3 dias até o seu servidor responder com um estado 2xx.
| Evento | Significado |
|---|---|
attempt.started | O candidato abriu a tentativa. |
attempt.submitted | O candidato entregou. |
attempt.graded | Todas as classificações são finais. Volta a ser enviado sempre que uma nota muda. |
attempt.integrity_flagged | O candidato saiu do teste ou tentou copiar ou colar 3 vezes. |
ping | Um evento de teste enviado da sua consola. |
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" }
}
O id de um evento nunca muda, por isso pode ignorar com segurança um que já tratou.
Verificar a assinatura
Calcule o HMAC-SHA256 de t, um ponto e o corpo original com o seu segredo de assinatura e compare com v1. Recuse uma marca temporal com mais de cinco minutos.
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", ""))
Erros
Os erros chegam em JSON com um código estável:
HTTP/1.1 404 Not Found
{"error": {"code": "test_not_found"}}
| Código | HTTP | Significado |
|---|---|---|
invalid_key |
401 | A chave falta, é desconhecida ou foi revogada. |
partner_suspended |
403 | A sua conta está suspensa. Contacte-nos. |
live_keys_need_approval |
403 | As chaves live funcionam depois de a conta ser aprovada. |
not_on_plan |
403 | O seu plano não inclui isto. |
test_not_found |
404 | Nenhum dos seus testes tem esse id. |
attempt_not_found |
404 | Nenhuma das suas tentativas tem esse id. |
candidate_not_found |
404 | Não tem nenhum candidato com esse id. |
test_not_open |
409 | O teste ainda não está aberto ou já fechou. |
already_submitted |
409 | Este candidato já entregou este teste. |
invalid_request |
400 | Falta um campo ou não tem a forma esperada. |
monthly_limit_reached |
429 | A quota do mês esgotou. As chaves de teste continuam a funcionar. |
internal_error |
500 | Algo correu mal do nosso lado. Tente de novo. |
Limites e dados
- Até 300 pedidos por minuto por chave de servidor. Acima disso, a resposta é 429 sem conteúdo; espere um minuto e tente de novo.
- As tentativas live e a correção por IA contam para a quota mensal do seu plano. As tentativas iniciadas com uma chave de teste não contam.
Os seus dados
O que guardamos sobre os seus testes e candidatos, durante quanto tempo e como o recuperar.
- Testes e as suas perguntas
- Guardados até os eliminar ou encerrar a sua conta.
- Candidatos
- O id que enviar, e um nome e email só se os enviar. Guardados durante um ano após a última vez que o candidato foi visto.
- Tentativas e resultados
- Respostas, gravações, classificações e eventos de integridade. Guardados durante um ano após o início da tentativa e depois apagados.
- Provas de treino
- Guardadas durante um ano, apenas para contar a sua utilização. A pontuação chega à sua página no evento completed.
- Entregas de webhooks
- Guardadas durante 30 dias, no registo de entregas da sua consola.
- Utilização da API
- Contagens diárias por chave, guardadas durante 400 dias, no ecrã Utilização da sua consola.
Obtenha os resultados a qualquer momento com GET /attempts. Nos planos Growth e Institution também pode transferir os resultados de cada teste em CSV a partir do menu do teste na sua consola: uma linha por tentativa com a classificação de cada pergunta e a resposta do candidato nas perguntas que escreveu. As perguntas do banco da Green Bridge mostram apenas as classificações.
Para apagar um candidato mais cedo:
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"}'
Um resultado que um candidato guarda na sua própria conta Green Bridge passa a pertencer-lhe a partir desse momento. Apagar o candidato ou encerrar a sua conta não o remove.
O proprietário da sua conta pode encerrá-la em Sites e chaves. As chaves e os webhooks param de imediato e tudo o que está acima é apagado no prazo de um dia, por isso transfira primeiro o que precisar.
Precisa de algo que os planos não cobrem? Use Contacte-nos no ecrã Plano da sua consola.