Documentation

API

Routes, champs, exemples et sécurité : tout pour piloter TurboTexte depuis vos scripts.

Avant de lire

  1. Faut-il une offre particulière pour s’en servir ?

    La réponse

    Non : toute licence en cours de validité l’ouvre, période d’essai comprise. Voir « Qui y a droit ».

  2. D’où peut-on appeler cette API ?

    La réponse

    Depuis votre propre ordinateur, et de lui seul — sauf si vous cochez vous-même l’option qui l’ouvre au réseau. Voir « Adresse, jeton, sécurité ».

  3. Quelle description de l’API fait autorité ?

    La réponse

    Celle que sert votre application : /api/v1/openapi.json et /api/v1/docs. Elles décrivent votre version ; cette page décrit l’état général.

À quoi ça sert

TurboTexte expose, sur votre ordinateur, une API REST qui donne accès par programme à tout ce que l’interface permet : raccourcis, groupes, préférences, statistiques, historique, sauvegardes. Un script peut créer des centaines de raccourcis depuis un tableur, exporter la liste, activer un groupe, ou suspendre la substitution le temps d’une tâche.

Chaque adresse correspond à une action, et le verbe dit laquelle : GET lit, POST crée ou déclenche, PATCH modifie, DELETE supprime.

Qui y a droit

Tout abonnement payant, période d’essai comprise ; l’offre gratuite ne l’inclut pas. Sans ce droit, le serveur ne démarre pas et Préférences › API le dit. Le droit est retenu d’une exécution à l’autre : une panne de réseau ne retire jamais la fonction à qui l’a payée.

Adresse, jeton, sécurité

L’adresse de base est http://127.0.0.1:8420/api/v1. Le port se change dans Préférences › API, ou pour une exécution avec TurboTexte.exe --api-port 8421 ; --no-api démarre sans le serveur.

Chaque appel porte le jeton, sauf trois routes publiques (/ping, /openapi.json, /docs) :

Authorization: Bearer VOTRE_JETON

Pour les outils qui ne posent pas cet en-tête : l’en-tête X-TurboTexte-Token. Le jeton ne passe jamais dans l’adresse : une URL finit dans les journaux et l’historique du terminal.

Le jeton est dans Préférences › API (boutons Copier et Régénérer). Il est aussi écrit, à chaque démarrage du serveur, dans %LOCALAPPDATA%\turbotexte.org\TurboTexte\apiToken.txt. Mieux : lisez le champ tokenFile que rend GET /ping, sans coder ce chemin en dur.

  • Le serveur n’écoute que sur 127.0.0.1. La case Accepter les connexions venant d’autres ordinateurs l’ouvre à tout le réseau : à ne cocher que pour une raison précise, elle donne vos raccourcis et vos préférences à toute machine qui joint la vôtre.
  • Le jeton fait 256 bits aléatoires et se compare en temps constant.
  • Aucune origine web n’est autorisée par défaut : une page visitée dans votre navigateur ne peut pas appeler l’API. Pour un tableau de bord maison, listez son origine dans allowedOrigins.
  • L’API ne rend jamais le jeton de licence ni l’identifiant de machine. Le jeton d’API n’est rendu qu’une fois, dans la réponse à sa régénération ; /ping et /api-settings donnent le chemin du fichier de jeton, jamais sa valeur.
  • Traitez le jeton comme un mot de passe : il donne accès à tous vos raccourcis.

Forme des réponses

Les listes ont toutes la même forme :

{ "items": [ … ], "total": 1042, "limit": 200, "offset": 0, "returned": 200 }

Les erreurs aussi :

{ "error": { "code": "not_found", "message": "Aucun raccourci ne correspond à « bjr »." } }

Codes rencontrés : bad_request (400), unauthorized (401), abbreviation_limit_reached (403), import_not_included (403), not_found (404), method_not_allowed (405), conflict (409), missing_inputs (422), internal_error (500).

Les deux codes en 403 viennent de la formule gratuite et ne se rencontrent pas avec un abonnement : la création d’un raccourci est refusée quand le nombre d’abréviations personnelles de la formule est atteint, et l’import quand la formule ne le comprend pas. Rien n’est effacé ni désactivé : seules les créations sont refusées, et l’export reste ouvert quelle que soit la formule.

Désigner un raccourci ou un groupe

Partout où une route attend un identifiant, l’UUID fonctionne, et à défaut : pour un raccourci, son abréviation exacte (GET /combos/bjr) ; pour un groupe, son nom, sans distinction de casse (GET /groups/Formules). L’UUID reste la seule désignation non ambiguë : rien n’interdit à deux raccourcis de partager une abréviation.

Système et application

MéthodeCheminEffet
GET/pingVérifier que l’API répond. Sans jeton. Rend le nom, la version et, appelée depuis le poste lui-même, tokenFile.
GET/statusÉtat complet : version, nombre de raccourcis, dernier développement, serveur.
GET/openapi.jsonDescription OpenAPI 3.1. Sans jeton.
GET/docsDocumentation HTML autonome. Sans jeton.
PATCH/appActiver ou suspendre la substitution : {"enabled": false}.
POST/app/toggleInverser l’état.
POST/app/showAfficher la fenêtre principale.
POST/app/pickerOuvrir le sélecteur de raccourcis.
POST/app/statsOuvrir le tableau de bord des statistiques.
POST/app/onboardingOuvrir le didacticiel de prise en main.
POST/app/helpOuvrir le volet d’aide sur l’assistant Turbo.
POST/app/reportOuvrir le volet d’aide sur le formulaire de signalement.
POST/app/quitQuitter proprement.
GET/app/logDernières lignes du journal (?lines=200).

Raccourcis

MéthodeCheminEffet
GET/combosLister. ?search=, ?keyword=, ?group=, ?enabled=, ?full=, ?limit=, ?offset=.
POST/combosCréer. keyword obligatoire.
GET/combos/{id}Lire, par UUID ou par abréviation.
PATCH ou PUT/combos/{id}Modifier les champs fournis.
DELETE/combos/{id}Supprimer.
DELETE/combosSupprimer une liste d’un coup : {"uuids": […]}.
POST/combos/{id}/duplicateDupliquer, en modifiant au passage les champs fournis.
POST/combos/{id}/previewÉvaluer le contenu, variables comprises, sans rien insérer. Un raccourci qui attend une saisie répond 422 avec la liste des inputs à fournir.
POST/combos/importImporter une liste. ?skipExisting=true par défaut.
GET/combos/exportExporter. ?format=json|csv|cheatsheet.
POST/combos/saveForcer l’enregistrement sur le disque.
POST/combos/reloadRecharger depuis le disque.

Champs d’un raccourci : uuid, name, keyword, snippet, description, enabled, groupUuid, matchingMode (default, strict, loose), caseSensitivity (default, sensitive, insensitive), mnemonicPhrase, frequencyScore (0 à 10). En lecture seule : displayName, usable, groupName, effectiveMatchingMode, effectiveCaseSensitivity, createdAt, modifiedAt, lastUsedAt.

name est une étiquette facultative ; lisez displayName si vous voulez un libellé dans tous les cas. Toute modification est enregistrée sur le disque et inscrite dans l’historique : elle s’annule avec Ctrl+Z dans l’application, ou avec POST /history/undo.

Groupes

MéthodeCheminEffet
GET/groupsLister.
POST/groupsCréer.
GET/groups/{id}Lire, par UUID ou par nom.
PATCH ou PUT/groups/{id}Modifier.
DELETE/groups/{id}Supprimer, avec ses raccourcis. ?moveCombosTo= les déplace au lieu de les supprimer. Le dernier groupe ne se supprime pas (409).
GET/groups/{id}/combosLister les raccourcis du groupe.
POST/groups/{id}/moveDéplacer le groupe : {"index": 0}.
POST/groups/sortTrier les groupes par nom.
GET/groups/categoriesLes catégories acceptées, avec leur couleur.
POST/groups/{id}/import-csvImporter du CSV : {"csv": "…"} ou {"path": "…"}.
GET/groups/{id}/export-csvExporter le groupe en CSV.
POST/groups/restore-nativeRemplacer tous les groupes par ceux d’origine, après une copie des groupes actuels. Exige {"confirm": true}.

Champs d’un groupe : name, description, enabled ; type (normal, tableau, dynamique — ce dernier calcule ses textes au développement) ; category, une valeur de /groups/categories ou "", une catégorie inconnue étant refusée (400) ; color, en lecture seule, découle de la catégorie ; keywordPrefix ajouté devant chaque abréviation du groupe ; snippetPrefix ajouté devant chaque contenu, avant évaluation des variables ; tableMetadata, objet libre des groupes de type tableau.

Texte

MéthodeCheminEffet
POST/text/expand{"text": "…"} → {"text": "…", "expansionCount": 3}. Ne tape rien nulle part.
GET/text/matchesLes raccourcis qui correspondent à une saisie : ?input=bj.
GET/text/document-formatsLes extensions que le développement de document accepte.
POST/text/expand-documentDévelopper les abréviations d’un document entier dans une copie : {"path": "…"} → {"outputPath": "…", "expansionCount": 12}.

expand-document garde la mise en forme intacte et suit trois garde-fous : le document d’origine n’est jamais écrasé (sans outputPath, la copie est écrite à côté) ; un outputPath égal au fichier d’entrée est refusé (400) ; un outputPath qui existe déjà est refusé (409) sans "overwrite": true. text/expand compte dans les statistiques d’usage, comme une frappe.

Essayez vos premières requêtes

  1. Sans jeton, lancez curl http://127.0.0.1:8420/api/v1/ping.

    Comment savoir que ça a marché

    Un objet JSON revient, avec le nom de l’application, sa version et tokenFile. Si rien ne répond, le serveur est arrêté ou le port n’est pas celui-là.

  2. Copiez le jeton depuis Préférences › API, puis appelez /status avec l’en-tête Authorization: Bearer ….

    Comment savoir que ça a marché

    Vous obtenez l’état complet. Sans l’en-tête, la même adresse répond 401 : c’est la preuve que le jeton sert à quelque chose.

Préférences

MéthodeCheminEffet
GET/preferencesToutes les préférences. C’est la liste exacte des clés acceptées en PATCH.
PATCH/preferencesModifier les clés fournies. Une clé inconnue ou une valeur du mauvais type rejette tout l’appel, sans rien modifier.
POST/preferences/resetRétablir les valeurs par défaut.

Les clés sont celles du fichier de préférences exporté par l’application, plus celles que l’interface règle sans l’exporter : KeepFinalSpaceCharacter, WarnAboutEmptyComboKeyword, ShowOnboardingAtStartup, OnboardingCompleted, StatsRecapEnabled, UiMode, UiModeWasChosen, TypingSpeedCpm, UseCustomPowershellVersion, CustomPowershellPath, HelpButtonVisible, SkipVersionNumber (la version écartée par « Ignorer cette version », chaîne vide pour la rétablir). Restent hors de portée, délibérément : géométries de fenêtre, état des colonnes, drapeaux internes de migration, et la liste des scripts PowerShell que vous avez autorisés.

  • UiMode vaut 0 (Essentiel) ou 1 (Complet). Le mode ne change que ce qui est montré, jamais ce qui est fait ; l’écriture est prise à chaud.
  • HelpButtonVisible montre ou cache le bouton « ? » de la fenêtre principale. Poser une question à Turbo ou envoyer un signalement n’est pas exposé : les deux consomment un quota facturé à l’éditeur.
  • ShowOnboardingAtStartup et OnboardingCompleted se lisent ensemble : remettre les deux à leur défaut rejoue le didacticiel au prochain lancement.
  • Le son de substitution : PlaySoundOnCombo (faux par défaut), ComboSoundId (tick, click, pop, blip, drop, chime, notification), UseCustomSound et CustomSoundPath.

Configuration de l’API, statistiques, historique, sauvegardes

MéthodeCheminEffet
GET/api-settingsÉtat et configuration du serveur. Le jeton n’est jamais renvoyé.
PATCH/api-settingsenabled, port, allowRemoteConnections, allowedOrigins. Un changement de port prend effet un quart de seconde après la réponse.
POST/api-settings/tokenRégénérer le jeton. Il est renvoyé une fois, dans la réponse.
GET/stats?period=thisMonth|last7Days|last30Days|lastMonth|thisYear|allTime, ou ?from=&to= en AAAA-MM-JJ.
POST/stats/eraseEffacer définitivement toutes les statistiques. Exige {"confirm": true}.
GET/historyLes modifications enregistrées, avec canUndo et canRedo.
POST/history/undoAnnuler la dernière modification.
POST/history/redoLa rétablir.
POST/history/positionAnnuler ou rétablir jusqu’à une position donnée.
GET/backupsLister les sauvegardes.
POST/backupsEn créer une.
POST/backups/restoreRestaurer : {"path": "…"}.

Confidentialité, synchronisation, mise à jour

MéthodeCheminEffet
GET/privacyLes réglages, plus statisticsRecorded et applicationNamesRecorded.
PATCH/privacystatsCollectionMode (full, noApplicationNames, disabled), encryptStatsFile, userMadeChoice. Agit sur l’existant : un mode plus strict efface ce qui est déjà enregistré.
GET/syncÉtat (disabled, idle, running, offline, refused), réglages, dernière synchronisation, dernière erreur.
PATCH/syncenabled, intervalMinutes (1 à 1440), excludedGroups.
POST/sync/nowLancer un cycle. Refuse (409) tant que la synchronisation est désactivée.
GET/updateVersion installée, state (neverChecked, upToDate, updateAvailable, checkFailed), version disponible et caractère obligatoire.
POST/update/checkDéclencher une vérification. Réponse immédiate ; relisez GET /update.

Les statistiques ne quittent jamais l’ordinateur, quel que soit le mode. sync/now est la seule route qui fait sortir du trafic réseau, avec votre clé de licence.

Ce que l’API ne fera jamais

La règle : aucune primitive dont l’effet dépasse ce qu’on peut annuler depuis l’interface. Trois choses en découlent, et le resteront :

  • Taper dans votre fenêtre active. /text/expand vous rend le résultat ; ce que vous en faites vous regarde.
  • Installer une mise à jour. L’installation quitte l’application et lance un installeur élevé. Derrière un appel HTTP, ce serait une arme.
  • Révéler un secret. Ni le jeton de licence, ni le jeton de l’API, ni l’identifiant de machine.

Exemples

En shell :

TOKEN=$(cat "$LOCALAPPDATA/turbotexte.org/TurboTexte/apiToken.txt")
API=http://127.0.0.1:8420/api/v1

curl "$API/ping"
curl -H "Authorization: Bearer $TOKEN" "$API/combos?search=bonjour&limit=5"

curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
     -d '{"keyword":"bjr","snippet":"Bonjour,"}' "$API/combos"

curl -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
     -d '{"text":"bjr comment allez-vous ?"}' "$API/text/expand"

En PowerShell, avec le client fourni dans le dépôt de l’application :

. .\scripts\PowerShell\TurboTexteApi.ps1

Get-TTStatus
Get-TTCombos -Search bonjour -Limit 5
New-TTCombo -Keyword bjr -Snippet 'Bonjour,'
Expand-TTText 'bjr comment allez-vous ?'

En Python, sans dépendance :

import json, os, urllib.request

TOKEN = open(os.path.expandvars(r"%LOCALAPPDATA%\turbotexte.org\TurboTexte\apiToken.txt")).read().strip()
API = "http://127.0.0.1:8420/api/v1"

def call(method, path, body=None):
    data = json.dumps(body).encode() if body is not None else None
    request = urllib.request.Request(API + path, data=data, method=method, headers={
        "Authorization": f"Bearer {TOKEN}",
        "Content-Type": "application/json",
    })
    with urllib.request.urlopen(request) as response:
        return json.load(response)

print(call("GET", "/status")["comboCount"])
print(call("POST", "/text/expand", {"text": "bjr"})["text"])

Description machine

L’application sert une description OpenAPI 3.1 à /api/v1/openapi.json et une documentation détaillée à /api/v1/docs. Ces deux adresses font toujours foi : elles décrivent la version que vous avez installée. La description se charge dans la plupart des outils clients, pour générer le code d’appel plutôt que l’écrire.

Le serveur vit sur le fil de l’interface et traite les requêtes de façon synchrone, comme les menus : pas de verrou, pas d’incohérence entre l’API et la fenêtre. Ce fil est aussi celui du crochet clavier, d’où des listes paginées par défaut.

À vous d’essayer

  1. Créez le raccourci ml avec l’exemple ci-dessus, puis relisez-le par GET /combos/ml.

    Comment savoir que ça a marché

    Le second appel vous rend le raccourci en JSON, et il apparaît aussi dans la fenêtre de TurboTexte : l’API et l’interface travaillent sur la même liste.

  2. Suspendez la substitution par PATCH /app avec {"enabled":false}, tapez une abréviation, puis rétablissez.

    Comment savoir que ça a marché

    Entre les deux appels, plus rien ne se déclenche, et l’icône de la zone de notification montre l’état suspendu. POST /app/toggle fait la même bascule sans corps.

  3. Ouvrez http://127.0.0.1:8420/api/v1/docs dans votre navigateur.

    Comment savoir que ça a marché

    Vous voyez les routes de votre version, sans jeton. Si cette liste diffère de cette page, c’est elle qui a raison.