Utiliser l'API
Toutes les applis Kombine passent par une seule API REST. Avec un jeton d’accès personnel, tes propres outils peuvent l’utiliser aussi. Tout ce qui suit fonctionne avec curl et jq.
- URL de base :
https://api.kombine.dev/v1 - Authentification : envoie le jeton sous la forme
Authorization: Bearer kmb_pat_… - Format : du JSON en entrée, du JSON en sortie. Les dates et heures sont au format ISO 8601 (
2026-10-23T09:00:00Z). - Référence complète : la spécification OpenAPI liste chaque endpoint et chaque champ. Colle-la dans n’importe quel visualiseur OpenAPI, ou donne-la à ton agent IA.
Configure ton shell une fois pour toutes :
export KOMBINE_TOKEN='kmb_pat_…'export API='https://api.kombine.dev/v1'k() { curl -sS -H "Authorization: Bearer $KOMBINE_TOKEN" -H 'Content-Type: application/json' "$@"; }Les exemples ci-dessous utilisent cette fonction k.
Il faut tasks : Lecture pour lister, Lecture et écriture pour modifier.
Lister les tâches. Les résultats arrivent par pages dans data, avec total, limit (200 par défaut, 500 max) et offset :
k "$API/tasks?limit=500" | jq '.data[] | {title, status, priority, due_date}'Il n’y a pas de filtre côté serveur par statut ou par date, alors filtre avec jq. Les tâches ouvertes dont l’échéance est aujourd’hui ou avant :
today=$(date +%F)k "$API/tasks?limit=500" | jq -r --arg d "$today" ' .data[] | select(.status != "DONE" and .is_archived == false and .due_date != null and .due_date[0:10] <= $d) | "\(.priority // "-")\t\(.title)"'Ajouter une tâche. C’est ton outil qui choisit l’id de la tâche (n’importe quel UUID), comme le font les applis. Ça rend les nouvelles tentatives sans risque : envoyer deux fois le même id ne peut pas créer deux tâches.
k -X POST "$API/tasks" -d "$(jq -n --arg id "$(uuidgen | tr A-Z a-z)" '{ id: $id, title: "Renew passport", priority: "HIGH", due_date: "2026-11-01T00:00:00Z", due_date_has_time: false, tags: ["errands"]}')"priority:LOW,MEDIUMouHIGH(omets-le pour aucune priorité)status:TODO(par défaut),IN_PROGRESSouDONEdue_date_has_time: falsesignifie « à faire ce jour-là », sans heure précise
Modifier une tâche. PUT ne modifie que les champs que tu envoies. Pour en marquer une comme terminée :
k -X PUT "$API/tasks/$TASK_ID" -d '{"status":"DONE"}'Terminer une tâche via l’API compte exactement comme dans les applis : c’est enregistré pour tes statistiques, et une tâche récurrente passe à sa prochaine date.
Sessions de concentration
Section intitulée « Sessions de concentration »Il faut sessions : Lecture et écriture. Enregistre une session faite ailleurs (une réunion, un footing, du temps suivi dans une autre appli) :
k -X POST "$API/sessions" -d "$(jq -n --arg id "$(uuidgen | tr A-Z a-z)" '{ id: $id, mode: "POMODORO", started_at: "2026-10-23T07:00:00Z", ended_at: "2026-10-23T07:25:00Z", duration_ms: 1500000, note: "Pairing on the importer"}')"mode vaut POMODORO, FLOW ou ADAPTIVE. Ajoute task_id ou activity_id pour l’associer. Liste tes activités avec k "$API/activities" | jq '.data[] | {id, name}'.
Minuteur
Section intitulée « Minuteur »Il faut timer : Lecture. Regarde ce qui tourne sur n’importe lequel de tes appareils :
k "$API/timer/state" | jq '{status, mode, is_break, started_at, elapsed_ms, task_id}'Une réponse vide (204) signifie qu’aucun minuteur ne tourne.
Démarrer ou arrêter le minuteur depuis un script n’est pas recommandé. Une session n’est enregistrée que par l’appli qui a fait tourner le minuteur, donc un minuteur lancé via l’API ne laisse aucune session derrière lui. Pour enregistrer du temps, crée plutôt une session (voir Sessions de concentration ci-dessus).
Statistiques
Section intitulée « Statistiques »Il faut stats : Lecture.
k "$API/stats/all-time" | jq '{totalFocusSessions, hours: ((.totalFocusSeconds // 0) / 3600 | floor), longestStreakLength}'k "$API/daily-snapshots?from=2026-10-01&to=2026-10-31" | jq '.snapshots[] | {date, sessions_completed, achieved}'Les statistiques globales sont calculées en arrière-plan. Sur un compte tout neuf, stats/all-time répond 404 (« No stats available yet ») tant qu’elles n’ont pas été calculées une première fois.
Les erreurs sont en JSON, avec un error_code sur lequel tu peux te baser, par exemple :
{ "title": "Forbidden", "status": 403, "detail": "Personal access token does not permit this route", "error_code": 1014 }| Statut | error_code |
Signification | Que faire |
|---|---|---|---|
| 400 | 5001, 5002 | Un champ manque ou n’est pas valide ; errors indique lequel |
Corrige la requête |
| 401 | 1013 | Jeton expiré | Crée un nouveau jeton |
| 401 | 1011 | Jeton révoqué | Crée un nouveau jeton |
| 401 | 1004 | Jeton non reconnu | Vérifie que tu l’as copié en entier |
| 403 | 1014 | Les permissions du jeton ne couvrent pas cette action | Crée un jeton avec les bonnes permissions |
| 409 | 4003 | Cet id est déjà pris |
Tu peux l’ignorer lors d’une nouvelle tentative |
| 409 | 4010 | Cette external_ref est déjà utilisée |
Voir Workflows |
| 429 | 6001 | Trop de requêtes | Attends Retry-After secondes |
GET /v1/error-codes les liste tous (pas besoin de jeton).
Chaque jeton a droit à 60 requêtes par minute, avec de courtes rafales jusqu’à 20. Au-delà, tu reçois un 429 avec un en-tête Retry-After. Les autres jetons et tes applis ne sont pas concernés.