Synchronisation des heures de vacances avec Everhour
Ceci est unHRworkflow d'automatisation du domainecontenant 23 nœuds.Utilise principalement des nœuds comme If, Set, Code, HttpRequest, GoogleCalendar. Synchronisation automatique des congés d'Everhour vers des événements全天 (journée entière) dans Google Agenda
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
Nœuds utilisés (23)
Catégorie
{
"id": "atCSLFdL7AyLdjJD",
"meta": {
"instanceId": "ed54b493f1b983b9b64b327a27338be1695af08f90b0f5fff3b6d18c570c4fc2"
},
"name": "Everhour Time Off",
"tags": [],
"nodes": [
{
"id": "fe08e8fe-779b-4428-8060-08da88a61118",
"name": "Déclencheur programmé",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-1856,
384
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "8082b4f8-5ff0-4af3-ac3f-268cdd8bee97",
"name": "Construire les groupes d'affectation",
"type": "n8n-nodes-base.code",
"position": [
-656,
576
],
"parameters": {
"jsCode": "// Input: per-day items from Edit Fields (each has externalKey, startDate, endDateExclusive)\n// Output: one item per assignmentId with the set of current keys and a search window\n\nconst groups = {}; // { [assignmentId]: { currentKeys:Set, minDate, maxDate } }\n\nfor (const it of items) {\n const j = it.json;\n const parts = (j.externalKey || '').split(':'); // [\"everhour\", \"<id>\", \"<date>\"]\n const assignmentId = parts[1];\n if (!assignmentId) continue;\n\n if (!groups[assignmentId]) {\n groups[assignmentId] = {\n assignmentId,\n currentKeys: new Set(),\n minDate: j.startDate,\n maxDate: j.endDateExclusive\n };\n }\n groups[assignmentId].currentKeys.add(j.externalKey);\n if (j.startDate < groups[assignmentId].minDate) groups[assignmentId].minDate = j.startDate;\n if (j.endDateExclusive > groups[assignmentId].maxDate) groups[assignmentId].maxDate = j.endDateExclusive;\n}\n\n// Emit one item per assignment, with a small buffer on the search window (optional)\nconst out = [];\nfor (const id of Object.keys(groups)) {\n const g = groups[id];\n out.push({\n json: {\n assignmentId: id,\n currentKeys: Array.from(g.currentKeys),\n searchTimeMin: g.minDate + 'T00:00:00',\n searchTimeMax: g.maxDate + 'T23:59:59'\n }\n });\n}\nreturn out;\n"
},
"typeVersion": 2
},
{
"id": "f210fb86-0d78-4140-adff-0573566b23ac",
"name": "Construire le jeu de clés global",
"type": "n8n-nodes-base.code",
"position": [
-656,
768
],
"parameters": {
"jsCode": "// Build the set of keys we SHOULD have right now\nlet minDate = null, maxDate = null;\nconst keys = new Set();\n\nfor (const it of items) {\n const j = it.json;\n if (j.externalKey) keys.add(j.externalKey);\n if (j.startDate && (!minDate || j.startDate < minDate)) minDate = j.startDate;\n if (j.endDateExclusive && (!maxDate || j.endDateExclusive > maxDate)) maxDate = j.endDateExclusive;\n}\n\n// Reasonable window (optional). Broaden if you want.\nif (!minDate) minDate = new Date().toISOString().slice(0,10);\nif (!maxDate) {\n const d = new Date(); d.setFullYear(d.getFullYear() + 1);\n maxDate = d.toISOString().slice(0,10);\n}\n\nreturn [{\n json: {\n currentKeys: Array.from(keys),\n searchTimeMin: minDate + 'T00:00:00',\n searchTimeMax: maxDate + 'T23:59:59'\n }\n}];\n"
},
"typeVersion": 2
},
{
"id": "c76c87dc-876c-46f0-ac7e-a4a15ac3661c",
"name": "Everhour - Récupérer les temps de congé",
"type": "n8n-nodes-base.httpRequest",
"notes": "Uses Header Auth credential (add `X-Api-Key`). No hardcoded keys.",
"position": [
-1568,
384
],
"parameters": {
"url": "https://api.everhour.com/resource-planner/assignments",
"options": {},
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth"
},
"notesInFlow": true,
"typeVersion": 4.2
},
{
"id": "92a16e7c-bb00-439f-b819-6b7557ff5017",
"name": "Filtrer les congés approuvés",
"type": "n8n-nodes-base.if",
"position": [
-1344,
384
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "9e28789f-61a6-4fcb-b132-294825f6ea39",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.status }}",
"rightValue": "approved"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "c20edb41-1400-4f8d-a90e-c61bda0295c7",
"name": "Construire le payload calendrier",
"type": "n8n-nodes-base.set",
"position": [
-896,
384
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "a7cb20ad-8a14-4252-9bb2-499db02852cd",
"name": "=searchQuery",
"type": "string",
"value": "={{ $json.externalKey }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "5fe3aab5-3136-4619-8857-96e53578adbd",
"name": "Préparer les éléments de congé",
"type": "n8n-nodes-base.code",
"position": [
-1120,
384
],
"parameters": {
"jsCode": "// All time-off (including half-day) → keep creating as ALL-DAY events,\n// but also expose `isAllDay` based on Everhour's original period.\n\nfunction* eachDateInclusive(startStr, endStr, includeWeekends) {\n const start = new Date(startStr + 'T00:00:00');\n const end = new Date(endStr + 'T00:00:00');\n for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {\n const dow = d.getDay(); // 0=Sun .. 6=Sat\n if (!includeWeekends && (dow === 0 || dow === 6)) continue;\n yield new Date(d);\n }\n}\nfunction fmtDate(d){ return d.toISOString().slice(0,10); }\n\nconst out = [];\nfor (const item of items) {\n const r = item.json;\n if ((r.status || '').toLowerCase() !== 'approved') continue;\n if (r.type !== 'time-off') continue;\n\n const userName = r.user?.name || 'Unknown';\n const userEmail = r.user?.email || '';\n const startDate = r.startDate;\n const endDate = r.endDate || r.startDate;\n const includeWeekends = !!r.includeWeekends;\n const period = r.timeOffPeriod || 'full-day'; // 'full-day' | 'half-of-day'\n const type = r.timeOffType?.name || 'Time Off';\n const note = r.note || '';\n const id = r.id;\n\n // Derive the original \"isAllDay\" from Everhour's period (without changing mapping)\n const isAllDayOriginal = (period !== 'half-of-day');\n\n // Expand per-day; skip weekends if flag=false\n for (const d of eachDateInclusive(startDate, endDate, includeWeekends)) {\n const day = fmtDate(d);\n\n // All-day mapping (end date exclusive)\n const endObj = new Date(d);\n endObj.setDate(endObj.getDate() + 1);\n const endExclusive = fmtDate(endObj);\n\n out.push({\n json: {\n // You are still creating ALL-DAY events\n isAllDay: isAllDayOriginal, // <-- added (reflects original Everhour period)\n startDate: day,\n endDateExclusive: endExclusive,\n\n employeeName: userName,\n employeeEmail: userEmail,\n type,\n note,\n status: r.status,\n\n // unique key per assignment-day\n externalKey: `everhour:${id}:${day}`,\n\n // keep for debugging/visibility\n originalPeriod: period\n }\n });\n }\n}\nreturn out;\n"
},
"typeVersion": 2
},
{
"id": "11e26f03-b016-445a-99b1-72b9e5b8c0c3",
"name": "Trouver l'événement existant par clé externe",
"type": "n8n-nodes-base.httpRequest",
"position": [
-672,
96
],
"parameters": {
"url": "={{ 'https://www.googleapis.com/calendar/v3/calendars/' + $items(\"Config\")[0].json.calendarId + '/events' }}",
"options": {},
"sendQuery": true,
"authentication": "predefinedCredentialType",
"queryParameters": {
"parameters": [
{
"name": "singleEvents",
"value": "true"
},
{
"name": "maxResults",
"value": "1"
},
{
"name": "=q",
"value": "={{ $json.externalKey }}"
}
]
},
"nodeCredentialType": "googleApi"
},
"typeVersion": 4.2
},
{
"id": "929dc366-f019-435e-88ed-9d1807ac70da",
"name": "Attacher l'ID d'événement trouvé",
"type": "n8n-nodes-base.code",
"position": [
-448,
96
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// This Function is in \"Run Once for Each Item\" mode.\n// $json here is the HTTP search response for THIS PTO item.\n\nconst ev = Array.isArray($json.items) ? $json.items[0] : null;\n\n// IMPORTANT: use the current index, not 0\nconst i = $itemIndex;\nconst src = $items(\"Build Calendar Payload\")[i].json;\n\nreturn {\n json: {\n ...src, // keep your PTO fields for THIS item\n existingEventId: ev ? ev.id : null, // id if found\n found: !!ev // boolean for IF node\n }\n};\n"
},
"typeVersion": 2
},
{
"id": "b05c97db-3810-4847-8a24-b81a824894ab",
"name": "Vérifier si l'événement existe",
"type": "n8n-nodes-base.if",
"position": [
-224,
96
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "59967d64-2b86-4c86-a653-45adec8fba72",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.found }}",
"rightValue": "true"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "1c3a725d-775e-452b-9567-b00f2a3181b2",
"name": "Mettre à jour l'événement全天",
"type": "n8n-nodes-base.googleCalendar",
"notes": "Calendar ID pulled from the Config node: `$items(\"Config\")[0].json.calendarId`.",
"position": [
0,
0
],
"parameters": {
"eventId": "={{ $json.existingEventId }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "={{ $items(\"Config\")[0].json.calendarId }}"
},
"operation": "update",
"updateFields": {
"end": "={{ $json.endDateExclusive }}",
"start": "={{ $json.startDate }}",
"allday": "yes",
"summary": "={{ $json.employeeName }} - {{ $json.type }}",
"description": "=Everhour PTO\nKey: {{$json.externalKey}}\nType: {{$json.type}}\nStatus: {{$json.status}}\nNote: {{$json.note}}\n"
}
},
"notesInFlow": true,
"typeVersion": 1.3
},
{
"id": "ba91bdf7-b56a-4f61-adc3-ef1a016ebde6",
"name": "Créer un événement全天",
"type": "n8n-nodes-base.googleCalendar",
"notes": "Calendar ID pulled from the Config node: `$items(\"Config\")[0].json.calendarId`.",
"position": [
0,
192
],
"parameters": {
"end": "={{ $json.endDateExclusive }}",
"start": "={{ $json.startDate }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "={{ $items(\"Config\")[0].json.calendarId }}"
},
"additionalFields": {
"allday": "yes",
"summary": "={{ $json.employeeName }} - {{ $json.type }}",
"description": "=Everhour PTO\nKey: {{$json.externalKey}}\nType: {{$json.type}}\nStatus: {{$json.status}}\nNote: {{$json.note}}\n"
}
},
"notesInFlow": true,
"typeVersion": 1.3
},
{
"id": "2d4aeb2e-742d-499c-9e94-8a8be2c5c9d6",
"name": "Lister les événements d'affectation",
"type": "n8n-nodes-base.httpRequest",
"notes": "Calendar ID pulled from the Config node: `$items(\"Config\")[0].json.calendarId`.",
"position": [
-432,
576
],
"parameters": {
"url": "={{ 'https://www.googleapis.com/calendar/v3/calendars/' + $items(\"Config\")[0].json.calendarId + '/events' }}",
"options": {},
"sendQuery": true,
"authentication": "predefinedCredentialType",
"queryParameters": {
"parameters": [
{
"name": "singleEvents",
"value": "true"
},
{
"name": "maxResults",
"value": "2500"
},
{
"name": "orderBy",
"value": "startTime"
},
{
"name": "q",
"value": "={{ 'everhour:' + $json.assignmentId + ':' }}"
}
]
},
"nodeCredentialType": "googleApi"
},
"notesInFlow": true,
"typeVersion": 4.2
},
{
"id": "cca57225-aef9-4426-9d21-816e8a882ab9",
"name": "Trouver les événements obsolètes (par affectation)",
"type": "n8n-nodes-base.code",
"position": [
-208,
576
],
"parameters": {
"jsCode": "// Run Once for ALL Items\n// Pair each HTTP Request2 result (events for an assignment) with the matching group from Code2\n\nconst groups = $items(\"Build Assignment Groups\").map(it => it.json); // <-- node name must match exactly\nconst out = [];\n\nfor (let i = 0; i < items.length; i++) {\n const group = groups[i];\n if (!group) continue;\n\n const current = new Set(group.currentKeys);\n const apiItems = Array.isArray(items[i].json.items) ? items[i].json.items : [];\n\n for (const ev of apiItems) {\n const desc = ev.description || \"\";\n const m = desc.match(/Key:\\s*(everhour:[^\\s]+)/i); // \"Key: everhour:<id>:<date>\"\n if (!m) continue;\n const key = m[1];\n\n if (!current.has(key)) {\n out.push({\n json: { eventId: ev.id, key, assignmentId: group.assignmentId }\n });\n }\n }\n}\n\nreturn out; // one item per stale event to delete\n"
},
"typeVersion": 2
},
{
"id": "acf5aa87-0784-4633-a127-0cae6a069bf8",
"name": "Supprimer l'événement calendrier",
"type": "n8n-nodes-base.googleCalendar",
"notes": "Calendar ID pulled from the Config node: `$items(\"Config\")[0].json.calendarId`.",
"position": [
16,
672
],
"parameters": {
"eventId": "={{ $json.eventId }}",
"options": {
"sendUpdates": "none"
},
"calendar": {
"__rl": true,
"mode": "list",
"value": "={{ $items(\"Config\")[0].json.calendarId }}"
},
"operation": "delete"
},
"notesInFlow": true,
"retryOnFail": true,
"typeVersion": 1.3
},
{
"id": "6c4c4f1e-7772-41f7-9ef9-22936167b523",
"name": "Lister tous les événements Everhour",
"type": "n8n-nodes-base.httpRequest",
"notes": "Calendar ID pulled from the Config node: `$items(\"Config\")[0].json.calendarId`.",
"position": [
-432,
768
],
"parameters": {
"url": "={{ 'https://www.googleapis.com/calendar/v3/calendars/' + $items(\"Config\")[0].json.calendarId + '/events' }}",
"options": {},
"sendQuery": true,
"authentication": "predefinedCredentialType",
"queryParameters": {
"parameters": [
{
"name": "singleEvents",
"value": "true"
},
{
"name": "maxResults",
"value": "2500"
},
{
"name": "orderBy",
"value": "startTime"
},
{
"name": "q",
"value": "everhour:"
}
]
},
"nodeCredentialType": "googleApi"
},
"notesInFlow": true,
"typeVersion": 4.2
},
{
"id": "6651bc72-0b3d-4fe3-99cd-e1ff5a092da0",
"name": "Trouver les événements obsolètes (global)",
"type": "n8n-nodes-base.code",
"position": [
-208,
768
],
"parameters": {
"jsCode": "// Run Once for ALL Items\n// Compare calendar events (items[0].json.items) vs currentKeys from \"Build global key set\"\n\nconst current = new Set($items(\"Build Global Key Set\")[0].json.currentKeys);\nconst evs = Array.isArray(items[0].json.items) ? items[0].json.items : [];\nconst out = [];\n\nfor (const ev of evs) {\n const desc = ev.description || \"\";\n const m = desc.match(/Key:\\s*(everhour:[^\\s]+)/i); // extracts \"everhour:<id>:<date>\"\n if (!m) continue;\n const key = m[1];\n if (!current.has(key)) {\n out.push({ json: { eventId: ev.id, key }});\n }\n}\nreturn out; // one item per stale event to delete\n"
},
"typeVersion": 2
},
{
"id": "ac73d08e-3e0b-416f-8ec9-89b11e4c3a25",
"name": "Config",
"type": "n8n-nodes-base.set",
"notes": "Set your Google Calendar ID here. Example: team-calendar@group.calendar.google.com",
"position": [
-1856,
160
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "0b59d6f6-4e28-4f6d-a4ad-0cb253b9a65f",
"name": "calendarId",
"type": "string",
"value": "REPLACE_WITH_YOUR_CALENDAR_ID@group.calendar.google.com"
}
]
},
"includeOtherFields": true
},
"notesInFlow": true,
"typeVersion": 3.4,
"alwaysOutputData": true
},
{
"id": "9bde197a-7009-41d3-ac7e-6b86ccdd2863",
"name": "🗒️ Description du modèle (Read Me)",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2960,
160
],
"parameters": {
"color": null,
"width": 1024,
"height": 736,
"content": "## Everhour time-off sync to Google Calendar\n\n### Who’s it for\nTeams using **Everhour** for time tracking and **Google Calendar** for visibility.\n\n### What it does\n- Fetches **approved time-off** from Everhour\n- Creates/updates **all-day events** per day of absence\n- Deletes **stale events** if requests change or are canceled\n\n### How it works\n1. **Schedule Trigger** runs on an interval.\n2. Fetch Everhour assignments via API (Header Auth — set your Everhour API key in n8n credentials).\n3. Filter to **approved** time-off.\n4. Create/update events keyed by `everhour:<assignmentId>:<YYYY-MM-DD>`.\n5. Remove obsolete calendar events by comparing current keys with what’s on the calendar.\n\n### Setup\n- Create Everhour **Header Auth** credential: `X-Api-Key: <YOUR_EVERHOUR_API_KEY>`.\n- Add your **Google Calendar** OAuth credential to Calendar nodes.\n- In the **Config** node, set `calendarId` (e.g., `team@group.calendar.google.com`).\n\n### Customize\n- Change schedule cadence.\n- Filter by users/time-off types.\n- Adjust event title/description template.\n"
},
"typeVersion": 1
},
{
"id": "3dbeed2f-b8db-493e-ac9f-32b393008668",
"name": "Note : Récupérer Everhour",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1632,
240
],
"parameters": {
"color": 7,
"height": 336,
"content": "## **Fetch Everhour**\n\nFetch approved time-off from Everhour using Header Auth (no keys in node)."
},
"typeVersion": 1
},
{
"id": "a595b36f-b23f-4356-85ce-2da5a0758d03",
"name": "Note : Construire les clés",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1168,
256
],
"parameters": {
"color": 7,
"width": 416,
"height": 336,
"content": "## **Build Keys**\n\nGenerate per-day `externalKey` like `everhour:<id>:<date>`."
},
"typeVersion": 1
},
{
"id": "b028f58c-bb85-4894-a274-a099a4ea92ec",
"name": "Note : Upsert des événements",
"type": "n8n-nodes-base.stickyNote",
"position": [
-720,
-112
],
"parameters": {
"color": 7,
"width": 976,
"height": 512,
"content": "## **Upsert Events**\n\nSearch by key → update if found, otherwise create all-day event."
},
"typeVersion": 1
},
{
"id": "921f878d-1014-4018-995c-bac11224961a",
"name": "Note : Nettoyage",
"type": "n8n-nodes-base.stickyNote",
"position": [
-704,
432
],
"parameters": {
"color": 7,
"width": 960,
"height": 528,
"content": "## **Cleanup**\n\nList events and delete those not present in current keys."
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "13a31a87-6b2e-4e1d-9f14-0f8a350b0d78",
"connections": {
"fe08e8fe-779b-4428-8060-08da88a61118": {
"main": [
[
{
"node": "c76c87dc-876c-46f0-ac7e-a4a15ac3661c",
"type": "main",
"index": 0
},
{
"node": "ac73d08e-3e0b-416f-8ec9-89b11e4c3a25",
"type": "main",
"index": 0
}
]
]
},
"f210fb86-0d78-4140-adff-0573566b23ac": {
"main": [
[
{
"node": "6c4c4f1e-7772-41f7-9ef9-22936167b523",
"type": "main",
"index": 0
}
]
]
},
"929dc366-f019-435e-88ed-9d1807ac70da": {
"main": [
[
{
"node": "b05c97db-3810-4847-8a24-b81a824894ab",
"type": "main",
"index": 0
}
]
]
},
"b05c97db-3810-4847-8a24-b81a824894ab": {
"main": [
[
{
"node": "1c3a725d-775e-452b-9567-b00f2a3181b2",
"type": "main",
"index": 0
}
],
[
{
"node": "ba91bdf7-b56a-4f61-adc3-ef1a016ebde6",
"type": "main",
"index": 0
}
]
]
},
"c20edb41-1400-4f8d-a90e-c61bda0295c7": {
"main": [
[
{
"node": "11e26f03-b016-445a-99b1-72b9e5b8c0c3",
"type": "main",
"index": 0
},
{
"node": "8082b4f8-5ff0-4af3-ac3f-268cdd8bee97",
"type": "main",
"index": 0
},
{
"node": "f210fb86-0d78-4140-adff-0573566b23ac",
"type": "main",
"index": 0
}
]
]
},
"2d4aeb2e-742d-499c-9e94-8a8be2c5c9d6": {
"main": [
[
{
"node": "cca57225-aef9-4426-9d21-816e8a882ab9",
"type": "main",
"index": 0
}
]
]
},
"5fe3aab5-3136-4619-8857-96e53578adbd": {
"main": [
[
{
"node": "c20edb41-1400-4f8d-a90e-c61bda0295c7",
"type": "main",
"index": 0
}
]
]
},
"8082b4f8-5ff0-4af3-ac3f-268cdd8bee97": {
"main": [
[
{
"node": "2d4aeb2e-742d-499c-9e94-8a8be2c5c9d6",
"type": "main",
"index": 0
}
]
]
},
"92a16e7c-bb00-439f-b819-6b7557ff5017": {
"main": [
[
{
"node": "5fe3aab5-3136-4619-8857-96e53578adbd",
"type": "main",
"index": 0
}
]
]
},
"6c4c4f1e-7772-41f7-9ef9-22936167b523": {
"main": [
[
{
"node": "6651bc72-0b3d-4fe3-99cd-e1ff5a092da0",
"type": "main",
"index": 0
}
]
]
},
"c76c87dc-876c-46f0-ac7e-a4a15ac3661c": {
"main": [
[
{
"node": "92a16e7c-bb00-439f-b819-6b7557ff5017",
"type": "main",
"index": 0
}
]
]
},
"6651bc72-0b3d-4fe3-99cd-e1ff5a092da0": {
"main": [
[
{
"node": "acf5aa87-0784-4633-a127-0cae6a069bf8",
"type": "main",
"index": 0
}
]
]
},
"11e26f03-b016-445a-99b1-72b9e5b8c0c3": {
"main": [
[
{
"node": "929dc366-f019-435e-88ed-9d1807ac70da",
"type": "main",
"index": 0
}
]
]
},
"cca57225-aef9-4426-9d21-816e8a882ab9": {
"main": [
[
{
"node": "acf5aa87-0784-4633-a127-0cae6a069bf8",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Avancé - Ressources Humaines
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
Partager ce workflow