Entwicklerdokumentation
Quickstart
In vier Schritten erstellen Sie einen API-Key, senden Ihre erste Anfrage und empfangen Webhooks sicher.
1. API-Key erstellen
Legen Sie in der Kontokonsole eine Integration an und erstellen Sie einen API-Key. Der vollständige Key wird nur einmal angezeigt; speichern Sie ihn sicher in einem Secret-Manager.
- Konto → API & Webhooks – legen Sie eine Integration für Ihren persönlichen Workspace oder einen Teamspace an, dessen Inhaber Sie sind.
- Wählen Sie die Scopes:
notes:read,transcripts:read,summaries:read,webhooks:manage. - Der Key hat die Form
alt_live_{key_id}.{secret}und wird nur einmal angezeigt. Bewahren Sie ihn in einem Secret-Manager auf.
Hinterlegen Sie den API-Key als Umgebungsvariable in Ihrer Shell, damit die folgenden Befehle unverändert funktionieren:
export ALT_API_KEY="alt_live_...paste-your-key-here..."2. Vorhandene Notizen abrufen
Übergeben Sie den von der API zurückgegebenen cursor an die nächste Anfrage, um die vollständige Notizliste abzurufen. Laden Sie anschließend für jede Notiz Transkript und Zusammenfassung.
curl 'https://public-api.altalt.io/v1/notes?limit=100' \
-H "Authorization: Bearer $ALT_API_KEY"
# Follow next_cursor until has_more is false
curl 'https://public-api.altalt.io/v1/notes?limit=100&cursor=NEXT_CURSOR' \
-H "Authorization: Bearer $ALT_API_KEY"
# Fetch content per note (scopes: transcripts:read / summaries:read)
curl 'https://public-api.altalt.io/v1/notes/NOTE_ID/transcript' \
-H "Authorization: Bearer $ALT_API_KEY"
curl 'https://public-api.altalt.io/v1/notes/NOTE_ID/summary' \
-H "Authorization: Bearer $ALT_API_KEY"Nach der ersten Synchronisierung müssen Sie nicht erneut alle Notizen laden. Mit ?updated_after=<last sync time> rufen Sie nur Änderungen seit der letzten Synchronisierung ab; alternativ verwenden Sie Webhooks.
3. Webhook-Endpunkt registrieren
Registrieren Sie einen öffentlichen HTTPS-Endpunkt, damit Sie Benachrichtigungen über neue und geänderte Notizen erhalten, statt die API wiederholt abzufragen.
curl -X POST 'https://public-api.altalt.io/v1/webhook-endpoints' \
-H "Authorization: Bearer $ALT_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"url": "https://example.com/webhooks/alt",
"events": ["note.ended", "note.summary.generated", "note.updated", "note.deleted"]
}'Die Antwort enthält das signing_secret (whsec_...) zur Prüfung der Webhook-Signaturen; der vollständige Wert wird nur einmal angezeigt. Der Endpunkt startet im Status pending_verification und wird aktiv, sobald Ihr Empfänger auf das Verification-Event mit 2xx antwortet. Die Registrierung ist auch ohne Code in der Konsole möglich.
4. Webhook-Signaturen verifizieren
Prüfen Sie bei jeder Webhook-Anfrage die Standard-Webhooks-Signatur, um die Herkunft von Alt zu bestätigen. Überspringen Sie Duplikate anhand der event_id, antworten Sie zuerst und laden Sie danach den aktuellen Inhalt über die REST API.
Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
import http from "node:http";
// whsec_... secret from endpoint creation (shown once). Keep it server-side.
const SECRET = process.env.ALT_WEBHOOK_SECRET;
const secretBytes = Buffer.from(SECRET.slice("whsec_".length), "base64url");
const TOLERANCE_SECONDS = 300;
function isValidSignature(headers, rawBody) {
const id = headers["webhook-id"];
const timestamp = headers["webhook-timestamp"];
const signatureHeader = headers["webhook-signature"];
if (!id || !timestamp || !signatureHeader) return false;
// Reject stale timestamps (replay protection)
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > TOLERANCE_SECONDS) return false;
const expected = createHmac("sha256", secretBytes)
.update(`${id}.${timestamp}.${rawBody}`)
.digest("base64");
// Header may contain multiple space-delimited signatures: "v1,abc v1,def"
return String(signatureHeader)
.split(" ")
.some((part) => {
const [version, signature] = part.split(",");
if (version !== "v1" || !signature) return false;
const a = Buffer.from(signature);
const b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
});
}
http
.createServer((req, res) => {
if (req.method !== "POST" || req.url !== "/webhooks/alt") {
res.writeHead(404).end();
return;
}
let rawBody = "";
req.on("data", (chunk) => (rawBody += chunk));
req.on("end", () => {
if (!isValidSignature(req.headers, rawBody)) {
res.writeHead(401).end();
return;
}
const event = JSON.parse(rawBody);
// 1. Dedupe on event.event_id (deliveries are at-least-once).
// 2. Enqueue for async processing, then ack fast.
// 3. Fetch the note from the REST API; apply only if revision is newer.
console.log(event.event_type, event.data.note_id, event.data.revision);
res.writeHead(204).end();
});
})
.listen(3000);Python
import base64, hashlib, hmac, json, os, time
from http.server import BaseHTTPRequestHandler, HTTPServer
# whsec_... secret from endpoint creation (shown once). Keep it server-side.
raw_secret = os.environ["ALT_WEBHOOK_SECRET"].removeprefix("whsec_")
SECRET = base64.urlsafe_b64decode(raw_secret + "=" * (-len(raw_secret) % 4))
TOLERANCE_SECONDS = 300
def is_valid_signature(headers, raw_body: bytes) -> bool:
msg_id = headers.get("webhook-id", "")
timestamp = headers.get("webhook-timestamp", "")
signature_header = headers.get("webhook-signature", "")
if not msg_id or not timestamp or not signature_header:
return False
# Reject stale timestamps (replay protection)
if abs(time.time() - float(timestamp)) > TOLERANCE_SECONDS:
return False
signed_content = f"{msg_id}.{timestamp}.".encode() + raw_body
digest = hmac.new(SECRET, signed_content, hashlib.sha256).digest()
expected = base64.b64encode(digest).decode()
# Header may contain multiple space-delimited signatures: "v1,abc v1,def"
for part in signature_header.split(" "):
version, _, signature = part.partition(",")
if version == "v1" and signature and hmac.compare_digest(signature, expected):
return True
return False
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
if self.path != "/webhooks/alt":
self.send_response(404); self.end_headers(); return
raw_body = self.rfile.read(int(self.headers.get("Content-Length", 0)))
if not is_valid_signature(self.headers, raw_body):
self.send_response(401); self.end_headers(); return
event = json.loads(raw_body)
# 1. Dedupe on event["event_id"] (deliveries are at-least-once).
# 2. Enqueue for async processing, then ack fast.
# 3. Fetch the note from the REST API; apply only if revision is newer.
print(event["event_type"], event["data"]["note_id"], event["data"]["revision"])
self.send_response(204); self.end_headers()
HTTPServer(("", 3000), Handler).serve_forever()Die Signaturen folgen der Spezifikation von Standard Webhooks. Daher können Sie die offiziellen standardwebhooks-Bibliotheken für npm und PyPI verwenden. Hinweise zu Duplikaten, Zustellreihenfolge und verpassten Änderungen finden Sie unter Webhooks.