Call the API as an application
An application can call the EasyLife 365 Collaboration API on its own, with no signed-in user. This is how a scheduled script, a function app or a workflow reads your governance data, changes templates and policies, or creates SharePoint sites and guests.
This page is the starting point. It lists every route an application can call, the role each route needs, how to get a token and what to expect when a call fails. Each route has its own page with the payloads.
How it works
- Register an app in Microsoft Entra ID and give it a secret or a certificate. See Create Application Registration.
- Grant a role to the app and give admin consent. A role is a permission of the application itself. The right role depends on what the app does (see Roles).
- Ask Entra for a token with the client credentials flow and send it as a bearer token.
A token of an application carries the role in its roles claim and has no scp claim. A token of a signed-in administrator carries a scope instead. Both kinds of token work on the same routes. The delegated scope is unchanged, so nothing changes for people who use the Admin Portal or call the API with their own sign-in.
Only the versioned routes (the ones with /v1/ in the path) accept an application role. Every other route answers 403 to an application token. Archiving, unarchiving and owner management of groups and sites have no versioned route yet, so they stay available to signed-in administrators only.
Roles
All roles are Application permissions. Admin consent is always required. A role is never inherited: a role of one product does not work in another product, a read role never writes and a create role never reads.
Roles of the EasyLife 365 Admin application
Select EasyLife 365 Admin when you add these roles. They work on the routes under /admin/.
| Role | What it allows |
|---|---|
Collab.Manage.ReadWrite.All | Read and change groups, guests, OneDrive accounts, SharePoint sites and dropdown field values. Delete groups. Read several groups at once. |
Collab.Manage.Read.All | Read a group, a guest, a OneDrive account and a SharePoint site. Nothing else. A change, a delete or the read of several groups answers 403. |
Roles of the EasyLife 365 Collaboration application
Select EasyLife 365 Collaboration when you add these roles. They work on the routes under /collab/.
| Role | What it allows |
|---|---|
Collab.Site.Provisioning.ReadWrite.All | Create SharePoint sites. |
Collab.Guest.Provisioning.ReadWrite.All | Invite guests. |
Collab.Provisioning.ReadWrite.All | Create SharePoint sites and invite guests. |
An application cannot create groups or Teams yet. If an application should stay limited to sites or to guests, give it the narrower role.
Grant a role
- Open the Microsoft Entra admin center and go to App registrations. Select your app.
- Select API permissions, then Add a permission, then APIs my organization uses.
- Search for EasyLife and select the application from the tables above.
- Select Application permissions and pick the role.
- Select Add permissions, then Grant admin consent.
Without admin consent the role has no effect and the API refuses the token.
Get a token
A certificate is the better credential for an application. If you use a client secret, keep it in a secret store or an environment variable, never in a script or in source control, and rotate it before it expires.
Ask the Microsoft identity platform for a token. The scope is the application ID URI of the API you want to call, followed by /.default.
| API | Scope for the token |
|---|---|
Manage routes (/admin/...) | https://api.easylife365.cloud/admin/.default |
Create routes (/collab/...) | https://api.easylife365.cloud/collab/.default |
curl -X POST "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" \
-d "client_id=<client-id>" \
--data-urlencode "client_secret=$CLIENT_SECRET" \
-d "grant_type=client_credentials" \
-d "scope=https://api.easylife365.cloud/admin/.default"
$tokenResponse = Invoke-RestMethod -Method Post `
-Uri "https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/token" `
-Body @{
client_id = "<client-id>"
client_secret = $env:CLIENT_SECRET
grant_type = "client_credentials"
scope = "https://api.easylife365.cloud/admin/.default"
}
$accessToken = $tokenResponse.access_token
The answer holds an access_token. Send it with every call:
Authorization: Bearer <access-token>
A token is valid for about an hour. Ask for a new one when it runs out. Do not ask for a token for every call.
Routes an application can call
Each route accepts the delegated scope of a signed-in administrator and the application roles in the table. The delegated scope for the manage routes and the field route is Config.ReadWrite.All. For the create routes it is App.ReadWrite.All.
The rate limit class says how often you can call: Read is 10 calls per 10 seconds, Create, update, delete is 4 calls per 10 seconds and Bulk is 20 calls per 2 seconds. The limit applies per caller and route. A call over the limit answers 429.
| Method | Route | What it does | Delegated scope | Application roles | Rate limit | Response codes |
|---|---|---|---|---|---|---|
| GET | /admin/collab/v1/manage/groups/{group-id}/ | Reads a group with its template and policy | Config.ReadWrite.All | Collab.Manage.Read.All, Collab.Manage.ReadWrite.All | Read | 200, 401, 403, 404, 429 |
| POST | /admin/collab/v1/manage/groups/batch/ | Reads several groups | Config.ReadWrite.All | Collab.Manage.ReadWrite.All | Read | 200, 400, 401, 403, 429 |
| PATCH | /admin/collab/v1/manage/groups/{group-id}/ | Changes the template and the policy of a group | Config.ReadWrite.All | Collab.Manage.ReadWrite.All | Create, update, delete | 200, 400, 401, 403, 404, 429 |
| DELETE | /admin/collab/v1/manage/groups/{group-id}/ | Deletes a group | Config.ReadWrite.All | Collab.Manage.ReadWrite.All | Create, update, delete | 200, 400, 401, 403, 404, 429 |
| GET | /admin/collab/v1/manage/guests/{guest-id}/ | Reads a guest with its template and policy | Config.ReadWrite.All | Collab.Manage.Read.All, Collab.Manage.ReadWrite.All | Read | 200, 400, 401, 403, 404, 429 |
| PATCH | /admin/collab/v1/manage/guests/{guest-id}/ | Changes the template, the policy and the owners of a guest | Config.ReadWrite.All | Collab.Manage.ReadWrite.All | Bulk | 200, 400, 401, 403, 404, 429 |
| GET | /admin/collab/v1/manage/onedrive/{user-id}/ | Reads a OneDrive account with its policy | Config.ReadWrite.All | Collab.Manage.Read.All, Collab.Manage.ReadWrite.All | Read | 200, 400, 401, 403, 404, 429 |
| PATCH | /admin/collab/v1/manage/onedrive/{user-id}/ | Changes the policy of a OneDrive account | Config.ReadWrite.All | Collab.Manage.ReadWrite.All | Bulk | 200, 400, 401, 403, 404, 429 |
| GET | /admin/collab/v1/manage/spo/{group-id}/ | Reads a SharePoint site with its template and policy | Config.ReadWrite.All | Collab.Manage.Read.All, Collab.Manage.ReadWrite.All | Read | 200, 401, 403, 404, 429 |
| PATCH | /admin/collab/v1/manage/spo/{group-id}/ | Changes the template and the policy of a SharePoint site | Config.ReadWrite.All | Collab.Manage.ReadWrite.All | Create, update, delete | 200, 400, 401, 403, 404, 429 |
| PATCH | /admin/v1/fields/select/{field-name}/ | Updates the values of a dropdown field | Config.ReadWrite.All | Collab.Manage.ReadWrite.All | Create, update, delete | 204, 400, 401, 403, 404, 429 |
| POST | /collab/v1/spo/ | Creates a SharePoint site from a template | App.ReadWrite.All | Collab.Site.Provisioning.ReadWrite.All, Collab.Provisioning.ReadWrite.All | Create, update, delete | 200, 400, 401, 403, 404, 429 |
| POST | /collab/v1/guests/ | Invites a guest from a template | App.ReadWrite.All | Collab.Guest.Provisioning.ReadWrite.All, Collab.Provisioning.ReadWrite.All | Create, update, delete | 200, 400, 401, 403, 404, 409, 429 |
The routes of a group, a guest, a OneDrive account and a site are described on Manage groups, Manage guests, Manage OneDrive accounts and Manage SharePoint sites. Dropdown values are on Update DropDowns. Creating sites and inviting guests are on New SharePoint site and Invite Guest.
What a read returns
A read of a group, a guest, a OneDrive account or a SharePoint site answers with the same core members, and so does a successful change:
{
"id": "57523d68-2913-4fc0-8f91-af100f37562f",
"displayName": "Project Aurora",
"isCompliant": true,
"metadata": { },
"policy": { },
"schema": { }
}
idanddisplayNameare always there. The other members are left out when the resource has nothing stored for them. They are nevernull.isComplianttells whether the resource met its policy at the last check. It can lag behind a policy change until the next check runs.metadata,policyandschemaare the data EasyLife 365 stores on the resource, returned as stored. The names inside them are short and can change, be added or be removed in any release. Read only the names you need and ignore the rest. The template and the policy of a resource are inside them.policyis the policy that is set on the resource. It is not the policy that would apply to a resource that has none.
To protect personal data, these members leave out the people behind an action: who started an access review or took an owner action, the owners of a guest or a OneDrive account, and the values of the dashboard filters. A guest or OneDrive account name is returned as displayName, so treat the answer as personal data.
A change (PATCH) answers with the changed resource. It keeps every member it had before and adds isCompliant and schema. The read of a group keeps its existing members too and adds the four members above.
Change a template or a policy
A PATCH names only what changes. A member you leave out stays as it is. To clear a template or a policy, send the empty ID 00000000-0000-0000-0000-000000000000.
An ID that names nothing, an inactive template or a template or policy that does not fit the resource is refused before anything is saved. The resource stays as it was.
Create a SharePoint site or invite a guest
An application has no signed-in user, so the request says who is involved:
- At least one owner is required. For a site, send
owners. For a guest, send at least one ofprimaryOwnertoquinaryOwner. The owners must be members of your tenant, not guests. The application itself never becomes an owner. - The requestor is optional, unless the template has an approval. The requestor is the person the request is for. Send
requestorIdfor a site andrequestor.idfor a guest. When the template needs an approval and you leave it out, the call answers400with the codeCollab.RequestorRequired. A requestor you name becomes an owner of the site. - If you name no requestor, the first owner you name stands in. That person becomes a site owner and gets the "your site is ready" mail. For a guest, the primary owner (the first owner you name, if you name no primary owner) appears as the sender of the invitation.
- Sites and guests follow the same template, naming rules and approvals as in the Admin Portal.
Errors
A failed call answers with application/problem+json. Every answer has the same four members you can rely on. The type member is a stable identifier for the kind of error, not a link to a page.
| Member | Meaning |
|---|---|
code | A stable code for the kind of error. Use it in your code. |
title | A short sentence in English for the code. |
detail | More about this call, when there is more to say. |
requestId | The ID of the call. Give it to support when you ask for help. It is not the requestId that a create call returns for the new site or guest. |
{
"type": "https://docs.easylife365.cloud/errors/collab/template-not-found",
"title": "The template does not exist.",
"status": 404,
"detail": "Template with Id 3b20926e-8ff5-4d8a-b0c6-ddd765df6821 does not exist",
"code": "Collab.TemplateNotFound",
"requestId": "0HNG2K4V7QJ3D:00000002"
}
| Status | Code | When |
|---|---|---|
| 400 | InvalidPayload | The body or an ID in the route is missing or not valid. |
| 400 | Collab.TemplateNotActive | The template is not active. |
| 400 | Collab.TemplateNotApplicable | The template is for another type of resource. |
| 400 | Collab.PolicyNotApplicable | The policy is for another type of resource. |
| 400 | Collab.OwnersNotSet | A create call names no owner. |
| 400 | Collab.OwnersNotInDirectory | An owner does not exist in your tenant. |
| 400 | Collab.OwnerNotAssignable | The person cannot be an owner, for example a guest account. |
| 400 | Collab.RequestorRequired | The template has an approval and the call names no requestor. |
| 400 | Collab.RequestorNotFound | The requestor does not exist in your tenant. |
| 400 | Collab.GroupNotUnified | The group is not a Microsoft 365 group. |
| 400 | Collab.ValidationFailed | A change to a group or site names owners, which this call does not change. |
| 400 | Collab.SiteNotManaged | The group is not a SharePoint site managed by EasyLife 365. |
| 400 | Collab.RequestFailed | The change could not be processed. |
| 400 | Collab.DescriptionRequired | The template requires a description. |
| 400 | Collab.MailAddressInvalid | The email address of a guest is missing or not valid. |
| 401 | AuthenticationRequired | The token is missing, expired or not valid. |
| 403 | NotAllowed | The token has no role for this route, or the route does not accept application tokens. |
| 404 | NotFound | The resource does not exist, or it is not a resource this route manages. |
| 404 | Collab.TemplateNotFound | The template does not exist. |
| 404 | Collab.PolicyNotFound | The policy does not exist. |
| 409 | Collab.GuestInvitationAlreadyAccepted, Collab.GuestInvitedByOther | The guest already accepted, or another person already invited the guest. |
| 429 | RateLimited | Too many calls. Wait a moment and try again. |
| 500 | InfrastructureError | The call could not be completed. Send the requestId to support. |
Audit log
Creating a resource and changing a resource are recorded in the audit log in different ways. Reading leaves no entry.
Creating a resource
A creation is recorded once, when the resource exists. It works the same for people and for applications. The API writes no entry for the request itself. The entry is written when the resource is created, in the category ENGINE, and its description names the requestor with the words "created on behalf of". The calling application is not named in the entry. A request that waits for approval, or that fails, leaves no entry until the resource exists.
| Resource | Event | Category |
|---|---|---|
| Group | CREATE-GROUP | ENGINE |
| Team | CREATE-TEAM | ENGINE |
| Guest invitation | INVITE | ENGINE |
| SharePoint site | CREATE-SITE | ENGINE |
The entry of a SharePoint site has the ID of the site's group as the resource and the URL of the site as the name, like the later entries of that site (archive, policy, delete). Its description reads "Site created on behalf of" and the requestor. It covers communication sites and team sites without a Microsoft 365 group. A team site that is connected to a Microsoft 365 group is recorded by CREATE-GROUP, and by CREATE-TEAM when it is a Team.
Changing a resource
A change through the manage routes is recorded in the category ADMIN, with the old and the new value. When an application makes the call, the entry shows the application as the actor, not a person.
| Change | Event |
|---|---|
| Assign a template | ASSIGN-TEMPLATE |
| Clear a template | REMOVE-TEMPLATE |
| Assign or change a policy | ASSIGN-POLICY |
| Clear a policy | REMOVE-POLICY |
| Add an owner to a guest | ASSIGN-OWNER |
| Remove an owner from a guest | REMOVE-OWNER |
| Delete a group | DELETE |
A OneDrive account has no template, so only the two policy events apply. A call that changes nothing writes no entry.
Reading
A read leaves no audit entry.
Switch from Collab.Config.ReadWrite.All
If your application used Collab.Config.ReadWrite.All, take these steps:
- Add
Collab.Manage.ReadWrite.All(orCollab.Manage.Read.Allfor an application that only reads) on EasyLife 365 Admin and grant admin consent. - Make sure the application only calls the versioned routes in the table above.
- Remove
Collab.Config.ReadWrite.Allfrom the app.