Entwickler-API-Referenz
Verwende die REST-API von Krokanti Notes, um Notizen programmgesteuert zu lesen und zu schreiben, Workflows zu automatisieren oder Integrationen zu erstellen. Alle Endpoints akzeptieren und geben JSON zurück.
https://notes.krokanti.com/api100 req/min per tokenPro-Abonnement erforderlich
Der Zugriff per API-Token erfordert ein aktives Pro-Abonnement. Generiere deinen Token in Einstellungen → Verbindungen nach dem Upgrade.
Auf Pro upgraden →Authentifizierung
Alle API-Anfragen müssen einen persönlichen API-Token im Header Authorizationenthalten. Tokens generieren in Einstellungen → Verbindungen (Pro-Plan erforderlich). Tokens beginnen mit kn_ und werden nur einmal bei der Erstellung angezeigt — bewahre sie sicher auf.
curl https://notes.krokanti.com/api/notes \
-H "Authorization: Bearer kn_your_token_here" \
-H "Content-Type: application/json"Notizen
/api/notesListet alle Notizen des authentifizierten Benutzers auf. Unterstützt Filterung, Sortierung und Paginierung.
| Parameter | Typ | Beschreibung |
|---|---|---|
search | string | Volltextsuche in Titel und Inhalt |
folderId | string | Nach Ordner-ID filtern |
tag | string | Nach Tag-Name filtern (exakte Übereinstimmung) |
trashed | boolean | Auf "true" setzen, um Notizen im Papierkorb aufzulisten |
sortBy | updatedAt | createdAt | title | Sortierfeld (Standard: "updatedAt") |
sortOrder | asc | desc | Sortierrichtung (Standard: "desc") |
limit | number | Ergebnisse pro Seite — 1 bis 100 (Standard: 50) |
offset | number | Anzahl der zu überspringenden Ergebnisse (Standard: 0) |
- →Antwort: { notes: Note[], hasMore: boolean }
- →Angeheftete Notizen werden immer zuerst zurückgegeben, dann nach dem gewählten Feld sortiert
- →Der Inhalt sicherer Notizen wird als verschlüsselter Blob zurückgegeben (JSON-String beginnend mit {"v":1)
/api/notesErstellt eine neue leere Notiz. Gibt das erstellte Notizobjekt zurück.
- →Die neue Notiz hat leeren Titel und Inhalt — aktualisiere sie sofort mit PATCH
- →Antwortstatus: 201 Created
/api/notes/:idRuft eine einzelne Notiz per ID ab.
| Parameter | Typ | Beschreibung |
|---|---|---|
iderforderlich | string | Notiz-UUID |
- →Gibt 404 zurück, wenn die Notiz nicht existiert oder einem anderen Benutzer gehört
- →Der Inhalt sicherer Notizen wird als verschlüsselter Blob zurückgegeben
/api/notes/:idAktualisiert Titel, Inhalt, Tags, Ordner oder Metadaten einer Notiz. Unterstützt Konflikterkennung.
| Parameter | Typ | Beschreibung |
|---|---|---|
iderforderlich | string | Notiz-UUID (Pfadparameter) |
title | string | Neuer Titel |
content | string | Neuer HTML-Inhalt |
tags | string[] | Ersetzt das vollständige Tags-Array |
folderId | string | null | In Ordner verschieben (null um aus Ordner zu entfernen) |
isPinned | boolean | Notiz anheften oder lösen (nur Eigentümer) |
isPublic | boolean | Notiz veröffentlichen oder verbergen (nur Eigentümer) |
action | trash | restore | In Papierkorb verschieben oder wiederherstellen (nur Eigentümer) |
clientUpdatedAt | string (ISO 8601) | Zuletzt bekanntes updatedAt — für Konflikterkennung verwendet |
force | boolean | Konflikterkennung überspringen und Serverstatus überschreiben |
- →Gibt 409 mit { conflict: true, serverNote } zurück, wenn clientUpdatedAt älter als die Serverversion ist
- →Sichere Notizen können nicht über die API bearbeitet werden (gibt 403 zurück)
- →Mitarbeiter mit Bearbeitungsberechtigung können nur Titel und Inhalt aktualisieren — Tags und Ordner sind nur für den Eigentümer
/api/notes/:idLöscht eine Notiz dauerhaft. Dies ist irreversibel — verwende action: 'trash' via PATCH für weiches Löschen.
| Parameter | Typ | Beschreibung |
|---|---|---|
iderforderlich | string | Notiz-UUID |
Ordner
/api/foldersListet alle Ordner des authentifizierten Benutzers auf.
- →Antwort: { folders: Folder[] }
/api/foldersErstellt einen neuen Ordner.
| Parameter | Typ | Beschreibung |
|---|---|---|
nameerforderlich | string | Ordnername |
- →Antwortstatus: 201 Created
/api/folders/:idBenennt einen Ordner um.
| Parameter | Typ | Beschreibung |
|---|---|---|
iderforderlich | string | Ordner-UUID (Pfadparameter) |
nameerforderlich | string | Neuer Ordnername |
/api/folders/:idLöscht einen Ordner. Notizen darin werden nicht gelöscht — sie werden ordnerlos.
| Parameter | Typ | Beschreibung |
|---|---|---|
iderforderlich | string | Ordner-UUID |
Paginierung
Der GET /api/notes-Endpoint verwendet offset-basierte Paginierung. Steuere sie mit zwei Abfrageparametern:
| Parameter | Standard | Beschreibung |
|---|---|---|
limit | 50 | Ergebnisse pro Seite (1–100) |
offset | 0 | Anzahl der zu überspringenden Ergebnisse |
Die Antwort enthält einen hasMore -Boolean. Rufe die nächste Seite ab, indem du offset erhöhst:
// Fetch all notes (auto-pagination)
async function fetchAllNotes(token) {
const notes = [];
let offset = 0;
while (true) {
const res = await fetch(
`https://notes.krokanti.com/api/notes?limit=100&offset=${offset}`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const { notes: page, hasMore } = await res.json();
notes.push(...page);
if (!hasMore) break;
offset += 100;
}
return notes;
}Konflikterkennung
Die API verwendet optimistische Nebenläufigkeitskontrolle, um verlorene Aktualisierungen zu verhindern, wenn mehrere Clients dieselbe Notiz gleichzeitig bearbeiten.
Füge das Feld clientUpdatedAt in jede PATCH-Anfrage ein — setze es auf den Wert updatedAt der zuletzt abgerufenen Notiz. Wenn ein anderer Client eine neuere Version gespeichert hat, gibt die API 409 Conflict mit der aktuellen Serverversion zurück, damit du zusammenführen kannst:
// PATCH with conflict detection
const res = await fetch(`https://notes.krokanti.com/api/notes/${id}`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
title: "Updated title",
content: "<p>New content</p>",
clientUpdatedAt: note.updatedAt, // ISO 8601 string
}),
});
if (res.status === 409) {
const { serverNote } = await res.json();
// Merge your changes with serverNote, then retry with force: true
await fetch(`https://notes.krokanti.com/api/notes/${id}`, {
method: "PATCH",
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
body: JSON.stringify({ content: merged, force: true }),
});
}Übergebe force: true um die Konflikterkennung zu überspringen und den Serverstatus bedingungslos zu überschreiben.
Sichere Notizen
Sichere Notizen werden vor der Speicherung clientseitig mit AES-256-GCM verschlüsselt. Die API gibt den rohen verschlüsselten Blob zurück — sie kann ihn nicht entschlüsseln (der PIN verlässt nie den Browser).
- →GET /api/notes/:id — gibt Inhalt als verschlüsselten JSON-Blob zurück, der mit {"v":1,"alg":"AES-256-GCM",...} beginnt
- →PATCH /api/notes/:id — blockiert für sichere Notizen (gibt 403 zurück). Verschlüsselung kann nur über die Web-App erfolgen.
- →Sichere Notizen können nicht öffentlich gemacht werden (gibt 400 zurück, wenn isPublic: true gesendet wird).
Fehlercodes
Alle Fehlerantworten enthalten einen JSON-Body mit einem error -String und manchmal ein code -Feld für maschinenlesbare Untercodes.
| Status | Bedeutung | Häufige Ursache |
|---|---|---|
400 | Fehlerhafte Anfrage | Ungültiger Anfrage-Body (z.B. sichere Notiz öffentlich machen) |
401 | Nicht autorisiert | API-Token fehlt oder ist ungültig |
402 | Zahlung erforderlich | Funktion erfordert Pro-Abonnement (code: pro_required) |
403 | Verboten | Notiz gehört einem anderen Benutzer oder Bearbeitung einer sicheren Notiz via API |
404 | Nicht gefunden | Notiz oder Ordner existiert nicht |
409 | Konflikt | clientUpdatedAt ist veraltet — Antwort enthält serverNote zum Zusammenführen |
429 | Zu viele Anfragen | Ratenlimit überschritten — überprüfe den Retry-After-Antwortheader |
// Error response body
{ "error": "Rate limit exceeded" }
// With machine-readable subcode
{ "error": "Secure notes require Pro", "code": "pro_required" }
// Conflict response
{ "conflict": true, "serverNote": { "id": "...", "title": "...", "updatedAt": "..." } }Ratenlimits
API-Token-Anfragen sind auf 100 Anfragen pro Minute pro Token begrenzt (festes Fenster). Sitzungsbasierte Anfragen (Browser) sind nicht begrenzt.
Wenn das Limit überschritten wird, gibt die API 429 Too Many Requests mit einem Retry-After -Header zurück, der angibt, wie viele Sekunden vor einem erneuten Versuch gewartet werden soll.
# 429 response headers
HTTP/1.1 429 Too Many Requests
Retry-After: 42
Content-Type: application/json
{ "error": "Rate limit exceeded" }Code-Beispiele
Ersetze kn_your_token_here durch deinen echten API-Token aus Einstellungen → Verbindungen.
cURL
# List your 10 most recently updated notes
curl "https://notes.krokanti.com/api/notes?limit=10" \
-H "Authorization: Bearer kn_your_token_here"
# Create a new note
curl -X POST "https://notes.krokanti.com/api/notes" \
-H "Authorization: Bearer kn_your_token_here"
# Update a note's title and content
curl -X PATCH "https://notes.krokanti.com/api/notes/NOTE_ID" \
-H "Authorization: Bearer kn_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "title": "My Note", "content": "<p>Hello world</p>", "clientUpdatedAt": "2026-01-01T00:00:00.000Z" }'
# Search notes
curl "https://notes.krokanti.com/api/notes?search=meeting&limit=20" \
-H "Authorization: Bearer kn_your_token_here"
# Move a note to trash
curl -X PATCH "https://notes.krokanti.com/api/notes/NOTE_ID" \
-H "Authorization: Bearer kn_your_token_here" \
-H "Content-Type: application/json" \
-d '{ "action": "trash" }'JavaScript (fetch)
const BASE = "https://notes.krokanti.com/api";
const TOKEN = "kn_your_token_here";
const headers = {
Authorization: `Bearer ${TOKEN}`,
"Content-Type": "application/json",
};
// List notes
const { notes, hasMore } = await fetch(`${BASE}/notes?limit=50`, { headers }).then(r => r.json());
// Create a note
const note = await fetch(`${BASE}/notes`, { method: "POST", headers }).then(r => r.json());
// Update title + content
await fetch(`${BASE}/notes/${note.id}`, {
method: "PATCH",
headers,
body: JSON.stringify({
title: "Shopping list",
content: "<ul><li>Milk</li><li>Eggs</li></ul>",
clientUpdatedAt: note.updatedAt,
}),
});
// Add a tag
await fetch(`${BASE}/notes/${note.id}`, {
method: "PATCH",
headers,
body: JSON.stringify({ tags: ["shopping", "weekly"] }),
});
// Pin the note
await fetch(`${BASE}/notes/${note.id}`, {
method: "PATCH",
headers,
body: JSON.stringify({ isPinned: true }),
});
// List folders
const { folders } = await fetch(`${BASE}/folders`, { headers }).then(r => r.json());
// Create a folder and move the note to it
const folder = await fetch(`${BASE}/folders`, {
method: "POST",
headers,
body: JSON.stringify({ name: "Groceries" }),
}).then(r => r.json());
await fetch(`${BASE}/notes/${note.id}`, {
method: "PATCH",
headers,
body: JSON.stringify({ folderId: folder.id }),
});Python (requests)
import requests
BASE = "https://notes.krokanti.com/api"
TOKEN = "kn_your_token_here"
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
# List notes
resp = requests.get(f"{BASE}/notes", headers=HEADERS, params={"limit": 50})
data = resp.json()
notes, has_more = data["notes"], data["hasMore"]
# Create a note
note = requests.post(f"{BASE}/notes", headers=HEADERS).json()
# Update it
requests.patch(
f"{BASE}/notes/{note['id']}",
headers=HEADERS,
json={
"title": "Meeting notes",
"content": "<p>Action items:</p><ul><li>Follow up with Alice</li></ul>",
"clientUpdatedAt": note["updatedAt"],
},
)
# Search and print titles
resp = requests.get(f"{BASE}/notes", headers=HEADERS, params={"search": "meeting"})
for n in resp.json()["notes"]:
print(n["title"])
# Delete a note permanently
requests.delete(f"{BASE}/notes/{note['id']}", headers=HEADERS)