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) — votredefineApptourne 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ÊMEdefineApp, 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 demain: 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 sansmainet 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) etonLogsont optionnels ;
verifyBackendSignature(rawBody, header, secret)et
parseBackendSignaturesi vous branchez vous-même.- Le
CapibaraClientporte une clé APIck_live_…(portail › Clés & API)
ou un jeton OAuth :createBackenden dérivectx.capibarapour
l’installation appelante (en-têteX-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 externallivre le starter « Intégration
externe » : manifestebackend+returnHosts, une page et un widget Kit,
server/backend.tssurcreateBackend.- Le harnais
@capibara-dev/sdk/testingfonctionne 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 logset la section Journal montrent chaque invocation (latence,
erreur, voslogs).
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.