{ "name": "SMB ยท Booking Sync", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "booking", "responseMode": "onReceived", "options": { "allowedOrigins": "*" } }, "id": "b0000000-1111-2222-3333-444444444444", "name": "Booking webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [ 240, 300 ], "webhookId": "smb-booking-webhook-0001" }, { "parameters": { "jsCode": "const w=$input.first().json; const b=w.body||w;\nconst s=v=>{v=(v==null?'':String(v));return /^[=+\\-@\\t\\r]/.test(v)?\"'\"+v:v;};\nconst EA='http://easyappointments';\nconst AUTH='Basic __EA_AUTH__';\nconst get=p=>this.helpers.httpRequest({method:'GET',url:EA+'/index.php/api/v1/'+p,headers:{Authorization:AUTH},json:true});\nlet booking, business_name='', notify_channel='telegram';\nif(b.action&&b.payload){\n const p=b.payload;\n const r=await Promise.all([get('customers/'+p.id_users_customer),get('services/'+p.id_services),get('providers/'+p.id_users_provider)]);\n const cust=r[0], svc=r[1], prov=r[2];\n const tz=prov.timezone||'UTC';\n const toUtc=dt=>{ if(!dt) return null; const d=DateTime.fromFormat(String(dt),'yyyy-MM-dd HH:mm:ss',{zone:tz}); return d.isValid?d.toUTC().toISO():String(dt).replace(' ','T'); };\n booking={booking_id:'EA-'+p.id,client_id:String(prov.notes||'').trim(),\n customer_name:s(((cust.firstName||'')+' '+(cust.lastName||'')).trim()),\n customer_contact:s(cust.email||cust.phone||''),service:s(svc.name),\n start_time:toUtc(p.start_datetime),end_time:toUtc(p.end_datetime),\n source:'easyappointments',status:p.status||'confirmed'};\n business_name=s((prov.firstName||'')+' '+(prov.lastName||''));\n} else {\n booking={booking_id:b.booking_id||'B-'+Date.now(),client_id:s(b.client_id),\n customer_name:s(b.customer_name||b.name),customer_contact:s(b.customer_contact||b.contact||b.email||b.phone),\n service:s(b.service||b.service_interest),start_time:b.start_time||null,end_time:b.end_time||null,\n source:s(b.source||'manual'),status:s(b.status||'confirmed')};\n business_name=s(b.business_name); notify_channel=s(b.notify_channel||'telegram');\n}\nreturn [{json:{booking,business_name,notify_channel}}];" }, "id": "b0000000-1111-2222-3333-555555555555", "name": "Build booking row", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 460, 300 ] }, { "parameters": { "method": "POST", "url": "http://smb-crm:8080/api/bookings", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "X-CRM-Token", "value": "__CRM_TOKEN__" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ JSON.stringify($json.booking) }}", "options": {} }, "id": "b0000000-1111-2222-3333-666666666666", "name": "Save to CRM (bookings)", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 680, 300 ], "retryOnFail": true, "maxTries": 4, "waitBetweenTries": 3000 }, { "parameters": { "resource": "message", "operation": "sendMessage", "chatId": "5499280257", "text": "=๐Ÿ“… {{ $json.body.event === 'cancelled' ? 'Buchung storniert' : $json.body.event === 'rescheduled' ? 'Buchung verschoben' : 'Neue Buchung' }}\nBetrieb: {{ $json.body.business_name || $json.body.booking.client_id }}\nKunde: {{ $json.body.booking.customer_name || 'โ€”' }}\nLeistung: {{ $json.body.booking.service || 'โ€”' }}\nWann: {{ $json.body.booking.start_time || 'โ€”' }}\nKontakt: {{ $json.body.booking.customer_contact || 'โ€”' }}\nQuelle: {{ $json.body.booking.source }}", "additionalFields": { "appendAttribution": false } }, "id": "b0000000-1111-2222-3333-777777777777", "name": "Notify owner (Telegram)", "type": "n8n-nodes-base.telegram", "typeVersion": 1.2, "position": [ 900, 500 ], "credentials": { "telegramApi": { "id": "d9s4Ec5ocEH8FAxh", "name": "SMB Telegram (leads bot)" } } }, { "parameters": { "httpMethod": "POST", "path": "owner-notify", "responseMode": "onReceived", "options": { "allowedOrigins": "*" } }, "id": "b0000000-1111-2222-3333-888888888888", "name": "Owner notify webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [ 240, 500 ], "webhookId": "smb-owner-notify-webhook-0001" }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "b0000000-1111-2222-3333-aaaaaaaaaaaa", "leftValue": "={{ $json.body.notify_channel }}", "rightValue": "telegram", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "options": {} }, "id": "b0000000-1111-2222-3333-999999999999", "name": "Telegram channel?", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [ 460, 500 ] } ], "connections": { "Booking webhook": { "main": [ [ { "node": "Build booking row", "type": "main", "index": 0 } ] ] }, "Build booking row": { "main": [ [ { "node": "Save to CRM (bookings)", "type": "main", "index": 0 } ] ] }, "Owner notify webhook": { "main": [ [ { "node": "Telegram channel?", "type": "main", "index": 0 } ] ] }, "Telegram channel?": { "main": [ [ { "node": "Notify owner (Telegram)", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "callerPolicy": "workflowsFromSameOwner", "availableInMCP": false } }