Integrations
Microsoft Graph SDK: get started
Microsoft Graph mail, calendar and user APIs through typed application or agent clients
Use an ordinary App, or an Agent when the workload needs agent identity. Alter builds provider requests from a reviewed contract and applies the same connection authorization, policy, approvals, and audit records as raw requests.
Install
Section titled “Install”npm install @alter-ai/sdk @alter-ai/microsoft# Python (installs core automatically)pip install alter-sdk-microsoftThe provider package includes only Microsoft Graph types and response schemas and pins its contract version.
Connect and call
Section titled “Connect and call”Configure Microsoft Graph, request the scopes the application needs, and retain each customer’s grant ID after Connect consent. Alter supplies the credential; it never belongs in operation input.
import { App } from "@alter-ai/sdk";import { MicrosoftIntegration } from "@alter-ai/microsoft";const app = new App({ apiKey: process.env.ALTER_API_KEY! });try { const client = new MicrosoftIntegration(app, { grantId: process.env.MICROSOFT_GRANT_ID! }); const result = await (await client.meUser.getUser({})).wait(); console.log(result.bodyJson());} finally { await app.close();}from alter_sdk import Appfrom alter_sdk_microsoft import MicrosoftIntegration
async def first_call(api_key: str, grant_id: str): async with App(api_key=api_key) as app: client = MicrosoftIntegration(app, {"grant_id": grant_id}) call = await client.me_user.get_user({}) result = await call.wait() return result.body_json()Complete versioned contract
Section titled “Complete versioned contract”Contract 2026-10-28 contains the 617 mail, calendar and user operations of Microsoft Graph’s official v1.0 OpenAPI document: every path under /me and /users/{user-id} for messages, mail folders, sending mail, calendars, calendar groups, calendar views and events, and the user resource itself. Files and Teams are not part of this contract. The API reference links every operation to its complete input fields, response models, TypeScript and Python examples, and policy identity. Browse by resource under this provider’s API reference in the Integrations sidebar, or read the native OpenAPI specification for these areas. The Developer Portal provider view and alter integrations operations microsoft --version 2026-10-28 also expose the schemas.
Generated calls pin the Alter contract version. Microsoft Graph’s own product, role, scope and subscription requirements still apply. There is no silent version fallback and no automatic write retry.
Paging and delta rounds
Section titled “Paging and delta rounds”Calls do not follow pages on their own. Graph returns a page of a collection with @odata.nextLink, and a delta round with @odata.nextLink until its last page, which carries @odata.deltaLink. To read the next page, call the same operation again with the $skiptoken value from @odata.nextLink in query; to start the next delta round, pass the $deltatoken value from @odata.deltaLink. Every list operation accepts $skiptoken, and every delta operation also accepts $deltatoken.
const page = (await (await client.meMessage.listMessages({ query: { $top: 50 } })).wait()).bodyJson();const next = page["@odata.nextLink"];if (next) { const skiptoken = new URL(next).searchParams.get("$skiptoken")!; await (await client.meMessage.listMessages({ query: { $top: 50, $skiptoken: skiptoken } })).wait();}alter integrations execute microsoft microsoft.me_user_getuser \ --version 2026-10-28 --grant "$MICROSOFT_GRANT_ID" --input '{}' --waitArguments use native path, query, headers, and body containers. Array query parameters are sent the way the provider’s document declares them: one delimited value where it declares explode: false (or a pipe- or space-delimited style), repeated keys otherwise. SDK methods preserve provider field names, decimal lexemes and large integers as strings when necessary. HTTP 204 returns null / None from the typed decoder. Binary responses use bodyBytes() / body_bytes(); the CLI can save them with --output-file.
Approvals
Section titled “Approvals”A policy rule can require approval for any operation. The call returns a pending approval; wait() resolves once the approver decides. Approval cards show the operation, its contract version and the request input the sensitivity review marked safe to display.
Resume after a restart
Section titled “Resume after a restart”Persist call.approvalId (TypeScript) or call.approval_id (Python), then construct a fresh provider client and call resume(savedId), followed by wait(). The stored approval selects the operation; this installed package verifies its provider and contract version before attaching the response validator. Mismatches raise ManagedOperationError, never silently decode using another contract. See persist-and-resume examples.
Message content and attachments
Section titled “Message content and attachments”Six operations replace a message’s whole MIME content (PUT .../messages/{message-id}/$value, three under /me and three under /users/{user-id}). Their body is opaque bytes that Alter cannot classify, so it cannot find the sensitive values to mask: an approval rule on them is refused with sensitive_input_not_retained before anything is stored, and a recipient rule cannot read who the message is addressed to. Attachments are JSON (contentBytes is base64 inside the attachment object), and the shared proxy accepts up to 5 MiB of serialized input.
The createUploadSession operations are not an upload path through Alter. Graph answers them with an uploadUrl on another host that accepts the file’s bytes without the OAuth token; anything sent to that URL bypasses Alter’s policy, approvals and audit, and the URL works for anyone who holds it.
Policy and sensitive data
Section titled “Policy and sensitive data”Every write carries a family reviewed from Microsoft’s documentation:
send(withwrite):sendMail, sending a draft,reply,replyAllandforward; creating, updating, cancelling or deleting an event andaccept,declineortentativelyAccept, because Graph sends meeting requests, updates, cancellations and responses to the attendees; and inbox rules, which can forward or redirect mail.admin: calendar sharing permissions, and creating, updating or deleting another user.delete: every delete andpermanentDelete.read:getSchedule, a free/busy query sent as a POST.
Recipient rules read every address a write sends to: recipients on sendMail, forward and createForward (toRecipients and the message’s to, cc, bcc and replyTo), on drafts, on events (attendees), on event forwards and on inbox rules (forwardTo, forwardAsAttachmentTo, redirectTo). A reply or reply-all also goes to the original message’s sender and recipients, a draft send to the stored draft’s recipients, and an event response or cancellation to the organizer or attendees, none of which the request carries: a condition on recipients there fails closed. Graph reads JSON property names regardless of case, and so does the policy projection.
Creating or updating a user, or /me, with a passwordProfile.password sets a password, so the call is refused by default with credential_minting_refused, on raw proxy calls as well as SDK calls, until an operator adds a credential_minting allowance naming provider microsoft and the operation (microsoft.users_user_createuser, microsoft.users_user_updateuser or microsoft.me_user_updateuser). This holds for PATCH and PUT, on the /v1.0 and /beta bases, for a user named by id or user principal name, through directoryObjects and the microsoft.graph.user cast, in the OData key form (users('id')), and inside a $batch request, which is refused when any request in it would be. The same calls without a password are ordinary edits and run without one. A user’s passwordProfile (and its password) is held encrypted with a pending approval and shown masked to the approver. The opaque MIME body above is refused under an approval rule. Payload capture follows the application’s capture setting, on managed and raw proxied calls alike: credentials are removed, every field Alter’s reviewed inventory for the provider marks sensitive is masked in requests and responses, including fields it locates only by operation, and binary bodies, calls that can return a credential and calls carrying raw card data are never stored.
Graph’s OpenAPI document names no permission per operation. Each operation’s required scopes come from Microsoft’s published permissions data (the source behind the permissions reference): any one of the listed scopes is enough, and they appear on each operation’s reference page. Operations the data does not list have no scope requirement, so a grant narrowed to scopes refuses them unless a restriction rule pins the route. Request the scopes the application needs from the connection’s scope list.
Changes to existing policy identities
Section titled “Changes to existing policy identities”The Microsoft policy catalog used to hold 28 hand-written operations; it now holds every operation of this contract, and the 28 identities keep their ids. A rule applies to the operations it names:
me/send-mailisPOST /me/sendMailonly. Another user’ssendMail,forward,reply,replyAlland draftsendare operations of their own, all in thesendfamily. A rule meant for every way of sending mail names thesendfamily.me/send-mailnow also carrieswrite, andchats/messages/createandteams/channel-messages/createtoo, so a rule on thewritefamily also applies to sending.me/events/createnow also carriessend(Graph sends the invitations), so a rule on thesendfamily also applies to creating events, and asendrule with arecipientscondition reads the event’s attendees.- Operations that were not in the catalog before (every route except the 28) are now classified, so a content rule on the provider applies to them by name and family instead of refusing them as unclassified.
Maintenance
Section titled “Maintenance”The pinned official source, its hash, the generated methods and the policy mapping are checked together. Scheduled checks save upstream candidates and report additions, removals and schema changes; they never replace a published contract automatically. Existing contract versions remain available for installed SDKs and pending approvals.
Rules for SDK functions
Section titled “Rules for SDK functions”Policy operation fields also accept the published SDK function IDs listed by alter integrations operations microsoft. Use when.operation for a json_match or conditional require_approval rule, or match.operations for content_match (including redaction and step-up). Conditional approval can also use when.match.operations with parameter conditions. alter policy simulate --operation <function-id> tests that exact function.
Managed calls carry a server-verified function identity. Alter still evaluates policy against the actual method, URL and body after building the request from the authorized connection, so endpoint, method, host, catalog-operation and family rules apply to managed calls as they do to raw ones (see the changes to existing policy identities above). A raw call can share an endpoint with several SDK functions and matches all of them; a function name never grants permission or bypasses existing restrictions.
For example, this rule requires approval for one function:
{ "effect": "require_approval", "when": { "operation": "microsoft.me_sendmail" }, "approval": { "approvers": ["reviewer@example.com"] }}Save it with alter policy rules create --app <app-id> --grant <grant-id> --type require_approval --body @rule.json, or select the function in the portal.