Référence de l'API développeur
Utilisez l'API REST de Krokanti Notes pour lire et écrire des notes par programmation, automatiser des workflows ou créer des intégrations. Tous les endpoints acceptent et retournent du JSON.
https://notes.krokanti.com/api100 req/min per tokenAbonnement Pro requis
L'accès par token d'API nécessite un abonnement Pro actif. Générez votre token dans Paramètres → Connexions après la mise à niveau.
Passer à Pro →Authentification
Toutes les requêtes API doivent inclure un token d'API personnel dans l'en-tête Authorization. Générez des tokens dans Paramètres → Connexions (abonnement Pro requis). Les tokens commencent par kn_ et ne sont affichés qu'une seule fois à la création — conservez-les en lieu sûr.
curl https://notes.krokanti.com/api/notes \
-H "Authorization: Bearer kn_your_token_here" \
-H "Content-Type: application/json"Notes
/api/notesListe toutes les notes de l'utilisateur authentifié. Prend en charge le filtrage, le tri et la pagination.
| Paramètre | Type | Description |
|---|---|---|
search | string | Recherche plein texte dans le titre et le contenu |
folderId | string | Filtrer par ID de dossier |
tag | string | Filtrer par nom d'étiquette (correspondance exacte) |
trashed | boolean | Mettre à "true" pour lister les notes dans la corbeille |
sortBy | updatedAt | createdAt | title | Champ de tri (par défaut : "updatedAt") |
sortOrder | asc | desc | Direction du tri (par défaut : "desc") |
limit | number | Résultats par page — 1 à 100 (par défaut : 50) |
offset | number | Nombre de résultats à ignorer (par défaut : 0) |
- →Réponse : { notes: Note[], hasMore: boolean }
- →Les notes épinglées sont toujours retournées en premier, puis triées par le champ choisi
- →Le contenu des notes sécurisées est retourné sous forme de blob chiffré (chaîne JSON commençant par {"v":1)
/api/notesCrée une nouvelle note vide. Retourne l'objet note créé.
- →La nouvelle note a un titre et un contenu vides — mettez-la à jour immédiatement avec PATCH
- →Statut de réponse : 201 Created
/api/notes/:idRécupère une seule note par ID.
| Paramètre | Type | Description |
|---|---|---|
idrequis | string | UUID de la note |
- →Retourne 404 si la note n'existe pas ou appartient à un autre utilisateur
- →Le contenu des notes sécurisées est retourné sous forme de blob chiffré
/api/notes/:idMet à jour le titre, le contenu, les étiquettes, le dossier ou les métadonnées d'une note. Prend en charge la détection des conflits.
| Paramètre | Type | Description |
|---|---|---|
idrequis | string | UUID de la note (paramètre de chemin) |
title | string | Nouveau titre |
content | string | Nouveau contenu HTML |
tags | string[] | Remplace le tableau complet des étiquettes |
folderId | string | null | Déplacer vers un dossier (null pour retirer du dossier) |
isPinned | boolean | Épingler ou désépingler la note (propriétaire uniquement) |
isPublic | boolean | Publier ou dépublier la note (propriétaire uniquement) |
action | trash | restore | Déplacer vers la corbeille ou restaurer (propriétaire uniquement) |
clientUpdatedAt | string (ISO 8601) | Dernier updatedAt connu — utilisé pour la détection des conflits |
force | boolean | Ignorer la détection des conflits et écraser l'état du serveur |
- →Retourne 409 avec { conflict: true, serverNote } si clientUpdatedAt est plus ancien que la version du serveur
- →Les notes sécurisées ne peuvent pas être éditées via l'API (retourne 403)
- →Les collaborateurs avec permission d'édition peuvent uniquement mettre à jour le titre et le contenu — les étiquettes et le dossier sont réservés au propriétaire
/api/notes/:idSupprime définitivement une note. C'est irréversible — utilisez action: 'trash' via PATCH pour une suppression douce.
| Paramètre | Type | Description |
|---|---|---|
idrequis | string | UUID de la note |
Dossiers
/api/foldersListe tous les dossiers de l'utilisateur authentifié.
- →Réponse : { folders: Folder[] }
/api/foldersCrée un nouveau dossier.
| Paramètre | Type | Description |
|---|---|---|
namerequis | string | Nom du dossier |
- →Statut de réponse : 201 Created
/api/folders/:idRenomme un dossier.
| Paramètre | Type | Description |
|---|---|---|
idrequis | string | UUID du dossier (paramètre de chemin) |
namerequis | string | Nouveau nom du dossier |
/api/folders/:idSupprime un dossier. Les notes à l'intérieur ne sont pas supprimées — elles deviennent sans dossier.
| Paramètre | Type | Description |
|---|---|---|
idrequis | string | UUID du dossier |
Pagination
L'endpoint GET /api/notes utilise la pagination par offset. Contrôlez-la avec deux paramètres de requête :
| Paramètre | Par défaut | Description |
|---|---|---|
limit | 50 | Résultats par page (1–100) |
offset | 0 | Nombre de résultats à ignorer |
La réponse inclut un booléen hasMore . Récupérez la page suivante en incrémentant offset :
// 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;
}Détection des conflits
L'API utilise le contrôle de concurrence optimiste pour éviter les mises à jour perdues lorsque plusieurs clients éditent la même note simultanément.
Incluez le champ clientUpdatedAt dans chaque requête PATCH — définissez-le à la valeur updatedAt de la note que vous avez récupérée. Si un autre client a enregistré une version plus récente, l'API retourne 409 Conflict avec la version actuelle du serveur pour que vous puissiez fusionner :
// 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 }),
});
}Passez force: true pour ignorer la détection des conflits et écraser l'état du serveur de manière inconditionnelle.
Notes sécurisées
Les notes sécurisées sont chiffrées côté client avec AES-256-GCM avant d'être stockées. L'API retourne le blob chiffré brut — elle ne peut pas le déchiffrer (le code PIN ne quitte jamais le navigateur).
- →GET /api/notes/:id — retourne le contenu sous forme de blob JSON chiffré commençant par {"v":1,"alg":"AES-256-GCM",...}
- →PATCH /api/notes/:id — bloqué pour les notes sécurisées (retourne 403). Le chiffrement ne peut être effectué que depuis l'application web.
- →Les notes sécurisées ne peuvent pas être rendues publiques (retourne 400 si isPublic: true est envoyé).
Codes d'erreur
Toutes les réponses d'erreur incluent un corps JSON avec une chaîne error et parfois un champ code pour les sous-codes lisibles par machine.
| Statut | Signification | Cause commune |
|---|---|---|
400 | Mauvaise requête | Corps de requête invalide (ex. rendre une note sécurisée publique) |
401 | Non autorisé | Token d'API manquant ou invalide |
402 | Paiement requis | La fonctionnalité nécessite un abonnement Pro (code: pro_required) |
403 | Interdit | La note appartient à un autre utilisateur, ou édition d'une note sécurisée via l'API |
404 | Non trouvé | La note ou le dossier n'existe pas |
409 | Conflit | clientUpdatedAt est obsolète — la réponse inclut serverNote pour la fusion |
429 | Trop de requêtes | Limite de débit dépassée — vérifiez l'en-tête de réponse Retry-After |
// 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": "..." } }Limites de débit
Les requêtes avec token d'API sont limitées à 100 requêtes par minute par token (fenêtre fixe). Les requêtes basées sur session (navigateur) ne sont pas limitées.
Quand la limite est dépassée, l'API retourne 429 Too Many Requests avec un en-tête Retry-After indiquant combien de secondes attendre avant de réessayer.
# 429 response headers
HTTP/1.1 429 Too Many Requests
Retry-After: 42
Content-Type: application/json
{ "error": "Rate limit exceeded" }Exemples de code
Remplacez kn_your_token_here par votre vrai token d'API depuis Paramètres → Connexions.
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)