Skip to main content
Version: Next

Submission Review

Once participants submit their forms, submissions appear in the staff review queue. Staff can inspect the data, flag fields, request corrections, reject, or approve (which triggers the roster import).


Submission statuses

StatusDescription
draftParticipant is still filling in the form
submittedReady for staff review
needs_correctionStaff sent back a correction request
resubmittedParticipant corrected and resubmitted
approvedAccepted by staff; import triggered
rejectedPermanently rejected
importedSuccessfully written to the person record
cancelledWithdrawn before approval

Review queue

Navigate to Foundation -> Self-Service Registration -> Submissions.

Submission review queue showing list of submissions with status badges, names, and action buttons

The review queue. Filter by status to focus on what needs attention. Each row shows the participant name, submission status, when they submitted, and quick action buttons (Review / Request Correction / Approve).

Filter the queue by:

  • sessionId - limit to one registration session
  • status - e.g. show only submitted or needs_correction
  • personType - teacher or student
  • classDivisionId - class teacher view (when classTeacherOnly: true)
  • search - name or code search
const { data } = useRegistrationSubmissions({
sessionId: "...",
status: "submitted",
});

Hook: useRegistrationSubmissions(params)


Submission record fields

Submission detail view showing participant data, validation warnings, field review annotations, and action bar

The submission detail view. Left panel shows the participant's submitted data. Right panel shows review annotations, validation warnings, and the action bar (flag fields / request correction / approve / reject).

FieldDescription
payloadRaw form data as submitted by the participant
normalizedIdentityServer-extracted key fields (name, DOB, phone, guardian info, placement IDs)
validationSummaryServer-computed warnings and missing required fields
sourceDocumentAny supporting document upload reference
versionIncremented on every save/resubmit - used for optimistic lock checks
correctionMessageShown to participant when status is needs_correction
reviewNotesInternal staff notes (not shown to participant)
rejectionReasonShown to participant on rejection
teacherDetailsExpanded teacher-specific data (subjects, department, class teacher role)

Review actions

Field-level review

Staff can annotate individual fields without changing the submission status. Use this to flag questionable values for colleagues or for your own tracking before making a final decision.

const review = useReviewRegistrationSubmissionFields();
review.mutate({
submissionId: "...",
data: {
version: 3,
fieldReviews: {
"firstName": { status: "ok" },
"dateOfBirth": { status: "flagged", note: "Looks wrong - born 2045?" },
},
reviewNotes: "Check DOB before approving.",
},
});

API: PATCH /registrations/submissions/{id}/review-fields
Hook: useReviewRegistrationSubmissionFields()


Request correction

Correction dialog showing message field and flagged fields highlighted in the submission

The request correction dialog. Staff enter a message visible to the participant and can flag specific fields. The flagged fields are highlighted when the participant re-enters their code.

Send the submission back to the participant with a specific message explaining what needs to be fixed.

const requestCorrection = useRequestRegistrationCorrection();
requestCorrection.mutate({
submissionId: "...",
data: {
version: 3,
message: "Please provide a valid date of birth. The year entered appears incorrect.",
fieldReviews: {
"dateOfBirth": { status: "flagged" },
},
},
});
  • Submission status moves to needs_correction.
  • Access code status moves to needs_correction.
  • The message is surfaced to the participant when they re-enter their code.
  • Participant resubmits -> status moves to resubmitted.

API: POST /registrations/submissions/{id}/request-correction
Hook: useRequestRegistrationCorrection()


Reject

Permanently reject a submission with a reason.

const reject = useRejectRegistrationSubmission();
reject.mutate({
submissionId: "...",
data: {
version: 3,
reason: "Identity could not be verified. Please contact the school office.",
},
});

The reason is stored on the submission. The participant cannot resubmit after rejection.

API: POST /registrations/submissions/{id}/reject
Hook: useRejectRegistrationSubmission()


Approve and import

Bulk approve dialog showing selected submissions list with import policy options

The bulk approve confirmation dialog. Select multiple submitted records, set the import mode, and confirm. Results show per-submission success or error after processing.

Approving a submission triggers the roster import. You can supply corrections to apply during import without asking the participant to resubmit.

const approve = useApproveRegistrationSubmission();
approve.mutate({
submissionId: "...",
data: {
version: 3,
approvalNotes: "Verified against admission file.",
fieldCorrections: {
"dateOfBirth": "2010-03-15",
},
importPolicy: {
mode: "update_existing_or_create",
createStudentPortalAccount: true,
createGuardianPortalAccount: false,
syntheticStudentUserWhenNoEmail: true,
},
},
});

The response (ApproveRegistrationSubmissionResult) includes:

  • officialStudentId / officialTeacherId - the resulting person record ID
  • createdGuardianIds / updatedGuardianIds - guardian records touched
  • eventsPublished - domain events raised (e.g. student.created, teacher.updated)

API: POST /registrations/submissions/{id}/approve
Hook: useApproveRegistrationSubmission()


Import modes

ModeBehaviour
update_existing_or_createUpdate if a matched record exists; create a new record otherwise
update_existing_onlyOnly update existing records; skip if no match found
create_new_onlyAlways create a new record; skip if a match already exists

Portal account creation

The importPolicy on an approval controls whether portal accounts are created:

FlagWhat it does
createStudentPortalAccountCreate a User account linked to the new/updated student
createGuardianPortalAccountCreate User accounts for guardian contacts
syntheticStudentUserWhenNoEmailCreate a synthetic user (username-only) when the student has no email address

Manual submission (paper capture)

Staff can submit on behalf of a participant - for example when a form was completed on paper and needs to be entered into the system.

const manual = useCreateManualRegistrationSubmission();
manual.mutate({
sessionId: "...",
data: {
source: "admin_paper_capture",
studentId: "existing-student-id", // optional - link to existing record
payload: { firstName: "Jane", lastName: "Doe", ... },
submitImmediately: true, // bypass draft state
},
});

source options:

  • teacher_mobile_paper_capture - teacher entered on behalf of a student in the field
  • admin_paper_capture - admin office entry from a physical form

API: POST /registrations/sessions/{id}/manual-submissions
Hook: useCreateManualRegistrationSubmission()


Class teacher view

Class teachers only see submissions for their assigned class divisions. Pass classTeacherOnly: true in the list params to activate this scoping on the query. The ClassTeacherRegistrationDashboard aggregates pending counts across all the teacher's classes.


API quick reference

OperationMethod + PathHook
List submissionsGET /registrations/submissionsuseRegistrationSubmissions(params)
Get submissionGET /registrations/submissions/{id}useRegistrationSubmission(id)
Review fieldsPATCH /registrations/submissions/{id}/review-fieldsuseReviewRegistrationSubmissionFields()
Request correctionPOST /registrations/submissions/{id}/request-correctionuseRequestRegistrationCorrection()
RejectPOST /registrations/submissions/{id}/rejectuseRejectRegistrationSubmission()
ApprovePOST /registrations/submissions/{id}/approveuseApproveRegistrationSubmission()
Bulk approvePOST /registrations/sessions/{id}/submissions/bulk-approveuseBulkApproveRegistrationSubmissions()
Manual submissionPOST /registrations/sessions/{id}/manual-submissionsuseCreateManualRegistrationSubmission()