| Location | Name | Required | Meaning |
|---|---|---|---|
| path | id | Yes | Use the ID from an authorized staff response; source validators reject malformed IDs. |
| query | cursor | Conditional / optional | {"type":"string"} |
| query | limit | Conditional / optional | {"type":"string","minimum":1,"maximum":100} |
| query | content | Conditional / optional | Requests unmasked titles, names, settings and emails. Requires owner/support, fresh step-up and audit. Never returns document text or file/audio bytes. |
| header | X-Admin-Reason | Conditional / optional | URI-encoded written audit reason; Cloud/billing may reuse a fresh target-specific session marker. |
{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./** GET /api/admin/orgs/:id/audit?cursor&limit[&content=1]: the organisation's own audit log, newest first (read-only). */
export const GET = cloudRoute<{ id: string }>("org.audit", orgTarget, async (request, { viewer, params }) => {
const org = await orgs.get(orgPk(params.id), "ORG");
if (!org) throw notFound("Organisation");
const query = new URL(request.url).searchParams;
const page = await orgAuditOf(org, { cursor: query.get("cursor") ?? undefined, limit: pageLimit(query.get("limit")) });
return { items: page.items.map((entry) => presentOrgAudit(entry, viewer)), cursor: page.cursor ?? null };
});