approve provisions the schoolreject replies with text and tags the ticket.| Location | Name | Required | Meaning |
|---|---|---|---|
| path | id | Yes | Use the ID from an authorized staff response; source validators reject malformed IDs. |
| header | X-Admin-CSRF | Yes | Session-bound token from the staff page; not a developer credential. |
{
"oneOf": [
{
"type": "object",
"properties": {
"decision": {
"const": "approve"
},
"name": {
"type": "string",
"minLength": 2,
"maxLength": 120
},
"adminEmail": {
"type": "string",
"format": "email",
"maxLength": 254
},
"adminName": {
"type": "string",
"description": "Optional school administrator display name; schoolApplication validator applies."
},
"note": {
"type": "string",
"maxLength": 5000
}
},
"required": [
"decision",
"name",
"adminEmail"
]
},
{
"type": "object",
"properties": {
"decision": {
"const": "reject"
},
"text": {
"type": "string",
"minLength": 1,
"maxLength": 20000
}
},
"required": [
"decision",
"text"
]
}
]
}approve provisions the schoolreject replies with text and tags the ticket.{error:{code,message}} for CloudError failures, attaches Request-Id, and disables caching. Handle 401 by signing in; show role refusal for 403 forbidden, reauthenticate only for step_up_required, and collect a reason for 400 reason_required. A CSRF failure needs a current page/session token, not blind retries. Operation-specific 404/409/413/422/502/503 errors retain their status. Honor Retry-After on 429./**
* POST /api/admin/support/tickets/:id/school (schools.approve, step-up; ADMIN.md §16). `approve` provisions the school
* on the site, solves the ticket and mails the school-approved reply → {orgId, schoolId, emailed, adminLinked,
* existing}; mail that didn't pass DMARC needs X-Admin-Reason. `reject` replies with `text` and tags the ticket.
*/
export const POST = adminRoute("schools.approve", async (request, ctx, { params }: Context) => {
const id = ticketIdParam((await params).id);
const body = await readBody(request, BODY);
if (body.decision === "reject") return adminJson(await rejectSchool(ctx, id, { text: body.text }));
return adminJson(await approveAsSchool(ctx, id, { name: body.name, adminEmail: body.adminEmail, adminName: body.adminName, note: body.note }));
}, { stepUp: true, rateLimit: "school-approve" });