Quickstart
Créer une app minimale, importer son manifest, l'installer, échanger un launch_token et écrire une première donnée.
Ce guide crée une app "Audit Hello" qui stocke et relit des inspections depuis un frontend externe.
Prérequis. Vous avez un espace client Superfasttt actif, un jeton
utilisateur disposant des droits d'administration nécessaires, et une URL de
frontend. En développement, http://localhost:3000 est accepté.
1. Créer le manifest
Créez manifest.json :
{
"manifest_version": "2.0",
"id": "audit-hello",
"name": "Audit Hello",
"version": "1.0.0",
"description": "Application de démonstration pour gérer des inspections.",
"runtime": {
"type": "external",
"entry_url": "http://localhost:3000",
"allowed_origins": ["http://localhost:3000"]
},
"permissions": [
"app_data:read",
"app_data:write"
],
"collections": {
"inspections": {
"schema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"status": { "type": "string", "enum": ["draft", "done"] }
},
"required": ["title", "status"],
"additionalProperties": false
},
"indexes": ["status"]
}
}
}entry_url est l'URL vers laquelle l'utilisateur sera envoyé au lancement.
allowed_origins doit contenir l'origin exacte de votre frontend
(scheme + host + port).
2. Valider le manifest
Les endpoints de manifest attendent une enveloppe JSON :
{
"manifest": {
"...": "contenu de votre manifest"
}
}Créez manifest-request.json avec cette enveloppe, puis validez :
curl -X POST https://api.superfasttt.ai/api/v1/app-platform/manifests/validate \
-H "Authorization: Bearer <user_access_token>" \
-H "X-Tenant-ID: <espace_client>" \
-H "Content-Type: application/json" \
-d @manifest-request.jsonRéponse attendue :
{
"valid": true,
"errors": [],
"warnings": []
}La validation ne modifie rien. Utilisez-la avant chaque import ou dans votre CI pour détecter les erreurs de manifest.
3. Importer puis installer
L'import enregistre la version du manifest pour l'espace client.
curl -X POST https://api.superfasttt.ai/api/v1/app-platform/manifests/import \
-H "Authorization: Bearer <user_access_token>" \
-H "X-Tenant-ID: <espace_client>" \
-H "Content-Type: application/json" \
-d @manifest-request.jsonExemple de réponse :
{
"app_id": "audit-hello",
"version": "1.0.0",
"lifecycle_status": "draft",
"created": true,
"validation": {
"valid": true,
"errors": [],
"warnings": []
}
}Installez ensuite l'app :
curl -X POST https://api.superfasttt.ai/api/v1/app-platform/apps/audit-hello/install \
-H "Authorization: Bearer <user_access_token>" \
-H "X-Tenant-ID: <espace_client>"Exemple de réponse :
{
"id": "<id>",
"app_id": "audit-hello",
"state": "active",
"enabled": true,
"app_version_id": "<version_id>",
"granted_permissions": ["app_data:read", "app_data:write"]
}N'exposez jamais un jeton utilisateur d'administration dans votre frontend externe. Les actions d'import et d'installation doivent être effectuées depuis un contexte autorisé.
4. Générer une URL de lancement
Un utilisateur autorisé peut demander un launch_token pour ouvrir l'app :
curl -X POST https://api.superfasttt.ai/api/v1/app-platform/apps/audit-hello/launch-token \
-H "Authorization: Bearer <user_access_token>" \
-H "X-Tenant-ID: <espace_client>"Réponse :
{
"launch_token": "<launch_token>",
"entry_url": "http://localhost:3000?launch_token=<launch_token>",
"expires_at": "2026-05-28T10:17:37Z"
}Redirigez l'utilisateur vers entry_url. Le launch_token est court et à
usage unique : votre frontend doit l'échanger immédiatement.
5. Échanger le launch_token dans le frontend
Dans votre app, lisez launch_token, appelez l'endpoint d'échange, puis retirez
le paramètre de l'URL.
const url = new URL(window.location.href);
const launchToken = url.searchParams.get("launch_token");
if (!launchToken) {
throw new Error("launch_token manquant");
}
const response = await fetch(
"https://api.superfasttt.ai/api/v1/app-platform/runtime/exchange",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ launch_token: launchToken }),
}
);
if (!response.ok) {
throw new Error(`Exchange failed: ${response.status}`);
}
const { access_token, token_type, expires_in, scopes } = await response.json();
url.searchParams.delete("launch_token");
window.history.replaceState({}, document.title, url.toString());curl -X POST https://api.superfasttt.ai/api/v1/app-platform/runtime/exchange \
-H "Content-Type: application/json" \
-H "Origin: http://localhost:3000" \
-d '{"launch_token":"<launch_token>"}'{
"access_token": "<app_access_token>",
"token_type": "Bearer",
"expires_in": 900,
"scopes": ["app_data:read", "app_data:write"]
}Gardez l'access_token uniquement le temps de la session app. Pour les appels
suivants, envoyez-le dans le header Authorization.
Échange navigateur vs serveur — le header Origin est obligatoire. Un
fetch lancé depuis le navigateur ajoute automatiquement l'Origin, donc
l'exemple ci-dessus fonctionne tel quel. Si vous échangez le launch_token
depuis votre backend (recommandé : l'access_token ne touche jamais le
navigateur), aucun Origin n'est posé automatiquement — vous devez
l'ajouter vous-même avec une valeur présente dans allowed_origins, sinon
l'échange renvoie 403 origin_required. La même règle s'applique aux appels
app-data si vous y joignez un Origin : il doit matcher allowed_origins.
6. Créer et lister une inspection
const headers = {
Authorization: `Bearer ${access_token}`,
"Content-Type": "application/json",
};
const created = await fetch(
"https://api.superfasttt.ai/api/v1/app-data/inspections",
{
method: "POST",
headers,
body: JSON.stringify({
data: { title: "Inspection ligne A", status: "draft" },
}),
}
).then((r) => r.json());
const list = await fetch(
"https://api.superfasttt.ai/api/v1/app-data/inspections/query",
{
method: "POST",
headers,
body: JSON.stringify({
filter: { status: "draft" },
sort: "-updated_at",
page: 1,
page_size: 50
}),
}
).then((r) => r.json());Réponse de liste :
{
"items": [
{
"id": "<record_id>",
"collection": "inspections",
"data": { "title": "Inspection ligne A", "status": "draft" },
"version": 1,
"created_at": "2026-05-28T10:20:00Z",
"updated_at": "2026-05-28T10:20:00Z"
}
],
"total": 1,
"page": 1,
"page_size": 50
}Savoir quel utilisateur agit. L'access_token est émis pour l'utilisateur
qui a ouvert l'app : son identifiant est porté par le claim sub du jeton
(avec tenant_id, app_id et installation_id). C'est ainsi qu'une app
externe sait qui l'utilise, même quand l'espace client compte des milliers
d'utilisateurs. En revanche, les records app-data n'exposent pas de champ
created_by_id dans leurs réponses : si vous voulez afficher une attribution
par utilisateur côté app, recopiez l'identifiant (sub) dans le data du
record au moment de la création.
7. Aller plus loin : documents riches et fichiers
Si votre app gère des rapports éditables ou des pièces jointes, vous appelez
deux API supplémentaires avec le même access_token. Pensez d'abord à ajouter
les permissions et déclarations dans votre manifest, puis réimportez et
réinstallez :
"permissions": [
"app_data:read", "app_data:write",
"rich_documents:read", "rich_documents:write",
"assets:read", "assets:write"
],
"rich_documents": {
"audit_report": {
"editor": "prosemirror",
"schema_version": "audit-report-v1"
}
},
"assets": {
"allowed_mime_types": ["application/pdf", "image/png"],
"max_file_size_mb": 25,
"max_total_size_mb": 1024
}Créer un document riche
La clé collection correspond à celle déclarée dans manifest.rich_documents.
editor et schema_version doivent matcher la déclaration du manifest installé.
const doc = await fetch(
"https://api.superfasttt.ai/api/v1/rich-documents",
{
method: "POST",
headers,
body: JSON.stringify({
collection: "audit_report",
title: "Rapport site A",
editor: "prosemirror",
schema_version: "audit-report-v1",
content: {
type: "doc",
content: [
{
type: "paragraph",
content: [{ type: "text", text: "Contenu initial." }],
},
],
},
}),
}
).then((r) => r.json());Le serveur extrait automatiquement plain_text depuis content pour la
recherche. Les mises à jour suivantes via PATCH /api/v1/rich-documents/{id}
incrémentent version. L'historique est listable via
GET /api/v1/rich-documents/{id}/versions.
Uploader un fichier
Le flow assets est en 3 appels — l'upload binaire va directement au stockage, votre serveur ne le voit jamais transiter.
// 1. URL signée
const { asset_id, upload_url, required_headers } = await fetch(
"https://api.superfasttt.ai/api/v1/app-assets/upload-url",
{
method: "POST",
headers,
body: JSON.stringify({
filename: "rapport.pdf",
content_type: "application/pdf",
size_bytes: 12345,
}),
}
).then((r) => r.json());
// 2. PUT direct au stockage S3-compatible
await fetch(upload_url, {
method: "PUT",
headers: required_headers,
body: fileBlob,
});
// 3. Confirmer — le serveur revérifie taille + content-type via HEAD
await fetch(
"https://api.superfasttt.ai/api/v1/app-assets/complete",
{
method: "POST",
headers,
body: JSON.stringify({ asset_id }),
}
);Pour télécharger ensuite, demandez une URL signée à durée limitée :
const { download_url } = await fetch(
`https://api.superfasttt.ai/api/v1/app-assets/${asset_id}/download-url`,
{ method: "POST", headers }
).then((r) => r.json());size_bytes doit être strictement positif et inférieur ou égal à
assets.max_file_size_mb de votre manifest. La somme des assets d'une
installation ne peut pas dépasser assets.max_total_size_mb. Le serveur
refuse les valeurs négatives avant d'enregistrer le fichier.
Erreurs fréquentes
| Erreur | Cause probable | Action |
|---|---|---|
422 à l'import | Le body n'est pas enveloppé dans { "manifest": ... } ou le manifest est invalide | Valider avec /manifests/validate et corriger les champs indiqués |
403 origin_required | L'échange est appelé sans header Origin | Tester depuis le navigateur ou ajouter Origin en curl |
403 origin_not_allowed | L'origin réelle n'est pas dans runtime.allowed_origins | Corriger le manifest, réimporter et réinstaller |
401 token_invalid_or_used_or_expired | launch_token déjà utilisé ou expiré | Générer un nouveau launch_token |
403 missing_scope | L'app n'a pas la permission requise | Ajouter la permission au manifest, réimporter et réinstaller |
404 collection_not_found | La collection n'est pas déclarée dans le manifest installé | Ajouter la collection, réimporter et réinstaller |
Et après
Consultez la référence du manifest pour ajouter des documents, des fichiers ou plusieurs collections. Consultez Authentification & sécurité pour les règles de session et d'origin.
Apps tierces
Concevoir une app externe qui s'ouvre depuis Superfasttt et utilise les API app_data, rich_documents et app_assets.
Exemple complet (de bout en bout)
Un scénario complet et copier-coller — qui fait quoi, à quel moment — de l'enregistrement de l'app jusqu'à l'écriture d'une donnée depuis un frontend Next.js.

