diff --git a/canvasapi/assignment.py b/canvasapi/assignment.py
index bbc4bda..03d1b56 100644
--- a/canvasapi/assignment.py
+++ b/canvasapi/assignment.py
@@ -5,6 +5,7 @@ from six import python_2_unicode_compatible
 from canvasapi.canvas_object import CanvasObject
 from canvasapi.exceptions import RequiredFieldMissing
 from canvasapi.paginated_list import PaginatedList
+from canvasapi.progress import Progress
 from canvasapi.submission import Submission
 from canvasapi.user import UserDisplay
 from canvasapi.util import combine_kwargs, obj_or_id
@@ -144,6 +145,27 @@ class Assignment(CanvasObject):
 
         return Submission(self._requester, response_json)
 
+    def submissions_bulk_update(self, **kwargs):
+        """
+        Update the grading and comments on multiple student's assignment
+        submissions in an asynchronous job.
+
+        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/ \
+            submissions/update_grades \
+        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.bulk_update>`_
+
+        :rtype: :class:`canvasapi.progress.Progress`
+        """
+        response = self._requester.request(
+            'POST',
+            'courses/{}/assignments/{}/submissions/update_grades'.format(
+                self.course_id,
+                self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs)
+        )
+        return Progress(self._requester, response.json())
+
 
 @python_2_unicode_compatible
 class AssignmentGroup(CanvasObject):
diff --git a/canvasapi/course.py b/canvasapi/course.py
index 725506c..5a6e6aa 100644
--- a/canvasapi/course.py
+++ b/canvasapi/course.py
@@ -11,6 +11,7 @@ from canvasapi.exceptions import RequiredFieldMissing
 from canvasapi.folder import Folder
 from canvasapi.page import Page
 from canvasapi.paginated_list import PaginatedList
+from canvasapi.progress import Progress
 from canvasapi.tab import Tab
 from canvasapi.submission import Submission
 from canvasapi.upload import Uploader
@@ -2143,6 +2144,25 @@ class Course(CanvasObject):
             _kwargs=combine_kwargs(**kwargs)
         )
 
+    def submissions_bulk_update(self, **kwargs):
+        """
+        Update the grading and comments on multiple student's assignment
+        submissions in an asynchronous job.
+
+        :calls: `POST /api/v1/courses/:course_id/submissions/update_grades \
+        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.bulk_update>`_
+
+        :rtype: :class:`canvasapi.progress.Progress`
+        """
+        response = self._requester.request(
+            'POST',
+            'courses/{}/submissions/update_grades'.format(
+                self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs)
+        )
+        return Progress(self._requester, response.json())
+
 
 @python_2_unicode_compatible
 class CourseNickname(CanvasObject):
diff --git a/canvasapi/section.py b/canvasapi/section.py
index 7a9a95f..0d22736 100644
--- a/canvasapi/section.py
+++ b/canvasapi/section.py
@@ -5,6 +5,7 @@ from six import python_2_unicode_compatible
 
 from canvasapi.canvas_object import CanvasObject
 from canvasapi.paginated_list import PaginatedList
+from canvasapi.progress import Progress
 from canvasapi.submission import Submission
 from canvasapi.util import combine_kwargs, obj_or_id
 
@@ -373,3 +374,22 @@ class Section(CanvasObject):
             'user_id': user_id
         })
         return submission.mark_unread(**kwargs)
+
+    def submissions_bulk_update(self, **kwargs):
+        """
+        Update the grading and comments on multiple student's assignment
+        submissions in an asynchronous job.
+
+        :calls: `POST /api/v1/sections/:section_id/submissions/update_grades \
+        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.bulk_update>`_
+
+        :rtype: :class:`canvasapi.progress.Progress`
+        """
+        response = self._requester.request(
+            'POST',
+            'sections/{}/submissions/update_grades'.format(
+                self.id
+            ),
+            _kwargs=combine_kwargs(**kwargs)
+        )
+        return Progress(self._requester, response.json())

Wrap “Grade or comment on multiple submissions” methods
The Canvas REST API offers [a suite of "Grade or comment on multiple submissions" methods](https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.bulk_update) that `canvasapi` 0.9.0 does not yet wrap. I recently had cause to use one of these methods, so proper `canvasapi` versions would be appreciated.

In my particular case I need to update grades for multiple assignments by multiple students. That presumably makes the `POST /api/v1/courses/:course_id/submissions/update_grades` entry point the right thing to use, although it is not clear to me whether one can indeed update multiple assignments for multiple students all in a single call.
diff --git a/tests/fixtures/assignment.json b/tests/fixtures/assignment.json
index 47f38b6..aec1393 100644
--- a/tests/fixtures/assignment.json
+++ b/tests/fixtures/assignment.json
@@ -84,5 +84,22 @@
 			"submission_type": "online_upload"
 		},
 		"status_code": 200
+	},
+	"update_submissions": {
+		"method": "POST",
+		"endpoint": "courses/1/assignments/1/submissions/update_grades",
+		"data": {
+			"id": 3,
+			"context_id": 1,
+			"context_type": "Course",
+			"user_id": null,
+			"tag": "submissions_update",
+			"completion": null,
+			"workflow_state": "queued",
+			"updated_at": "2013-01-15T15:04:00Z",
+			"message": null,
+			"url": "https://canvas.example.edu/api/v1/progress/3"
+		},
+		"status_code": 200
 	}
 }
diff --git a/tests/fixtures/course.json b/tests/fixtures/course.json
index 2f30d67..9f1f08e 100644
--- a/tests/fixtures/course.json
+++ b/tests/fixtures/course.json
@@ -1458,5 +1458,22 @@
 			}
 		],
 		"status_code": 200
+	},
+	"update_submissions": {
+		"method": "POST",
+		"endpoint": "courses/1/submissions/update_grades",
+		"data": {
+			"id": 3,
+			"context_id": 1,
+			"context_type": "Course",
+			"user_id": null,
+			"tag": "submissions_update",
+			"completion": null,
+			"workflow_state": "queued",
+			"updated_at": "2013-01-15T15:04:00Z",
+			"message": null,
+			"url": "https://canvas.example.edu/api/v1/progress/3"
+		},
+		"status_code": 200
 	}
 }
diff --git a/tests/fixtures/progress.json b/tests/fixtures/progress.json
index 8642747..3be42a0 100644
--- a/tests/fixtures/progress.json
+++ b/tests/fixtures/progress.json
@@ -16,5 +16,21 @@
 			"url": "https://canvas.example.edu/api/v1/progress/1"
 		},
 		"status_code": 200
+	},
+	"course_progress": {
+		"method": "GET",
+		"endpoint": "progress/3",
+		"data":{
+			"id": 3,
+			"context_id": 1,
+			"context_type": "Course",
+			"user_id": null,
+			"tag": "submissions_update",
+			"completion": 100,
+			"workflow_state": "completed",
+			"updated_at": "2013-01-15T15:04:00Z",
+			"message": null,
+			"url": "https://canvas.example.edu/api/v1/progress/3"
+		}
 	}
-}
\ No newline at end of file
+}
diff --git a/tests/fixtures/section.json b/tests/fixtures/section.json
index 19c860b..c4caecb 100644
--- a/tests/fixtures/section.json
+++ b/tests/fixtures/section.json
@@ -182,5 +182,22 @@
 		"method": "DELETE",
 		"endpoint": "sections/1/assignments/1/submissions/1/read",
 		"status_code": 204
+	},
+	"update_submissions": {
+		"method": "POST",
+		"endpoint": "sections/1/submissions/update_grades",
+		"data": {
+			"id": 3,
+			"context_id": 1,
+			"context_type": "Course",
+			"user_id": null,
+			"tag": "submissions_update",
+			"completion": null,
+			"workflow_state": "queued",
+			"updated_at": "2013-01-15T15:04:00Z",
+			"message": null,
+			"url": "https://canvas.example.edu/api/v1/progress/3"
+		},
+		"status_code": 200
 	}
 }
diff --git a/tests/test_assignment.py b/tests/test_assignment.py
index e0adc34..e5fec7c 100644
--- a/tests/test_assignment.py
+++ b/tests/test_assignment.py
@@ -6,6 +6,7 @@ import requests_mock
 from canvasapi import Canvas
 from canvasapi.assignment import Assignment, AssignmentGroup
 from canvasapi.exceptions import RequiredFieldMissing
+from canvasapi.progress import Progress
 from canvasapi.submission import Submission
 from canvasapi.user import UserDisplay
 from tests import settings
@@ -101,6 +102,23 @@ class TestAssignment(unittest.TestCase):
         string = str(self.assignment)
         self.assertIsInstance(string, str)
 
+    # submissions_bulk_update()
+    def test_submissions_bulk_update(self, m):
+        register_uris({'assignment': ['update_submissions']}, m)
+        register_uris({'progress': ['course_progress']}, m)
+        progress = self.assignment.submissions_bulk_update(grade_data={
+            '1': {
+                'posted_grade': 97
+             },
+            '2': {
+                'posted_grade': 98
+            }
+        })
+        self.assertIsInstance(progress, Progress)
+        self.assertTrue(progress.context_type == "Course")
+        progress = progress.query()
+        self.assertTrue(progress.context_type == "Course")
+
 
 @requests_mock.Mocker()
 class TestAssignmentGroup(unittest.TestCase):
diff --git a/tests/test_course.py b/tests/test_course.py
index e6e728d..48053dc 100644
--- a/tests/test_course.py
+++ b/tests/test_course.py
@@ -22,6 +22,7 @@ from canvasapi.folder import Folder
 from canvasapi.group import Group, GroupCategory
 from canvasapi.module import Module
 from canvasapi.outcome import OutcomeGroup, OutcomeLink
+from canvasapi.progress import Progress
 from canvasapi.quiz import Quiz
 from canvasapi.rubric import Rubric
 from canvasapi.section import Section
@@ -1387,6 +1388,25 @@ class TestCourse(unittest.TestCase):
         self.assertEqual(migration_systems[1].requires_file_upload, False)
         self.assertEqual(migration_systems[1].name, "Dummy Importer 02")
 
+    # submissions_bulk_update()
+    def test_submissions_bulk_update(self, m):
+        register_uris({'course': ['update_submissions']}, m)
+        register_uris({'progress': ['course_progress']}, m)
+        progress = self.course.submissions_bulk_update(grade_data={
+            '1': {
+                '1': {
+                    'posted_grade': 97
+                },
+                '2': {
+                    'posted_grade': 98
+                }
+            }
+        })
+        self.assertIsInstance(progress, Progress)
+        self.assertTrue(progress.context_type == "Course")
+        progress = progress.query()
+        self.assertTrue(progress.context_type == "Course")
+
 
 @requests_mock.Mocker()
 class TestCourseNickname(unittest.TestCase):
diff --git a/tests/test_section.py b/tests/test_section.py
index 92b500c..eef7694 100644
--- a/tests/test_section.py
+++ b/tests/test_section.py
@@ -8,6 +8,7 @@ from six import text_type
 from canvasapi import Canvas
 from canvasapi.enrollment import Enrollment
 from canvasapi.exceptions import RequiredFieldMissing
+from canvasapi.progress import Progress
 from canvasapi.section import Section
 from canvasapi.submission import Submission
 from tests import settings
@@ -319,3 +320,21 @@ class TestSection(unittest.TestCase):
 
             self.assertEqual(len(warning_list), 1)
             self.assertEqual(warning_list[-1].category, DeprecationWarning)
+
+    def test_submissions_bulk_update(self, m):
+        register_uris({'section': ['update_submissions']}, m)
+        register_uris({'progress': ['course_progress']}, m)
+        progress = self.section.submissions_bulk_update(grade_data={
+            '1': {
+                '1': {
+                    'posted_grade': 97
+                },
+                '2': {
+                    'posted_grade': 98
+                }
+            }
+        })
+        self.assertIsInstance(progress, Progress)
+        self.assertTrue(progress.context_type == "Course")
+        progress = progress.query()
+        self.assertTrue(progress.context_type == "Course")

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-xdist pytest-mock pytest-asyncio requests_mock
apt-get update apt-get install -y gcc
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
-e git+https://github.com/ucfopen/canvasapi.git@6030f6bcb9de01c536617f4832caf51473195260#egg=canvasapi
certifi==2025.1.31
charset-normalizer==3.4.1
coverage==7.8.0
exceptiongroup==1.2.2
execnet==2.1.1
idna==3.10
iniconfig==2.1.0
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
pytest-asyncio==0.26.0
pytest-cov==6.0.0
pytest-mock==3.14.0
pytest-xdist==3.6.1
pytz==2025.2
requests==2.32.3
requests-mock==1.12.1
six==1.17.0
tomli==2.2.1
typing_extensions==4.13.0
urllib3==2.3.0

name: canvasapi
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - coverage==7.8.0
      - exceptiongroup==1.2.2
      - execnet==2.1.1
      - idna==3.10
      - iniconfig==2.1.0
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-asyncio==0.26.0
      - pytest-cov==6.0.0
      - pytest-mock==3.14.0
      - pytest-xdist==3.6.1
      - pytz==2025.2
      - requests==2.32.3
      - requests-mock==1.12.1
      - six==1.17.0
      - tomli==2.2.1
      - typing-extensions==4.13.0
      - urllib3==2.3.0
prefix: /opt/conda/envs/canvasapi

tests/test_assignment.py::TestAssignment::test_submissions_bulk_update tests/test_course.py::TestCourse::test_submissions_bulk_update tests/test_section.py::TestSection::test_submissions_bulk_update
tests/test_course.py::TestCourse::test_get_submission tests/test_course.py::TestCourse::test_list_assignment_groups tests/test_course.py::TestCourse::test_list_external_feeds tests/test_course.py::TestCourse::test_list_files tests/test_course.py::TestCourse::test_list_folders tests/test_course.py::TestCourse::test_list_gradeable_students tests/test_course.py::TestCourse::test_list_group_categories tests/test_course.py::TestCourse::test_list_groups tests/test_course.py::TestCourse::test_list_multiple_submissions tests/test_course.py::TestCourse::test_list_rubrics tests/test_course.py::TestCourse::test_list_sections tests/test_course.py::TestCourse::test_list_submissions tests/test_course.py::TestCourse::test_list_tabs tests/test_course.py::TestCourse::test_mark_submission_as_read tests/test_course.py::TestCourse::test_mark_submission_as_unread tests/test_course.py::TestCourse::test_submit_assignment tests/test_course.py::TestCourse::test_submit_assignment_fail tests/test_course.py::TestCourse::test_update_submission tests/test_course.py::TestCourse::test_update_tab tests/test_section.py::TestSection::test_get_submission tests/test_section.py::TestSection::test_list_multiple_submissions tests/test_section.py::TestSection::test_list_submissions tests/test_section.py::TestSection::test_mark_submission_as_read tests/test_section.py::TestSection::test_mark_submission_as_unread tests/test_section.py::TestSection::test_subit_assignment_fail tests/test_section.py::TestSection::test_submit_assignment tests/test_section.py::TestSection::test_update_submission
tests/test_assignment.py::TestAssignment::test__str__ tests/test_assignment.py::TestAssignment::test_delete_assignments tests/test_assignment.py::TestAssignment::test_edit_assignment tests/test_assignment.py::TestAssignment::test_get_gradeable_students tests/test_assignment.py::TestAssignment::test_get_submission tests/test_assignment.py::TestAssignment::test_get_submissions tests/test_assignment.py::TestAssignment::test_submit tests/test_assignment.py::TestAssignment::test_submit_fail tests/test_assignment.py::TestAssignmentGroup::test__str__ tests/test_assignment.py::TestAssignmentGroup::test_delete_assignment_group tests/test_assignment.py::TestAssignmentGroup::test_edit_assignment_group tests/test_course.py::TestCourse::test__str__ tests/test_course.py::TestCourse::test_add_grading_standards tests/test_course.py::TestCourse::test_add_grading_standards_empty_list tests/test_course.py::TestCourse::test_add_grading_standards_missing_name_key tests/test_course.py::TestCourse::test_add_grading_standards_missing_value_key tests/test_course.py::TestCourse::test_add_grading_standards_non_dict_list tests/test_course.py::TestCourse::test_conclude tests/test_course.py::TestCourse::test_create_assignment tests/test_course.py::TestCourse::test_create_assignment_fail tests/test_course.py::TestCourse::test_create_assignment_group tests/test_course.py::TestCourse::test_create_content_migration tests/test_course.py::TestCourse::test_create_content_migration_bad_migration_type tests/test_course.py::TestCourse::test_create_content_migration_migrator tests/test_course.py::TestCourse::test_create_course_section tests/test_course.py::TestCourse::test_create_discussion_topic tests/test_course.py::TestCourse::test_create_external_feed tests/test_course.py::TestCourse::test_create_external_tool tests/test_course.py::TestCourse::test_create_folder tests/test_course.py::TestCourse::test_create_group_category tests/test_course.py::TestCourse::test_create_module tests/test_course.py::TestCourse::test_create_module_fail tests/test_course.py::TestCourse::test_create_page tests/test_course.py::TestCourse::test_create_page_fail tests/test_course.py::TestCourse::test_create_quiz tests/test_course.py::TestCourse::test_create_quiz_fail tests/test_course.py::TestCourse::test_delete tests/test_course.py::TestCourse::test_delete_external_feed tests/test_course.py::TestCourse::test_edit_front_page tests/test_course.py::TestCourse::test_enroll_user tests/test_course.py::TestCourse::test_get_assignment tests/test_course.py::TestCourse::test_get_assignment_group tests/test_course.py::TestCourse::test_get_assignment_groups tests/test_course.py::TestCourse::test_get_assignments tests/test_course.py::TestCourse::test_get_content_migration tests/test_course.py::TestCourse::test_get_content_migrations tests/test_course.py::TestCourse::test_get_course_level_assignment_data tests/test_course.py::TestCourse::test_get_course_level_participation_data tests/test_course.py::TestCourse::test_get_course_level_student_summary_data tests/test_course.py::TestCourse::test_get_discussion_topic tests/test_course.py::TestCourse::test_get_discussion_topics tests/test_course.py::TestCourse::test_get_enrollments tests/test_course.py::TestCourse::test_get_external_feeds tests/test_course.py::TestCourse::test_get_external_tool tests/test_course.py::TestCourse::test_get_external_tools tests/test_course.py::TestCourse::test_get_file tests/test_course.py::TestCourse::test_get_files tests/test_course.py::TestCourse::test_get_folder tests/test_course.py::TestCourse::test_get_folders tests/test_course.py::TestCourse::test_get_full_discussion_topic tests/test_course.py::TestCourse::test_get_grading_standards tests/test_course.py::TestCourse::test_get_group_categories tests/test_course.py::TestCourse::test_get_groups tests/test_course.py::TestCourse::test_get_migration_systems tests/test_course.py::TestCourse::test_get_module tests/test_course.py::TestCourse::test_get_modules tests/test_course.py::TestCourse::test_get_multiple_submissions tests/test_course.py::TestCourse::test_get_multiple_submissions_grouped_param tests/test_course.py::TestCourse::test_get_outcome_group tests/test_course.py::TestCourse::test_get_outcome_groups_in_context tests/test_course.py::TestCourse::test_get_outcome_links_in_context tests/test_course.py::TestCourse::test_get_outcome_result_rollups tests/test_course.py::TestCourse::test_get_outcome_results tests/test_course.py::TestCourse::test_get_page tests/test_course.py::TestCourse::test_get_pages tests/test_course.py::TestCourse::test_get_quiz tests/test_course.py::TestCourse::test_get_quiz_fail tests/test_course.py::TestCourse::test_get_quizzes tests/test_course.py::TestCourse::test_get_recent_students tests/test_course.py::TestCourse::test_get_root_outcome_group tests/test_course.py::TestCourse::test_get_rubric tests/test_course.py::TestCourse::test_get_rubrics tests/test_course.py::TestCourse::test_get_section tests/test_course.py::TestCourse::test_get_sections tests/test_course.py::TestCourse::test_get_settings tests/test_course.py::TestCourse::test_get_single_grading_standard tests/test_course.py::TestCourse::test_get_tabs tests/test_course.py::TestCourse::test_get_user tests/test_course.py::TestCourse::test_get_user_id_type tests/test_course.py::TestCourse::test_get_user_in_a_course_level_assignment_data tests/test_course.py::TestCourse::test_get_user_in_a_course_level_messaging_data tests/test_course.py::TestCourse::test_get_user_in_a_course_level_participation_data tests/test_course.py::TestCourse::test_get_users tests/test_course.py::TestCourse::test_preview_html tests/test_course.py::TestCourse::test_reorder_pinned_topics tests/test_course.py::TestCourse::test_reorder_pinned_topics_comma_separated_string tests/test_course.py::TestCourse::test_reorder_pinned_topics_invalid_input tests/test_course.py::TestCourse::test_reorder_pinned_topics_tuple tests/test_course.py::TestCourse::test_reset tests/test_course.py::TestCourse::test_show_front_page tests/test_course.py::TestCourse::test_update tests/test_course.py::TestCourse::test_update_settings tests/test_course.py::TestCourse::test_upload tests/test_course.py::TestCourseNickname::test__str__ tests/test_course.py::TestCourseNickname::test_remove tests/test_section.py::TestSection::test__str__ tests/test_section.py::TestSection::test_cross_list_section tests/test_section.py::TestSection::test_decross_list_section tests/test_section.py::TestSection::test_delete tests/test_section.py::TestSection::test_edit tests/test_section.py::TestSection::test_get_enrollments tests/test_section.py::TestSection::test_get_multiple_submissions tests/test_section.py::TestSection::test_get_multiple_submissions_grouped_param
canvasapi/course.py canvasapi/section.py canvasapi/assignment.py
canvasapi/course.py canvasapi/section.py canvasapi/assignment.py