Skip to content
requestany language
GET /exchange/v1.0/mailboxes
    ?$filter=RecipientTypeDetails eq 'SharedMailbox'
    &$select=DisplayName,PrimarySmtpAddress&$top=3
Authorization: Bearer eyJ0eXAiOiJKV1Qi...
response200 OK
{
  "@odata.context": ".../$metadata#mailboxes(DisplayName,PrimarySmtpAddress)",
  "value": [
    { "DisplayName": "Finance", "PrimarySmtpAddress": "[email protected]" },
    { "DisplayName": "Front desk", "PrimarySmtpAddress": "[email protected]" },
    { "DisplayName": "Support", "PrimarySmtpAddress": "[email protected]" }
  ]
}

exonaut

Early access

the unofficial REST API for Exchange Online

A Microsoft-Graph-shaped REST and OData v4 API in .NET 10 that fronts the Exchange Online PowerShell cmdlet surface with typed JSON. Self-hosted in your own tenant, callable from any language.

See it work

One minute, captions only: a REST client lists shared mailboxes, previews a change with dryRun, then applies it. Mock tenant, real routes.

Watch the film

Why it exists

The problem

Nearly everything about your organisation's email system is administered from one place: a PowerShell terminal, one cryptic command at a time. That suits an expert at the keyboard and nothing else. A phone app, a company portal or an automated assistant cannot type at a terminal; they speak plain, labelled requests over HTTPS.

Microsoft Graph covers a slice of this, mostly mail content and a handful of settings. The bulk of day-to-day Exchange Online administration still lives only at that terminal.

What exonaut does

exonaut is the self-service counter in front of that terminal. Any app, in any language, sends a plain web request; behind the scenes the service runs the right cmdlets, cleans up the output and returns a tidy, predictable result. The app never has to know PowerShell exists.

You host it yourself, and it signs into Exchange Online with credentials you control, secret-free in production.

Before: an expert admin types commands at a PowerShell terminal and apps cannot. After: any app sends a web request to exonaut, which runs the commands and returns clean JSON.Before: an expert admin types commands at a PowerShell terminal and apps cannot. After: any app sends a web request to exonaut, which runs the commands and returns clean JSON.
Read the overview

What it lets you do

One web request each, typed JSON back.

Look things up

Show me all the shared mailboxes. Who is in the Sales group. Where did this message go.

Make changes

Create a distribution group, add a member, set an out-of-office, change a retention policy, recover a deleted mailbox.

Build on top of it

Clean, stable data powers a help-desk tool, an internal portal, an onboarding automation or a chatbot, with no PowerShell embedded in any of them.

How it works

The baseline is the Exchange Online cmdlet surface: it decides what can be done and which fields exist, and nothing is invented beyond it. The shape is Microsoft Graph: entity sets, OData query options, a $metadata document, $ref for relationships and a paginated collection envelope. Graph-style where Graph has the concept, cmdlet-aligned where it does not.

readwho has access to a mailbox
GET /exchange/v1.0/mailboxes/[email protected]/permissions
Authorization: Bearer ...

200 OK: one entry per access control entry, typed and paged
writeGraph URL, cmdlet body
POST /exchange/v1.0/distributionGroups/[email protected]/members/$ref
Content-Type: application/json

{ "member": "[email protected]" }

204 No Content: Add-DistributionGroupMember -Member [email protected]
Sequence of one request: the caller sends a GET with a bearer token; Entra JWT auth validates it and checks the route's role; the OData controller translates $filter to OPATH and picks the cmdlet; the executor borrows a warm runspace from the pool; Exchange Online returns PowerShell objects; the mapper turns them into typed JSON and the caller gets 200 OK with a paging link.Sequence of one request: the caller sends a GET with a bearer token; Entra JWT auth validates it and checks the route's role; the OData controller translates $filter to OPATH and picks the cmdlet; the executor borrows a warm runspace from the pool; Exchange Online returns PowerShell objects; the mapper turns them into typed JSON and the caller gets 200 OK with a paging link.
Read the API guide

What is covered today

Counted from the API's own manifests when this site was built. The coverage page breaks the numbers down by tier.

live entity sets
124
documented routes
601
cmdlets behind them
476
narrow roles
30

The Explorer

A Graph-Explorer-style web UI ships with the API: delegated sign-in, a sidebar reflected from the live catalog, path and $filter autocomplete, body-field chips reflected from the schemas, a JSON viewer and a Reference mode with per-endpoint documentation and curated examples. New endpoints appear by themselves.

The Explorer's Try mode: a request builder with the verb and URL, query and body chips, and the JSON response below.
Try: build a request from the verb, the URL and the reflected query and body chips, then read the live JSON response.
The Explorer's Reference mode: the routes of one entity with their roles, backing cmdlets, parameters and examples.
Reference: every route under an entity with its roles, backing cmdlets, parameters and curated examples.
The Explorer's Coverage matrix: Exchange and Security and Compliance cmdlets cross-referenced against the catalog, the routes and the allowlist.
Coverage: the Exchange and Security and Compliance cmdlets cross-referenced against the catalog, the routes and the allowlist.
About the Explorer

Built to be safe

Every request proves who it is, and a caller can do only the specific things it was granted.

  • Entra sign-in that fails closed Bearer tokens are validated for issuer, audience and signature; no token means 401, and production refuses to start without its identity configuration. The service itself signs into Exchange Online secret-free, with tokens held in memory only.
  • 30 narrow permissions Read and read-write roles, roughly one per persona, instead of one all-powerful key. Every write carries a read-write role.
  • A cmdlet allowlist at the seam Every cmdlet is checked against a hard allowlist before PowerShell runs. There is no arbitrary-cmdlet endpoint.
  • No injection surface Write bodies and the $filter translation bind as structured parameters, never as interpolated script.
  • dryRun that is really dry A preview never runs the real operation. A cmdlet whose preview mode is a no-op answers 422 before anything executes.
Read the security model

Plans

Reads and dryRun previews are free on every plan, with no key at all. Writes are gated by an offline license key you configure on your own host; no key means Community. Pricing is announced at launch.

What each plan covers
CapabilityCommunityProEnterprise
Reads and ?dryRun=true previewsyesyesyes
Per-object writes (mailbox, group, contact, device, folder, migration user) plus mail flownoyesyes
Tenant-wide and security writes (compliance, org config, RBAC, threat policy, Purview)nonoyes
MCP server for agents (planned, v1.2.0)noyesyes
PricingAnnounced at launch
Compare the plans

Join the early access waitlist

Tell us about your tenant and what you would automate first. We write to you about early access, the launch and the pricing, and for nothing else.