Superfasttt

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.json

Ré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.json

Exemple 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.

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
}

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

ErreurCause probableAction
422 à l'importLe body n'est pas enveloppé dans { "manifest": ... } ou le manifest est invalideValider avec /manifests/validate et corriger les champs indiqués
403 origin_requiredL'échange est appelé sans header OriginTester depuis le navigateur ou ajouter Origin en curl
403 origin_not_allowedL'origin réelle n'est pas dans runtime.allowed_originsCorriger le manifest, réimporter et réinstaller
401 token_invalid_or_used_or_expiredlaunch_token déjà utilisé ou expiréGénérer un nouveau launch_token
403 missing_scopeL'app n'a pas la permission requiseAjouter la permission au manifest, réimporter et réinstaller
404 collection_not_foundLa 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.

On this page