This article shows how to set custom permissions for a list. This process works the same for a subsite.
Set custom permissions on a list by using the REST interface

// Change placeholder values before you run this code.
var siteUrl = 'http://server/site';
var listTitle = 'List 1';
var groupName = 'Group A';
var targetRoleDefinitionName = 'Contribute';
var groupId;
var targetRoleDefinitionId;
$(document).ready( function() {
getTargetGroupId();
});
// Get the ID of the target group.
function getTargetGroupId() {
$.ajax({
url: siteUrl + '/_api/web/sitegroups/getbyname(\'' + groupName + '\')/id',
type: 'GET',
headers: { 'accept':'application/json;odata=verbose' },
success: function(responseData) {
groupId = responseData.d.Id;
getTargetRoleDefinitionId();
},
error: errorHandler
});
}
// Get the ID of the role definition that defines the permissions
// you want to assign to the group.
function getTargetRoleDefinitionId() {
$.ajax({
url: siteUrl + '/_api/web/roledefinitions/getbyname(\''
+ targetRoleDefinitionName + '\')/id',
type: 'GET',
headers: { 'accept':'application/json;odata=verbose' },
success: function(responseData) {
targetRoleDefinitionId = responseData.d.Id;
breakRoleInheritanceOfList();
},
error: errorHandler
});
}
// Break role inheritance on the list.
function breakRoleInheritanceOfList() {
$.ajax({
url: siteUrl + '/_api/web/lists/getbytitle(\'' + listTitle
+ '\')/breakroleinheritance(true)',
type: 'POST',
headers: { 'X-RequestDigest':$('#__REQUESTDIGEST').val() },
success: deleteCurrentRoleForGroup,
error: errorHandler
});
}
// Remove the current role assignment for the group on the list.
function deleteCurrentRoleForGroup() {
$.ajax({
url: siteUrl + '/_api/web/lists/getbytitle(\'' + listTitle
+ '\')/roleassignments/getbyprincipalid(' + groupId + ')',
type: 'POST',
headers: {
'X-RequestDigest':$('#__REQUESTDIGEST').val(),
'X-HTTP-Method':'DELETE'
},
success: setNewPermissionsForGroup,
error: errorHandler
});
}
// Add the new role assignment for the group on the list.
function setNewPermissionsForGroup() {
$.ajax({
url: siteUrl + '/_api/web/lists/getbytitle(\'' + listTitle
+ '\')/roleassignments/addroleassignment(principalid='
+ groupId + ',roledefid=' + targetRoleDefinitionId + ')',
type: 'POST',
headers: { 'X-RequestDigest':$('#__REQUESTDIGEST').val() },
success: successHandler,
error: errorHandler
});
}
function successHandler() {
alert('Request succeeded.');
}
function errorHandler(xhr, ajaxOptions, thrownError) {
alert('Request failed: ' + xhr.status + '\n' + thrownError + '\n' + xhr.responseText);
}
Update to address comment:
It does not appear that you can use the AddRoleAssignment method when targeting a site in the same way you can when targeting a list. I'm not sure why that would be.
I tried to find a sample or some documentation that showed how to add a role assignment to a subsite using the REST API but I came up empty. The best I can offer is a sample that shows how to do it using the JavaScript Object Model (JSOM).
In the code snippet below the group Demo 3 Members is being given Edit permission in the subsite with the URL /sites/Demo3/TestSubSite
.
function addRoleAssignment() {
var clientContext = new SP.ClientContext("https://robwindsortest985.sharepoint.com/sites/Demo3/TestSubSite");
var web = clientContext.get_web();
var group = web.get_siteGroups().getByName("Demo 3 Members");
var roleDefinition = web.get_roleDefinitions().getByName("Edit");
var bindingCollection = SP.RoleDefinitionBindingCollection.newObject(clientContext);
bindingCollection.add(roleDefinition);
var roleAssignments = web.get_roleAssignments();
roleAssignments.add(group, bindingCollection);
clientContext.executeQueryAsync(
function(sender, args) {
alert("Role assignment added");
},
function(sender, args) {
alert(args.get_message());
}
);
}