2026-06-18
calendar
scheduling
ai-agents
booking
api

How to Give Your AI Agent Its Own Calendar

How to Give Your AI Agent Its Own Calendar

How to Give Your AI Agent Its Own Calendar

An AI outreach agent can email a hundred leads, detect the replies, and write a perfect follow-up. Then someone says "sure, how's Thursday?" — and the agent has nowhere to put the meeting. The conversation it worked for stalls at the one step that closes: getting on the calendar.

The usual fix is to bolt on a scheduling provider — connect the agent to a human's Google or Outlook calendar, or drop a Calendly link in the reply. Both work, but both are the wrong shape for an agent. This post covers a cleaner model: give the agent its own calendar, the same way you'd give it its own inbox. We'll cover why that model fits agents better, and exactly how to build it with real API calls.

Two models: sync a human's calendar, or host the agent's own

There are two ways an agent can "have" a calendar.

Model 1 — sync a human's calendar. You OAuth into the user's Google/Outlook, read their free/busy, and write events into their calendar. This is what calendar-API companies (Nylas, Cal.com, Calendly) are built around. It's powerful, but it's also heavy: every user must connect an account, you store and refresh OAuth tokens, you handle two-way sync and conflict resolution, and the agent is always acting on behalf of a person who owns the calendar.

Model 2 — the agent hosts its own calendar. The agent gets a dedicated calendar identity. It creates events under its own name, sends invites, RSVPs to invitations that arrive for it, and exposes its own availability. No OAuth, no token refresh, no syncing someone else's calendar.

For an autonomous agent — a scheduling assistant, an outreach agent that books demos, an event-hosting service — Model 2 is almost always what you actually want. The agent is the host. And critically, you don't need to see a prospect's calendar to book them: the agent proposes a time and emails them an invite (an .ics file); their own Google or Outlook renders it and they accept. No account connection required on either side.

The mental model: an agent's calendar should work like its inbox — a real, hosted identity the agent owns, not a borrowed view into a human's account.

Every MyAgentMail inbox already has a calendar

This is the part most people don't expect. In MyAgentMail, every agent inbox is a real mailbox on a full mail-and-collaboration server — and that server ships with calendars built in. So the moment your agent has an inbox, it also has a calendar at the same identity, with zero extra provisioning. The agent's email address is its calendar identity.

That gives you the whole loop on one credential: send and receive email, and host events, send invites, RSVP, and check availability — all scoped to the same inbox.

The four things an agent needs

A scheduling agent needs to do four things. Here's each one as a real API call against an inbox.

1. Create an event and invite people

When the agent and a prospect agree on a time, the agent hosts the meeting and invites the prospect. Adding an attendee automatically sends them a calendar invite by email.

curl -X POST https://myagentmail.com/v1/inboxes/INBOX_ID/calendar/events \
  -H "X-API-Key: $MAM_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "summary": "Intro call",
    "start": "2026-07-20T15:00:00Z",
    "end":   "2026-07-20T15:30:00Z",
    "attendees": [{ "email": "[email protected]", "name": "Dana" }]
  }'

The prospect gets a normal calendar invite in their inbox — Google, Outlook, Apple Mail, whatever they use — and accepting it puts the meeting on their calendar. No account connection, no scheduling-link round-trip.

2. RSVP to invitations that arrive for it

Agents receive invites too. When one lands, the agent can read it and respond. Because the calendar shares the inbox, the invite shows up as a webhook event (calendar.invite.received) the moment it arrives, so the agent can decide and reply:

curl -X POST https://myagentmail.com/v1/inboxes/INBOX_ID/calendar/events/EVENT_UID/rsvp \
  -H "X-API-Key: $MAM_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "accepted" }'

The organizer gets the reply automatically — exactly as if a human had clicked "Accept."

3. Check its own availability

To propose times that actually work, the agent reads its own busy intervals:

curl "https://myagentmail.com/v1/inboxes/INBOX_ID/calendar/free-busy?start=2026-07-20T00:00:00Z&end=2026-07-25T00:00:00Z" \
  -H "X-API-Key: $MAM_KEY"

You get back the busy blocks; the gaps are the agent's open slots. That's enough to offer "I have Tuesday at 10, 2, or 4 — which works?" without ever touching the prospect's calendar.

4. Share a booking link

Sometimes you don't want a back-and-forth at all — you want the agent to publish its availability and let people self-serve. Enable a booking page and the agent gets a public scheduling link, the agent-native equivalent of a Calendly page:

curl -X POST https://myagentmail.com/v1/inboxes/INBOX_ID/calendar/booking \
  -H "X-API-Key: $MAM_KEY"
# → { "slug": "...", "url": "https://myagentmail.com/book/your-agent", ... }

Anyone who opens that link sees the agent's open slots, picks one, and the meeting is hosted on the agent's calendar — with the invite emailed to the visitor.

A worked example: booking from a reply

Here's the whole loop an outreach agent actually runs, end to end. A prospect replies to a thread; the agent reads intent, proposes times from its own availability, and books on confirmation.

// On an inbound reply (webhook: message.received)
const msg = await mam("GET", `/inboxes/${inboxId}/messages/${messageId}`);

// Is this a meeting request? (your LLM intent check)
if (await isMeetingRequest(msg.plainBody)) {
  // 1. Pull the agent's own busy times and compute three open slots
  const { busy } = await mam("GET", `/inboxes/${inboxId}/calendar/free-busy`);
  const slots = openSlots(busy, { duration: 30, count: 3 });

  // 2. Reply in-thread with the options
  await mam("POST", `/inboxes/${inboxId}/reply/${messageId}`, {
    plainBody: `Happy to chat. I have:\n${slots.map(fmt).join("\n")}\nWhich works?`,
  });
}

// On their confirmation ("the 2pm works"):
await mam("POST", `/inboxes/${inboxId}/calendar/events`, {
  summary: "Intro call",
  start: chosen.start,
  end: chosen.end,
  attendees: [{ email: extractEmail(msg.from) }],
});

No external calendar provider, no OAuth, no Calendly redirect. The agent reads its mail, checks its own calendar, and books — all on one API key.

When you do want calendar sync

To be fair about the trade-off: if your product's core job is to read and write a specific human's existing calendar — a personal EA that manages your Google Calendar, with two-way sync — then you want the sync model, and a dedicated calendar-sync provider is the right tool. The agent-owns-its-calendar model is for when the agent is the host: scheduling agents, outreach agents that book their own demos, event and office-hours bots, multi-agent workflows that coordinate among themselves.

For that large and growing category, giving the agent its own calendar is simpler to build, cheaper to run, and a better fit conceptually — the agent owns its schedule the same way it owns its inbox.

Try it

If your agent already has a MyAgentMail inbox, it already has a calendar — start with the calendar API and the create_calendar_event / rsvp_calendar_event / get_calendar_free_busy tools in the MCP server. If you're building a booking or scheduling agent specifically, see the scheduling-agent use case. And if you're new here, the why agents need their own email post explains the identity model the calendar is built on.

← All posts