Thank you for your response.
Actually i just found an alternative to register the webhooks with calendar events:
curl -X POST
-u “user:pass”
-H “Content-Type: application/json”
-H “OCS-APIRequest: true”
“https://nextcloud-instance/ocs/v2.php/apps/webhook_listeners/api/v1/webhooks”
-d ‘{
“httpMethod”: “POST”,
“uri”: “https://n8n-instance/webhook/xxxx-xxx-xxx-xxx”,
“event”: “OCP\\Calendar\\Events\\CalendarObjectCreatedEvent”,
“authMethod”: “none”
}’
Type of events:
OCP\Calendar\Events\CalendarObjectMovedToTrashEvent
OCP\Calendar\Events\CalendarObjectCreatedEvent
OCP\Calendar\Events\CalendarObjectUpdatedEvent
OCP\Calendar\Events\CalendarObjectDeletedEvent
Be aware that in this example there’s no authmethod.
Also notice that a cronjob must be executed in order for the webhooks fire.
Sharing the code node after the n8n’s webhook node to separate the events data (Be sure to use Raw Body option in the webhook node):
// =====================================================
//
Ler payload binário base64 ou JSON
// =====================================================
let rawData;
if ($input.first().binary && $input.first().binary.data) {
// Payload binário base64
const base64Data = $input.first().binary.data.data;
const buff = Buffer.from(base64Data, ‘base64’);
rawData = buff.toString(‘utf8’);
} else {
// fallback: já é JSON
rawData = $input.first().json;
}
//
Parse para JSON
const webhookData = typeof rawData === ‘string’ ? JSON.parse(rawData) : rawData;
//
Log para depuração
console.log(‘Payload decodificado:’, JSON.stringify(webhookData, null, 2));
// =====================================================
//
Extrair dados principais do webhook
// =====================================================
const ical = webhookData?.event?.objectData?.calendardata;
const eventType = webhookData?.event?.class || “”;
const calendarName = webhookData?.event?.calendarData?.[‘{DAV:}displayname’] || “”;
const userName = webhookData?.user?.displayName || “”;
// EXTRAIR O URI ORIGINAL - ESTA É A INFORMAÇÃO CRÍTICA
const originalUri = webhookData?.event?.objectData?.uri;
if (!ical) {
throw new Error(“Payload inválido: ‘objectData.calendardata’ não encontrado.”);
}
// =====================================================
//
Funções auxiliares
// =====================================================
function extractField(fieldName, vevent) {
const regex = new RegExp(${fieldName}(?:;[^:]+)?:([^\r\n]+));
const match = vevent.match(regex);
return match ? match[1].trim() : null;
}
function extractAllAttendees(vevent) {
const matches = […vevent.matchAll(/ATTENDEE(?:;[^:]+)?:([^\r\n]+)/g)];
return matches.map(m => cleanEmail(m[1]));
}
function cleanEmail(email) {
return email ? email.replace(/^mailto:/i, ‘’) : null;
}
function toMysqlDateTime(icalDate) {
if (!icalDate) return null;
icalDate = icalDate.replace(/Z$/, ‘’);
icalDate = icalDate.replace(/TZID=[^:]+:/, ‘’);
if (icalDate.includes(‘T’)) {
const year = icalDate.substring(0, 4);
const month = icalDate.substring(4, 6);
const day = icalDate.substring(6, 8);
const hour = icalDate.substring(9, 11) || ‘00’;
const minute = icalDate.substring(11, 13) || ‘00’;
return ${year}-${month}-${day} ${hour}:${minute}:00;
} else {
const year = icalDate.substring(0, 4);
const month = icalDate.substring(4, 6);
const day = icalDate.substring(6, 8);
return ${year}-${month}-${day} 00:00:00;
}
}
// =====================================================
//
Extrair VEVENTs
// =====================================================
const vevents = ical.match(/BEGIN:VEVENT([\s\S]*?)END:VEVENT/g) || ;
const events = vevents.map(v => ({
eventType,
calendarName,
userName,
uid: extractField(“UID”, v),
summary: extractField(“SUMMARY”, v),
description: extractField(“DESCRIPTION”, v),
location: extractField(“LOCATION”, v),
status: extractField(“STATUS”, v),
category: extractField(“CATEGORIES”, v),
start: toMysqlDateTime(extractField(“DTSTART”, v)),
end: toMysqlDateTime(extractField(“DTEND”, v)),
created: toMysqlDateTime(extractField(“CREATED”, v)),
lastModified: toMysqlDateTime(extractField(“LAST-MODIFIED”, v)),
dtstamp: toMysqlDateTime(extractField(“DTSTAMP”, v)),
organizer: cleanEmail(extractField(“ORGANIZER”, v)),
attendees: extractAllAttendees(v),
sequence: extractField(“SEQUENCE”, v),
calendardata: v,
// ADICIONAR O URI ORIGINAL
originalUri: originalUri
}));
// =====================================================
//
Output final
// =====================================================
return events.map(e => ({ json: e }));