Meetings

Content-Type: text/calendar; method=REQUEST

Your agent can take meetings.

It accepts invites and sends real calendar invitations, by email. Invites from Google Calendar, Outlook, Apple Calendar, Calendly or Zoom become events your agent can read and answer, and the invitations it sends land in people’s calendars. There is no calendar account to connect.

METHOD:REPLY
Answers, invitations, changes and cancellations are standard calendar email, so Google Calendar, Outlook and Apple Calendar show them as usual.
organizer_verified
Checked with DMARC, so your agent knows whether an invite really comes from its organizer.
messages:send
Every answer and invitation is an email from your agent’s inbox, with the same limits and checks as any other send.

BEGIN:VCALENDAR

Three steps, all by email.

Each step is one API call. The examples use the TypeScript and Python SDKs, with the plain HTTP call for the answer; every field is in the API reference and the whole flow in the Meetings guide.

  1. calendar.invite.received

    An invite arrives

    Someone invites your agent’s address from Google Calendar, Outlook, Apple Calendar, Calendly or Zoom. Once the email is screened, the invite becomes an event: title, time, organizer, guests, and the join link for Zoom, Meet or Teams.

    agent.ts
    import { Agentboxd } from 'agentboxd';
    
    const mr = new Agentboxd(); // reads AGENTBOXD_API_KEY
    
    // Invites waiting for an answer, soonest first.
    const { data: invites } = await mr.calendar.list(inboxId, { role: 'attendee', response: 'needs_action' });
    
    for (const e of invites) {
      console.log(e.title, e.start, e.organizer.email, e.organizer_verified);
    }
  2. POST /v1/calendar/events/:id/respond

    Your agent answers

    Accept, decline, say maybe or propose another time. The answer goes to the organizer only, never to Reply-To or the other guests, and their calendar updates as usual. Or save it as a draft that a person approves first.

    agent.ts
    import type { CalendarEvent } from 'agentboxd';
    
    async function answer(e: CalendarEvent) {
      // Your code decides, not the model: a verified organizer, an invite that isn't held.
      if (!e.organizer_verified || e.withheld) return 'ask a person';
    
      await mr.calendar.respond(e.id, { response: 'accepted', comment: 'See you then.' });
      // Another time instead: { response: 'tentative', propose: { start, end } }
      // A person approves first: add draft: true, and it waits in Approvals.
      return 'accepted';
    }
  3. POST /v1/inboxes/:id/calendar/events

    It sends its own

    Your agent sends real invitations, with a video link if you like, and changes or cancels them later. Guests answer from their own calendar, and each answer comes back as calendar.response.received.

    agent.ts
    const { event } = await mr.calendar.create(inboxId, {
      title: 'Onboarding call',
      start: '2026-11-18T15:00:00Z',
      duration_minutes: 30,
      time_zone: 'Europe/Paris', // how the email words the time
      attendees: [{ email: 'dana@example.com', name: 'Dana Lee' }],
      conference_url: 'https://meet.google.com/abc-defg-hij',
    });
    // The invitation is on its way. Later: mr.calendar.update(event.id, { … }) to change it,
    // mr.calendar.cancel(event.id) to call it off.

npx @agentboxd/mcp

Or just ask.

In Claude, Cursor or any MCP client, your agent handles meetings in plain words: the MCP server finds the invite and answers it.

Tools: list_events, get_event, respond_to_invite, create_meeting, update_meeting, cancel_meeting. The four that send can save a draft for a person to approve instead (draft: true). Set up the MCP server.

an MCP client
You:     Accept the invite from Sam for Thursday.

Claude:  list_events → “Pricing review”, Thu 12 Nov, 15:00–15:30 UTC,
         from sam@example.com (organizer verified)
         respond_to_invite → accepted
         Done. Sam gets the answer; nobody else does.

organizer_verified: false

An invite is mail from a stranger.

Anyone can send your agent an invite, and everything in it is text they chose. Meetings treats it that way.

A held invite, as an API key reads it: when and from whom, never what the sender wrote.

a held invite (trimmed)
{
  "title": "[held: injection_risk]",
  "description": null,
  "location": null,
  "conference": null,
  "start": "2026-11-12T15:00:00.000Z",
  "end": "2026-11-12T15:30:00.000Z",
  "organizer": { "email": "it-desk@lookalike.example", "name": null },
  "organizer_verified": false,
  "withheld": { "state": "held", "reason": "injection_risk" }
}
  • SCREENED

    Invite text is screened first

    The title, description, location and links of an invite are checked for prompt injection like the rest of the email, before your agent sees the event.

  • HELD

    A held invite shows no content

    If the check holds the invite, your agent sees only its times, the addresses and why it is held, and can’t answer until a person releases it. On for new workspaces; older ones turn it on in Settings.

  • DMARC ✓

    The organizer is verified, or not

    organizer_verified says whether an authenticated sender vouches for the organizer: the organizer, their own company domain, or a calendar service such as Google Calendar or Calendly. An unverified message can’t change or cancel a verified meeting.

  • ORGANIZER ONLY

    Answers go to the organizer only

    Never to Reply-To, never to the other guests. A forged reply address can’t turn your agent’s answer into mail to someone else.

  • NO AUTO-REPLY

    Nothing is sent because mail arrived

    Every answer and invitation is a call your code makes. An invite on its own never makes your agent’s inbox write to anyone.

  • draft: true

    A person can approve first

    With draft: true, an answer, invitation, change or cancellation waits in Approvals as a draft until a person sends it, and the meeting changes only then. A key with drafts:write but not messages:send can propose meetings, never send them.

  • messages:send

    The same rules as any send

    Answers and invitations go through your send limits, block lists and suppressions, and count toward your plan’s emails. A key needs calendar:write and messages:send to send them.

Questions

Questions

Does my agent need a Google or Microsoft account?

No. Meetings work over email: invites arrive in your agent’s inbox and answers go out from it, as standard calendar messages. Nothing connects to anyone’s calendar account.

Will people see a normal invitation?

Yes. The email carries a standard calendar invitation and an invite.ics file, so Google Calendar, Outlook and Apple Calendar show it with their usual buttons to answer.

Can my agent see when I’m free, or let people pick a time?

Not yet. Today it knows the meetings its inbox was invited to and the ones it sent. Free times, “pick a time” emails, booking pages, a calendar feed and reminders are coming next. Roadmap.

What does it cost?

Meetings has no separate price. Each answer, invitation, change or cancellation is an email from your agent’s inbox and counts like any other send. Pricing.

What about recurring meetings and time zones?

A series arrives as one event with its rule, and your agent can send one too. To see each date, list events with expand=occurrences (two years at most per list). Times are in UTC with the invite’s time zone alongside. A series your agent sends with a time zone keeps its local time when the clocks change.

RSVP=TRUE

Put your agent on the invite.

Create an inbox, invite it to a meeting, and answer from your code.