Void a completed attendance import
Requires participation_configure, programs_view and access to this organization’s program, with participation enabled. Atomically voids the batch’s draft/submitted checks in reverse date/ID order, marks committed source rows voided and records the reason. Only a completed batch may be voided; retrying an already voided batch is allowed. Later submitted evidence can block reversal. Historical records remain available for audit. Requires permission: one of participation_configure.
curl --request POST \
--url https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"reason": "Imported the incorrect workbook."
}
'import requests
url = "https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void"
payload = { "reason": "Imported the incorrect workbook." }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({reason: 'Imported the incorrect workbook.'})
};
fetch('https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reason' => 'Imported the incorrect workbook.'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void"
payload := strings.NewReader("{\n \"reason\": \"Imported the incorrect workbook.\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"Imported the incorrect workbook.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reason\": \"Imported the incorrect workbook.\"\n}"
response = http.request(request)
puts response.read_body{
"id": 42,
"program_id": 12,
"participation_period_id": 18,
"original_filename": "attendance.xlsx",
"source_type": "xlsx",
"status": "review",
"progress": 100,
"mapping": {
"evidence_source": "official_record",
"existing_session_action": "block",
"symbols": {},
"sheets": [
{
"sheet": "Sheet1",
"header_row": 1,
"columns": {
"name": 0,
"gratona_id": 0,
"student_id": 0,
"gender": 0
},
"site": {
"fixed_id": 42,
"column": 0,
"value_map": {}
},
"cohort": {
"fixed_id": 42,
"column": 0,
"value_map": {}
},
"attendance_columns": [
{
"column": 4,
"date": "2026-10-20"
}
],
"enabled": true,
"profile_columns": {}
}
],
"external_student_id_field_key": "student_id",
"gender_field_key": "gender"
},
"inspection": [
{
"name": "Sheet1",
"suggested_header_row": 1,
"columns": [
{
"index": 0,
"letter": "A"
}
],
"sample_rows": [
{
"row_number": 2,
"values": [
"Jane Recipient"
]
}
]
}
],
"summary": {
"total_rows": 1,
"ready_rows": 1,
"review_rows": 1,
"blocked_rows": 1,
"unresolved_rows": 1,
"committed_rows": 1,
"skipped_rows": 1,
"exact_id_matches": 1,
"provisional_rows": 1,
"estimated_rows": 1,
"maximum_rows": 1
},
"validation_errors": [
{
"sheet": "Sheet1",
"row": 2,
"date": "2026-10-20",
"codes": [
"placement_conflict"
]
}
],
"error_message": "The attendance file could not be validated. Review the mapping and retry.",
"failure_stage": "validation",
"can_commit": true,
"can_void": false,
"created_at": "2026-10-20T12:00:00Z",
"completed_at": "2026-10-20T12:05:00Z",
"voided_at": "2023-11-07T05:31:56Z",
"void_reason": "Imported the incorrect workbook.",
"created_checks": [
{
"id": 120,
"scheduled_for": "2026-10-20",
"status": "submitted",
"revision": 1,
"site": {
"id": 12,
"name": "Main campus"
},
"cohort": {
"id": 12,
"name": "Main campus"
},
"counts": {
"expected": 25,
"seen": 23,
"unresolved": 2
}
}
],
"rows": {
"items": [
{
"id": 84,
"sheet": "Sheet1",
"source_row_number": 2,
"attendance_date": "2026-10-20",
"display_name": "Jane Recipient",
"gratona_id": "42",
"external_student_id": "STU-001",
"site_id": 12,
"cohort_id": 18,
"site_source_value": "Main campus",
"cohort_source_value": "Group A",
"symbol": "P",
"encounter_status": "seen",
"enrollment_confirmation": "confirmed_enrolled",
"match_type": "suggested_candidate",
"decision": "match",
"status": "review",
"entity_id": 42,
"candidates": [
{
"entity_id": 42,
"gratona_id": 42,
"display_name": "Jane Recipient",
"site_id": 12,
"cohort_id": 18,
"score": 95,
"agreed": [
"name"
],
"conflicted": [
"gender"
]
}
],
"errors": [
"placement_conflict"
],
"warnings": [
"candidate_confirmation_required"
],
"participation_session_id": 120
}
],
"total": 25,
"current_page": 1,
"per_page": 50,
"last_page": 1
},
"recipient_fields": [
{
"key": "student_id",
"label": "Student ID",
"type": "hysCustomID",
"is_title": false
}
]
}{
"message": "Unauthorized",
"status": "error"
}{
"message": "Not Found",
"status": "error"
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}Authorizations
Passport bearer token authentication for legacy admin sessions.
Path Parameters
Program id in the current organization.
Participation import id in the current organization.
Body
Validated request fields for this operation.
Reason retained with the voided import.
3 - 2000"Imported the incorrect workbook."
Response
Operation result.
42
12
18
"attendance.xlsx"
csv, xlsx "xlsx"
pending, validating, review, processing, completed, failed, voided "review"
100
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Counts after validation; empty array before counts exist. Limit failures add estimated_rows/maximum_rows.
Show child attributes
Show child attributes
100Show child attributes
Show child attributes
"The attendance file could not be validated. Review the mapping and retry."
validation, commit, null "validation"
True only in review with zero blocked and review rows.
true
True only while completed.
false
"2026-10-20T12:00:00Z"
"2026-10-20T12:05:00Z"
"Imported the incorrect workbook."
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
curl --request POST \
--url https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"reason": "Imported the incorrect workbook."
}
'import requests
url = "https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void"
payload = { "reason": "Imported the incorrect workbook." }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({reason: 'Imported the incorrect workbook.'})
};
fetch('https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reason' => 'Imported the incorrect workbook.'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void"
payload := strings.NewReader("{\n \"reason\": \"Imported the incorrect workbook.\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"reason\": \"Imported the incorrect workbook.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gratona.com/v1/admin/programs/{program_id}/participation/imports/{participation_import_id}/void")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reason\": \"Imported the incorrect workbook.\"\n}"
response = http.request(request)
puts response.read_body{
"id": 42,
"program_id": 12,
"participation_period_id": 18,
"original_filename": "attendance.xlsx",
"source_type": "xlsx",
"status": "review",
"progress": 100,
"mapping": {
"evidence_source": "official_record",
"existing_session_action": "block",
"symbols": {},
"sheets": [
{
"sheet": "Sheet1",
"header_row": 1,
"columns": {
"name": 0,
"gratona_id": 0,
"student_id": 0,
"gender": 0
},
"site": {
"fixed_id": 42,
"column": 0,
"value_map": {}
},
"cohort": {
"fixed_id": 42,
"column": 0,
"value_map": {}
},
"attendance_columns": [
{
"column": 4,
"date": "2026-10-20"
}
],
"enabled": true,
"profile_columns": {}
}
],
"external_student_id_field_key": "student_id",
"gender_field_key": "gender"
},
"inspection": [
{
"name": "Sheet1",
"suggested_header_row": 1,
"columns": [
{
"index": 0,
"letter": "A"
}
],
"sample_rows": [
{
"row_number": 2,
"values": [
"Jane Recipient"
]
}
]
}
],
"summary": {
"total_rows": 1,
"ready_rows": 1,
"review_rows": 1,
"blocked_rows": 1,
"unresolved_rows": 1,
"committed_rows": 1,
"skipped_rows": 1,
"exact_id_matches": 1,
"provisional_rows": 1,
"estimated_rows": 1,
"maximum_rows": 1
},
"validation_errors": [
{
"sheet": "Sheet1",
"row": 2,
"date": "2026-10-20",
"codes": [
"placement_conflict"
]
}
],
"error_message": "The attendance file could not be validated. Review the mapping and retry.",
"failure_stage": "validation",
"can_commit": true,
"can_void": false,
"created_at": "2026-10-20T12:00:00Z",
"completed_at": "2026-10-20T12:05:00Z",
"voided_at": "2023-11-07T05:31:56Z",
"void_reason": "Imported the incorrect workbook.",
"created_checks": [
{
"id": 120,
"scheduled_for": "2026-10-20",
"status": "submitted",
"revision": 1,
"site": {
"id": 12,
"name": "Main campus"
},
"cohort": {
"id": 12,
"name": "Main campus"
},
"counts": {
"expected": 25,
"seen": 23,
"unresolved": 2
}
}
],
"rows": {
"items": [
{
"id": 84,
"sheet": "Sheet1",
"source_row_number": 2,
"attendance_date": "2026-10-20",
"display_name": "Jane Recipient",
"gratona_id": "42",
"external_student_id": "STU-001",
"site_id": 12,
"cohort_id": 18,
"site_source_value": "Main campus",
"cohort_source_value": "Group A",
"symbol": "P",
"encounter_status": "seen",
"enrollment_confirmation": "confirmed_enrolled",
"match_type": "suggested_candidate",
"decision": "match",
"status": "review",
"entity_id": 42,
"candidates": [
{
"entity_id": 42,
"gratona_id": 42,
"display_name": "Jane Recipient",
"site_id": 12,
"cohort_id": 18,
"score": 95,
"agreed": [
"name"
],
"conflicted": [
"gender"
]
}
],
"errors": [
"placement_conflict"
],
"warnings": [
"candidate_confirmation_required"
],
"participation_session_id": 120
}
],
"total": 25,
"current_page": 1,
"per_page": 50,
"last_page": 1
},
"recipient_fields": [
{
"key": "student_id",
"label": "Student ID",
"type": "hysCustomID",
"is_title": false
}
]
}{
"message": "Unauthorized",
"status": "error"
}{
"message": "Not Found",
"status": "error"
}{
"errors": {},
"status": "error",
"message": "The given data was invalid."
}