Cómo integrar Outlook Calendar API en tu aplicación
Publicado el
En nuestro artículo anterior sobre cómo integrar la API de Google Calendar en tu aplicación, repasamos paso a paso lo que un desarrollador debe hacer para conectar Google Calendar a su app.
En este artículo haremos lo mismo con la API de Outlook Calendar. Veremos el registro de la aplicación en Azure, los ámbitos, la verificación, las complicaciones más comunes de la integración y ejemplos de código reales.
Requisitos previos
Esta guía asume que ya tienes una cuenta Microsoft Work o Developer con acceso a Azure Active Directory (ahora llamado Microsoft Entra ID).
Ten en cuenta que ya no es posible crear aplicaciones fuera de un directorio. Si todavía no tienes uno, únete al Programa para Desarrolladores de Microsoft 365 o regístrate en Azure.
Cómo usar e integrar la API de Outlook Calendar en tu aplicación
Paso 1: Inicia sesión en el Portal de Microsoft Azure
Abre la página de inicio de sesión del Portal de Microsoft Azure e inicia sesión con tu cuenta.
La página del Portal de Microsoft Azure.
Paso 2: Registra una nueva aplicación
Después de iniciar sesión en el Portal de Microsoft Azure:
- Navega a Azure Active Directory

- Busca “App Registrations” en la barra de búsqueda

- Haz clic en “App Registrations”

- Haz clic en “New registration”

- Rellena los campos requeridos:
- El primer campo es el Nombre de tu aplicación. Es el nombre que los usuarios verán en la pantalla de consentimiento.
- A continuación, selecciona los tipos de cuenta admitidos. La opción correcta depende del tipo de aplicación que estés desarrollando (uso interno o multi-tenant). Para este ejemplo, seleccionaré “ Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) ”, porque permite que usuarios de cualquier organización (incluidos los de Outlook.com) utilicen mi aplicación. Es la mejor opción para productos SaaS y otras aplicaciones multi-tenant.
- Introduce la URI de redirección: este campo es opcional, porque no todos los tipos de aplicación lo necesitan. Si desarrollas una aplicación web, casi seguro la necesitarás, ya que esta URI es donde Azure envía las respuestas OAuth. En el desplegable “Select a platform”, elige Web y rellena la URI de redirección (por ejemplo,
https://tuapp.com/auth/callback). Para un flujo de autenticación del lado del servidor, una URI web es la opción correcta. Asegúrate de que el dominio sea accesible y esté bajo tu control. - Haz clic en “Register”.
- Tras hacer clic en “Register”, Azure Active Directory crea tu aplicación y te lleva a la página de resumen, donde puedes copiar el Client ID y el Tenant ID. El Application (client) ID es un GUID que identifica tu app. El Directory (tenant) ID no siempre es necesario. En apps multi-tenant normalmente se usa el endpoint
common, pero el tenant ID resulta útil para hacer pruebas en tu propio tenant.
Paso 3: Configura los permisos de la API
Con la app registrada, es momento de configurar los permisos de calendario. Estos permisos se muestran durante el flujo OAuth, así el usuario ve qué ámbitos solicita tu aplicación antes de conceder acceso a sus calendarios.
De forma predeterminada, tu aplicación solo tiene el permiso “User.Read”. Si lo único que necesitas es iniciar sesión y leer el perfil del usuario, puedes omitir este paso.
Para añadir permisos de API, sigue estos pasos:
- Haz clic en la pestaña “Manage” en la barra lateral izquierda.
- Haz clic en “API Permissions”.

- Haz clic en el botón “+ Add a permission”.

- Busca la tarjeta “Microsoft Graph” (suele ser la primera del panel que se abre a la derecha tras hacer clic en “Add a permission”).

- Elige entre “Delegated permissions” y “Application permissions”. Los permisos delegados son la opción correcta cuando tu app llama a la API en nombre del usuario autenticado. Los permisos de aplicación se usan cuando tu app funciona como un servicio en segundo plano sin usuario autenticado. Para este ejemplo usaré “Delegated Permissions”.

- Busca “Calendars”: la búsqueda muestra todos los permisos relacionados con calendarios. Selecciona solo los que tu app necesita para funcionar correctamente. En la mayoría de los casos, querrás “Calendars.ReadWrite” y “Calendars.ReadWrite.Shared” (si necesitas acceder a calendarios compartidos). Estos ámbitos no suelen requerir consentimiento de administrador, porque son ámbitos delegados al usuario, pero ten en cuenta que algunas organizaciones restringen el consentimiento del usuario. Si un usuario de un tenant externo no puede consentir, un administrador de ese tenant tendrá que otorgar el consentimiento a tu app (normalmente mediante un aviso o una URL de consentimiento de administrador).

Paso 4: Habilitar los tokens de ID
No todas las aplicaciones necesitan este paso, pero si quieres acceder a información del perfil del usuario, como el nombre, el correo electrónico o la URL de la foto de perfil, debes habilitar la opción Tokens de ID en Administrar -> Autenticación.
Con los tokens de ID, tu aplicación puede identificar al usuario justo después de conectar su calendario, sin hacer una llamada extra a la API.
Paso 5: Genera un Client Secret
Recomendamos ejecutar todas las operaciones de calendario (lecturas, escrituras, actualizaciones, etc.) desde el servidor. Por eso necesitas generar un client secret.
Para generar un client secret, sigue estos pasos:
- Haz clic en la pestaña “Certificates & secrets”.

- Haz clic en “New client secret”.

- Introduce una descripción y una fecha de expiración.

Después de generar el client secret, cópialo de inmediato y guárdalo en un lugar seguro (normalmente en tu archivo .env).
Paso 6: Marca y verificación
En la sección Branding & Properties del registro de la app, puedes añadir un logo e información (descripción, URL de términos de servicio, etc.). Es opcional, pero lo recomendamos para tener una pantalla de consentimiento cuidada. Es importante establecer un dominio de editor (normalmente tu dominio personalizado, verificado en Azure AD), porque evita que la app aparezca como “sin verificar” cuando los usuarios dan su consentimiento. Para apps multi-tenant, Microsoft ahora espera que estén publisher-verified para un uso amplio. Si tu app no lo está, los usuarios de fuera de tu tenant podrían no poder dar su consentimiento por las políticas de seguridad introducidas en noviembre de 2020.
Paso 7: Familiarízate con la Graph API de Outlook
Con la aplicación configurada, es hora de explorar la API de Microsoft Calendar Graph para familiarizarte con los endpoints de creación, actualización y eliminación de eventos.
Paso 8: Considera usar un servicio de API de Calendario Unificado para integrar todos los proveedores con una sola API
La Microsoft Graph API está bastante bien documentada, pero aun así recomendamos echar un vistazo a una API de Calendario Unificado que te permita integrar todos los proveedores mediante una única API.
Con una API de Calendario Unificado, implementas una sola API en tu aplicación y das soporte a todos los proveedores, sin importar sus limitaciones o las diferencias entre sus APIs.
Otra ventaja de usar una sola API para todos los calendarios es que no tienes que mantener varias integraciones, lidiar con cambios incompatibles ni resolver casos límite en los que nunca pensaste.
La Apiroc Unified Calendar API
Ejemplo de flujo de autorización de Outlook Calendar
El siguiente diagrama de flujo muestra un flujo OAuth sencillo de Outlook Calendar con el que los usuarios conectan su calendario de Outlook a tu app.
Consulta la página de documentación del flujo OAuth2 de Microsoft si quieres saber más sobre el flujo OAuth2 de Microsoft.
Lado cliente (UI)
const microsoftOauthUrl = getMicrosoftOAuthUrl()
<button href="microsoftOauthUrl" rel="noopener noreferrer"> Connect Outlook Calendar </button>
export const SCOPES = [
"openid",
"email",
"profile",
"offline_access",
"Calendars.ReadWrite",
"User.Read",
];
export interface ClientState {
session: Session;
returnUrl?: string;
}
export function stateToB64(session: ClientState): string {
return encode(JSON.stringify(session));
}
export function getMicrosoftOAuthUrl(
state: ClientState,
) {
const nonce = uuid();
const TENANT_ID = process.env.NEXT_PUBLIC_MICROSOFT_TENANT_ID;
const params = new URLSearchParams({
client_id: process.env.MICROSOFT_CLIENT_ID || "",
redirect_uri: `${getHostName()}/api/connect/microsoft`,
response_type: "code id_token",
scope: SCOPES.join(" "),
prompt: "consent",
response_mode: "form_post",
state: stateToB64(state),
nonce,
});
return `https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/authorize?${params}`;
}
- El parámetro “prompt” acepta uno de estos cuatro valores:
login,none,consentyselect_account. - El parámetro “response_mode” acepta
query,fragmentoform_post. Elegimosform_postporque indica a Microsoft que envíe una solicitud POST a nuestra URI de redirección (en el servidor).
Lado servidor (Backend)
A continuación, creamos el handler de la API. Recibe el código y los ámbitos del servidor de Microsoft y los canjea por tokens.
En este ejemplo usamos zod para la validación.
const successSchema = z.object({
code: z.string(),
state: z.string(),
id_token: z.string(),
session_state: z.string().optional(),
});
const errorSchema = z.object({
error: z.string(),
error_description: z.string().optional(),
});
type ErrorParams = z.infer<typeof errorSchema>;
const querySchema = z.union([successSchema, errorSchema]);
function isError(query: Record<string, any>): query is ErrorParams {
return Boolean(query.error);
}
const microsoftHandler: NextApiHandler = async (req, res) => {
try {
const result = querySchema.parse(req.body);
if (isError(result)) {
const q = new URLSearchParams({
error: "ACCESS_DENIED",
provider: CalendarProvider.MICROSOFT,
});
console.error({ result });
return res.redirect(302, `/?${q}`);
}
const { session, returnUrl } = stateFromB64(result.state);
const { email } = decodeIdToken(result.id_token);
const { access_token, refresh_token, expires_in, scope } =
await exchangeCodeForTokens(result.code);
const connection = await upsertConnection(
{
email,
accessToken: access_token,
refreshToken: refresh_token,
expiresInSeconds: expires_in,
status: ConnectionStatus.ACTIVE,
provider: CalendarProvider.MICROSOFT,
scopes: scope,
},
session.user
);
const q = new URLSearchParams({
cid: connection.id,
});
if (returnUrl) q.append("returnUrl", returnUrl);
res.redirect(302, returnUrl ? returnUrl : `/calendars/microsoft?${q}`);
} catch (e: any) {
let error = JSON.stringify(e);
const querystr =
typeof req.query === "string" ? req.query : JSON.stringify(req.query);
const q = new URLSearchParams({
error,
provider: CalendarProvider.MICROSOFT,
});
return res.redirect(302, `/?${q}`);
}
};
export default microsoftHandler;
Como en el lado cliente, recomendamos tener pequeñas funciones utilitarias para canjear el código por tokens y tareas similares.
const TENANT_ID = process.env.MICROSOFT_TENANT_ID;
export async function exchangeCodeForTokens(code: string) {
const data = new FormData();
data.append("client_id", process.env.MICROSOFT_CLIENT_ID || "");
data.append("scope", SCOPES.join(" "));
data.append("code", code);
data.append("redirect_uri", `${getHostName()}/api/connect/microsoft`);
data.append("grant_type", "authorization_code");
data.append("client_secret", process.env.MICROSOFT_CLIENT_SECRET || "");
try {
const result = await fetch(
`https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token`,
{
method: "POST",
body: data,
}
);
const json = await result.json();
if (json.error) throw json;
const parsed = responseSchema.parse(json);
return parsed;
} catch (e) {
console.error("Exchange failed");
throw e;
}
}
Complicaciones de la integración con la API de Outlook Calendar
-
La verificación puede tardar y ser frustrante : Ten en cuenta que miles, si no millones, de desarrolladores construyen sobre Outlook, por lo que Microsoft revisa una gran cantidad de solicitudes cada día. Completa todos los detalles al enviar tu app a revisión y reserva tiempo para la verificación en tu hoja de ruta.
-
Solicita solo los ámbitos necesarios : El equipo de Microsoft revisa las apps a fondo, así que pide solo lo que tu aplicación realmente necesita para sus funciones. Esto facilita la aprobación y también ayuda cuando los usuarios conceden acceso a tu aplicación. Los usuarios se confunden si una app solicita ámbitos que no tienen nada que ver con sus funciones reales.
-
Los webhooks caducan, renuévalos a tiempo : Si registras webhooks para detectar cambios en el calendario, configura un job en segundo plano que se ejecute cada pocas horas y renueve cualquier suscripción a punto de caducar.
-
Limitación y throttling : Microsoft impone reglas estrictas de limitación y throttling. Evita obtener elementos uno por uno y aplica limitación en tus propias llamadas a la API para no recibir los famosos errores “MailboxConcurrency”. La siguiente tabla resume los límites de peticiones y de throttling:
Ámbito Límite Notas Por buzón (par app ID y buzón) 10 000 solicitudes / 10 min y 4 solicitudes concurrentes. El famoso error “MailboxConcurrency”. Carga 150 MB totales PATCH/POST/PUT por 5 min por buzón. Puede afectarte al adjuntar archivos ICS grandes o adjuntos de archivo. Graph global 130 000 solicitudes / 10 s por app en todos los tenants. Poco frecuente, pero los grandes procesos de relleno de datos en SaaS pueden activarlo. Etiqueta de reintento Ante 429o503/504, busca la cabeceraRetry-Aftery aplica backoff exponencialLa Graph API seguirá aplicando throttling si la bombardeas cada segundo. -
Problemas de zona horaria : En Outlook, un usuario puede escribir manualmente el nombre de su zona horaria (ya imaginas lo que puede pasar), así que asegúrate de que tu código maneja también este caso.
-
Problemas de consentimiento y permisos : como mencionamos en la sección de ámbitos,
Calendars.ReadWritees un permiso delegado. Muchos tenants permiten el consentimiento del usuario, pero otros no. Prepárate para un error “admin consent required” y muestra un flujo amigable de “Pide ayuda a tu administrador”.
Integra todos los proveedores de calendario en tu app con la Apiroc Unified Calendar API
Las integraciones de calendario son nuestra especialidad. Nuestro equipo lleva años trabajando con Google Calendar, Outlook e iCloud Calendar y ha construido integraciones de calendario que gestionan miles de millones de llamadas a la API.
Las lecciones aprendidas al trabajar con todas las principales APIs de calendario dieron forma a la Apiroc Unified Calendar API. Ahorra a los desarrolladores cientos de horas en problemas de calendario, para que puedan centrarse en las funciones que hacen avanzar su producto.
Regístrate en Apiroc para probar la Unified Calendar API e integrar varios proveedores de calendario usando una sola API. El plan gratuito no requiere tarjeta de crédito.
Preguntas frecuentes
¿Qué cuenta necesito para usar la API de Calendario de Outlook?
Necesitas una cuenta de Microsoft Work o Developer con acceso a Azure Active Directory.
¿Qué ámbitos de permisos debo agregar para obtener acceso completo al calendario?
Agrega Calendars.ReadWrite (y Calendars.ReadWrite.Shared si necesitas calendarios compartidos) en Microsoft Graph.
¿Por qué establecer un dominio de editor y un branding?
La verificación del editor y una pantalla de consentimiento con tu marca evitan que tu aplicación aparezca como “no verificada”, y hoy en día se esperan en la mayoría de las apps multi-tenant.
¿Con qué frecuencia debo renovar las suscripciones de webhooks de Outlook?
Los webhooks de calendario de Graph caducan a las pocas horas, así que conviene programar un trabajo en segundo plano que renueve cualquier suscripción que esté a punto de expirar.
¿La API de Calendario de Outlook admite notificaciones push?
Sí. Crea una suscripción de Microsoft Graph y recibirás notificaciones de cambios en lugar de tener que hacer polling.
¿Existe una forma más sencilla de integrar calendarios de Outlook, Google e iCloud?
Sí. Una API de Calendario Unificado como Apiroc reúne todos los proveedores principales tras una interfaz JSON coherente. Con la Apiroc Unified Calendar API no necesitas desarrollar ni mantener una integración separada para cada proveedor de calendario.
