Aller au contenu principal
Documentation développeur

Widget d'onboarding Scell.io

Intégrez un flux complet de vérification d'entreprise et d'onboarding à la facturation électronique en une seule ligne de code. Validation SIREN, vérification TVA et confirmation du représentant légal incluses.

Installé en 30 secondes
index.html
html
<!-- 1. Charger le script (un seul include, n'importe ou dans <head> ou <body>) -->
<script src="https://cdn.scell.io/widget/v1/onboarding.js"></script>

<!-- 2. Poser le widget la ou il doit s'afficher -->
<scell-onboarding
  publishable-key="pk_test_xxxxxxxx"
  external-id="user_42"
  callback-url="https://votre-app.com/onboarding/done"
></scell-onboarding>

<!-- 3. Ecouter l'evenement de fin pour recuperer sub_tenant + credentials -->
<script>
  document.querySelector('scell-onboarding')
    .addEventListener('onboarding:completed', (e) => {
      const { subTenant, credentials } = e.detail;
      console.log('Sub-tenant cree :', subTenant.id, subTenant.name);
      console.log('A utiliser pour facturer :', credentials);
    });
</script>

Démarrage rapide

Mode Sandbox disponible : Utilisez votre propre clé publishable de test pk_test_* (obtenue dans votre dashboard) pour tester le composant en mode sandbox. Les données de test ne sont pas persistées.

Le composant d'onboarding Scell.io gère l'intégralité du flux de vérification d'entreprise : recherche SIREN/SIRET, validation du numéro de TVA, vérification d'adresse et confirmation du représentant légal.

Étape 1 : Inclure le script

html
<script src="https://cdn.scell.io/widget/v1/onboarding.js"></script>

Étape 2 : Ajouter le composant

html
<scell-onboarding
  publishable-key="pk_live_xxxxxxxx"
  external-id="user_42"
  callback-url="https://votre-app.com/onboarding/done"
  theme="auto"
  locale="fr"
></scell-onboarding>

Étape 3 : Gérer les événements

javascript
const widget = document.querySelector('scell-onboarding');

widget.addEventListener('onboarding:completed', (event) => {
  // event.detail respecte le type OnboardingCompletedPayload
  const { subTenant, credentials, externalId } = event.detail;

  // subTenant : { id, tenant_id, name, siret, vat_number, onboarding_status, is_active }
  //   onboarding_status : pending_superpdp | superpdp_redirected | superpdp_authorized
  //                       | superpdp_pending_review | active | superpdp_failed
  // credentials : { api_endpoint, parent_tenant_id, sub_tenant_id, external_id, superpdp_company_id }

  // A partir d'ici votre backend peut emettre des factures via :
  //   POST {credentials.api_endpoint}/invoices
  //   X-API-Key: <votre sk_live_*>            (cle parent — securisee, JAMAIS dans le navigateur)
  //   body: { "sub_tenant_id": subTenant.id, ... }   (scope sur le sub-tenant)
});

widget.addEventListener('onboarding:error', (event) => {
  console.error(event.detail.code, event.detail.message);
});

Démo interactive

Cette démo utilise une clé publishable de test. Créez votre compte pour obtenir votre propre clé pk_test_* et tester le widget avec vos données.

Testez le composant Scell.io Onboarding directement ci-dessous. Ce widget permet à vos utilisateurs de vérifier leur entreprise (SIREN, TVA, représentant légal) et de compléter leur inscription.

Ce widget fonctionne en mode sandbox. Pour l'intégrer, consultez le guide Quick Start ci-dessus.

Référence API

Attributs

Configurez le comportement du composant via des attributs HTML.

AttributTypeRequisDescription
publishable-keystringOuiVotre clé publishable (pk_live_xxx ou pk_test_xxx)
external-idstringNonVotre identifiant interne pour ce sub-tenant (lien avec votre système)
callback-urlstringNonURL de redirection plein écran après onboarding (utilisée si le widget n'est PAS ouvert dans une popup, ex. embed iframe sans opener). Reçoit ?onboarding=success&sub_tenant_id=…&external_id=…
theme"light" | "dark" | "auto"NonThème de couleur. Par défaut : "light"
locale"fr" | "en"NonLangue du widget. Par défaut : "fr"
widthstringNonLargeur du widget. Par défaut : "100%"
heightstringNonHauteur du widget. Par défaut : "600px"
white-labelboolean (attribut HTML)NonMode marque blanche : masque le header avec le logo Scell.io. Le tracker de progression et le contenu métier restent visibles. Suffisant en attribut nu (<scell-onboarding white-label>) ou avec valeur "true" / "1" / "on" / "yes". Par défaut : header Scell.io affiché.

Mode marque blanche

L'attribut white-label masque le header avec le logo Scell.io. Le tracker de progression et tout le contenu métier (formulaire SIRET, redirect SUPER PDP, écran de fin) restent visibles. Utile pour intégrer le widget sans aucune mention Scell.io visible côté signataire/utilisateur final.

Valeurs acceptées : attribut nu (<scell-onboarding white-label>), ou "true" / "1" / "on" / "yes". Tout autre valeur (incluant "false" et l'absence de l'attribut) garde le header visible.

<!-- Mode marque blanche (attribut nu, ou white-label="true") -->
<scell-onboarding
  publishable-key="pk_live_xxxxxxxx"
  external-id="user_42"
  callback-url="https://votre-app.com/onboarding/done"
  theme="light"
  locale="fr"
  white-label
></scell-onboarding>

Événements

Écoutez les événements du composant pour réagir aux actions de l'utilisateur et aux changements d'état.

ÉvénementPayloadDescription
onboarding:started{ sessionId: string }Une session d'onboarding a été créée côté Scell.io. Aucun appel SUPER PDP encore émis.
onboarding:step{ step: "connect" | "redirect" | "complete", progress: number }L'utilisateur a changé d'étape (0% → 50% → 100%).
onboarding:completed{ subTenant: SubTenantSummary, credentials: OnboardingCredentials, externalId?: string }Le sub-tenant Scell.io est créé et opérationnel pour la facturation. Les tokens OAuth 2.1 SUPER PDP sont chiffrés en base et utilisés automatiquement par le backend pour transmettre les factures.
onboarding:error{ code: string, message: string }Une erreur a eu lieu (popup fermé, state CSRF invalide, échec KYB SUPER PDP, etc.).

Comment ça marche

Le widget <scell-onboarding> est l'unique méthode d'intégration officielle. Il pilote un flux OAuth 2.1 + PKCE qui crée simultanément un sub-tenant Scell.io et l'enregistrement chez SUPER PDP, dans la même session utilisateur.

  1. 1Le widget appelle POST /onboarding/sessions avec votre publishable key (pk_*) pour créer une session liée à votre tenant parent.
  2. 2Le widget appelle POST /onboarding/superpdp/authorize : le backend Scell.io génère le PKCE (code_verifier/code_challenge S256), un state CSRF, et renvoie l'URL d'autorisation SUPER PDP.
  3. 3Le widget ouvre un popup vers cette URL. L'utilisateur final s'authentifie chez SUPER PDP et complète le KYB (SIREN, TVA, représentant légal).
  4. 4SUPER PDP redirige vers POST /onboarding/superpdp/callback avec un code et le state.
  5. 5Le backend Scell.io échange code+verifier contre des tokens (access + refresh), récupère les infos entreprise, puis crée un sub-tenant rattaché à votre tenant parent (avec ses propres clés sk_/pk_, son numéroteur de factures, sa balance).
  6. 6Le widget reçoit l'event scell:onboarding:complete avec le sub_tenant_id et les credentials initiales.

Pourquoi un seul mode ?

Depuis le 5 mai 2026, les modes 'Redirect Flow' et 'API Only' sont retirés. Le widget couvre l'intégralité des cas d'usage tout en garantissant la conformité OAuth 2.1 + PKCE et l'isolation parent/sub-tenant. Le code OAuth, la rotation des refresh tokens et le KYB SUPER PDP sont gérés côté backend Scell.io — vous n'avez qu'une ligne de code à intégrer.

Sandbox vs Production

Scell.io fournit deux environnements totalement isolés. Le mode est déterminé automatiquement par le préfixe de la clé publishable que vous fournissez au widget — aucun paramètre supplémentaire à configurer.

CritèreSandboxProduction
Préfixe clé publishablepk_test_*pk_live_*
Préfixe clé secrètesk_test_*sk_live_*
Base de donnéesIsolée. Données de test, pas de valeur fiscale.Données réelles, conservées 10 ans (autocertification ISCA).
SUPER PDPCompte sandbox SUPER PDP. Les factures ne sont PAS transmises au réseau Peppol/PPF réel.Compte SUPER PDP production. Transmission réelle au réseau électronique français (PPF).
KYB SUPER PDPKYB simplifié — n'importe quel SIREN test fonctionne. Aucune vérification réelle.KYB complet (SIREN, TVA, représentant légal vérifiés par SUPER PDP).
Sub-tenantsCréés en base sandbox, jamais visibles depuis vos clés live.Créés en base production, immédiatement opérationnels pour facturer.
TarificationGratuit, illimité.Voir page Tarifs.

Comment basculer ?

Il suffit de remplacer la valeur de l'attribut publishable-key. Le widget, le backend Scell.io et le compte SUPER PDP utilisé sont basculés automatiquement. Aucun changement de code, d'URL d'API ou de configuration n'est nécessaire.

Exemple — passer de test à live

-<scell-onboarding publishable-key="pk_test_xxxxxxxx" />
+<scell-onboarding publishable-key="pk_live_xxxxxxxx" />

Bonnes pratiques

  • Tester en sandbox jusqu'à validation complète du parcours utilisateur AVANT de basculer en live.
  • Stocker les clés live en variable d'environnement serveur — JAMAIS dans le navigateur.
  • Les clés pk_test_* sont publiques par design (front-end OK). Les clés sk_test_*/sk_live_* sont secrètes (back-end uniquement).
  • Une facture émise en sandbox n'a aucune valeur juridique ni fiscale.

Exemples par framework

Exemples prêts à copier pour les frameworks populaires.

ScellOnboarding.tsx
tsx
import { useEffect, useRef } from 'react';
// Declarer le custom element pour TypeScript (React 19)
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'scell-onboarding': React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement> & {
'publishable-key': string;
'external-id'?: string;
'callback-url'?: string;
'theme'?: 'light' | 'dark' | 'auto';
'locale'?: 'fr' | 'en';
'width'?: string;
'height'?: string;
},
HTMLElement
>;
}
}
}
interface OnboardingResult {
subTenant: {
id: string;
tenant_id: string;
name: string;
siret: string | null;
vat_number: string | null;
onboarding_status:
| 'pending_superpdp'
| 'superpdp_redirected'
| 'superpdp_authorized'
| 'superpdp_pending_review'
| 'active'
| 'superpdp_failed';
is_active: boolean;
};
credentials: {
api_endpoint: string;
parent_tenant_id: string;
sub_tenant_id: string;
external_id: string | null;
superpdp_company_id: string | null;
};
externalId?: string;
}
interface Props {
publishableKey: string;
externalId?: string;
callbackUrl?: string;
onComplete?: (result: OnboardingResult) => void;
onError?: (err: { code: string; message: string }) => void;
}
export function ScellOnboarding({ publishableKey, externalId, callbackUrl, onComplete, onError }: Props) {
const ref = useRef<HTMLElement>(null);
useEffect(() => {
// Le script CDN s'auto-enregistre comme custom element global,
// donc on n'a a le charger qu'une seule fois par page.
if (document.querySelector('script[data-scell-widget]')) return;
const script = document.createElement('script');
script.src = 'https://cdn.scell.io/widget/v1/onboarding.js';
script.async = true;
script.dataset.scellWidget = 'true';
document.head.appendChild(script);
}, []);
useEffect(() => {
const el = ref.current;
if (!el) return;
const handleComplete = (e: Event) => onComplete?.((e as CustomEvent<OnboardingResult>).detail);
const handleError = (e: Event) => onError?.((e as CustomEvent<{ code: string; message: string }>).detail);
el.addEventListener('onboarding:completed', handleComplete);
el.addEventListener('onboarding:error', handleError);
return () => {
el.removeEventListener('onboarding:completed', handleComplete);
el.removeEventListener('onboarding:error', handleError);
};
}, [onComplete, onError]);
return (
<scell-onboarding
ref={ref}
publishable-key={publishableKey}
external-id={externalId}
callback-url={callbackUrl}
theme="auto"
locale="fr"
/>
);
}

URIs OAuth 2.1 enregistrées chez SUPER PDP

Information de référence : Scell.io a déclaré 3 redirect_uris officielles côté SUPER PDP. Vous n'avez RIEN à configurer pour intégrer le widget — ces URIs sont utilisées par les flows internes Scell.

URLUsage
/api/v1/widget/oauth-callbackCallback du widget <scell-onboarding> embed sur votre site. Crée le sub-tenant + retourne sub_tenant + credentials au widget via postMessage.
/api/v1/onboarding/superpdp/callbackEndpoint legacy POST exposé pour les intégrations widget v1 (rétrocompat). Même contrat de réponse que le widget v2.
/api/v1/me/superpdp/callbackOnboarding self-service depuis le dashboard Scell.io (admin tenant connecté). Pas concerné par l'intégration widget.

Webhooks

Recevez des notifications en temps réel lorsque des événements d'onboarding se produisent. Configurez votre URL webhook depuis le tableau de bord.

Sécurité : Vérifiez toujours la signature du webhook avec la clé secrète de votre tableau de bord. La signature est incluse dans le header x-scell-signature.

Payload reçu côté widget (event onboarding:completed)

Ce payload est livré simultanément via window.opener.postMessage(...) (au parent qui héberge le widget) et comme event.detail de l'event onboarding:completed sur l'élément <scell-onboarding>.

scell:onboarding:complete
json
// Payload envoye par window.opener.postMessage(...) ET recu via
// l'event 'onboarding:completed' (event.detail) cote widget consumer.
{
"type": "scell:onboarding:complete",
"success": true,
"sub_tenant": {
"id": "01975f7c-...",
"tenant_id": "01975f78-...",
"name": "ACME SAS",
"siret": "12345678901234",
"vat_number": "FR12345678901",
"onboarding_status": "active",
"is_active": true
},
"credentials": {
"api_endpoint": "https://api.scell.io/api/v1",
"parent_tenant_id": "01975f78-...",
"sub_tenant_id": "01975f7c-...",
"external_id": "user_42",
"superpdp_company_id": "spp_company_99"
}
}

Émettre une facture immédiatement après onboarding

Dès que l'event onboarding:completed est reçu, le sub-tenant est opérationnel : tokens OAuth 2.1 SUPER PDP chiffrés en base, KYB validé, numéroteur de factures isolé. Aucune attente.

POST /api/v1/invoices
javascript
// Apres l'event onboarding:completed, votre backend peut emettre des
// factures Factur-X au nom du sub-tenant immediatement. Les tokens
// OAuth 2.1 SUPER PDP sont chiffres en base et utilises automatiquement
// par Scell pour transmettre la facture chez SUPER PDP.
//
// IMPORTANT — Numerotation : ne jamais passer 'invoice_number' dans le
// body. La numerotation est entierement geree par Scell.io. La facture
// recoit un identifiant brouillon 'DRAFT-XXXXX' a la creation, puis un
// numero definitif 'XXXXX-YYYYMM-NNNNN' a l'emission (sequence chrono-
// logique sans rupture, conforme aux articles 242 nonies A et 289 du CGI).
// Le numero attribue est retourne dans la reponse (champ 'invoice_number').
// Modele d'auth : la cle sk_live_* appartient au TENANT parent. Pour
// emettre au nom d'un sub-tenant, on passe son 'sub_tenant_id' dans le
// body. La company emettrice est resolue automatiquement par Scell.io —
// aucun 'company_id' a fournir.
const res = await fetch('https://api.scell.io/api/v1/invoices', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.SCELL_PARENT_SECRET_KEY, // sk_live_* (parent — JAMAIS dans le navigateur)
},
body: JSON.stringify({
sub_tenant_id: subTenant.id, // scope sur le sub-tenant
issue_date: '2026-05-05',
buyer_siret: '98765432100012',
buyer_name: 'Customer SAS',
lines: [
{ description: 'Prestation', quantity: 1, unit_price_excl_tax: 1000, vat_rate: 20 }
],
}),
});
// Reponse (extrait) :
// {
// "id": "inv_01975f80...",
// "invoice_number": "T0001-202605-00042", <- attribue par Scell.io
// "status": "issued",
// "issue_date": "2026-05-05",
// "total_excl_tax": 1000,
// ...
// }
const { invoice_number } = await res.json();

Événements webhook disponibles

ÉvénementDescription
sub_tenant.onboardedUn sub-tenant Scell.io vient d'être créé via le widget. Le payload contient sub_tenant_id, external_id, siret, onboarding_status. C'est le moment de persister le mapping côté votre base et d'activer la facturation pour ce client.
invoice.transmittedUne facture émise pour ce sub-tenant a été transmise avec succès à SUPER PDP. Inclut superpdp_id et timestamp.
invoice.acceptedLa facture a été acceptée par le destinataire (lifecycle Factur-X).
invoice.rejectedLa facture a été rejetée par le destinataire ou par SUPER PDP. Le payload inclut rejection_reason.
invoice.incoming.receivedUne facture entrante destinée à ce sub-tenant vient d'arriver via SUPER PDP. Scell.io la résout automatiquement par superpdp_company_id et la rend disponible dans /tenant/incoming-invoices.

Prêt à intégrer ?

Créez votre compte et obtenez vos clés API en quelques minutes. Démarrez avec 100 crédits gratuits.

Vos préférences cookies

Nous utilisons des cookies pour améliorer votre expérience. Les cookies essentiels sont toujours actifs. Politique cookies.