Content-Type: text/calendar; method=REQUEST
Votre agent gère ses réunions.
Il accepte les invitations et envoie de vraies invitations d’agenda, par e-mail. Les invitations de Google Calendar, Outlook, Apple Calendar, Calendly ou Zoom deviennent des événements que votre agent lit et auxquels il répond, et les invitations qu’il envoie arrivent dans l’agenda des participants. Aucun compte d’agenda à connecter.
- METHOD:REPLY
- Réponses, invitations, modifications et annulations sont des e-mails d’agenda standard : Google Calendar, Outlook et Apple Calendar les affichent comme d’habitude.
- organizer_verified
- Vérifié avec DMARC : votre agent sait si une invitation vient vraiment de son organisateur.
- messages:send
- Chaque réponse et chaque invitation est un e-mail envoyé depuis la boîte de votre agent, avec les mêmes limites et contrôles que tout autre envoi.
BEGIN:VCALENDAR
Trois étapes, toutes par e-mail.
Chaque étape est un appel API. Les exemples utilisent les SDK TypeScript et Python, avec l’appel HTTP brut pour la réponse ; chaque champ est dans la référence de l’API et tout le parcours dans le guide des réunions (en anglais).
calendar.invite.received
Une invitation arrive
Quelqu’un invite l’adresse de votre agent depuis Google Calendar, Outlook, Apple Calendar, Calendly ou Zoom. Une fois l’e-mail vérifié, l’invitation devient un événement : titre, horaire, organisateur, invités, et le lien Zoom, Meet ou Teams.
agent.tsimport { 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); }from agentboxd import Agentboxd mr = Agentboxd() # reads AGENTBOXD_API_KEY # Invites waiting for an answer, soonest first. invites = mr.calendar.list(inbox_id, role="attendee", response="needs_action")["data"] for e in invites: print(e["title"], e["start"], e["organizer"]["email"], e["organizer_verified"]){ "id": "9d7b5f3e-1c0a-4e8d-b6f4-2a0c8e6d4b13", "role": "attendee", "status": "confirmed", "response": "needs_action", "title": "Pricing review", "start": "2026-11-12T15:00:00.000Z", "end": "2026-11-12T15:30:00.000Z", "conference": { "provider": "google_meet", "url": "https://meet.google.com/abc-defg-hij" }, "organizer": { "email": "sam@example.com", "name": "Sam" }, "organizer_verified": true, "attendees": [ { "email": "sam@example.com", "partstat": "accepted" }, { "email": "support-bot@homingbox.net", "partstat": "needs_action" } ], "screening": { "state": "screened", "reason": null, "released_at": null } }POST /v1/calendar/events/:id/respond
Votre agent répond
Accepter, refuser, répondre « peut-être » ou proposer un autre horaire. La réponse part à l’organisateur seulement, jamais au Reply-To ni aux autres invités, et son agenda se met à jour comme d’habitude. Ou l’enregistrer en brouillon qu’une personne approuve d’abord.
agent.tsimport 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'; }def answer(e: dict) -> str: # Your code decides, not the model: a verified organizer, an invite that isn't held. if not e["organizer_verified"] or e.get("withheld"): return "ask a person" mr.calendar.respond(e["id"], "accepted", comment="See you then.") # Another time instead: "tentative", propose={"start": ..., "end": ...} # A person approves first: add draft=True, and it waits in Approvals. return "accepted"curl -s -X POST https://api.agentboxd.com/v1/calendar/events/$EVENT_ID/respond \ -H "Authorization: Bearer $AGENTBOXD_API_KEY" \ -H "Content-Type: application/json" \ -d '{"response":"accepted","comment":"See you then."}'POST /v1/inboxes/:id/calendar/events
Il envoie les siennes
Votre agent envoie de vraies invitations, avec un lien de visio si vous le souhaitez, puis les modifie ou les annule. Les invités répondent depuis leur agenda, et chaque réponse revient en calendar.response.received.
agent.tsconst { 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.event = mr.calendar.create( inbox_id, 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", )["event"] # 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
Ou demandez simplement.
Dans Claude, Cursor ou tout client MCP, votre agent gère ses réunions avec des mots simples : le serveur MCP trouve l’invitation et y répond.
Outils : list_events, get_event, respond_to_invite, create_meeting, update_meeting, cancel_meeting. Les quatre qui envoient peuvent plutôt enregistrer un brouillon qu’une personne approuve (draft: true). Installer le serveur MCP (en anglais).
Vous : Accepte l’invitation de Sam pour jeudi.
Claude : list_events → « Pricing review », jeu. 12 nov., 15:00–15:30 UTC,
de sam@example.com (organisateur vérifié)
respond_to_invite → accepted
C’est fait. Sam reçoit la réponse, personne d’autre.organizer_verified: false
Une invitation vient d’un inconnu.
N’importe qui peut envoyer une invitation à votre agent, et tout ce qu’elle contient est du texte choisi par l’expéditeur. Les réunions la traitent comme telle.
Une invitation retenue, telle qu’une clé API la lit : quand et de qui, jamais ce que l’expéditeur a écrit.
{
"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
Le texte est vérifié d’abord
Le titre, la description, le lieu et les liens d’une invitation sont analysés (injection de prompt) comme le reste de l’e-mail, avant que votre agent ne voie l’événement.
- HELD
Une invitation retenue ne montre rien
Si l’analyse retient l’invitation, votre agent n’en voit que les horaires, les adresses et la raison, et ne peut pas répondre tant qu’une personne ne l’a pas libérée. Activé pour les nouveaux espaces de travail ; les plus anciens l’activent dans Settings.
- DMARC ✓
L’organisateur est vérifié, ou non
organizer_verifiedindique si un expéditeur authentifié se porte garant de l’organisateur : l’organisateur lui-même, le domaine de son entreprise, ou un service d’agenda comme Google Calendar ou Calendly. Un message non vérifié ne peut ni modifier ni annuler une réunion vérifiée. - ORGANIZER ONLY
Les réponses vont à l’organisateur seulement
Jamais au Reply-To, jamais aux autres invités. Une fausse adresse de réponse ne peut pas détourner la réponse de votre agent vers quelqu’un d’autre.
- NO AUTO-REPLY
Rien ne part parce qu’un e-mail est arrivé
Chaque réponse et chaque invitation est un appel fait par votre code. Une invitation seule ne fait jamais écrire la boîte de votre agent à qui que ce soit.
- draft: true
Une personne peut approuver d’abord
Avec
draft: true, une réponse, une invitation, une modification ou une annulation attend dans Approvals sous forme de brouillon jusqu’à ce qu’une personne l’envoie, et la réunion ne change qu’à ce moment-là. Une clé qui adrafts:writesansmessages:sendpeut proposer des réunions, jamais les envoyer. - messages:send
Les mêmes règles que tout envoi
Réponses et invitations passent par vos limites d’envoi, vos listes de blocage et vos suppressions, et comptent dans les e-mails de votre offre. Une clé a besoin de
calendar:writeet demessages:sendpour les envoyer.
Questions
Questions
Mon agent a-t-il besoin d’un compte Google ou Microsoft ?
Non. Les réunions passent par l’e-mail : les invitations arrivent dans la boîte de votre agent et les réponses en partent, sous forme de messages d’agenda standard. Rien ne se connecte au compte d’agenda de qui que ce soit.
Les participants voient-ils une invitation normale ?
Oui. L’e-mail contient une invitation d’agenda standard et un fichier invite.ics : Google Calendar, Outlook et Apple Calendar l’affichent avec leurs boutons de réponse habituels.
Mon agent peut-il voir mes disponibilités, ou laisser choisir un créneau ?
Pas encore. Aujourd’hui, il connaît les réunions auxquelles sa boîte a été invitée et celles qu’il a envoyées. Disponibilités, e-mails « choisissez un créneau », pages de réservation, flux d’agenda et rappels arrivent ensuite. Feuille de route (en anglais).
Combien ça coûte ?
Les réunions n’ont pas de prix à part. Chaque réponse, invitation, modification ou annulation est un e-mail envoyé depuis la boîte de votre agent et compte comme tout autre envoi. Tarifs.
Et les réunions récurrentes, les fuseaux horaires ?
Une série arrive comme un seul événement avec sa règle, et votre agent peut en envoyer une. Pour voir chaque date, listez les événements avec expand=occurrences (deux ans au plus par liste). Les horaires sont en UTC, avec le fuseau de l’invitation à côté. Une série envoyée par votre agent avec un fuseau garde son heure locale au changement d’heure.
RSVP=TRUE
Mettez votre agent dans l’invitation.
Créez une boîte mail, invitez-la à une réunion, et répondez depuis votre code.