Krokanti Notes
API REST

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.

URL de base :https://notes.krokanti.com/api
Limite de débit :100 req/min per token

Abonnement 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"
Remarque : La gestion des tokens (créer, lister, révoquer) n'est disponible que via le navigateur — vous ne pouvez pas gérer les tokens via l'API elle-même.

Notes

GET/api/notes

Liste toutes les notes de l'utilisateur authentifié. Prend en charge le filtrage, le tri et la pagination.

ParamètreTypeDescription
searchstringRecherche plein texte dans le titre et le contenu
folderIdstringFiltrer par ID de dossier
tagstringFiltrer par nom d'étiquette (correspondance exacte)
trashedbooleanMettre à "true" pour lister les notes dans la corbeille
sortByupdatedAt | createdAt | titleChamp de tri (par défaut : "updatedAt")
sortOrderasc | descDirection du tri (par défaut : "desc")
limitnumberRésultats par page — 1 à 100 (par défaut : 50)
offsetnumberNombre 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)
POST/api/notes

Cré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
GET/api/notes/:id

Récupère une seule note par ID.

ParamètreTypeDescription
idrequisstringUUID 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é
PATCH/api/notes/:id

Met à 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ètreTypeDescription
idrequisstringUUID de la note (paramètre de chemin)
titlestringNouveau titre
contentstringNouveau contenu HTML
tagsstring[]Remplace le tableau complet des étiquettes
folderIdstring | nullDéplacer vers un dossier (null pour retirer du dossier)
isPinnedbooleanÉpingler ou désépingler la note (propriétaire uniquement)
isPublicbooleanPublier ou dépublier la note (propriétaire uniquement)
actiontrash | restoreDéplacer vers la corbeille ou restaurer (propriétaire uniquement)
clientUpdatedAtstring (ISO 8601)Dernier updatedAt connu — utilisé pour la détection des conflits
forcebooleanIgnorer 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
DELETE/api/notes/:id

Supprime définitivement une note. C'est irréversible — utilisez action: 'trash' via PATCH pour une suppression douce.

ParamètreTypeDescription
idrequisstringUUID de la note

Dossiers

GET/api/folders

Liste tous les dossiers de l'utilisateur authentifié.

  • Réponse : { folders: Folder[] }
POST/api/folders

Crée un nouveau dossier.

ParamètreTypeDescription
namerequisstringNom du dossier
  • Statut de réponse : 201 Created
PATCH/api/folders/:id

Renomme un dossier.

ParamètreTypeDescription
idrequisstringUUID du dossier (paramètre de chemin)
namerequisstringNouveau nom du dossier
DELETE/api/folders/:id

Supprime un dossier. Les notes à l'intérieur ne sont pas supprimées — elles deviennent sans dossier.

ParamètreTypeDescription
idrequisstringUUID du dossier

Pagination

L'endpoint GET /api/notes utilise la pagination par offset. Contrôlez-la avec deux paramètres de requête :

ParamètrePar défautDescription
limit50Résultats par page (1–100)
offset0Nombre 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.

StatutSignificationCause commune
400Mauvaise requêteCorps de requête invalide (ex. rendre une note sécurisée publique)
401Non autoriséToken d'API manquant ou invalide
402Paiement requisLa fonctionnalité nécessite un abonnement Pro (code: pro_required)
403InterditLa note appartient à un autre utilisateur, ou édition d'une note sécurisée via l'API
404Non trouvéLa note ou le dossier n'existe pas
409ConflitclientUpdatedAt est obsolète — la réponse inclut serverNote pour la fusion
429Trop de requêtesLimite 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)