Du willst sharepa direkt aus dem Chat benutzen? So verbindest du Claude oder ChatGPT
Mit einer Terminbuchung wählen Besucher direkt auf deiner Seite eine freie Zeit, etwa für ein Erstgespräch. Der Termin landet in deinem Google-Kalender, auf Wunsch mit Meet-Link, und beide bekommen eine Bestätigung. Die Buchung sitzt mitten in deiner Seite, im Design, das dein Chat gebaut hat.
Terminbuchung schalten wir gerade nach und nach frei. Wenn du sie nutzen möchtest, schreib an konrad@getsharepa.ch. Du richtest sie einmal in der App ein und sagst dann deinem Chat, dass er sie in die Seite einbauen soll.
So geht es
- Verbinde deinen Google-Kalender (nächster Abschnitt).
- Leg einen Termintyp an, zum Beispiel „Erstgespräch, 40 Minuten“.
- Wähl in den Einstellungen der Seite, welche Termintypen sie zeigt.
- Lass deinen Chat die Seite mit der Buchung bauen, mit dem Prompt weiter unten, und veröffentliche sie.
- Buch auf deiner Seite einmal selbst einen Termin. Er erscheint in deinem Google-Kalender und als Eintrag in der App. Sag ihn danach wieder ab.
Google Calendar verbinden
Öffne in der App Einstellungen › Termine und klick „Google Calendar verbinden“. Google fragt dich, ob sharepa zwei Dinge darf: sehen, wann du frei oder belegt bist, und Termine eintragen, die sharepa selbst anlegt. Stimm zu, dann zeigt die App „Verbunden mit“ und deine Google-Adresse.
sharepa sieht dabei nie, was in deinem Kalender steht, also keine Titel, Gäste oder Orte deiner Termine, nur die belegten Zeiträume. Gebucht wird in deinen Hauptkalender. Mit „Trennen“ nimmst du sharepa den Zugriff wieder, auch bei Google.
Termintyp anlegen
Unter Einstellungen › Termine klickst du „Termintyp anlegen“. Ein Termintyp beschreibt eine Art von Termin:
- Name und Dauer, etwa „Erstgespräch“ mit 40 Minuten.
- Wochenzeiten: an welchen Tagen und zu welchen Zeiten er buchbar ist, zum Beispiel Mo–Fr 9–12 Uhr.
- Puffer vor und nach dem Termin, damit du zwischen zwei Gesprächen Luft hast.
- Vorlauf: wie kurzfristig jemand buchen darf, zum Beispiel frühestens in 24 Stunden.
- Vorschau: wie weit im Voraus, zum Beispiel höchstens 60 Tage.
- Orte: Google Meet (sharepa erzeugt den Link beim Buchen), Telefon (die buchende Person gibt ihre Nummer an), vor Ort (deine Adresse) oder ein eigener Link, etwa zu deinem Zoom-Raum. Bietest du mehrere an, wählt die buchende Person.
Dazu legst du einmal fest, wann überhaupt gebucht werden darf, zum Beispiel Mo–Fr 7–20 Uhr. Kein Termintyp öffnet Zeiten ausserhalb davon. Jeder Typ bekommt einen Kurznamen wie erstgespraech, den dein Chat im Code verwendet.
Termintypen pro Seite wählen und eingrenzen
Öffne die Seite unter „Meine Seiten“, wechsle zu „Einstellungen“ und hak in der Karte „Termine“ an, welche Termintypen die Seite zeigt. Ohne Häkchen zeigt die Seite keine Zeiten.
Mit „Zeiten eingrenzen“ schränkst du einen Typ nur für diese Seite weiter ein: bestimmte Wochentage, bestimmte Zeitfenster oder ein Zeitraum von Datum bis Datum. So zeigt eine Seite für einen Workshop im März nur Zeiten im März, obwohl derselbe Typ sonst das ganze Jahr buchbar ist. Eingrenzen nimmt nur Zeiten weg, es fügt nie welche hinzu.
Prompt für den Chat
Hast du sharepa als Connector verbunden, kennt dein Chat die Terminbuchung von selbst. Sag ihm, was du willst, zum Beispiel:
Bau mir eine Seite für Erstgespräche mit Buchung. Oben ein kurzer Satz, wer ich bin und was im Gespräch passiert. Darunter die freien Zeiten der nächsten zwei Wochen, nach Tag gruppiert. Vor dem Buchen fragt die Seite: Worum geht es? und Wie hast du von mir gehört? Termintyp: erstgespraech. Ruhig, viel Weiss, gut am Handy.
Lädst du den Code von Hand hoch, häng diesen Block an deinen Prompt:
Technische Vorgaben für die Terminbuchung (die Seite wird auf sharepa gehostet):
- sharepa fügt der veröffentlichten Seite ein Skript hinzu, das window.sharepaTermine bereitstellt. Kein eigenes Skript dafür einbinden, keinen fremden Buchungsdienst und kein iframe verwenden.
- Das Skript lädt eventuell erst nach deinem Code. Vor dem ersten Aufruf prüfen, ob window.sharepaTermine da ist, sonst auf das Ereignis "sharepaTermine" auf document warten.
- sharepaTermine.typen() liefert { types: [{ id, name, description, duration, locations }], timezone }. locations enthält "meet", "telefon", "vorort" oder "link".
- sharepaTermine.zeiten(type, from, to) liefert { slots: [...] } mit freien Startzeiten in UTC. from und to sind Daten im Format JJJJ-MM-TT, höchstens 31 Tage auseinander.
- Zeiten immer mit Intl.DateTimeFormat in der Zeitzone des Besuchers anzeigen, nie selbst umrechnen.
- sharepaTermine.buchen({ type, start, name, email, location, phone, answers }) bucht. start ist genau ein Wert aus slots. location muss in locations des Typs stehen. phone nur bei location "telefon". answers ist ein flaches Objekt mit den eigenen Fragen der Seite (Feldnamen klein, ohne Unterstrich am Anfang).
- Beim Buchen erscheint kurz eine Sicherheitsprüfung von sharepa. Nichts dafür bauen.
- Fehler haben ein Feld code: "termine.belegt" (Zeit weg, Zeiten neu laden), "termine.turnstile" (Prüfung fehlgeschlagen, nochmals versuchen), "formular.heikel" (Antworten sehen nach Passwort oder Zahlungsdaten aus). Für alle anderen eine allgemeine Fehlermeldung zeigen.
- Gibt es window.sharepaTermine nach 5 Sekunden nicht, oder meldet typen() den Fehler "termine.aus", „Termine sind für diese Seite noch nicht eingerichtet.“ zeigen statt weiter zu laden.
- Keine Fragen nach Passwörtern, Kreditkarten- oder anderen Zahlungsdaten und keine Gesundheitsdaten.
- Nach dem Buchen „Gebucht“ zeigen und sagen, dass die Bestätigung per Mail kommt.Im Chat selbst siehst du noch keine freien Zeiten, weil das Skript erst auf der veröffentlichten Seite dazukommt. Veröffentliche die Seite und schau sie dir dort an.
Für Leute, die selbst bauen
Auf jeder Seite, die mindestens einen Termintyp zeigt, fügt sharepa das Skript /__sharepa/termine.js ein. Es stellt window.sharepaTermine bereit und spricht nur mit /__sharepa/termine auf der Adresse der Seite, nie mit Google direkt. Weil das Skript nach deinem Code laden kann, wartest du auf das Ereignis sharepaTermine.
Ein Beispiel in HTML für den Termintyp erstgespraech mit Google Meet:
<section id="buchung">
<div id="zeiten">Freie Zeiten werden geladen …</div>
<form id="angaben" hidden>
<p id="gewaehlt"></p>
<input name="name" required placeholder="Dein Name">
<input name="email" type="email" required placeholder="Deine E-Mail">
<textarea name="anliegen" placeholder="Worum geht es?"></textarea>
<button type="submit">Verbindlich buchen</button>
</form>
<p id="meldung" role="status"></p>
</section>
<script>
const TYP = "erstgespraech";
const format = new Intl.DateTimeFormat(undefined, { weekday: "short", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" });
const tag = (d) => d.toISOString().slice(0, 10);
let gewaehlt = null;
function bereit(fn) {
if (window.sharepaTermine) fn();
else document.addEventListener("sharepaTermine", fn, { once: true });
}
async function zeitenLaden() {
const box = document.getElementById("zeiten");
const heute = new Date();
try {
const { slots } = await sharepaTermine.zeiten(TYP, tag(heute), tag(new Date(heute.getTime() + 13 * 86400000)));
box.textContent = slots.length ? "" : "Gerade sind keine Zeiten frei.";
for (const s of slots) {
const knopf = document.createElement("button");
knopf.type = "button";
knopf.textContent = format.format(new Date(s));
knopf.onclick = () => {
gewaehlt = s;
document.getElementById("gewaehlt").textContent = knopf.textContent;
document.getElementById("angaben").hidden = false;
};
box.append(knopf);
}
} catch (e) {
box.textContent = "Termine sind gerade nicht verfügbar.";
}
}
document.getElementById("angaben").addEventListener("submit", async (ev) => {
ev.preventDefault();
const f = new FormData(ev.target);
const meldung = document.getElementById("meldung");
try {
await sharepaTermine.buchen({
type: TYP, start: gewaehlt, location: "meet",
name: f.get("name"), email: f.get("email"),
answers: { anliegen: f.get("anliegen") },
});
ev.target.hidden = true;
meldung.textContent = "Gebucht. Die Bestätigung ist unterwegs in dein Postfach.";
} catch (e) {
if (e.code === "termine.belegt") { meldung.textContent = "Diese Zeit ist eben weggegangen. Bitte wähl eine andere."; zeitenLaden(); }
else if (e.code === "termine.turnstile") meldung.textContent = "Die Sicherheitsprüfung hat nicht geklappt. Bitte nochmals versuchen.";
else if (e.code === "formular.heikel") meldung.textContent = "Bitte keine Passwörter oder Zahlungsdaten eingeben.";
else meldung.textContent = "Das hat nicht geklappt. Bitte nochmals versuchen.";
}
});
bereit(zeitenLaden);
</script>Dasselbe in React:
import { useEffect, useState } from "react";
const TYP = "erstgespraech";
const format = new Intl.DateTimeFormat(undefined, { weekday: "short", day: "numeric", month: "long", hour: "2-digit", minute: "2-digit" });
const tag = (d) => d.toISOString().slice(0, 10);
function useTermine() {
const [api, setApi] = useState(() => window.sharepaTermine ?? null);
useEffect(() => {
if (api) return;
const da = () => setApi(window.sharepaTermine);
document.addEventListener("sharepaTermine", da, { once: true });
return () => document.removeEventListener("sharepaTermine", da);
}, [api]);
return api;
}
export default function Buchung() {
const termine = useTermine();
const [zeiten, setZeiten] = useState(null);
const [gewaehlt, setGewaehlt] = useState(null);
const [meldung, setMeldung] = useState("");
const [fertig, setFertig] = useState(false);
async function laden() {
const heute = new Date();
try {
const { slots } = await termine.zeiten(TYP, tag(heute), tag(new Date(heute.getTime() + 13 * 86400000)));
setZeiten(slots);
} catch {
setMeldung("Termine sind gerade nicht verfügbar.");
}
}
useEffect(() => { if (termine) laden(); }, [termine]);
async function buchen(ev) {
ev.preventDefault();
const f = new FormData(ev.currentTarget);
try {
await termine.buchen({ type: TYP, start: gewaehlt, location: "meet", name: f.get("name"), email: f.get("email"), answers: { anliegen: f.get("anliegen") } });
setFertig(true);
} catch (e) {
if (e.code === "termine.belegt") { setMeldung("Diese Zeit ist eben weggegangen. Bitte wähl eine andere."); setGewaehlt(null); laden(); }
else if (e.code === "termine.turnstile") setMeldung("Die Sicherheitsprüfung hat nicht geklappt. Bitte nochmals versuchen.");
else if (e.code === "formular.heikel") setMeldung("Bitte keine Passwörter oder Zahlungsdaten eingeben.");
else setMeldung("Das hat nicht geklappt. Bitte nochmals versuchen.");
}
}
if (fertig) return <p>Gebucht. Die Bestätigung ist unterwegs in dein Postfach.</p>;
return (
<section>
{zeiten === null ? <p>Freie Zeiten werden geladen …</p> : zeiten.length === 0 ? <p>Gerade sind keine Zeiten frei.</p> :
zeiten.map((s) => <button key={s} type="button" aria-pressed={s === gewaehlt} onClick={() => setGewaehlt(s)}>{format.format(new Date(s))}</button>)}
{gewaehlt && (
<form onSubmit={buchen}>
<input name="name" required placeholder="Dein Name" />
<input name="email" type="email" required placeholder="Deine E-Mail" />
<textarea name="anliegen" placeholder="Worum geht es?" />
<button type="submit">Verbindlich buchen</button>
</form>
)}
{meldung && <p role="status">{meldung}</p>}
</section>
);
}Zu den Zeitzonen: zeiten() liefert die Startzeiten in UTC, zum Beispiel 2026-11-03T09:00:00Z. Intl.DateTimeFormat ohne Zeitzone zeigt sie in der Zeitzone des Besuchers an, wer in New York bucht, sieht also New Yorker Zeit. from und to sind Kalendertage in deiner Zeitzone, to zählt mit. typen() nennt deine Zeitzone unter timezone, falls du sie dazuschreiben willst.
Was die buchende Person bekommt
Nach dem Buchen zeigt deine Seite, was du gebaut hast, etwa „Gebucht“. Gleichzeitig passiert Folgendes:
- Bestätigung per Mail an die buchende Person, mit Termintyp, Zeit in ihrer und in deiner Zeitzone, Ort oder Meet-Link und einem Link zum Absagen.
- Einladung in den Kalender von Google: Die buchende Person ist Gast im Termin. Er erscheint bei ihr automatisch im Kalender, Absagen ebenso, und bei Google Meet kommt sie ohne Anfrage hinein. Als Organisator sieht sie deine Google-Adresse. Absender ist „Titel deiner Seite über sharepa“. Antwortet sie auf die Mail, landet die Antwort bei dir; deine E-Mail-Adresse ist dafür als Antwortadresse sichtbar.
- Mail an dich mit allen Angaben und Antworten und einem Link zum Eintrag in der App.
- Termin in deinem Google-Kalender, mit dem Titel „Erstgespräch mit Anna“, den Angaben in der Beschreibung und bei Google Meet mit einem neuen Meet-Link.
- Eintrag in der App im Bereich „Einträge“ der Seite, als „Buchung · Erstgespräch“ mit Zeit und Status. Hat die Seite auch ein Formular, filterst du nach „Formulare“ oder „Buchungen“. Hast du einen Webhook eingerichtet, geht die Buchung auch dorthin, mit dem Formularnamen
buchung:erstgespraech.

Absagen und Erinnerungen
24 Stunden vor dem Termin bekommt die buchende Person eine Erinnerung, sofern beim Buchen mehr als 24 Stunden Zeit blieben.
Absagen kann sie über den Link in der Mail, bis der Termin beginnt. Danach verschwindet der Termin aus deinem Kalender, beide bekommen eine Mail, und die Zeit ist wieder frei. Du selbst sagst unter Einstellungen › Termine › Buchungen ab, auf Wunsch mit einem Satz an die buchende Person. Verschieben gibt es nicht als eigenen Schritt: absagen und neu buchen.
Datenschutz
Name, E-Mail, Telefon und die Antworten auf deine Fragen speichert sharepa als Formulareintrag. Es gelten dieselben Regeln wie für jedes Formular: Du kannst Einträge löschen, und nach 12 Monaten löschen wir sie automatisch. Für diese Angaben bist du verantwortlich. Sag bei der Buchung, wer du bist und wofür du die Angaben brauchst, und nimm Google als Empfänger in deine Datenschutzerklärung auf, weil der Termin in deinem Google-Kalender steht.
Von Google liest sharepa nur, wann du belegt bist, und legt nur die gebuchten Termine an oder löscht sie. Die Daten aus deinem Kalender nutzen wir für nichts anderes, nicht für Werbung, und wir geben sie nicht weiter. Die Einzelheiten stehen in der Datenschutzerklärung.
Was das kostet
Terminbuchung gehört zum Einmal-Plan und kostet nichts extra. Jede Buchung zählt als Eintrag, es gelten also dieselben Grenzen wie für Formulare: 500 pro Seite und Tag und 5000 pro Konto in 30 Tagen. Dazu kommen höchstens 50 Buchungen pro Konto und Tag. Fällt dein Konto auf Gratis zurück, gehen keine neuen Buchungen mehr. Bestehende Termine, Erinnerungen und Absagen laufen weiter.
Fragen
Sieht sharepa, was in meinem Kalender steht?
Nein. sharepa fragt bei Google nur ab, wann du belegt bist. Titel, Gäste, Orte und Beschreibungen deiner Termine bekommt sharepa nie zu sehen. Eintragen und löschen kann sharepa nur die Termine, die es selbst angelegt hat.
Was passiert, wenn ich einen gebuchten Termin direkt in Google lösche?
sharepa merkt das und zeigt die Buchung als von dir abgesagt. Die buchende Person bekommt dann keine Mail, weil nicht klar ist, ob du das wolltest. Sag lieber in der App ab, dann bekommt sie Bescheid.
Geht das auch mit Outlook, Apple oder Cal.com?
Nein, vorerst nur mit Google Calendar. Bezahlte Termine, Termine für Teams und SMS-Erinnerungen gibt es auch nicht.
Geht das im Gratis-Plan?
Nein, Terminbuchung gibt es im Einmal-Plan. Gratis kannst du ein Formular bauen, in dem Besucher ihre Wunschzeit angeben.