Documentation

Référence

Backend externe : servir une app depuis votre serveur

Mis à jour le 4 septembre 2026Plateforme v1 Markdown brut

Deux façons de faire tourner une app

  • Code hébergé (main) — votre defineApp tourne chez Capibara, dans
    un bac à sable (workerd sous gVisor, réseau limité aux hôtes déclarés).
    C’est la voie par défaut : rien à héberger, données et moteurs à portée de
    ctx.
  • Backend externe (backend: { url }) — le MÊME defineApp, mais
    c’est votre serveur qui reçoit les requêtes du protocole (écrans,
    actions, événements, planifications, HTTP entrant), signées et horodatées,
    et qui répond du Kit. Capibara rend l’interface, applique les mêmes bornes
    et le même disjoncteur.

Choisissez le backend externe quand vous avez déjà un serveur, une base ou
des dépendances lourdes. Les contreparties sont explicites : l’organisation
voit « Backend chez l’éditeur (votre hôte) » et consent à l’envoi de ses
interactions vers votre serveur, la review humaine est obligatoire, la
latence réseau s’ajoute à chaque écran, et la disponibilité comme la sécurité
de ce serveur vous incombent (CGV marketplace §11 :
incident notifié sous 48 h, données effacées 30 jours après désinstallation).


1. Déclarer le backend au manifeste

{
  "key": "mon-app",
  "name": "Mon app",
  "version": "1.0.0",
  "backend": { "url": "https://api.mon-app.example/capibara" },
  "returnHosts": ["mon-app.example"],
  "contributes": { "menuEntries": [{ "key": "home", "label": "Mon app", "view": "home" }] }
}
  • backend.url : HTTPS, hôte public (jamais une IP, ni localhost, ni
    un domaine interne). Exclusif de main : une app est hébergée OU
    externe, jamais les deux.
  • Ce qu’un backend peut servir : entrées de menu view, widgets
    kind: "kit", panneaux, blocs et pages du site public, events,
    schedules, http.
  • Ce qui reste réservé au code hébergé : collections, files.private
    et les capabilities des moteurs (mail.send,
    notify.send, calendar.project, search.index,
    approvals.request). Le manifeste les refuse sans main et renvoie vers
    les façades.
  • returnHosts (≤ 5) : les domaines vers lesquels vos liens de paiement
    peuvent ramener le client (§5).

Référence complète des champs : Le manifeste.


2. Le secret et la signature

Le secret cbk_… se génère dans le portail, sur la page de l’app,
section Backend & webhooks › « Backend externe ». Il est affiché une
fois
, chiffré au repos, et se régénère à volonté (l’ancien est invalidé
aussitôt). Il vit dans les variables d’environnement de votre serveur, jamais
dans le dépôt. Tant qu’aucun secret n’est posé, Capibara n’envoie rien
(journal de l’app : backend_secret_missing).

Chaque requête arrive ainsi :

POST /capibara HTTP/1.1
content-type: application/json
x-capibara-timestamp: 1756900000
x-capibara-signature: t=1756900000,v1=<hex(hmac-sha256(secret, "1756900000." + corps))>
x-capibara-kind: render
x-capibara-delivery: <identifiant de l'invocation = ligne du journal>

Vérification : recalculez hmac-sha256(secret, t + "." + corps BRUT),
comparez en temps constant, refusez si le t s’écarte de plus de
300 s de votre horloge (stale). x-capibara-delivery identifie
l’invocation : servez-vous-en pour rendre vos traitements idempotents. Avec
le SDK, tout cela est fait par createBackend (§4).


3. Le protocole

Le corps JSON est la même enveloppe que celle reçue par le code hébergé
(Le runtime › Le protocole d’interaction) : kind
(render, action, event, schedule, http), la surface, l’installation
(identifiant, configuration, réglages déchiffrés), viewer ou visitor,
le sujet, l’état signé, les paramètres ou le formulaire. Vous répondez
{ ok, result, logs } — result est un document du Kit
pour un rendu, le résultat d’action (ui, patch, toast, navigate,
openForm, close, refresh) sinon.

Bornes, identiques au code hébergé : 15 s par requête, réponse ≤ 1 Mo,
corps entrant ≤ 256 Ko, journal ≤ 200 lignes de 500 caractères, 8
invocations simultanées
par app, disjoncteur (10 échecs sur 5 minutes à
≥ 50 % d’erreurs → app suspendue 5 minutes, puis une sonde). Une réponse hors
enveloppe est une erreur pour l’utilisateur, jamais un rendu partiel.


4. Avec le SDK : createBackend

import { createBackend, defineApp, ui, CapibaraClient } from '@capibara-dev/sdk';

const app = defineApp({
  pages: { home: () => ui.text({ markdown: 'Rendu depuis mon serveur.' }) },
});

export const backend = createBackend({
  app,
  secret: process.env.CAPIBARA_BACKEND_SECRET!,                              // cbk_…, jamais dans le dépôt
  capibara: new CapibaraClient({ token: process.env.CAPIBARA_API_KEY! }),  // ctx.capibara.* via l'API publique
});

// Node / Express : const { status, body } = await backend.handle(rawBody, req.headers);
// Next.js, Cloudflare Workers, Deno, Bun : export default { fetch: (req) => backend.fetch(req) };
  • handle(rawBody, headers) pour les serveurs à corps brut, fetch(request)
    pour les runtimes à Request, dispatch(req) pour vos tests.
  • maxSkewSec (défaut 300) et onLog sont optionnels ;
    verifyBackendSignature(rawBody, header, secret) et
    parseBackendSignature si vous branchez vous-même.
  • Le CapibaraClient porte une clé API ck_live_… (portail › Clés & API)
    ou un jeton OAuth : createBackend en dérive ctx.capibara pour
    l’installation appelante (en-tête X-Capibara-Install, compte de service
    de l’app, scopes consentis par l’organisation).

Détail des exports : SDK › Backend externe.


5. Ce qui change dans ctx

Membre Code hébergé Backend externe
ctx.capibara.* (façades) pont interne API publique via le CapibaraClient fourni
ctx.fetch réseau limité aux hôtes http.fetch:<hôte> du manifeste le fetch de votre serveur, sans restriction
ctx.kv, ctx.data, ctx.files disponibles rejettent avec une explication : vos données vivent chez vous
ctx.mail, ctx.notify, ctx.calendar, ctx.search, ctx.approvals disponibles rejettent ; l’écriture métier passe par les façades
ctx.followup disponible rejette
ctx.log journal de l’invocation identique, renvoyé dans logs
ctx.install.config réglages déchiffrés identiques (transmis dans la requête signée)

Paiements et retour sur votre site. Les façades
billing.documents.payLink et billing.charges.create acceptent un
returnUrl : il est validé contre returnHosts puis signé ; le client règle
sur le site de l’organisation et voit un bouton « Retourner sur votre-hôte ».
Les événements sales.document.paid et pos.charge.paid vous préviennent
(events du manifeste, ou webhooks). Cf. Moteurs ›
Paiements
.


6. Tester et déployer

  • capibara init --template external livre le starter « Intégration
    externe » : manifeste backend + returnHosts, une page et un widget Kit,
    server/backend.ts sur createBackend.
  • Le harnais @capibara-dev/sdk/testing fonctionne tel quel (defineApp
    est le même) ; backend.dispatch(req) rejoue une requête du protocole.
  • Une installation de test (capibara dev --org <slug> ou section Tests du
    portail) appelle votre URL : elle doit être joignable en HTTPS public —
    Capibara ne fournit pas de tunnel, prévoyez une adresse de préproduction.
  • capibara logs et la section Journal montrent chaque invocation (latence,
    erreur, vos logs).

7. Publication, consentement, review

Le badge « Backend chez l’éditeur (hôte) » et la phrase de consentement
sont dérivés du manifeste et affichés partout : catalogue des apps, écran
d’installation, fiche marketplace, panneau de review. Une version à backend
externe n’est jamais auto-approuvée : un humain la relit
(Publication).


Backend externe ≠ webhooks

Les webhooks sortants (createServerHandler) vous
notifient des événements d’une organisation — pour toute app, hébergée ou
non. Le backend externe sert l’app (écrans, actions, planifications).
Les deux se combinent : une app hébergée peut recevoir des webhooks, un
backend externe peut aussi s’abonner aux événements.

Backend externe : servir une app depuis votre serveur · Capibara for Developers