# Organization connection

Let a Microsoft 365 administrator grant Zernio access to the organization's mailboxes once, then add mailboxes through the API without each user signing in.

A Microsoft 365 administrator approves Zernio's application permissions once. You then add the tenant's mailboxes as `microsoft` accounts, with no sign-in from their users.

## Before you start

[Admin consent](/platforms/microsoft/admin-consent) is different: it only removes the approval prompt so users can connect their own mailboxes.


- A profile, and an API key with write access to it.
- A Global Administrator, Privileged Role Administrator or Cloud Application Administrator in the tenant.

## Create the connection

```bash
curl -X POST "https://zernio.com/api/v1/connect/microsoft/org" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "profileId": "PROFILE_ID", "scopes": ["email", "calendar"], "redirectUrl": "https://example.com/org-done" }'
```

```json
{
  "data": {
    "id": "6a1f...",
    "provider": "microsoft",
    "status": "pending",
    "setup": {
      "type": "microsoft_admin_consent",
      "adminConsentUrl": "https://login.microsoftonline.com/organizations/v2.0/adminconsent?...",
      "applicationPermissions": ["User.Read.All", "Mail.ReadWrite", "Mail.Send", "Calendars.ReadWrite"]
    }
  }
}
```

## Get the administrator's consent

Send `setup.adminConsentUrl` to the administrator. They sign in, review the application permissions of **Zernio Organizations** and accept them for the organization.

Zernio Organizations is a separate Entra app from the one users sign in to, so their own connect and consent screens never change.

Microsoft then sends them to `redirectUrl` with:

- `orgConnectionId`
- `status`: `active`, `pending` (consent given but a permission is missing) or `denied`
- `tenant`, the organization's tenant id

## Limit which mailboxes Zernio can reach

Application permissions reach every mailbox in the tenant. We recommend the administrator limits them:

- **Exchange Online application access policy:** `New-ApplicationAccessPolicy -AppId <Zernio app id> -PolicyScopeGroupId <mail-enabled security group> -AccessRight RestrictAccess`.
- **RBAC for Applications** in Exchange Online, scoped to a management scope.

Mailboxes outside that scope answer `403` from Microsoft. You can also set `allowedEmails` on the connection.

## Add mailboxes

List the organization's users:

```bash
curl "https://zernio.com/api/v1/org-connections/ORG_CONNECTION_ID/users" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"
```

Add one:

```bash
curl -X POST "https://zernio.com/api/v1/org-connections/ORG_CONNECTION_ID/mailboxes" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "ana@contoso.com" }'
```

The answer is a `microsoft` account (`201`, or `200` when the address was already on the profile). Use its `_id` with every email, calendar, files and contacts endpoint.

`account.connected` fires and change notifications start.

## How it behaves

- Each mailbox counts as one connected account, like any other.
- Access lasts until an administrator removes Zernio under Enterprise applications, or you delete the connection.
- Outlook categories need `MailboxSettings.ReadWrite`, which this grant does not include: categories created on the mailbox still apply.
- `POST /v1/org-connections/{id}/verify` re-checks the consent at any time.

## If it fails

| Error | Cause | Fix |
|-------|-------|-----|
| `status=denied` on the redirect | The administrator declined or lacks the role | Ask an administrator with an app-approval role. |
| `status=pending` with `error=permissions_missing` | Consent was given before Zernio listed every permission | Open a fresh `adminConsentUrl` from `GET /v1/org-connections/{id}`. |
| `404` on add | The address is not a user in the tenant | Use an existing user's address. |
| `401` `reconnect_required` on a mailbox | Consent was withdrawn, the connection deleted, or the address left `allowedEmails` | Fix the grant, then call the endpoint again. |

## Related

- [Google organization connection](/platforms/google/organization)
- [Admin consent](/platforms/microsoft/admin-consent)
- [Limits & errors](/platforms/microsoft/reference)