The rest 2.1 API supports CRUD operations on the TermStore. There is an useful write-up of accessing the terms located here: https://www.c-sharpcorner.com/blogs/sharepoint-managed-metadata-services-rest-api
To avoid this being a link-only answer, I have replicated the examples below.
TermStore groups:
To list:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups
Method : GET
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
To create:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups
Method : POST
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
Body : {"name":"FromRESTAPI", "description":"Description For FromRESTAPI"}
Term Sets:
To List:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab- d7a8-479f-9888-8d4421f8218f/sets
Method : GET
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
To Create:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab-d7a8-479f-9888-8d4421f8218f/sets
Method : POST
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
Body : {"description": "","localizedNames": [{"name": "OperationLevel","languageTag": "en-US"}]}
To Update:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab-d7a8-479f-9888-8d4421f8218f/sets/dbc06a0b-7f38-42dc-84a7-0b734f350303
Method : PATCH
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
Body : {"description": "Added description","localizedNames": [{"name": "OperationLevelUpdated","languageTag": "en-US"}]}
To Delete:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab-d7a8-479f-9888-8d4421f8218f/sets/dbc06a0b-7f38-42dc-84a7-0b734f350303
Method : DELETE
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
Terms
To List:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab-d7a8-479f-9888-8d4421f8218f/sets/8ed8c9ea-7052-4c1d-a4d7-b9c10bffea6f/terms
Method : GET
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
To Create (note, isDefault must be true or it will fail):
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab-d7a8-479f-9888-8d4421f8218f/sets/8ed8c9ea-7052-4c1d-a4d7-b9c10bffea6f/children
Method : POST
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
Body : {"labels": [{"name": "AI","isDefault":true,"languageTag": "en-US"}],"descriptions": [{"description": "AI Innovation","languageTag": "en-US"}]}
To Update (I haven't used this):
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab-d7a8-479f-9888-8d4421f8218f/sets/8ed8c9ea-7052-4c1d-a4d7-b9c10bffea6f/terms/b8b3e828-cdf7-46b2-889e-f5f797a05aa3
Method : PATCH
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
Body : {"labels": [{"name": "AI Updated","isDefault":true,"languageTag": "en-US"}],"descriptions": [{"description": "AI Innovation Updated","languageTag": "en-US"}]}
To Delete:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab-d7a8-479f-9888-8d4421f8218f/sets/8ed8c9ea-7052-4c1d-a4d7-b9c10bffea6f/terms/b8b3e828-cdf7-46b2-889e-f5f797a05aa3
Method : DELETE
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
Nested Terms (my minor contribution)
To List:
Endpoint : https://testinglala.sharepoint.com/_api/v2.1/termStore/groups/122d92ab-d7a8-479f-9888-8d4421f8218f/sets/8ed8c9ea-7052-4c1d-a4d7-b9c10bffea6f/terms/12345678-1234-1234-1234-123456789012/children
Method : GET
Headers : {"Content-Type": "application/json",
"Authorization": "Bearer <Bearer Token>"}
I haven't yet created, updated, or deleted a nested term. I'll update this answer if I do.