People
Units, members, learners and guardian consent.
/v1/people/{id}/membershipsGive a person another place
A role at a unit, or at the organisation level. The same place again is returned as it is (200). ageBand: "18+" marks an adult learner, where the organisation marks adult learners (409 conflict otherwise). The API never gives, changes, switches off or removes an owner's place, and only a full-access key gives, changes, switches off or removes an ADMIN, AVATAR_BUILDER or WORKSPACE_ADMIN place (403 forbidden otherwise): people:write alone manages learners, leaders and observers.
Path parameters
idstringrequiredPerson id (
usr_…); the id without its prefix is accepted too.
Body
role"OWNER" | "ADMIN" | "AVATAR_BUILDER" | "WORKSPACE_ADMIN" | "LEADER" | "LEARNER" | "OBSERVER"requiredOWNER (never given or changed through the API), ADMIN, AVATAR_BUILDER, WORKSPACE_ADMIN (these four at the organisation level only), LEADER, LEARNER, OBSERVER.
unitIdstring | nullworkspaceIdstring | nullgradeBandstring | nullageBand"18+" | null
Returns
201 The place. data is Membership.
Fields of data
idstringrequiredMembership id (
mbr_…).pattern `^mbr_.*`
personIdstringrequiredPerson id (
usr_…).pattern `^usr_.*`
rolestringrequiredOne of the member roles.
unitIdstring | nullrequiredThe unit it is held at; null at the organisation level.
workspaceIdstring | nullrequiredA workspace admin's subject (
sub_…; bare for keys on 2026-07-08).statusstringrequiredactive, waiting_consent (a child's place waiting for a parent's consent) or disabled.
gradeBandstring | nullrequiredageBand"18+" | nullrequired"18+": an adult learner, who starts without a parent's or guardian's consent.consentAtstring (date-time) | nullrequiredconsentBy"organisation" | "guardian" | "teacher" | nullrequiredWho gave a learner's consent: the organisation, a guardian or a teacher (never their details).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictidempotency_conflictidempotency_in_progressrate_limitedserver_error
Events
Request
curl -X POST "https://app.zentiqai.com/v1/people/usr_123/memberships" \
-H "Authorization: Bearer $ZENTIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "OWNER"
}'import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.addMembership("usr_123", {
role: "OWNER",
});import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.add_membership("usr_123", {
"role": "OWNER",
})Example answer
{
"data": {
"id": "mbr_cmfq2b7x10000abcd1234",
"personId": "usr_cmfq2b7x10000abcd1234",
"role": "…",
"unitId": "unit_cmfq2b7x10000abcd1234",
"workspaceId": "sub_cmfq2b7x10000abcd1234",
"status": "active"
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}/v1/peopleList people
Everyone in the organisation (members, learners, parents) with their places here, newest first. updatedAfter lists those whose account or places changed since: for keeping your system in step.
Query parameters
limitintegerPage size, 1-200 (default 50).
cursorstringThe
nextCursorof the previous page.unitIdstringPeople with a place at this unit.
subtree"true" | "false"With unitId: the unit and every unit below it.
role"OWNER" | "ADMIN" | "AVATAR_BUILDER" | "WORKSPACE_ADMIN" | "LEADER" | "LEARNER" | "OBSERVER"People holding this role here.
status"active" | "waiting_consent" | "disabled"People with a place in this status.
externalIdstringThe person you know by this id.
emailstringupdatedAfterstringChanged since (the account or one of its places): for syncing.
Returns
200 A page of people. A page: data is a list of Person, and nextCursor fetches the next page.
Fields of data
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
externalIdstring | nullrequiredYour own id for the person (the sync key), when you gave one.
namestringrequiredemailstring | nullrequiredNull for a login card or a person known only by your id.
loginNamestring | nullrequiredA login card's sign-in name (
<organisation code>/<username>).lastSignInAtstring (date-time) | nullrequireddisabledbooleanrequiredSwitched off: no sign-in anywhere; their places keep their own status.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
Errors
invalid_requestunauthorizedforbiddenupgrade_requiredrate_limitedserver_error
Request
curl "https://app.zentiqai.com/v1/people?limit=20" \
-H "Authorization: Bearer $ZENTIQ_API_KEY"import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const page = await zentiq.listPeople({
limit: 20,
});import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
page = zentiq.list_people(limit=20)Example answer
{
"data": [
{
"id": "usr_cmfq2b7x10000abcd1234",
"externalId": "…",
"name": "Zoe",
"email": "sam@example.com",
"loginName": "…",
"memberships": [
{
"id": "mbr_cmfq2b7x10000abcd1234",
"personId": "usr_cmfq2b7x10000abcd1234",
"role": "…",
"unitId": "unit_cmfq2b7x10000abcd1234",
"workspaceId": "sub_cmfq2b7x10000abcd1234",
"status": "active"
}
]
}
],
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d",
"nextCursor": null
}/v1/peopleAdd a person (or find them) and give them a place
By externalId (your own id, the sync key: a repeat returns the same person, 200), else by email, else a login card for a learner without an email. A new learner's place waits for a parent's consent where the organisation's rules say so (status: waiting_consent); never an adult learner's (ageBand: "18+", where the organisation marks adult learners). A new login card's PIN is in this answer only (Cache-Control: no-store): a retry never gets it again. No email is sent. The API never gives, changes, switches off or removes an owner's place, and only a full-access key gives, changes, switches off or removes an ADMIN, AVATAR_BUILDER or WORKSPACE_ADMIN place (403 forbidden otherwise): people:write alone manages learners, leaders and observers.
Body
externalIdstring | nullYour own id for the person: the sync key. A repeat with it returns the same person.
emailstring (email) | nullWithout an externalId, the person is found or added by email. An email another account already has is refused (409).
namestring | nullrole"OWNER" | "ADMIN" | "AVATAR_BUILDER" | "WORKSPACE_ADMIN" | "LEADER" | "LEARNER" | "OBSERVER"requiredOWNER (never given or changed through the API), ADMIN, AVATAR_BUILDER, WORKSPACE_ADMIN (these four at the organisation level only), LEADER, LEARNER, OBSERVER.
unitIdstring | nullworkspaceIdstring | nullA workspace admin's subject.
gradeBandstring | nullageBand"18+" | nullloginCardboolean | nullA learner without an email gets a login card (needs accounts without email switched on).
Returns
201 The person (201 when a person or a place was made, 200 when both existed). data is PersonCreated.
Fields of data
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
externalIdstring | nullrequiredYour own id for the person (the sync key), when you gave one.
namestringrequiredemailstring | nullrequiredNull for a login card or a person known only by your id.
loginNamestring | nullrequiredA login card's sign-in name (
<organisation code>/<username>).lastSignInAtstring (date-time) | nullrequireddisabledbooleanrequiredSwitched off: no sign-in anywhere; their places keep their own status.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
loginCardLoginCard | nullrequiredOnly on the answer that made the card; never replayed.
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictidempotency_conflictidempotency_in_progressrate_limitedserver_error
Events
Request
curl -X POST "https://app.zentiqai.com/v1/people" \
-H "Authorization: Bearer $ZENTIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"role": "OWNER"
}'import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.createPerson({
role: "OWNER",
});import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.create_person({
"role": "OWNER",
})Example answer
{
"data": {
"id": "usr_cmfq2b7x10000abcd1234",
"externalId": "…",
"name": "Zoe",
"email": "sam@example.com",
"loginName": "…",
"memberships": [
{
"id": "mbr_cmfq2b7x10000abcd1234",
"personId": "usr_cmfq2b7x10000abcd1234",
"role": "…",
"unitId": "unit_cmfq2b7x10000abcd1234",
"workspaceId": "sub_cmfq2b7x10000abcd1234",
"status": "active"
}
]
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}/v1/unitsList units
The organisation's classes, teams and groups, in tree order, with their counts.
Query parameters
limitintegerPage size, 1-200 (default 50).
cursorstringThe
nextCursorof the previous page.parentIdstringOnly the units directly under this one.
includeDisabled"true" | "false"Include switched-off units (default true).
Returns
200 A page of units. A page: data is a list of Unit, and nextCursor fetches the next page.
Fields of data
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
parentIdstring | nullrequiredThe unit above it; null at the top level.
namestringrequiredkindstringrequiredclass, team, group, department, region, school or club.
gradeBandstring | nullrequiredA class's year or grade: the default for learners who join with its code.
disabledbooleanrequiredSwitched off (itself or a unit above it): it grants nothing until switched on.
joinCodestring | nullrequiredThe code learners join with, where joining by code is on.
sortOrderintegerrequiredcountsobjectrequiredmembersintegerrequiredlearnersintegerrequiredleadersintegerrequiredwaitingintegerrequiredLearners whose place waits for a parent's consent.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
Errors
invalid_requestunauthorizedforbiddenupgrade_requiredrate_limitedserver_error
Request
curl "https://app.zentiqai.com/v1/units?limit=20" \
-H "Authorization: Bearer $ZENTIQ_API_KEY"import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const page = await zentiq.listUnits({
limit: 20,
});import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
page = zentiq.list_units(limit=20)Example answer
{
"data": [
{
"id": "unit_cmfq2b7x10000abcd1234",
"parentId": "unit_cmfq2b7x10000abcd1234",
"name": "Zoe",
"kind": "team",
"gradeBand": "…",
"disabled": true
}
],
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d",
"nextCursor": null
}/v1/unitsAdd a unit (a class, team or group)
Under another unit (parentId) or at the top level. A second unit with the same name at the same level is allowed and flagged (duplicateName). A leader named by email is invited and takes a staff seat (403 upgrade_required when they are all in use).
Body
namestringrequired1-80 characters
parentIdstring | nullkindstring | nullclass, team, group, department, region, school or club (default: the organisation's).
gradeBandstring | nullleaderobject | nullInvites the unit's leader by email (takes a staff seat).
emailstring (email)required
Returns
201 The new unit. data is UnitWritten.
Fields of data
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
parentIdstring | nullrequiredThe unit above it; null at the top level.
namestringrequiredkindstringrequiredclass, team, group, department, region, school or club.
gradeBandstring | nullrequiredA class's year or grade: the default for learners who join with its code.
disabledbooleanrequiredSwitched off (itself or a unit above it): it grants nothing until switched on.
joinCodestring | nullrequiredThe code learners join with, where joining by code is on.
sortOrderintegerrequiredcountsobjectrequiredmembersintegerrequiredlearnersintegerrequiredleadersintegerrequiredwaitingintegerrequiredLearners whose place waits for a parent's consent.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
duplicateNameobject | nullrequiredAnother unit at the same level already has this name (allowed, flagged).
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
namestringrequired
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundidempotency_conflictidempotency_in_progressrate_limitedserver_error
Events
Request
curl -X POST "https://app.zentiqai.com/v1/units" \
-H "Authorization: Bearer $ZENTIQ_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"name": "Zoe"
}'import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.createUnit({
name: "Zoe",
});import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.create_unit({
"name": "Zoe",
})Example answer
{
"data": {
"id": "unit_cmfq2b7x10000abcd1234",
"parentId": "unit_cmfq2b7x10000abcd1234",
"name": "Zoe",
"kind": "team",
"gradeBand": "…",
"disabled": true
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}/v1/memberships/{id}Change a place
Its role, unit, year or grade, whether it is an adult learner's, or switch it off or on. A place waiting for a parent's consent turns active only through guardian consent, or when it is marked as an adult learner's (ageBand: "18+", where the organisation marks adult learners: 409 conflict otherwise). The API never gives, changes, switches off or removes an owner's place, and only a full-access key gives, changes, switches off or removes an ADMIN, AVATAR_BUILDER or WORKSPACE_ADMIN place (403 forbidden otherwise): people:write alone manages learners, leaders and observers.
Path parameters
idstringrequiredMembership id (
mbr_…); the id without its prefix is accepted too.
Body
role"OWNER" | "ADMIN" | "AVATAR_BUILDER" | "WORKSPACE_ADMIN" | "LEADER" | "LEARNER" | "OBSERVER"OWNER (never given or changed through the API), ADMIN, AVATAR_BUILDER, WORKSPACE_ADMIN (these four at the organisation level only), LEADER, LEARNER, OBSERVER.
unitIdstring | nullgradeBandstring | nullageBand"18+" | null"18+"marks an adult learner (a place waiting for consent is switched on); null clears it.status"active" | "disabled"Switch this place off or on. A place waiting for consent turns active only through guardian consent.
Returns
200 The place. data is Membership.
Fields of data
idstringrequiredMembership id (
mbr_…).pattern `^mbr_.*`
personIdstringrequiredPerson id (
usr_…).pattern `^usr_.*`
rolestringrequiredOne of the member roles.
unitIdstring | nullrequiredThe unit it is held at; null at the organisation level.
workspaceIdstring | nullrequiredA workspace admin's subject (
sub_…; bare for keys on 2026-07-08).statusstringrequiredactive, waiting_consent (a child's place waiting for a parent's consent) or disabled.
gradeBandstring | nullrequiredageBand"18+" | nullrequired"18+": an adult learner, who starts without a parent's or guardian's consent.consentAtstring (date-time) | nullrequiredconsentBy"organisation" | "guardian" | "teacher" | nullrequiredWho gave a learner's consent: the organisation, a guardian or a teacher (never their details).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictrate_limitedserver_error
Events
member.updatedmember.disabledmember.enabled
Request
curl -X PATCH "https://app.zentiqai.com/v1/memberships/mbr_123" \
-H "Authorization: Bearer $ZENTIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.updateMembership("mbr_123", {});import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.update_membership("mbr_123", {})Example answer
{
"data": {
"id": "mbr_cmfq2b7x10000abcd1234",
"personId": "usr_cmfq2b7x10000abcd1234",
"role": "…",
"unitId": "unit_cmfq2b7x10000abcd1234",
"workspaceId": "sub_cmfq2b7x10000abcd1234",
"status": "active"
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}/v1/memberships/{id}Remove a place
The account stays. Someone's only organisation-level owner or admin place can't be removed this way, nor the last place of an owner or admin invited in the console (409 conflict: without a place their account would count as an owner; an owner or admin removes them from the organisation in the console). The API never gives, changes, switches off or removes an owner's place, and only a full-access key gives, changes, switches off or removes an ADMIN, AVATAR_BUILDER or WORKSPACE_ADMIN place (403 forbidden otherwise): people:write alone manages learners, leaders and observers.
Path parameters
idstringrequiredMembership id (
mbr_…); the id without its prefix is accepted too.
Returns
200 Removed. data is object.
Fields of data
removedtruerequiredidstringrequiredMembership id (
mbr_…).pattern `^mbr_.*`
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictrate_limitedserver_error
Events
Request
curl -X DELETE "https://app.zentiqai.com/v1/memberships/mbr_123" \
-H "Authorization: Bearer $ZENTIQ_API_KEY"import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.deleteMembership("mbr_123");import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.delete_membership("mbr_123")Example answer
{
"data": {
"removed": true,
"id": "mbr_cmfq2b7x10000abcd1234"
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}/v1/people/{id}Get a person
Path parameters
idstringrequiredPerson id (
usr_…); the id without its prefix is accepted too.
Returns
200 The person. data is Person.
Fields of data
idstringrequiredPerson id (
usr_…).pattern `^usr_.*`
externalIdstring | nullrequiredYour own id for the person (the sync key), when you gave one.
namestringrequiredemailstring | nullrequiredNull for a login card or a person known only by your id.
loginNamestring | nullrequiredA login card's sign-in name (
<organisation code>/<username>).lastSignInAtstring (date-time) | nullrequireddisabledbooleanrequiredSwitched off: no sign-in anywhere; their places keep their own status.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error
Request
curl "https://app.zentiqai.com/v1/people/usr_123" \
-H "Authorization: Bearer $ZENTIQ_API_KEY"import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.getPerson("usr_123");import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.get_person("usr_123")Example answer
{
"data": {
"id": "usr_cmfq2b7x10000abcd1234",
"externalId": "…",
"name": "Zoe",
"email": "sam@example.com",
"loginName": "…",
"memberships": [
{
"id": "mbr_cmfq2b7x10000abcd1234",
"personId": "usr_cmfq2b7x10000abcd1234",
"role": "…",
"unitId": "unit_cmfq2b7x10000abcd1234",
"workspaceId": "sub_cmfq2b7x10000abcd1234",
"status": "active"
}
]
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}/v1/units/{id}Get a unit
Path parameters
idstringrequiredUnit id (
unit_…); the id without its prefix is accepted too.
Returns
200 The unit. data is Unit.
Fields of data
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
parentIdstring | nullrequiredThe unit above it; null at the top level.
namestringrequiredkindstringrequiredclass, team, group, department, region, school or club.
gradeBandstring | nullrequiredA class's year or grade: the default for learners who join with its code.
disabledbooleanrequiredSwitched off (itself or a unit above it): it grants nothing until switched on.
joinCodestring | nullrequiredThe code learners join with, where joining by code is on.
sortOrderintegerrequiredcountsobjectrequiredmembersintegerrequiredlearnersintegerrequiredleadersintegerrequiredwaitingintegerrequiredLearners whose place waits for a parent's consent.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error
Request
curl "https://app.zentiqai.com/v1/units/unit_123" \
-H "Authorization: Bearer $ZENTIQ_API_KEY"import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.getUnit("unit_123");import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.get_unit("unit_123")Example answer
{
"data": {
"id": "unit_cmfq2b7x10000abcd1234",
"parentId": "unit_cmfq2b7x10000abcd1234",
"name": "Zoe",
"kind": "team",
"gradeBand": "…",
"disabled": true
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}/v1/units/{id}Rename, move or switch off a unit
Switching a unit off switches off everything below it: nothing is deleted, and it grants nothing until switched on. A unit can't move under itself.
Path parameters
idstringrequiredUnit id (
unit_…); the id without its prefix is accepted too.
Body
namestring1-80 characters
parentIdstring | nullMove it under another unit; null moves it to the top level.
sortOrderintegergradeBandstring | nullnull clears it.
disabledbooleanSwitch it (and everything below it) off or on. Nothing is deleted.
Returns
200 The unit. data is UnitWritten.
Fields of data
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
parentIdstring | nullrequiredThe unit above it; null at the top level.
namestringrequiredkindstringrequiredclass, team, group, department, region, school or club.
gradeBandstring | nullrequiredA class's year or grade: the default for learners who join with its code.
disabledbooleanrequiredSwitched off (itself or a unit above it): it grants nothing until switched on.
joinCodestring | nullrequiredThe code learners join with, where joining by code is on.
sortOrderintegerrequiredcountsobjectrequiredmembersintegerrequiredlearnersintegerrequiredleadersintegerrequiredwaitingintegerrequiredLearners whose place waits for a parent's consent.
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
duplicateNameobject | nullrequiredAnother unit at the same level already has this name (allowed, flagged).
idstringrequiredUnit id (
unit_…).pattern `^unit_.*`
namestringrequired
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundrate_limitedserver_error
Events
unit.renamedunit.updatedunit.disabledunit.enabled
Request
curl -X PATCH "https://app.zentiqai.com/v1/units/unit_123" \
-H "Authorization: Bearer $ZENTIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.updateUnit("unit_123", {});import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.update_unit("unit_123", {})Example answer
{
"data": {
"id": "unit_cmfq2b7x10000abcd1234",
"parentId": "unit_cmfq2b7x10000abcd1234",
"name": "Zoe",
"kind": "team",
"gradeBand": "…",
"disabled": true
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}/v1/memberships/{id}/guardian-consentRecord a parent's or guardian's consent
On a learner's place that waits for it: the place turns active. A place that already has consent is returned as it is; a place switched off is refused (409). consent.recorded says who gave it, never the guardian's address.
Path parameters
idstringrequiredMembership id (
mbr_…); the id without its prefix is accepted too.
Body
by"organisation" | "guardian" | "teacher"requiredWho gave it: the organisation attests, a guardian gave it, a teacher recorded it on file.
guardianEmailstring (email) | nullKept on the place as evidence; never sent in any event or webhook.
methodstringrequiredHow it was given: school_form, in_person, email, …
1-40 characters
evidenceRefstring | nullYour own reference to the evidence.
Returns
200 The place. data is Membership.
Fields of data
idstringrequiredMembership id (
mbr_…).pattern `^mbr_.*`
personIdstringrequiredPerson id (
usr_…).pattern `^usr_.*`
rolestringrequiredOne of the member roles.
unitIdstring | nullrequiredThe unit it is held at; null at the organisation level.
workspaceIdstring | nullrequiredA workspace admin's subject (
sub_…; bare for keys on 2026-07-08).statusstringrequiredactive, waiting_consent (a child's place waiting for a parent's consent) or disabled.
gradeBandstring | nullrequiredageBand"18+" | nullrequired"18+": an adult learner, who starts without a parent's or guardian's consent.consentAtstring (date-time) | nullrequiredconsentBy"organisation" | "guardian" | "teacher" | nullrequiredWho gave a learner's consent: the organisation, a guardian or a teacher (never their details).
createdAtstring (date-time)requiredISO 8601 UTC timestamp.
updatedAtstring (date-time)requiredISO 8601 UTC timestamp.
Errors
invalid_requestunauthorizedforbiddenupgrade_requirednot_foundconflictidempotency_conflictidempotency_in_progressrate_limitedserver_error
Events
Request
curl -X POST "https://app.zentiqai.com/v1/memberships/mbr_123/guardian-consent" \
-H "Authorization: Bearer $ZENTIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"by": "organisation",
"method": "school_form"
}'import { Zentiq } from "@zentiq/node";
const zentiq = new Zentiq({ apiKey: process.env.ZENTIQ_API_KEY });
const result = await zentiq.recordGuardianConsent("mbr_123", {
by: "organisation",
method: "school_form",
});import os
from zentiq import Zentiq
zentiq = Zentiq(api_key=os.environ["ZENTIQ_API_KEY"])
result = zentiq.record_guardian_consent("mbr_123", {
"by": "organisation",
"method": "school_form",
})Example answer
{
"data": {
"id": "mbr_cmfq2b7x10000abcd1234",
"personId": "usr_cmfq2b7x10000abcd1234",
"role": "…",
"unitId": "unit_cmfq2b7x10000abcd1234",
"workspaceId": "sub_cmfq2b7x10000abcd1234",
"status": "active"
},
"error": null,
"requestId": "req_4f1c2e9a7b3d5e6f7a8b9c0d"
}