A tutor inside your app
By the end of this guide the students already signed in to your app open a tutor inside it, with no second login. A student under the school's consent age waits until consent is recorded; their conversations stay in Zentiq.
You need: an organisation set up as a school, a key made with the Learning platform preset, and the Node SDK.
1. Build and publish the tutor#
const tutor = await zentiq.createPortal({ name: "Northfield Tutor", templates: ["maths-tutor"], loginMethods: ["login_card"] });
const ready = await zentiq.getPortalGoLive(tutor.id);
if (ready.ready) await zentiq.publishPortal(tutor.id);2. Add the class and the student#
const classroom = await zentiq.createUnit({ name: "Class 5B", kind: "class", gradeBand: "5" });
const sam = await zentiq.createPerson({ externalId: "4821", name: "Sam Okafor", role: "LEARNER", unitId: classroom.id, gradeBand: "5" });
const place = sam.memberships[0]; // mbr_…: "waiting_consent" for a student under the consent ageYour own id for the student (externalId) is how Zentiq knows them from then on: send it again and you get the same person. A student under the consent age gets a place that is waiting_consent.
3. Record consent#
if (place.status === "waiting_consent") {
// Record the consent your school collected (a form, a signed letter): who gave it and how.
await zentiq.recordGuardianConsent(place.id, { by: "guardian", guardianEmail: "parent@example.com", method: "school_form" });
}The place turns active. consent.recorded goes out without the guardian's address.
An adult learner (18 or over) needs no guardian: where your organisation has switched on "Mark learners who are adults (18+)", send ageBand: "18+" with the person or the place, and it starts active (a place already waiting is switched on when you mark it). With the setting off, the mark is 409 conflict (details.reason: "adult_learners_off").
4. Open the tutor from your app#
On every page view, after your own sign-in, your server asks for an embed token for that student and your page mounts the tutor with it (the React component does the mounting):
// On every page view, after your own sign-in: a token for this student, then the page mounts the tutor with it.
async function tutorAddress(student: { id: string; name: string }) {
const t = await zentiq.createEmbedToken(tutor.id, { externalUserId: student.id, name: student.name, role: "learner", unitId: classroom.id });
return t.embedUrl; // works once, for five minutes: fetch a new one for every page view
}A token lasts five minutes and works once: ask for a new one each time. It works only on a published portal. When you stop issuing tokens for someone, they are out at their next visit.
5. Read how they did#
// Numbers only: a child's conversation never leaves Zentiq.
const results = await zentiq.listResults({ externalUserId: "4821" });
for (const r of results.data) console.log(r.subjectName, r.percent, r.passed);
const first = results.data[0];
if (first?.sessionId) {
try {
await zentiq.sessionTranscript(first.sessionId);
} catch (e) {
if (e instanceof ZentiqError && e.code === "learner_conversation") console.log("A young learner's words stay in Zentiq.");
}
}Results give numbers only. A young learner's conversation is never given out, to any key: its transcript is 403 learner_conversation, and no webhook ever carries its words.