Hello,
I’m trying to build something for my customer, I’m working with dart and GCP with node
When my user is created, here is the flow
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const axios = require("axios");
if (!admin.apps.length) admin.initializeApp();
function generateSlug(name, uid) {
if (!name) return `${uid}-booking`;
return (
name
.toLowerCase()
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "")
.substring(0, 50) +
`-${uid.slice(0, 6)}`
);
}
exports.onUserCreated = functions
.region("europe-west1")
.auth.user()
.onCreate(async (user) => {
const firestore = admin.firestore();
const nylasApiKey =
"***";
try {
console.log("🆕 New user:", user.uid, user.email);
// 1️⃣ Create Virtual Calendar Grant
const grantResp = await axios.post(
"https://api.eu.nylas.com/v3/grants",
{
provider: "virtual-calendar",
name: user.displayName || "User Calendar",
settings: { email: user.email },
scope: ["calendar"],
},
{ headers: { Authorization: `Bearer ${nylasApiKey}` } }
);
const grantId = grantResp.data.data.id;
console.log("✅ Grant created:", grantId);
// 2️⃣ Create Virtual Calendar under this Grant
const calendarResp = await axios.post(
`https://api.eu.nylas.com/v3/grants/${grantId}/calendars`,
{
name: `${user.displayName || "User"} Calendar`,
description: "Primary virtual calendar for scheduling",
},
{ headers: { Authorization: `Bearer ${nylasApiKey}` } }
);
const calendarId = calendarResp.data.data.id;
console.log("✅ Virtual calendar created:", calendarId);
// 3️⃣ Generate slug
const slug = generateSlug(user.displayName, user.uid);
// 4️⃣ Create Scheduler Configuration (auto-hosted)
const schedulerResp = await axios.post(
`https://api.eu.nylas.com/v3/grants/${grantId}/scheduling/configurations`,
{
slug: slug,
requires_session_auth: false,
round_robin: false, // <-- this fixes the organizer error
participants: [
{
name: user.displayName || "Organizer",
email: user.email,
is_organizer: true,
grant_id: grantId,
availability: {
calendar_ids: [calendarId],
open_hours: [
{
days: [1, 2, 3, 4, 5],
timezone: "Europe/Paris",
start: "09:00",
end: "17:00",
exdates: [],
},
],
},
booking: { calendar_id: calendarId },
},
],
availability: {
duration_minutes: 30,
interval_minutes: 30,
},
event_booking: {
title: "Meeting with " + (user.displayName || "User"),
},
},
{ headers: { Authorization: `Bearer ${nylasApiKey}` } }
);
const scheduler = schedulerResp.data.data;
console.log("✅ Scheduler created:", scheduler.id);
console.log("🔗 Scheduler data:", scheduler);
const hostedUrl = `https://book.nylas.com/${slug}`;
console.log("🔗 Hosted URL:", hostedUrl);
// 5️⃣ Save to Firestore
await firestore.collection("users").doc(user.uid).set(
{
nylas_grant_id: grantId,
nylas_calendar_id: calendarId,
nylas_scheduler_id: scheduler.id,
nylas_scheduler_slug: slug,
nylas_scheduler_url:
scheduler.hosted_url || `https://book.nylas.com/${slug}`,
},
{ merge: true }
);
console.log("✅ Nylas setup completed for:", user.uid);
} catch (err) {
console.error(
"❌ Nylas setup error:",
err.response?.data || err.message
);
}
});
And here are the response log
{
“logs”: [
{
“timestamp”: “2025-10-17T08:38:29.330862Z”,
“level”: “INFO”,
“message”: “
New user: lxMlbTtXZwNsKhlclnnq1iFVMKg1 ***@gmail.comgmail.com”
},
{
“timestamp”: “2025-10-17T08:38:30.220065Z”,
“level”: “INFO”,
“message”: “
Grant created: df10e1b1-7bbf-4dd4-8eb1-6a1591ad6336”
},
{
“timestamp”: “2025-10-17T08:38:30.432640Z”,
“level”: “INFO”,
“message”: “
Virtual calendar created: 7a707781-aada-4b94-b9f8-16ab538b1cec”
},
{
“timestamp”: “2025-10-17T08:38:30.608522Z”,
“level”: “INFO”,
“message”: “
Scheduler created: cdd602f5-3491-4f24-888c-9e5eda9c860a”
},
{
“timestamp”: “2025-10-17T08:38:30.611121Z”,
“level”: “INFO”,
“message”: “
Hosted URL: Nylas - Scheduler v3
},
{
“timestamp”: “2025-10-17T08:38:34.276445Z”,
“level”: “INFO”,
“message”: “
Nylas setup completed for: lxMlbTtXZwNsKhlclnnq1iFVMKg1”
}
]
}
With detailed schedulerResp
{
“id”: “cdd602f5-3491-4f24-888c-9e5eda9c860a”,
“slug”: “lxMlbTtXZwNsKhlclnnq1iFVMKg1-booking”,
“participants”: [
{
“name”: “Organizer”,
“email”: “***@gmail.com”,
“is_organizer”: true,
“grant_id”: “df10e1b1-7bbf-4dd4-8eb1-6a1591ad6336”,
“availability”: {
“calendar_ids”: [“7a707781-aada-4b94-b9f8-16ab538b1cec”],
“open_hours”: [
{
“days”: [1,2,3,4,5],
“timezone”: “Europe/Paris”,
“start”: “09:00”,
“end”: “17:00”,
“exdates”:
}
]
},
“booking”: {
“calendar_id”: “7a707781-aada-4b94-b9f8-16ab538b1cec”
}
}
],
“requires_session_auth”: false,
“availability”: {
“duration_minutes”: 30,
“interval_minutes”: 30
},
“event_booking”: {
“title”: “Meeting with User”,
“booking_type”: “booking”,
“hide_participants”: null,
“disable_emails”: null
},
“scheduler”: {
“available_days_in_future”: 30,
“min_cancellation_notice”: 0,
“min_booking_notice”: 60,
“hide_rescheduling_options”: false,
“hide_cancellation_options”: false,
“email_template”: {
“booking_confirmed”: {}
}
},
“appearance”: null,
“hosted_url”: “Nylas - Scheduler v3
}
It’s been few days I can’t get why the hosted URL not working even tho I followed the doc, did someone had similar issue please ?