Aller au contenu principal
Référence développeur

SDKs officiels & Référence API

La référence complète pour intégrer Scell.io. SDKs type-safe pour TypeScript et PHP, plus un agent MCP pour les workflows IA. Chaque ressource, chaque méthode, entièrement documentée.

TypeScript

TypeScript SDK

TypeScript / JavaScript

v3.5.3

Installation

npm install @scell/sdk

Fonctionnalités

  • Typage TypeScript complet (strict mode)
  • API async/await basée sur les Promises
  • 4 classes client (Bearer, API Key, Tenant, Public)
  • Factures B2B + B2C, avoirs, signatures, fiscal, webhooks
  • Invoice Templates (upload logo + couleurs + mentions)
  • Coordonnées bancaires Factur-X (IBAN/BIC) + délai paiement par défaut
  • Clôture journalière auto + email + CSV
  • Auto-attestation ISCA nominative (tenant + sub_tenant)
  • Mode sandbox avec préfixe sk_test_
  • Paiement Stripe en ligne des factures Scell.io (depuis v2.2.0)
  • Sub-tenants management : delete cascade ISCA + SuperPDP authorize URL (depuis v2.9.0)
  • Receipt OpenTimestamps `ots_proof_base64` sur les clôtures fiscales (depuis v2.10.0)
  • Signature blocks : paraphe automatique + mentions juridiques + date du jour (depuis v2.12.0)
  • Devis (Quotes) : CRUD, envoi par email, signature, conversion en acomptes (depuis v2.13.0)
  • PaymentSchedule complet : set/patch/delete/summary/convertLine/presets (depuis v2.13.0)
  • Quote `callback_url` : redirige le buyer vers le site tenant après accept/refuse (depuis v2.13.1)
  • `PaymentSummary.lines[]` : tracker visuel complet sans seconde requête (depuis v2.14.0)
  • invoices.update() / delete() + creditNotes.update() / delete() — brouillons uniquement (depuis v2.16.0)
  • Initiales multi-pages : `initials_block.positions[]` avec position et style override par page (depuis v2.17.0)
  • Webhook secret affiché 1 fois à création / régénération + `secret_last4` pour fingerprint (depuis v2.19.0)
  • `parent_quote_id` sur facture standard : lien soft vers un devis source pour la traçabilité (depuis v2.21.0)
  • Statuts `refunded` / `partially_refunded` posés automatiquement par le backend + champs `refund_status` et `total_refunded` exposés (depuis v2.22.0)
  • Couverture exhaustive des énumérations : 19 union types stricts (`InvoiceType`, `QuoteStatus`, `VatCategory`, `SignatureStatus`, etc.) — fin des `string` génériques côté SDK (depuis v2.23.0)
  • BT-81 Payment Means Code : conformité Factur-X EN16931 avec les 11 codes UN/ECE 4461 (depuis v2.25.0)
  • Registre fournisseurs (`suppliers`) : alimenté automatiquement par les factures reçues (GET + PATCH email/phone/notes uniquement — pas de création ni suppression manuelle, depuis v2.26.0 / v3.0.0)
  • `InvoiceStatus` aligné sur les 16 statuts canoniques du backend (depuis v2.27.1)
  • Référentiel sociétés par pays (`reference.countries()` / `.country(code)`) : TVA, identifiant national (registre + scheme ISO 6523), formes juridiques — pour des formulaires acheteur/vendeur adaptés au pays (depuis v2.29.0)
  • Suivi de seuils micro-entrepreneur (`subTenants.getThresholds`) : jauges franchise TVA + plafond micro, projection de franchissement (règles datées loi 2025-1044) ; bascule TVA via `updateFiscalStatus` (depuis v2.30.0)
  • Téléchargement des clôtures par sous-tenant (`fiscal.downloadClosing`, filtres `closing_type`/`sub_tenant_id`) + FEC par sous-tenant (depuis v2.30.0)
  • Simulateur pré-émission de seuils (`subTenants.simulateThresholds`) : vérifier un franchissement AVANT d'émettre une facture (depuis v2.31.0)
  • Contrat avoir explicite : un avoir partiel SÉLECTIONNE des lignes de la facture (`items[].invoice_line_id`), TVA exacte héritée par ligne (multi-taux) ; `remainingCreditable` typé (depuis v2.32.0)
  • Déconnexion / reconnexion forcée SuperPDP d'un sous-tenant (`subTenants.superpdpDisconnect` / `superpdpReconnect`) + jeton signé 24h pour le widget en mode SuperPDP seul (`superpdpWidgetToken`) (depuis v3.1.0)
  • Aperçu HTML live d'un document en cours de saisie (`documents.preview`), upload direct du logo e-mail (`branding.tenant.uploadLogoFile` / `branding.subTenants.uploadLogoFile`), overrides d'aperçu branding non persistés (`branding.tenant.preview(overrides)`) et dérivation des couleurs du template depuis le logo (`invoiceTemplates.deriveColorsFromEmailLogo`) (depuis v3.2.0)
  • Groupes d'acomptes (deals multi-factures) `invoices.depositGroups()` / `depositGroup(id)`, assistant de mentions légales `invoiceMentions.assistant()` / `preview()`, échéancier de devis câblé `quotes.paymentSchedule`, couleurs dérivées du logo de facture `invoiceTemplates.deriveColorsFromInvoiceLogo()` + aperçu template `invoiceTemplates.preview()` ; correctifs devis `quotes.regeneratePublicLink` / `revokePublicLink` / `preview` (depuis v3.5.0)
PHP

PHP SDK

PHP 8.2+

v3.5.1

Installation

composer require scell/sdk

Fonctionnalités

  • PHP 8.2+ avec types stricts (readonly DTOs)
  • Autoloading PSR-4
  • Auto-discovery Laravel (config/scell.php)
  • 4 classes client (Bearer, API Key, Tenant, Public)
  • Factures B2B + B2C, avoirs, signatures, fiscal, webhooks
  • Invoice Templates (upload logo + couleurs + mentions)
  • Coordonnées bancaires Factur-X (IBAN/BIC) + délai paiement par défaut
  • Auto-attestation ISCA nominative (tenant + sub_tenant)
  • Builder fluent (buyerIndividual, asB2c, etc.)
  • Mode sandbox intégré
  • Paiement Stripe en ligne des factures Scell.io (depuis v2.2.0)
  • Sub-tenants management : delete cascade ISCA + SuperPDP authorize URL (depuis v2.9.0)
  • Receipt OpenTimestamps `ots_proof_base64` sur les clôtures fiscales (depuis v2.10.0)
  • Signature blocks : DTOs InitialsBlock + Mention + DateBlock (depuis v2.12.0)
  • Devis (Quotes) : CRUD + QuoteBuilder fluent (depuis v2.13.0)
  • QuotePaymentScheduleResource : list/set/patch/delete/summary/convertLine/presets (depuis v2.13.0)
  • QuoteBuilder::callbackUrl() : redirige le buyer vers le site tenant après accept/refuse (depuis v2.13.1)
  • invoices()->update() / delete() + creditNotes()->update() / delete() — brouillons uniquement (depuis v2.14.0)
  • Initiales multi-pages : DTO `InitialsPosition` + `InitialsBlock::withPositions([...])` (depuis v2.15.0)
  • DTO `Webhook::$secret_last4` + secret affiché 1 fois à création (depuis v2.17.0)
  • `InvoiceBuilder::parentQuoteId()` sur facture standard : lien soft vers un devis source (depuis v2.19.0)
  • Enum `InvoiceStatus` complet (refunded, partially_refunded) + champs `refund_status` et `total_refunded` sur le DTO Invoice (depuis v2.20.0)
  • Couverture exhaustive des énumérations : 19 classes d'enum typées dans `Scell\Sdk\Enums\*` (`InvoiceType`, `QuoteStatus`, `VatCategory`, `SignatureStatus`, etc.) — fin des `string` génériques côté DTO (depuis v2.21.0)
  • BT-81 Payment Means Code : enum `PaymentMeansCode` avec les 11 codes UN/ECE 4461 pour conformité Factur-X EN16931 (depuis v2.25.0)
  • Registre fournisseurs (`suppliers()`) : alimenté automatiquement par les factures reçues (GET + PATCH email/phone/notes/metadata uniquement — pas de création ni suppression manuelle, depuis v2.26.0 / v3.0.0)
  • Référentiel sociétés par pays (`reference()->countries()` / `->country($code)`) : DTO `CountryReference` (TVA, identifiant national + scheme ISO 6523, formes juridiques) — pour des formulaires acheteur/vendeur adaptés au pays (depuis v2.29.0)
  • Suivi de seuils micro-entrepreneur (`subTenants()->getThresholds`) + bascule TVA (`updateFiscalStatus`) + simulateur pré-émission (`simulateThresholds`) (depuis v2.30.0/v2.31.0)
  • Téléchargement des clôtures par sous-tenant (`fiscal()->downloadClosing`) + FEC par sous-tenant (depuis v2.30.0)
  • Contrat avoir explicite : un avoir partiel SÉLECTIONNE des lignes de la facture (`items[].invoice_line_id`), TVA exacte héritée par ligne ; `remainingCreditable()` documenté (depuis v2.32.0)
  • Déconnexion / reconnexion forcée SuperPDP d'un sous-tenant (`subTenants()->superpdpDisconnect` / `superpdpReconnect`) + jeton signé 24h pour le widget en mode SuperPDP seul (`superpdpWidgetToken`) (depuis v3.1.0)
  • Aperçu HTML live d'un document (`$client->documents->preview($payload)`), upload direct du logo e-mail (`branding->uploadLogoTenant` / `uploadLogoSubTenant`), overrides d'aperçu branding non persistés (`previewTenant($overrides)` / `previewSubTenant`) et dérivation des couleurs du template depuis le logo (`invoiceTemplates->deriveColorsFromEmailLogo()`) (depuis v3.4.0)
  • Groupes d'acomptes (deals multi-factures) `invoices()->depositGroups()` / `depositGroup($id)`, assistant de mentions légales `invoiceMentions()->assistant()` / `preview()`, couleurs dérivées du logo de facture `invoiceTemplates()->deriveColorsFromInvoiceLogo()` + aperçu template `invoiceTemplates()->preview()` (depuis v3.5.0)
🤖

MCP Agent

Claude Desktop / Cursor / VS Code

v3.5.0

Installation

npx -y mcp-remote https://api.scell.io/api/mcp

Fonctionnalités

  • Compatible protocole MCP
  • Claude Desktop, Cursor, VS Code, autres LLM
  • 148 outils : factures B2B/B2C, avoirs, devis, échéanciers de paiement, factures récurrentes, acheteurs, produits & catégories, fournisseurs, signatures, fiscal, templates, mentions légales, branding, documents, sub-tenants & onboarding, billing, credit packs, stats (depuis v3.5.0)
  • Templates invoice avec upload logo + couleurs (one-time setup)
  • Auto-attestation ISCA nominative (tenant + sub_tenant) en 1 prompt
  • Heuristiques LLM B2C (particulier, individual, M./Mme/...)
  • Zéro dépendance d'exécution
  • Support du mode sandbox
  • Paiement Stripe d'une facture Scell.io en 1 prompt (depuis v2.2.0)
  • Signature blocks : initialsBlock + mentions + dateBlock en camelCase LLM-friendly (depuis v2.12.0)
  • scell_mark_invoice_paid : marquer une facture sortante comme payée (depuis v2.15.0)
  • Initiales multi-pages : `initialsBlock.positions[]` (1 entrée par page avec overrides) découvrable par le LLM (depuis v2.16.0)
  • `parentQuoteId` sur facture standard : lien soft vers un devis source pour la traçabilité (depuis v2.20.0)
  • Statuts `refunded` / `partially_refunded` automatiques + champs `refundStatus` et `totalRefunded` discoverables par le LLM (depuis v2.21.0)
  • Couverture exhaustive des énumérations : descriptions d'outils enrichies avec les valeurs autorisées des 19 énumérations de l'API (le LLM voit le vocabulaire complet, fin des erreurs 422 dues à des valeurs inventées) (depuis v2.22.0)
  • BT-81 Payment Means Code : conformité Factur-X EN16931 avec les 11 codes UN/ECE 4461 (depuis v2.25.0)
  • Types référentiel sociétés par pays (`CountryReference`, `LegalForm`…) pour adapter la saisie acheteur/vendeur au pays (depuis v2.28.0)
  • Outils seuils micro-entrepreneur : `scell_get_subtenant_thresholds`, `scell_update_subtenant_fiscal_status` (bascule TVA), `scell_simulate_subtenant_thresholds` (simulateur pré-émission) (depuis v2.29.0/v2.30.0)
  • Outils de clôture fiscale : `scell_list_fiscal_closings` + `scell_export_fec` (CSV/FEC, scope tenant et sous-tenant) (depuis v2.29.0)
  • Contrat avoir explicite : `scell_create_credit_note` sélectionne des lignes (`invoice_line_id`, TVA héritée par ligne), `scell_get_remaining_creditable` pour la découverte (depuis v2.31.0)
  • Aperçu email brandé : `scell_preview_tenant_branding` / `scell_preview_sub_tenant_branding` rendent l'email (HTML ou PDF) tel qu'il sera reçu, avant tout envoi (depuis v2.34.0)
  • Déconnexion / reconnexion SuperPDP d'un sous-tenant : `scell_disconnect_subtenant_superpdp`, `scell_reconnect_subtenant_superpdp` + `scell_mint_subtenant_widget_token` (jeton signé 24h pour le widget en mode SuperPDP seul) (depuis v3.1.0)
  • Aperçu HTML live d'un document : `scell_preview_document` + dérivation des couleurs du template depuis le logo e-mail : `scell_derive_template_colors_from_email_logo` (depuis v3.2.0)
  • Documentation des outils alignée exactement sur les 148 outils du serveur (source : backend `config/mcp.php`) : ajout des groupes d'acomptes (`scell_list_deposit_groups` / `scell_get_deposit_group`), de l'assistant de mentions légales (`scell_suggest_invoice_mentions` / `scell_preview_invoice_mentions`), des couleurs dérivées du logo de facture (`scell_derive_template_colors_from_invoice_logo`) ; noms fantômes retirés / renommés (depuis v3.5.0)

Installation

Installez le SDK officiel Scell.io pour votre plateforme. Les trois options se connectent à la même API.

TypeScript / PHP

terminal
typescript
npm install @scell/sdk
# or with yarn
yarn add @scell/sdk
# or with pnpm
pnpm add @scell/sdk

MCP Agent

~/.claude/.mcp.json
json
// Coller ce bloc dans le fichier de config MCP de votre client IA.
// Cree le fichier s'il n'existe pas (chemin selon le client) :
//
//   - Claude Code (CLI)   ~/.claude/.mcp.json
//   - Claude Desktop      ~/Library/Application Support/Claude/claude_desktop_config.json   (macOS)
//                         %APPDATA%\\Claude\\claude_desktop_config.json                  (Windows)
//   - Cursor              ~/.cursor/mcp.json
//   - VS Code (Copilot)   ~/.vscode/mcp.json
//
// Remplacer sk_live_xxxx par votre cle Scell.io (sk_live_* en prod, sk_test_* en sandbox).
// Recuperez vos cles depuis le dashboard : https://app.scell.io/dashboard/api-keys

{
  "mcpServers": {
    "scell": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.scell.io/api/mcp",
        "--header",
        "X-Scell-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      ]
    }
  }
}

Authentification

Scell.io supporte trois modes d'authentification, chacun avec une classe client dédiée.

ModeClasse clientPréfixe de cléCas d'usage
Bearer TokenScellClientSanctum tokenSessions dashboard, opérations utilisateur
Secret API KeyScellApiClient / ScellTenantClientsk_live_* / sk_test_*Serveur à serveur. Headers acceptés : X-API-Key OU X-Tenant-Key (alias historique).
Publishable KeyScellPublicClientpk_live_* / pk_test_*Widget public d'onboarding (browser-safe). Header X-Publishable-Key.

Bearer Token (Dashboard)

Utilisez ScellClient avec un bearer token Sanctum pour les opérations utilisateur dashboard. Ressources : auth, companies, apiKeys, balance, webhooks, invoices (lecture), signatures (lecture).

auth-bearer.ts
typescript
import { ScellClient } from '@scell/sdk';
// Authenticate with a Sanctum bearer token (dashboard sessions)
const client = new ScellClient('your_bearer_token');
// Resources available on ScellClient:
// client.auth — login, register, logout, me
// client.companies — CRUD on companies + KYC
// client.apiKeys — manage API keys
// client.balance — check balance, reload, transactions
// client.webhooks — manage webhooks
// client.invoices — read-only invoice access
// client.signatures — read-only signature access
const me = await client.auth.me();
console.log(me.email);

Clé API (Serveur à serveur)

Utilisez ScellApiClient avec une clé secrète (sk_live_* ou sk_test_*) pour les opérations serveur à serveur complètes. Ressources : invoices, signatures, creditNotes, subTenants, fiscal, stats, billing, tenantInvoices, tenantCreditNotes, incomingInvoices.

auth-api-key.ts
typescript
import { ScellApiClient } from '@scell/sdk';
// Production
const client = new ScellApiClient('sk_live_your_api_key');
// Sandbox mode (sk_test_ prefix)
const sandbox = new ScellApiClient('sk_test_your_api_key');
// Une cle sk_* appartient au tenant master. Pour cibler un sub-tenant,
// passer sub_tenant_id dans le payload POST (factures, signatures, avoirs).
// Sans sub_tenant_id : action sur le tenant master, company emettrice =
// tenant.default_company_id (configure depuis le dashboard Profil).
// Resources available on ScellApiClient:
// client.invoices — full invoice CRUD + submit + download
// client.signatures — full signature CRUD + cancel + remind
// client.creditNotes — credit note management
// client.subTenants — manage sub-tenants
// client.fiscal — fiscal compliance (ISCA)
// client.stats — overview + monthly statistics
// client.billing — billing, usage, top-up
// client.tenantInvoices — tenant direct invoices (CRUD + submit + download Factur-X/UBL/CII)
// client.tenantCreditNotes — tenant credit notes
// client.incomingInvoices — incoming invoice management

ScellTenantClient — header X-Tenant-Key (alias historique)

⚠ Important — il n'existe PAS de format de clé tk_* distinct. ScellTenantClient accepte la même clé secrète sk_live_* / sk_test_* que ScellApiClient. La seule différence : il envoie le header X-Tenant-Key au lieu de X-API-Key. Cote serveur, le middleware TenantApiKeyMiddleware lit X-Tenant-Key ?? X-API-Key et valide la même regex /^sk_(live|test)_[A-Za-z0-9]{32}$/ — donc les deux clients fonctionnent avec n'importe laquelle de vos clés sk_*. Conserve pour la rétro-compatibilité ; préférer ScellApiClient (header X-API-Key) dans le code nouveau.

Le client ScellTenantClient expose en plus quelques méthodes directes pratiques : me(), updateProfile(), balance(), quickStats(), regenerateKey(). Tout le reste (invoices, signatures, sub_tenants…) est strictement identique à ScellApiClient.

auth-tenant.ts
typescript
import { ScellTenantClient } from '@scell/sdk';
// IMPORTANT — meme cle secrete que ScellApiClient (sk_*).
// La SEULE difference : ce client envoie le header X-Tenant-Key
// au lieu de X-API-Key. Il n'existe PAS de format tk_* distinct.
// Production
const client = new ScellTenantClient('sk_live_your_secret_key');
// Sandbox mode
const sandbox = new ScellTenantClient('sk_test_your_secret_key');
// Resources:
// client.directInvoices — create invoices for sub-tenants
// client.directCreditNotes — create credit notes
// client.incomingInvoices — manage incoming invoices
// client.subTenantCreditNotes — sub-tenant credit notes
// client.fiscal — fiscal compliance
// client.billing — billing & usage
// client.stats — statistics
// client.subTenants — manage sub-tenants
// Direct methods on ScellTenantClient:
// client.me() — tenant profile
// client.updateProfile() — update profile
// client.balance() — check balance
// client.quickStats() — summary stats
// client.regenerateKey() — regenerate tenant key

Référence API

Référence complète des méthodes pour chaque ressource SDK. Exemples de code en TypeScript et PHP pour chaque ressource.

Factures

13 méthodes

Créez, validez, soumettez et téléchargez des factures électroniques aux formats Factur-X, UBL et CII. Disponible sur ScellApiClient (CRUD complet) et ScellClient (lecture seule).

MéthodeDescription
list(options?)Lister les factures avec pagination et filtres optionnels
get(id)Obtenir une facture par son UUID
create(data)Créer une facture (format Factur-X, UBL ou CII)
submit(id)Soumettre une facture au réseau PDP (Peppol / Chorus Pro)
markPaid(id)Marquer comme payée (paiement manuel, statuts acceptés : validated/transmitted/sent/accepted)
sendByEmail(id, data?)Envoyer la facture Factur-X par email au buyer
download(id, format)Télécharger en PDF, XML ou Factur-X. format : "pdf" | "xml" | "facturx"
auditTrail(id)Obtenir la piste d'audit complète (création, validation, soumission…)
convert(data)Convertir entre formats de facture (Factur-X ↔ UBL ↔ CII)
depositGroups(options?)Lister les groupes d'acomptes (deals multi-factures) avec progression — filtres `has_no_balance`, etc. (depuis v3.5.0)
depositGroup(id)Détail d'un groupe d'acomptes : total du deal, acomptes émis, solde, % facturé (depuis v3.5.0)
incoming(options?)Lister les factures entrantes (reçues via le PDP)
accept(id, data?)Accepter une facture entrante (PDP)
reject(id, reason, code)Rejeter une facture entrante avec motif et code
dispute(id, reason, code)Contester une facture entrante (litige)

Créer une facture

create.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// ── B2B Invoice (Factur-X) ──────────────────────────────────────────
const { data: invoice } = await scell.invoices.create({
direction: 'outgoing',
output_format: 'facturx', // 'facturx' | 'ubl' | 'cii'
issue_date: '2026-06-01',
due_date: '2026-07-01',
currency: 'EUR',
// Seller (flat fields — server validates per country)
seller_name: 'QR Communication SAS',
seller_siret: '90347842500015', // required if seller_country=FR
seller_vat_number: 'FR42903478425',
seller_country: 'FR',
seller_address: {
line1: '123 Avenue de la République',
postal_code: '75011',
city: 'Paris',
country: 'FR',
},
// Buyer — option 1: flat fields
buyer_name: 'GN IMMO',
buyer_siret: '49438068600076', // required if buyer_country=FR && !buyer_is_individual
buyer_vat_number: 'FR42494380686',
buyer_country: 'FR',
buyer_address: {
line1: '453 Route Nationale 7',
postal_code: '13670',
city: 'Verquières',
country: 'FR',
},
// Amounts (HT + TVA = TTC)
total_ht: 2500.00,
total_tax: 500.00,
total_ttc: 3000.00,
// Lines (min 1)
lines: [
{
description: 'Prestation conseil transformation digitale',
quantity: 10,
unit: 'HUR', // UN/ECE Rec 20 (optional)
unit_price: 250.00,
tax_rate: 20.0, // 0 | 5.5 | 10 | 20
total_ht: 2500.00,
total_ttc: 3000.00,
},
],
});
console.log(invoice.invoice_number); // 'FAC-2026-000042'
console.log(invoice.status); // 'draft'
console.log(invoice.download_url); // presigned S3 URL
// ── B2C Invoice (individual — no SIRET/VAT required) ────────────────
const { data: b2cInvoice } = await scell.invoices.create({
direction: 'outgoing',
output_format: 'facturx',
issue_date: '2026-06-01',
due_date: '2026-06-15',
currency: 'EUR',
seller_name: 'QR Communication SAS',
seller_siret: '90347842500015',
seller_country: 'FR',
seller_address: { line1: '123 Avenue de la République', postal_code: '75011', city: 'Paris', country: 'FR' },
buyer_name: 'Marie Dupont',
buyer_is_individual: true, // BT-46/47/48 omitted, no L441-10
buyer_country: 'FR',
buyer_address: { line1: '12 Rue des Lilas', postal_code: '75011', city: 'Paris', country: 'FR' },
total_ht: 150.00,
total_tax: 30.00,
total_ttc: 180.00,
lines: [{ description: 'Formation individuelle', quantity: 1, unit_price: 150.00, tax_rate: 20.0, total_ht: 150.00, total_ttc: 180.00 }],
});
// ── With buyer_id (registry shortcut) ───────────────────────────────
const { data: fromRegistry } = await scell.invoices.create({
direction: 'outgoing',
output_format: 'facturx',
issue_date: '2026-06-01',
due_date: '2026-07-01',
currency: 'EUR',
seller_name: 'QR Communication SAS',
seller_siret: '90347842500015',
seller_country: 'FR',
seller_address: { line1: '123 Avenue de la République', postal_code: '75011', city: 'Paris', country: 'FR' },
buyer_id: '019e2dbe-362a-7105-87a5-f45fad1382ed', // auto-snapshot
total_ht: 2500.00,
total_tax: 500.00,
total_ttc: 3000.00,
lines: [{ description: 'Consulting', quantity: 10, unit_price: 250.00, tax_rate: 20.0, total_ht: 2500.00, total_ttc: 3000.00 }],
});
// ── Sub-tenant scoping ──────────────────────────────────────────────
const { data: subInvoice } = await scell.invoices.create({
sub_tenant_id: '019d5ea8-0000-0000-0000-000000000000',
direction: 'outgoing',
output_format: 'facturx',
issue_date: '2026-06-01',
due_date: '2026-07-01',
currency: 'EUR',
buyer_id: '019e2dbe-362a-7105-87a5-f45fad1382ed',
total_ht: 1000.00,
total_tax: 200.00,
total_ttc: 1200.00,
lines: [{ description: 'Service', quantity: 1, unit_price: 1000.00, tax_rate: 20.0, total_ht: 1000.00, total_ttc: 1200.00 }],
});
// ── Standard invoice from a quote (parent_quote_id, since v2.21.0) ──
// Lien soft vers un devis source pour tracabilite (devis -> facture).
// IMPORTANT : parent_quote_id est accepte UNIQUEMENT pour invoice_type='standard'
// (ou champ omis). Pour une facture d'acompte ou de solde, utiliser les
// endpoints dedies POST /quotes/{id}/convert-to-deposit / convert-to-balance.
// Backend : 404 PARENT_QUOTE_NOT_FOUND si le devis n'appartient pas au tenant,
// 422 si invoice_type='deposit' ou 'balance' est combine avec parent_quote_id.
const { data: fromQuote } = await scell.invoices.create({
direction: 'outgoing',
output_format: 'facturx',
issue_date: '2026-06-01',
due_date: '2026-07-01',
currency: 'EUR',
parent_quote_id: '019e3f00-7c8d-7000-9000-000000000001', // UUID du devis source
buyer_id: '019e2dbe-362a-7105-87a5-f45fad1382ed',
total_ht: 2500.00,
total_tax: 500.00,
total_ttc: 3000.00,
lines: [{ description: 'Consulting (devis DEV-2026-0042)', quantity: 10, unit_price: 250.00, tax_rate: 20.0, total_ht: 2500.00, total_ttc: 3000.00 }],
});

Modifier un brouillon

update.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Update a draft invoice (only draft status allowed)
// All fields are optional — partial update via PUT /invoices/{id}
const { data: invoice } = await scell.invoices.update(
'019dfae2-abef-73e4-b6b2-e4cdae938f3b',
{
// Change due date
due_date: '2026-08-15',
// Update buyer info
buyer_name: 'GN IMMO — Siège social',
buyer_email: 'comptabilite@gnimmo.com',
// Update buyer address
buyer_address: {
line1: '453 Route Nationale 7',
postal_code: '13670',
city: 'Verquières',
country: 'FR',
},
// Add shipping address (BG-13 EN16931)
buyer_shipping_address: {
name: 'Entrepôt Lyon',
line1: '15 Rue de l\'Industrie',
postal_code: '69003',
city: 'Lyon',
country: 'FR',
},
// Replace lines entirely
lines: [
{
description: 'Audit transformation digitale',
quantity: 5,
unit_price: 300.00,
vat_rate: 20.0,
},
{
description: 'Accompagnement mensuel',
quantity: 3,
unit_price: 500.00,
vat_rate: 20.0,
},
],
}
);
console.log(invoice.status); // still 'draft'

Soumettre au PDP

submit.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Submit a draft invoice to the PDP network (Peppol/Chorus Pro)
// Idempotent — calling twice returns the same transmitted_at
const invoice = await scell.invoices.submit('019dfae2-abef-73e4-b6b2-e4cdae938f3b');
console.log(invoice.status); // 'transmitted'
console.log(invoice.transmitted_at); // ISO 8601
// Bulk submit multiple invoices at once
const results = await scell.invoices.bulkSubmit([
'019dfae2-abef-73e4-b6b2-e4cdae938f3b',
'019dfae2-abef-73e4-b6b2-e4cdae938f3c',
]);

Marquer comme payée

mark-paid.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Mark an outgoing invoice as paid (manual payment)
// Accepted statuses: validated, transmitted, sent, accepted
// Returns 422 INVOICE_NOT_PAYABLE if status is draft or already paid
const { data: invoice } = await scell.invoices.markPaid(
'019dfae2-abef-73e4-b6b2-e4cdae938f3b'
);
// invoice.status === 'paid'
// invoice.paid_at === '2026-06-15T14:30:00Z'
// invoice.payment_method === 'manual'
// With optional payment details
const { data: detailed } = await scell.invoices.markPaid(
'019dfae2-abef-73e4-b6b2-e4cdae938f3b',
{
payment_reference: 'VIR-2026-0542',
paid_at: '2026-06-14T09:00:00Z',
note: 'Virement reçu — relevé BNP 06/2026',
}
);

Télécharger (PDF / XML / Factur-X)

download.ts
typescript
import { ScellApiClient } from '@scell/sdk';
import { writeFileSync } from 'node:fs';
const scell = new ScellApiClient('sk_live_your_api_key');
// Download as Factur-X (PDF/A-3b + embedded CII XML)
const facturx = await scell.invoices.download(
'019dfae2-abef-73e4-b6b2-e4cdae938f3b',
'facturx'
);
writeFileSync('invoice.pdf', Buffer.from(facturx));
// Download as plain PDF (visual only, no embedded XML)
const pdf = await scell.invoices.download(
'019dfae2-abef-73e4-b6b2-e4cdae938f3b',
'pdf'
);
// Download as raw XML (CII EN16931)
const xml = await scell.invoices.download(
'019dfae2-abef-73e4-b6b2-e4cdae938f3b',
'xml'
);

Supprimer un brouillon

delete.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Delete a draft invoice — only 'draft' status allowed
// Returns 422 if invoice is validated/transmitted/paid (ISCA immutability)
await scell.invoices.delete('019dfae2-abef-73e4-b6b2-e4cdae938f3b');

Mentions légales par défaut & override

Scell génère automatiquement les mentions légales obligatoires. Chaque défaut est calculé si vous ne fournissez pas de valeur ; fournir une valeur non vide la remplace.

  • Pied de page (raison sociale, SIRET, TVA, adresse) — override invoice_footer
  • Conditions de paiement L441-10 (B2B : pénalités 3× taux légal + 40 €) — override payment_terms
  • Franchise en base de TVA « TVA non applicable, art. 293 B du CGI » (sous-tenant micro en franchise) — override metadata.vat_exemption_mention
  • Justifications TVA par ligne (autoliquidation art. 196, exonération art. 261…) — selon la catégorie TVA de la ligne

La mention 293 B est légalement obligatoire tant que l'émetteur est en franchise : l'override sert à reformuler, pas à supprimer. Passez le sous-tenant à vat_status: "liable" via subTenants.updateFiscalStatus(id, …) pour basculer la facturation vers la TVA.

Aperçu de document

1 méthode

Aperçu HTML live, non persisté, d'une facture, d'un avoir ou d'un devis en cours de saisie (POST /api/v1/documents/preview). Le rendu utilise le vrai template, le branding et les mentions légales de la société émettrice — idéal pour un aperçu A4 en temps réel pendant la création. Disponible via client.documents.preview(input) (JS v3.2.0), $client->documents->preview($payload) (PHP v3.4.0) et le tool MCP scell_preview_document (v3.2.0).

MéthodeDescription
preview(input)Aperçu HTML live (non persisté) d'un document en cours de saisie — `type` requis (`invoice` | `credit_note` | `quote`), `buyer`, `lines` (max 200), dates, devise, notes, conditions de paiement optionnels. Rendu avec le vrai template + branding + mentions légales de la société émettrice. Retourne le HTML (string). 422 si payload invalide (depuis v3.2.0 JS / v3.4.0 PHP)
document-preview.ts
typescript
// TypeScript — since v3.2.0
// Live HTML preview of a draft document — nothing is persisted.
// Rendered with the REAL template, branding and legal mentions of the issuer.
const html = await client.documents.preview({
type: 'invoice', // 'invoice' | 'credit_note' | 'quote'
document_number: 'FAC-2026-0042', // optional
buyer: {
name: 'Client SARL',
siret: '98765432109876',
is_individual: false,
address: { line1: '2 av. Lyon', postal_code: '69001', city: 'Lyon', country: 'FR' },
},
lines: [
{ description: 'Prestation conseil', quantity: 2, unit_price: 450.0, tax_rate: 20 },
],
due_date: '2026-07-11', // defaults: due +30d, quote validity +90d
notes: 'Conditions particulières…',
});
// Show it in an iframe for a real-time A4 preview while drafting
// <iframe sandbox="" srcDoc={html} />

Signatures

7 méthodes

Créez des demandes de signature électronique simple eIDAS EU-SES (le seul niveau exposé par Scell.io). Multi-signataires (1-10), authentification email/SMS/les deux, OTP avec message custom, positions visuelles avec unité percent ou pixel, archivage 10 ans. Le signing_url retourné pointe vers la page wrapper Scell.io (https://sign.scell.io/sign/...) qui embed le page de signature upstream dans une iframe avec branding Scell par défaut. Disponible sur ScellApiClient et ScellTenantClient.

MéthodeDescription
list(options?)Lister les demandes de signature (filtres : status, environment, company_id, sub_tenant_id, per_page max 100). Scopé par tenant via sk_live_* / sk_test_*.
get(id)Obtenir une demande de signature par ID (scope tenant strict, 404 si appartient à un autre tenant)
create(data)Créer une demande de signature eIDAS EU-SES
cancel(id)Annuler une demande de signature en attente
remind(id)Envoyer une relance aux signataires en attente
download(id, type)Télécharger le document signé ou le fichier de preuve
auditTrail(id)Obtenir la piste d'audit complète de la signature
signatures.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Read PDF and encode to base64
const pdfBytes = await fs.readFile('contrat.pdf');
const base64Pdf = pdfBytes.toString('base64');
const signature = await scell.signatures.create({
// Required
title: 'Contrat de prestation',
document: base64Pdf,
document_name: 'contrat.pdf',
signers: [
{
first_name: 'Marie',
last_name: 'Dupont',
email: 'marie.dupont@example.com',
auth_method: 'email',
// Custom message with {OTP} placeholder (max 500 chars)
message: 'Bonjour Marie, votre contrat est pret. Code OTP: {OTP}',
},
],
// Optional: where the signature box is dropped on the PDF
signature_positions: [
{ page: 1, x: 70, y: 80, unit: 'percent' }, // unit: 'percent' (default) | 'pixel'
],
// Optional: redirects after signing / cancelling
redirect_complete_url: 'https://yourapp.com/contracts/done',
redirect_cancel_url: 'https://yourapp.com/contracts/cancelled',
// Optional: 10-year eIDAS archiving
archive_enabled: true,
});
console.log(signature.id);
console.log(signature.status); // 'pending' | 'waiting_signers' | ...
console.log(signature.signers[0].signing_url); // https://sign.scell.io/sign/{id}/{signerId}?...&signature=HMAC
// Cancel a signature request
await scell.signatures.cancel(signature.id);
// Send a reminder to pending signers
await scell.signatures.remind(signature.id);
// Download the signed document
const signed = await scell.signatures.download(signature.id, 'signed');
// List signatures — scope automatique au tenant courant via sk_live_* / sk_test_*.
// Filtres disponibles : status, environment ('production' | 'sandbox'), company_id,
// sub_tenant_id (anti-IDOR — limité aux sub_tenants du tenant courant), per_page (max 100).
const pending = await scell.signatures.list({
status: 'pending',
environment: 'production',
sub_tenant_id: '019d5ea8-0000-0000-0000-000000000000',
per_page: 50,
});
// --- Demande de signature au nom d'un sub-tenant (depuis 2026-05-11) ---
// Passer sub_tenant_id dans le payload POST. La company emettrice
// devient la 1re company du sub-tenant. 404 SUB_TENANT_NOT_FOUND si
// le sub_tenant n'appartient pas au tenant courant.
const signatureSub = await scell.signatures.create({
sub_tenant_id: '019d5ea8-0000-0000-0000-000000000000',
title: 'Contrat de prestation',
document: base64Pdf,
document_name: 'contrat.pdf',
signers: [{ first_name: 'Marie', last_name: 'Dupont', email: 'marie@example.com', auth_method: 'email' }],
});

Personnalisation de la page de signature (white-label)

Le payload ui_config (21 champs alignés sur la spec EU-SES eIDAS v1.0.17) et signature_options (4 champs comportementaux) permettent de white-labeler intégralement la page que voient vos signataires. Tout est optionnel : si vous omettez ui_config, le backend applique la palette Scell.io. Si vous fournissez un sous-ensemble, seuls les champs absents sont remplis avec les défauts — vos overrides sont préservés. iframe_ancestors est automatiquement étendu avec https://sign.scell.io et https://scell.io (cap 20, dédupliqué) pour que le wrapper puisse embarquer la page upstream.

ui_config — 21 champs

ChampTypeDescription
Sidebar (4)
sidebar_logoURLLogo affiché dans la sidebar (HTTPS, max 500 chars).
sidebar_background_color#RRGGBBCouleur de fond de la sidebar.
sidebar_title_color#RRGGBBCouleur des titres dans la sidebar.
sidebar_text_color#RRGGBBCouleur du texte dans la sidebar.
Header (3)
header_background_color#RRGGBBCouleur de fond du header.
header_title_color#RRGGBBCouleur du titre principal du header.
header_subtitle_color#RRGGBBCouleur du sous-titre du header.
Footer (1)
footer_background_color#RRGGBBCouleur de fond du footer.
Boutons standards (4)
button_text_color#RRGGBBCouleur du texte des boutons.
button_text_color_hover#RRGGBBCouleur du texte au survol.
button_background_color#RRGGBBCouleur de fond des boutons.
button_background_color_hover#RRGGBBCouleur de fond au survol.
Bouton « Signer » (4) — override des boutons standards
sign_button_text_color#RRGGBBTexte du bouton Signer.
sign_button_text_color_hover#RRGGBBTexte du bouton Signer au survol.
sign_button_background_color#RRGGBBFond du bouton Signer.
sign_button_background_color_hover#RRGGBBFond du bouton Signer au survol.
Toggles d'affichage (4)
hide_sidebarbooleanMasque entièrement la sidebar.
hide_headerbooleanMasque le header.
hide_download_validatedbooleanMasque le bouton de téléchargement après validation OTP.
hide_download_signedbooleanMasque le bouton de téléchargement après signature.
Iframe (1)
iframe_ancestorsURL[]Domaines autorisés à embarquer la page (max 20). Le backend ajoute automatiquement sign.scell.io et scell.io.

signature_options — 4 champs comportementaux

ChampTypeDescription
signature_mode'typed' | 'drawn' | 'both'Mode de saisie de la signature. typed = clavier, drawn = dessinée, both = laisse le signataire choisir.
signer_must_readbooleanForce le signataire à parcourir tout le document avant que le bouton Signer ne soit actif.
user_editable_data{name?, mobile?, email?}Champs que le signataire peut modifier sur ses propres données (booléens par champ).
timezonestringIdentifiant IANA (ex: Europe/Paris). Affecte les horodatages affichés et le PDF audit trail.

Autres champs notables

  • signers[].message (max 500 chars) — message custom envoyé par email/SMS au signataire. Supporte le placeholder {OTP} qui sera remplacé par le code à 6 chiffres.
  • signers[].auth_method = 'email' | 'sms' | 'both' — méthode d'envoi du code OTP. both envoie l'OTP par email ET par SMS (renforce la sécurité).
  • signers[].order — ordre de signature pour le mode séquentiel (1, 2, 3...). Si absent, ordre d'apparition dans le tableau.
  • signature_positions[].unit = 'percent' (défaut) ou 'pixel'. Si pixel, vous pouvez fournir page_width_px / page_height_px pour override la détection auto via parser PDF (fallback A4 595×842).
  • archive_enabled — active l'archivage 10 ans eIDAS conforme.

Signature blocks — paraphe (initiales), mentions juridiques, date

3 blocs optionnels que Scell grave sur le PDF avant envoi au service de signature certifié EU-SES (qui ne supporte pas nativement les mentions). Le PDF original est conservé pour l'audit trail.

initials_blockparaphe automatique multi-pages(positions[] depuis v2.17.0 JS / v2.15.0 PHP / v2.16.0 MCP)
ChampTypeDescription
enabledbooleanActive ou désactive le bloc paraphe.
mode'auto' | 'custom''auto' = initiales depuis nom du 1er signataire ; 'custom' = utilise custom_text.
custom_textstringTexte custom (max 8 chars). Requis si source=custom.
positions[]{page, x, y, ...}[]Nouveau format recommandé. Une entrée par page avec sa propre position (x, y, unit) et ses overrides optionnels (font_size, color, bold). Max 500 entrées. Si fourni, prévaut sur position+pages (legacy).
position{x, y, unit}Legacy. Position commune appliquée à toutes les pages choisies par pages. Ignoré si positions[] est fourni.
pages'all' | 'except_last' | number[]Legacy. Sélecteur de pages pour position commune. Ignoré si positions[] est fourni.
font_sizenumber (6-20)Défaut bloc, surchargeable par positions[].font_size.
color#RRGGBBDéfaut bloc, surchargeable per-position.
boldbooleanDéfaut bloc, surchargeable per-position.
  • mentions[] — tableau de mentions juridiques (max 20). Chaque entrée : {label, signer_index?, position: {page, x, y}, required?, fallback_text?}. Le bloc est gravé directement par Scell (texte du label ou du fallback_text à défaut).
  • date_block — date du jour pré-remplie (timezone IANA). position.page accepte un entier 1-indexé OU la string 'last' (dernière page).
  • Référence complète — voir scell-api-llms.txt section "Signature blocks (v2.12.0)".

Exemple complet — personnalisation white-label + blocs

signatures-full.ts
typescript
// White-label override with ui_config (21 fields) and signature_options.
// Any field omitted falls back to Scell.io defaults.
const signature = await scell.signatures.create({
title: 'Contrat de prestation',
document: base64Pdf,
document_name: 'contrat.pdf',
signers: [
{ first_name: 'Marie', last_name: 'Dupont', phone: '+33612345678', auth_method: 'sms' },
{ first_name: 'Jean', last_name: 'Martin', email: 'jean@example.com', auth_method: 'email', order: 2 },
],
signature_positions: [
{ page: 1, x: 70, y: 80, width: 20, height: 8, unit: 'percent' },
],
ui_config: {
// Sidebar (4)
sidebar_logo: 'https://yourcdn.com/logo.svg',
sidebar_background_color: '#0F172A',
sidebar_title_color: '#FFFFFF',
sidebar_text_color: '#CBD5E1',
// Header (3)
header_background_color: '#FFFFFF',
header_title_color: '#0F172A',
header_subtitle_color: '#475569',
// Footer (1)
footer_background_color: '#F8FAFC',
// Standard buttons (4)
button_text_color: '#FFFFFF',
button_text_color_hover: '#FFFFFF',
button_background_color: '#6366F1',
button_background_color_hover: '#4F46E5',
// Sign button (4) — overrides standard buttons for the Sign action
sign_button_text_color: '#FFFFFF',
sign_button_text_color_hover: '#FFFFFF',
sign_button_background_color: '#10B981',
sign_button_background_color_hover: '#059669',
// Visibility toggles (4)
hide_sidebar: false,
hide_header: false,
hide_download_validated: false,
hide_download_signed: false,
// Iframe ancestors (max 20). Scell auto-injects sign.scell.io + scell.io.
iframe_ancestors: ['https://app.acme.com', 'https://acme.com'],
},
signature_options: {
// 'typed' (keyboard only) | 'drawn' (mouse/finger only) | 'both' (signer chooses)
signature_mode: 'both',
// Force scrolling through the entire document before sign button enables
signer_must_read: true,
// Per-field control over what the signer can edit on their own data
user_editable_data: { name: false, mobile: true, email: false },
// IANA timezone identifier
timezone: 'Europe/Paris',
},
// Initials block — paraphe burned by Scell on each page BEFORE forwarding
// to the certified EU-SES signature service. Two formats accepted (v2.17.0+):
//
// 1. NEW — positions[] (one entry per page, recommended for multi-page)
// 2. LEGACY — position + pages (same position on all pages)
//
// If both are provided, positions[] wins.
initials_block: {
enabled: true,
mode: 'auto', // 'auto' (initials from signer name) | 'custom'
source: 'signer_name',
font_size: 10, // block default (overridable per-position)
color: '#1a1a1a', // block default (overridable per-position)
bold: false, // block default (overridable per-position)
positions: [
{ page: 1, x: 90, y: 90, unit: 'percent' },
{ page: 2, x: 88, y: 92, unit: 'percent', font_size: 12 },
{ page: 3, x: 85, y: 90, unit: 'percent', color: '#aa0000' },
],
},
// Mentions — legal mentions burned on the PDF (max 20)
mentions: [
{
label: 'Lu et approuvé',
required: true,
signer_index: 0,
position: { page: 1, x: 10, y: 80, unit: 'percent' },
font_size: 9,
color: '#333333',
},
],
// Date block — today's date in the tenant timezone
date_block: {
enabled: true,
format: 'dd/MM/yyyy',
timezone: 'Europe/Paris',
position: { page: 'last', x: 70, y: 88, unit: 'percent' },
font_size: 9,
color: '#555555',
},
redirect_complete_url: 'https://yourapp.com/contracts/done',
redirect_cancel_url: 'https://yourapp.com/contracts/cancelled',
expires_at: '2026-12-31T23:59:59Z',
archive_enabled: true,
external_id: 'CRM-INV-2026-0042',
});

Avoirs

8 méthodes

Créez des avoirs liés à des factures existantes. Supporte les remboursements partiels et totaux. Disponible sur ScellApiClient.

MéthodeDescription
list(options?)Lister les avoirs avec pagination et filtres
get(id)Obtenir un avoir par UUID
create(data)Créer un avoir lié à une facture. `type` (`partial` | `total`, PAS `full`) requis. Pour un avoir PARTIEL, il faut SÉLECTIONNER des lignes de la facture source via `items[].invoice_line_id` — le prix et le taux de TVA EXACT de chaque ligne sont hérités (une facture peut mêler 20 % / 5,5 % / exonéré 0 %). Appeler `remainingCreditable` d'abord.
update(id, data)Mettre à jour un avoir en brouillon
delete(id)Supprimer un avoir en brouillon (ISCA : draft uniquement)
send(id)Envoyer l'avoir au destinataire (irréversible)
download(id)Télécharger l'avoir en PDF
remainingCreditable(invoiceId)Lister les lignes encore créditables (quantité restante + taux TVA par ligne) — étape de découverte avant un avoir partiel. Retourne `data.items[]` (invoice_line_id, remaining_quantity, tax_rate, remaining_amount_ht) + `can_be_credited`.
credit-notes.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// ── Total credit note (refund entire invoice) ───────────────────────
const { data: totalCN } = await scell.creditNotes.create({
invoice_id: '019dfae2-abef-73e4-b6b2-e4cdae938f3b',
reason: 'Annulation de la prestation',
type: 'total',
});
// totalCN.status === 'draft'
// totalCN.credit_note_number === 'AVO-2026-000005'
// ── Partial credit note (specific lines) ────────────────────────────
const { data: partialCN } = await scell.creditNotes.create({
invoice_id: '019dfae2-abef-73e4-b6b2-e4cdae938f3b',
reason: 'Remboursement partiel — 2 articles retournés',
type: 'partial',
items: [
{
invoice_line_id: '019dfae2-bbbb-0000-0000-000000000001',
quantity: 2, // credit 2 of original quantity
},
],
});
// ── Check remaining creditable amount ───────────────────────────────
const { data: remaining } = await scell.creditNotes.remainingCreditable(
'019dfae2-abef-73e4-b6b2-e4cdae938f3b'
);
// remaining.total_ht, remaining.total_ttc, remaining.lines[]
// ── Update a draft credit note ──────────────────────────────────────
const { data: updated } = await scell.creditNotes.update(partialCN.id, {
reason: 'Remboursement partiel — 3 articles retournés (corrigé)',
});
// ── Send credit note (irreversible — enters ISCA chain) ─────────────
await scell.creditNotes.send(partialCN.id);
// ── Download as PDF ─────────────────────────────────────────────────
const pdf = await scell.creditNotes.download(partialCN.id);
// ── Delete a draft (only draft status — ISCA compliance) ────────────
await scell.creditNotes.delete(totalCN.id);
// ── List with filters ───────────────────────────────────────────────
const { data: list, meta } = await scell.creditNotes.list({
status: 'draft',
per_page: 25,
});

Entreprises

7 méthodes

Gérez les entités entreprises avec leurs informations légales (SIREN, numéro TVA, adresse). Inclut le flux de vérification KYC/KYB. Disponible sur ScellClient (Bearer token).

MéthodeDescription
list()Lister toutes les entreprises de l'utilisateur authentifié
get(id)Obtenir une entreprise par ID
create(data)Enregistrer une nouvelle entreprise avec ses données légales
update(id, data)Mettre à jour les informations de l'entreprise
delete(id)Supprimer une entreprise
initiateKyc(id)Démarrer le processus de vérification KYC/KYB
kycStatus(id)Vérifier le statut actuel de la vérification KYC
companies.ts
typescript
import { ScellClient } from '@scell/sdk';
const client = new ScellClient('your_bearer_token');
// Create a company
const company = await client.companies.create({
name: 'ACME Corp',
siren: '123456789',
vat_number: 'FR12345678901',
address: {
street: '10 Rue de la Paix',
city: 'Paris',
postal_code: '75002',
country: 'FR',
},
});
// List all companies
const companies = await client.companies.list();
// Update a company
await client.companies.update(company.id, { name: 'ACME Corp Updated' });
// Initiate KYC/KYB verification
await client.companies.initiateKyc(company.id);
// Check KYC status
const kyc = await client.companies.kycStatus(company.id);
console.log(kyc.status); // 'pending' | 'approved' | 'rejected'

Référentiel pays

2 méthodes

Référentiel authentifié des sociétés par pays : numéro de TVA, identifiant national d’entreprise (registre + format) et formes juridiques connues. Permet d’adapter dynamiquement un formulaire de saisie acheteur/vendeur au pays sélectionné. Disponible sur ScellClient, ScellApiClient et ScellPublicClient.

MéthodeDescription
countries()Lister tous les pays catalogués (TVA, identifiant national, formes juridiques)
country(code)Obtenir le référentiel d'un pays par code ISO 3166-1 alpha-2 (ex: FR, DE)
reference.ts
typescript
import { ScellClient } from '@scell/sdk';
const client = new ScellClient(process.env.SCELL_API_KEY!);
// Référentiel sociétés par pays (GET /v1/reference/countries, authentifié).
// Permet d'adapter un formulaire de saisie acheteur/vendeur au pays choisi.
// 1. Lister tous les pays catalogués
const countries = await client.reference.countries();
// 2. Récupérer un pays précis (code ISO 3166-1 alpha-2)
const fr = await client.reference.country('FR');
console.log(fr);
// {
// code: 'FR',
// name: 'France',
// known: true,
// is_eu: true,
// currency: 'EUR',
// vat: {
// label: 'Numéro de TVA intracommunautaire',
// example: 'FR12345678901',
// regex: '^FR[A-Z0-9]{2}\\d{9}$', // utilisable via new RegExp(regex)
// vies_checkable: true, // vérifié contre le registre VIES
// },
// national_id: {
// label: 'SIREN / SIRET',
// scheme: '0002', // code ISO 6523 du registre
// example: '12345678901234',
// regex: '^(\\d{9}|\\d{14})$',
// required_for_b2b: true,
// },
// legal_forms: [
// { code: 'SAS', label: 'SAS — Société par actions simplifiée' },
// { code: 'SARL', label: 'SARL — Société à responsabilité limitée' },
// // ...
// ],
// }
// 3. Construire dynamiquement un formulaire adapté au pays sélectionné
const de = await client.reference.country('DE');
const idLabel = de.national_id.label; // "Handelsregisternummer"
const idRegex = de.national_id.regex; // null => saisie libre acceptée
const legalFormOptions = de.legal_forms; // pour une liste déroulante
const validate = idRegex ? new RegExp(idRegex) : null;
// Un pays non catalogué renvoie known=false + un format permissif (regex null) :
// le client doit alors accepter la saisie libre, sans bloquer.
const xx = await client.reference.country('ZZ');
console.log(xx.known); // false

Schéma de la réponse

Chaque pays renvoie le bloc vat, le bloc national_id (registre + format) et la liste legal_forms. Les regex sont des motifs ancrés directement utilisables (new RegExp(regex)) ; null sur national_id.regex signifie « format non vérifié » → accepter la saisie libre. Un pays non catalogué renvoie known: false.

CountryReference
typescript
interface CountryReference {
code: string; // ISO 3166-1 alpha-2 (FR, DE, BE, …)
name: string | null; // nom du pays
known: boolean; // false = pays non catalogué (fallback permissif)
is_eu: boolean; // appartenance à l'Union européenne
currency: string | null; // devise ISO 4217 (EUR, SEK, …)
vat: {
label: string; // libellé localisé ("Numéro de TVA intracommunautaire")
example: string | null; // exemple ("FR12345678901")
regex: string | null; // motif ancré JS-compatible, null si non vérifié
vies_checkable: boolean; // vérifiable contre le registre VIES (UE)
};
national_id: {
label: string; // libellé du registre ("SIREN / SIRET", "KvK-nummer", …)
scheme: string | null; // code ISO 6523 / Peppol EAS ("0002" SIRENE, "0106" KvK)
example: string | null; // exemple ("12345678901234")
regex: string | null; // motif ancré, null = format non vérifié → saisie libre
required_for_b2b: boolean; // identifiant requis en B2B pour ce pays
};
legal_forms: Array<{
code: string; // code stable ("SAS", "GMBH", "LTD", …)
label: string; // libellé pour une liste déroulante
}>;
}

Clés API

4 méthodes

Créez et gérez des clés API pour l'authentification serveur à serveur. Les clés peuvent être live (sk_live_*) ou sandbox (sk_test_*). La valeur de la clé secrète n'est affichée qu'une seule fois à la création. Disponible sur ScellClient (Bearer token).

MéthodeDescription
list()Lister toutes les clés API du compte
get(id)Obtenir une clé API par ID (valeur masquée)
create(data)Créer une nouvelle clé API (environnement live ou test)
delete(id)Révoquer et supprimer une clé API
api-keys.ts
typescript
import { ScellClient } from '@scell/sdk';
const client = new ScellClient('your_bearer_token');
// Create a new API key
const key = await client.apiKeys.create({
name: 'Production Key',
environment: 'live', // 'live' | 'test'
});
console.log(key.id);
console.log(key.key); // sk_live_... (shown only once)
// List all API keys
const keys = await client.apiKeys.list();
// Delete an API key
await client.apiKeys.delete(key.id);

Webhooks

8 méthodes

Gérez les endpoints webhook pour recevoir des notifications en temps réel. Chaque webhook possède un secret de signature (wh_sec_*) pour la vérification HMAC-SHA256. Supporte le filtrage d'événements, les tests et les journaux de livraison. Disponible sur ScellClient (Bearer token).

MéthodeDescription
list()Lister tous les endpoints webhook
get(id)Obtenir les détails d'un webhook par ID
create(data)Créer un endpoint webhook avec abonnements aux événements
update(id, data)Mettre à jour l'URL, les événements ou le statut actif
delete(id)Supprimer un endpoint webhook
test(id)Envoyer un payload de test à l'URL du webhook
regenerateSecret(id)Régénérer le secret de signature du webhook (wh_sec_…)
logs(id)Voir les journaux de livraison et codes de réponse
webhooks.ts
typescript
import { ScellClient } from '@scell/sdk';
const client = new ScellClient('your_bearer_token');
// Create a webhook endpoint
const webhook = await client.webhooks.create({
url: 'https://yourapp.com/webhooks/scell',
events: [
'invoice.created',
'invoice.validated',
'signature.completed',
'balance.low',
],
active: true,
});
console.log(webhook.id);
console.log(webhook.secret); // wh_sec_... (for signature verification)
// List all webhooks
const list = await client.webhooks.list();
// Update a webhook
await client.webhooks.update(webhook.id, {
events: ['invoice.created', 'signature.completed'],
});
// Test a webhook (sends a test payload)
await client.webhooks.test(webhook.id);
// Regenerate the signing secret
const newSecret = await client.webhooks.regenerateSecret(webhook.id);
// View delivery logs
const logs = await client.webhooks.logs(webhook.id);
// Delete a webhook
await client.webhooks.delete(webhook.id);

Conformité fiscale

26 méthodes

Suite complète de conformité fiscale ISCA autocertifiée (article 286-I-3° bis CGI). Ledger increvable depuis v0.6.0 : chaînes ISCA isolées par paire (tenant_id, sub_tenant_id), triggers PostgreSQL en défense en profondeur, chaîne SHA-256, clôtures journalières/mensuelles/annuelles (1 par tenant + 1 par sub_tenant actif), ancrage TSA RFC 3161 + ancrage blockchain Bitcoin gratuit via OpenTimestamps (best effort), export FEC, kill switch d'arrêt d'urgence, moteur de règles, health check intégrité (gaps, orphans, chain_invalid) et auto-attestation ISCA nominative par tenant ou sub_tenant. Disponible sur ScellApiClient et ScellTenantClient.

MéthodeDescription
compliance()Obtenir le statut global de conformité fiscale (ISCA)
entries()Lister les entrées du registre immuable SHA-256
closings(options?)Lister les clôtures. `options.closing_type` (daily | monthly | annual), `options.sub_tenant_id` (chaîne ISCA d'un sous-tenant, anti-IDOR). Chaque item porte un `download_url`.
downloadClosing(closingId)Télécharger le CSV (format de marché) d'une clôture (daily/monthly/annual, sous-tenant inclus). Scope tenant strict (404 cross-tenant).
dailyClosing()Déclencher une clôture journalière immédiate
integrity()Lancer une vérification complète de la chaîne de hachage
integrityHistory()Obtenir l'historique de toutes les vérifications d'intégrité
integrityForDate(date)Vérifier l'intégrité pour une date précise
rules()Lister toutes les règles d'automatisation fiscale
createRule(data)Créer une règle fiscale (clé, valeur, description)
updateRule(id, data)Mettre à jour une règle fiscale existante
ruleDetail(key)Obtenir les détails d'une règle fiscale par clé
ruleHistory(key)Obtenir l'historique des modifications d'une règle
exportRules()Exporter toutes les règles fiscales en fichier téléchargeable
replayRules()Rejouer toutes les règles fiscales (recalculer les données dérivées)
anchors()Lister les ancres de timestamping TSA RFC 3161
killSwitchStatus()Obtenir le statut du kill switch (arrêt d'urgence)
killSwitchActivate(input)Activer le kill switch — scope fiscal:admin + step-up (raison ≥ 20 car., confirmation e-mail en prod)
killSwitchDeactivate(input)Désactiver le kill switch — même step-up (raison ≥ 20 car. + confirmation prod)
fecExport()Générer l'export FEC pour les autorités fiscales françaises
forensicExport()Générer un export forensique avec données d'audit complètes
attestation(year)Obtenir l'attestation de conformité ISCA pour une année
attestationDownload(year)Télécharger le PDF de l'attestation pour une année
iscaSelfAttestationDownload(subTenantId?)Télécharger l'auto-attestation ISCA NOMINATIVE (PDF) pour le tenant ou un sub_tenant — depuis v1.17.0 (JS) / v1.16.0 (PHP)
iscaMeasuresRegisterDownload()Télécharger le registre des mesures ISCA (PDF non-nominatif)
iscaTechnicalDossierDownload()Télécharger le dossier technique ISCA conforme NF Z 42-025 (PDF non-nominatif)
integrityStatus()Statut résumé de l'intégrité du ledger (gaps, orphans, chain_invalid) — endpoint /api/v1/fiscal/integrity
fiscal.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// ─── Compliance overview ───────────────────────────────
const status = await scell.fiscal.compliance();
console.log(status.is_compliant); // true | false
console.log(status.isca_status);
// ─── Immutable ledger entries ──────────────────────────
const entries = await scell.fiscal.entries();
// ─── Closings ──────────────────────────────────────────
const closings = await scell.fiscal.closings();
await scell.fiscal.dailyClosing(); // Trigger a daily closing
// ─── Integrity verification ───────────────────────────
const integrity = await scell.fiscal.integrity();
const history = await scell.fiscal.integrityHistory();
const forDate = await scell.fiscal.integrityForDate('2026-03-30');
// ─── Fiscal rules engine ──────────────────────────────
const rules = await scell.fiscal.rules();
const newRule = await scell.fiscal.createRule({
key: 'auto_daily_closing',
value: true,
description: 'Automatically trigger daily closings at midnight',
});
await scell.fiscal.updateRule(newRule.id, { value: false });
const detail = await scell.fiscal.ruleDetail('auto_daily_closing');
const ruleHist = await scell.fiscal.ruleHistory('auto_daily_closing');
await scell.fiscal.exportRules();
await scell.fiscal.replayRules();
// ─── TSA Anchors ──────────────────────────────────────
const anchors = await scell.fiscal.anchors();
// ─── Kill switch (emergency halt) ─────────────────────
const ksStatus = await scell.fiscal.killSwitchStatus();
// activate/deactivate require the fiscal:admin scope + a reason >= 20 chars.
// In production, the 1st call returns 403 OOB_CONFIRMATION_REQUIRED and emails
// a confirmation_token — re-call with it to apply.
await scell.fiscal.killSwitchActivate({
reason: 'Incident de securite confirme, gel des emissions',
// confirmation_token: '...', // production only
});
await scell.fiscal.killSwitchDeactivate({
reason: 'Incident resolu, reprise de la facturation normale',
// confirmation_token: '...',
});
// ─── Exports ──────────────────────────────────────────
const fec = await scell.fiscal.fecExport();
const forensic = await scell.fiscal.forensicExport();
const attestation = await scell.fiscal.attestation(2026);
const download = await scell.fiscal.attestationDownload(2026);
// ─── ISCA self-attestation (NOMINATIVE — depuis v1.17.0) ──
// Auto-attestation pour le tenant courant (donnees KYB)
const tenantPdf = await scell.fiscal.iscaSelfAttestationDownload();
fs.writeFileSync('attestation-tenant.pdf', Buffer.from(tenantPdf));
// Auto-attestation pour un sub_tenant specifique
const subPdf = await scell.fiscal.iscaSelfAttestationDownload('019d5ea8-...');
fs.writeFileSync('attestation-sub-tenant.pdf', Buffer.from(subPdf));
// Documents de conformite (non-nominatifs)
const measures = await scell.fiscal.iscaMeasuresRegisterDownload();
const dossier = await scell.fiscal.iscaTechnicalDossierDownload();

Statistiques

2 méthodes

Obtenez des statistiques agrégées et mensuelles pour les factures, signatures et revenus. Disponible sur ScellApiClient et ScellTenantClient.

MéthodeDescription
overview()Obtenir les statistiques agrégées (factures, signatures, revenus)
monthly()Obtenir la ventilation mois par mois de l'activité et des revenus
stats.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Get overview statistics
const overview = await scell.stats.overview();
console.log(overview.total_invoices);
console.log(overview.total_signatures);
console.log(overview.total_revenue);
// Get monthly breakdown
const monthly = await scell.stats.monthly();
monthly.forEach(m => {
console.log(m.month, m.invoices_count, m.revenue);
});

Facturation, solde & recharge

8 méthodes

Point d'entrée unique pour la facturation Scell.io — depuis v2.2.0 cette ressource remplace l'ancien BalanceResource (supprimé : les endpoints /api/v1/balance/* renvoient 404). Couvre le solde courant (usage()), la recharge Stripe (topUp() + confirmTopUp()), l'historique des transactions (transactions()), la liste des factures Scell.io émises au tenant (invoices()) et le paiement en ligne d'une facture (payInvoice() → PaymentIntent Stripe). Disponible sur ScellApiClient et ScellTenantClient.

MéthodeDescription
invoices()Lister toutes les factures de facturation Scell.io
showInvoice(id)Obtenir les détails d'une facture de facturation
downloadInvoice(id)Télécharger une facture de facturation en PDF
usage()Obtenir les métriques d'utilisation de la période en cours
topUp(data)Initier une recharge de crédits
confirmTopUp(data)Confirmer une recharge en attente avec le code de confirmation
payInvoice(id)Initier le paiement Stripe d'une facture Scell.io (PaymentIntent + client_secret pour Stripe.js)
transactions()Lister toutes les transactions de facturation
billing.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// List billing invoices
const invoices = await scell.billing.invoices();
// Get a specific billing invoice
const inv = await scell.billing.showInvoice('billing_inv_id');
// Download billing invoice PDF
const pdf = await scell.billing.downloadInvoice('billing_inv_id');
// Get current usage metrics
const usage = await scell.billing.usage();
console.log(usage.invoices_used);
console.log(usage.signatures_used);
console.log(usage.credits_remaining);
// Top up credits
await scell.billing.topUp({ amount: 100, payment_method: 'card' });
// Confirm a pending top-up
await scell.billing.confirmTopUp({ top_up_id: 'tu_id', confirmation_code: '1234' });
// Pay a Scell.io billing invoice (depuis v2.2.0 - Wave 6 2026-05-10)
// Initiates a Stripe PaymentIntent. Use the client_secret with Stripe.js
// to complete the payment client-side; webhook marks invoice as paid.
const intent = await scell.billing.payInvoice('billing_inv_id');
console.log(intent.clientSecret); // Pass to stripe.confirmCardPayment()
console.log(intent.paymentIntentId); // pi_xxx
console.log(intent.amount); // amount in cents (EUR)
console.log(intent.status); // requires_payment_method | requires_confirmation
// List billing transactions
const transactions = await scell.billing.transactions();

Authentification & Gestion Tenant

15 méthodes

Inscription / connexion utilisateur dashboard ET gestion du compte tenant partenaire. Inclut la création de clés sk_* / pk_*, la mise à jour du profil + Company "self" (logo, IBAN, mentions Factur-X), l'upload du logo via S3 presigned. Disponible sur ScellClient (Bearer Sanctum) et ScellTenantClient.

MéthodeDescription
register(data)Inscription d'un nouvel utilisateur dashboard
login(data)Connexion (Bearer token Sanctum)
logout()Déconnexion + révocation du token
me()Obtenir le profil de l'utilisateur connecté
forgotPassword(email)Envoyer un email de réinitialisation
resetPassword(token, password)Réinitialiser le mot de passe avec le token reçu par email
tenantLogin(data)Connexion tenant partenaire (séparé du dashboard utilisateur)
tenantRegister(data)Inscription tenant partenaire
tenantMe()Profil du tenant courant
tenantLogout()Déconnexion tenant + révocation du token
tenantKeys()Lister les clés (sk_/pk_) du tenant
createSecretKey()Créer une nouvelle clé secrète tenant (sk_live_* / sk_test_*)
createPublishableKey()Créer une clé publishable tenant (pk_live_* / pk_test_*)
updateTenantProfile(data)Mettre à jour le profil tenant + Company "self" (logo, IBAN, mentions Factur-X)
logoUploadUrl()Obtenir une URL S3 presigned pour uploader le logo de la Company self
regenerateApiKey()Régénérer la clé API tenant

Factures Sub-Tenant (directes)

14 méthodes

Émission de factures Factur-X / UBL / CII au nom d'un sub_tenant (B2B2B). Inclut validation Schematron, soumission PDP/Peppol, envoi email, téléchargement scopé, opérations en lot, et accès au solde encore créditable. Disponible sur ScellApiClient (sk_*) et ScellTenantClient (tk_*).

MéthodeDescription
list(subTenantId, options?)Lister les factures d'un sub_tenant
get(id)Obtenir une facture par UUID
create(subTenantId, data)Créer une facture au nom d'un sub_tenant
update(id, data)Mettre à jour une facture en brouillon
delete(id)Supprimer une facture en brouillon
submit(id)Soumettre la facture au réseau PDP/Peppol
validate(id)Valider la facture sans la soumettre (Schematron Factur-X)
send(id, data?)Envoyer la facture par email au buyer
download(id, format?)Télécharger en facturx | pdf | xml
downloadForSubTenant(subTenantId, id, format?)Téléchargement scopé sub_tenant strict
remainingCreditable(id)Solde encore créditable de la facture
bulkCreate(subTenantId, data[])Créer plusieurs factures en lot
bulkSubmit(ids[])Soumettre plusieurs factures au PDP en lot
bulkStatus(ids[])Statut courant de plusieurs factures

Factures entrantes (Sub-Tenant)

8 méthodes

Gestion des factures reçues par un sub_tenant via le réseau PDP — flux complet accept / reject / dispute / mark-paid. Permet aussi d'enregistrer manuellement une facture reçue hors PDP (papier, email, etc.).

MéthodeDescription
create(subTenantId, data)Enregistrer une facture entrante reçue hors PDP (saisie manuelle)
listForSubTenant(subTenantId, options?)Lister les factures entrantes d'un sub_tenant
get(id)Obtenir une facture entrante par UUID
accept(id, data?)Accepter une facture entrante (PDP)
reject(id, reason)Rejeter une facture entrante avec motif
markPaid(id, data?)Marquer comme payée (date, référence)
delete(id)Supprimer une facture entrante en brouillon
download(id, format?)Télécharger la facture entrante (facturx | pdf | xml)

Avoirs Tenant (multi sub_tenants)

8 méthodes

Avoirs émis pour le compte d'un sub_tenant. Conserve l'héritage strict des champs buyer/seller depuis la facture associée (compliance ISCA — pas d'override possible).

MéthodeDescription
list(options?)Lister tous les avoirs du tenant + sub_tenants
get(id)Obtenir un avoir par UUID
create(data)Créer un avoir lié à une facture
update(id, data)Mettre à jour un avoir en brouillon
delete(id)Supprimer un avoir en brouillon
send(id, data?)Envoyer l'avoir par email
download(id, format?)Télécharger en facturx | pdf | xml
remainingCreditable(invoiceId)Solde encore créditable d'une facture

Templates de facture

8 méthodes

Personnalisation des PDF Factur-X : logo, couleurs, footer, mentions légales. Cascade explicite > sub_tenant default > tenant default > system default. Cache Redis 5 min. Nouveau champ is_enabled (bool, défaut true) : à false, le template est ignoré par la cascade (repli sur le template système). deriveColorsFromEmailLogo() déduit les couleurs primary/accent du logo e-mail (depuis v3.2.0 JS / v3.4.0 PHP).

MéthodeDescription
list(options?)Lister les templates (system / tenant / sub_tenant scope)
get(id)Obtenir un template par UUID
create(data)Créer un template personnalisé (logo, couleurs, mentions)
update(id, data)Mettre à jour un template
delete(id)Supprimer un template
markDefault(id)Marquer un template comme défaut (PUT /:id/default)
uploadLogo(id, file)Uploader un logo pour le template (multipart)
deriveColorsFromEmailLogo()Déduire les couleurs primary/accent du logo e-mail et les appliquer au template par défaut du tenant. 404 si pas de logo e-mail, 422 si extraction impossible (depuis v3.2.0 JS / v3.4.0 PHP)
deriveColorsFromInvoiceLogo()Extraire la palette `{ primary_color, accent_color }` du logo de facture (template) — retournée sans être persistée (depuis v3.5.0)
preview(branding?)Aperçu HTML/PDF d'une facture d'exemple avec un branding donné — champs omis repris du template par défaut (cascade) (depuis v3.5.0)

Acheteurs (registre)

5 méthodes

Registre d'acheteurs réutilisables, scopé strictement par (tenant_id, sub_tenant_id). Référencer un buyer via buyer_id dans la création de facture pour éviter de re-saisir les données. Supporte B2B (SIRET/SIREN/TVA) et B2C (particulier is_individual=true) + adresse de livraison BG-13.

MéthodeDescription
list(options?)Lister les acheteurs du registre (paginé, filtres q / is_individual)
get(id)Obtenir un acheteur par UUID
create(data)Enregistrer un nouvel acheteur (B2B SIRET ou B2C particulier)
update(id, data)Mettre à jour les données d'un acheteur (PATCH)
delete(id)Supprimer un acheteur (soft delete)
resolveVatContext(data)Pré-résoudre le contexte TVA d'une ligne (taux, catégorie, code EN16931, exemption_reason, justification CGI)
buyers.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Create a B2B buyer (French company — SIRET required)
const buyer = await scell.buyers.create({
name: 'GN IMMO',
is_individual: false,
siret: '49438068600076',
vat_number: 'FR42494380686',
email: 'contact@gnimmo.com',
country: 'FR',
billing_address: {
line1: '453 Route Nationale 7',
postal_code: '13670',
city: 'Verquières',
country: 'FR',
},
});
// Create a B2C buyer (individual — no SIRET/VAT)
const individual = await scell.buyers.create({
name: 'Marie Dupont',
is_individual: true,
email: 'marie.dupont@gmail.com',
country: 'FR',
billing_address: {
line1: '12 Rue des Lilas',
postal_code: '75011',
city: 'Paris',
country: 'FR',
},
});
// Use buyer_id when creating invoices (auto-snapshot)
const invoice = await scell.invoices.create({
buyer_id: buyer.id,
due_date: '2026-07-15',
lines: [
{ description: 'Consulting', quantity: 1, unit_price: 2500, tax_rate: 20 },
],
});

Produits (catalogue)

5 méthodes

Catalogue de produits et services réutilisables, scopé par (tenant_id, sub_tenant_id). Référencer un produit via product_id dans une ligne de facture ou devis pour pré-remplir automatiquement tous les champs (description, unit_price_ht, tax_rate, unit, revenue_category). Utiliser save_to_catalog: true sur une ligne pour ajouter un article au catalogue en même temps que la facture (upsert atomique, dédupliqué par SKU puis par nom).

MéthodeDescription
list(options?)Lister les produits du catalogue (paginé, filtres q / revenue_category / is_active)
get(id)Obtenir un produit par UUID
create(data)Créer un produit dans le catalogue (champs Factur-X : revenue_category, unit, unit_price_ht)
update(id, data)Mettre à jour un produit (PATCH)
delete(id)Désactiver un produit (is_active = false, soft delete)
products-create.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Create a service product
const service = await scell.products.create({
name: 'Consulting journalier',
description: 'Accompagnement technique sur site',
revenue_category: 'service',
unit: 'C62',
unit_price_ht: 1200,
default_tax_rate: 20,
sku: 'CONS-JOUR',
is_active: true,
});
// Create a goods product
const goods = await scell.products.create({
name: 'Licence logicielle annuelle',
revenue_category: 'goods',
unit: 'C62',
unit_price_ht: 499,
default_tax_rate: 20,
default_discount_rate: 10,
sku: 'LIC-ANNUAL',
});
// Use product_id when creating a quote line (auto-fill + soft link)
const quote = await scell.quotes.create({
buyer_id: 'buyer_uuid',
lines: [
{
product_id: service.id, // pre-fills all line fields from the product
quantity: 3,
},
],
});
// Save an ad-hoc line back to the catalogue
const invoice = await scell.invoices.create({
buyer_id: 'buyer_uuid',
lines: [
{
description: 'Formation React avancée',
quantity: 1,
unit_price_ht: 800,
tax_rate: 20,
save_to_catalog: true, // atomic backend upsert by name/SKU
product_category_id: 'cat_uuid', // optional: assign to a category
},
],
});

Catégories produits

5 méthodes

Organiser le catalogue avec des catégories colorées et ordonnées. Chaque catégorie expose un compteur products_count. Associer un produit à une catégorie via product_category_id dans les endpoints produits, ou directement depuis les lignes de facture via save_to_catalog: true + product_category_id.

MéthodeDescription
list(options?)Lister les catégories produits (paginé, filtre q)
get(id)Obtenir une catégorie par UUID
create(data)Créer une catégorie (name, color #RRGGBB, position)
update(id, data)Mettre à jour une catégorie (PATCH)
delete(id)Supprimer une catégorie (sans produits liés)
products-list.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// List all active products
const { data: products } = await scell.products.list({ is_active: true });
// Filter by revenue category
const { data: services } = await scell.products.list({
revenue_category: 'service',
per_page: 50,
});
// Full-text search across name, description, and SKU
const { data: results } = await scell.products.list({ q: 'consulting' });
// Get a single product
const product = await scell.products.get('product_uuid');
// List product categories
const { data: categories } = await scell.productCategories.list();
// Create a category and assign products to it
const category = await scell.productCategories.create({
name: 'Prestations de service',
color: '#0066FF',
position: 1,
});
// Assign product to category
await scell.products.update(product.id, {
product_category_id: category.id,
});

TVA automatique (vat-context)

1 méthode

POST /api/v1/tenant/buyers/vat-context pré-résout le contexte TVA d'une ligne de facture avant émission : taux applicable, catégorie EN16931 (S, AE, O, Z, E), exemption_reason et justification CGI (art. 259, 259-1, 259-2, 259 A). Couvre FR→FR, FR→UE B2B (autoliquidation), FR→UE B2C, FR→hors UE (export) et l'override art. 259 A via place_of_supply (services immobiliers, restauration, événementiel). Si line.tax_rate est fourni, retourne aussi des warnings de cohérence (mismatch, catégorie incohérente, etc.).

Catégorie TVATaux par défaut FREN16931Usage
STANDARD20 %STaux normal (art. 278 CGI)
INTERMEDIATE10 %STaux intermédiaire (restauration, transport)
REDUCED5,5 %STaux réduit (alimentation, livres)
SUPER_REDUCED2,1 %STaux super-réduit (médicaments)
ZERO_RATED0 %ZTaux zéro (exports hors UE)
EXEMPTEOpération exonérée (médical, financier)
REVERSE_CHARGE0 %AEAutoliquidation services intra-UE B2B (art. 283-2 CGI)
OUT_OF_SCOPE0 %OServices preneur hors UE (art. 259-1 CGI)
INTRACOM_GOODS0 %KLivraison intracommunautaire de biens (art. 262 ter, I CGI)
EXPORT0 %GExportation de biens hors UE (art. 262, I CGI)
FRANCHISE_BASE0 %EFranchise en base, auto-entrepreneur (art. 293 B CGI)
EXEMPT_TRAINING0 %EFormation professionnelle continue (art. 261-4-4°a CGI)
Règles de résolution (cascade)
  • R1FR→FR (entreprise ou particulier) : TVA française selon la catégorie (art. 278+ CGI).
  • R2FR→UE B2B avec vat_number_valid : services → REVERSE_CHARGE (AE, art. 283-2) ; biens (supply_type="goods") → INTRACOM_GOODS (K, art. 262 ter, I).
  • R3FR→UE entreprise SANS vat_number ou particulier : TVA française (art. 259-2 lieu prestataire).
  • R4FR→hors UE : services → OUT_OF_SCOPE (O, art. 259-1) ; biens (supply_type="goods") → EXPORT (G, art. 262, I).
  • R0Vendeur en franchise en base (auto-entrepreneur non assujetti) : FRANCHISE_BASE (E, art. 293 B) — prime sur tout.
  • R6Override 259 A : si place_of_supply ≠ pays buyer, applique la TVA du pays lieu de prestation (immobilier, restauration, événementiel en France).

Articles CGI : art. 259, art. 259-1, art. 259-2, art. 259 A.

Émission : champs de pilotage TVA par ligne

À l'émission (invoices.create), le serveur RE-RÉSOUT la TVA de chaque ligne. Quatre champs top-level (pas dans metadata) pilotent la résolution :

ChampRôle
vat_categoryCatégorie explicite (sinon résolue serveur).
supply_type`goods` | `services` — discrimine K/G (biens) vs AE/O (services).
place_of_supplyPays ISO-2 du lieu de prestation (override art. 259 A).
vat_override_reasonAssume un taux divergent (évite le 409, trace fiscale).

Les builders posent ces champs au bon endroit : JS createInvoiceLine({ category }).supplyType('goods').overrideReason('…') · PHP (new InvoiceLineBuilder)->withCategory(VatCategory::IntracomGoods)->withSupplyType('goods')->withOverrideReason('…'). L'enum porte 12 cas (VatCategory) et une méthode justification($lang) bilingue (mention légale exacte).

409 VAT_CORRECTION_REQUIRED — si un taux est incohérent avec le contexte (VIES) sans vat_override_reason, la facture N'EST PAS persistée. Le SDK lève une exception typée : JS VatCorrectionRequiredError (.corrections / .hint), PHP VatCorrectionRequiredException (getCorrections() / getHint()). Chaque correction porte line_index, provided_rate, suggested_rate, suggested_category, en16931_code, mention, rule. Issue : re-soumettre avec les valeurs suggérées, ou poser vat_override_reason.
vat-context.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// ---------------------------------------------------------------------------
// Mode 1 — Acheteur déjà enregistré dans le registre (buyer_id)
// ---------------------------------------------------------------------------
// Pré-résout le contexte TVA pour une ligne STANDARD (20 % par défaut FR→FR).
// Le sub-tenant (s'il existe) est résolu côté serveur depuis la clé d'API.
const fr = await scell.buyers.resolveVatContext({
buyer_id: '019cb416-b6db-730c-b3a5-f8b7a4512eb1',
line: {
category: 'STANDARD',
place_of_supply: 'FR',
},
});
console.log(fr.resolution);
// {
// rate: 20,
// category: 'STANDARD',
// en16931_code: 'S',
// exemption_reason: null,
// justification: 'TVA française standard (art. 278 CGI)',
// is_auto_resolved: true,
// rule: 'R1_fr_domestic'
// }
// ---------------------------------------------------------------------------
// Mode 2 — Acheteur inline (B2B UE avec numéro de TVA vérifié VIES)
// ---------------------------------------------------------------------------
// Autoliquidation (reverse charge) déclenchée automatiquement par la règle R2.
const ue = await scell.buyers.resolveVatContext({
buyer: {
country: 'DE',
is_individual: false,
vat_number: 'DE123456789',
vat_number_valid: true, // typiquement validé via VIES en amont
},
line: { category: 'STANDARD' },
});
console.log(ue.resolution);
// {
// rate: 0,
// category: 'REVERSE_CHARGE',
// en16931_code: 'AE',
// exemption_reason: 'reverse_charge',
// justification: 'TVA non applicable, art. 259-1 du CGI (autoliquidation)',
// is_auto_resolved: true,
// rule: 'R2_eu_b2b_vat_valid'
// }
// ---------------------------------------------------------------------------
// Mode 3 — B2C UE sans numéro de TVA (TVA française restante)
// ---------------------------------------------------------------------------
// Règle R3 : pas de numéro de TVA valide → TVA du prestataire (art. 259-2 CGI).
const b2cUe = await scell.buyers.resolveVatContext({
buyer: {
country: 'IT',
is_individual: true, // particulier italien
},
line: { category: 'STANDARD' },
});
console.log(b2cUe.resolution.rate); // 20 (TVA française)
console.log(b2cUe.resolution.rule); // 'R3_eu_b2c_no_vat'
// ---------------------------------------------------------------------------
// Mode 4 — Override art. 259 A CGI via place_of_supply
// ---------------------------------------------------------------------------
// Service immobilier rendu en France à un client UE → TVA française même
// si le buyer a un numéro de TVA valide (lieu de prestation = France).
const immo = await scell.buyers.resolveVatContext({
buyer: {
country: 'DE',
is_individual: false,
vat_number: 'DE123456789',
vat_number_valid: true,
},
line: {
category: 'STANDARD',
place_of_supply: 'FR', // override 259 A : lieu du bien immobilier
service_nature: 'real_estate_service',
},
});
console.log(immo.resolution.rate); // 20 (TVA française appliquée)
console.log(immo.resolution.rule); // 'R6_place_of_supply_override'
// ---------------------------------------------------------------------------
// Warnings — incohérence détectée si line.tax_rate est fourni
// ---------------------------------------------------------------------------
const check = await scell.buyers.resolveVatContext({
buyer_id: '019cb416-b6db-730c-b3a5-f8b7a4512eb1',
line: {
category: 'STANDARD',
tax_rate: 10, // valeur saisie par l'utilisateur, à valider
},
});
if (check.warnings.length > 0) {
console.warn('Incohérence TVA détectée :', check.warnings);
// [{ code: 'VAT_RATE_MISMATCH', expected: 20, actual: 10,
// message: 'Le taux saisi diffère du taux résolu (R1_fr_domestic).' }]
}
// ---------------------------------------------------------------------------
// Mode 5 — Livraison intracommunautaire de BIENS (supply_type='goods')
// ---------------------------------------------------------------------------
// supply_type discrimine l'exonération : biens → INTRACOM_GOODS (K, art. 262 ter)
// au lieu de REVERSE_CHARGE (AE, services). À TOUJOURS renseigner pour une vente
// transfrontalière de biens physiques.
const biens = await scell.buyers.resolveVatContext({
buyer: { country: 'DE', is_individual: false, vat_number: 'DE123456789', vat_number_valid: true },
line: { category: 'INTRACOM_GOODS', supply_type: 'goods' },
});
console.log(biens.resolution.en16931_code); // 'K'
console.log(biens.resolution.exemption_reason); // 'intracom_goods'
// ---------------------------------------------------------------------------
// Émission : résolution AUTORITAIRE serveur + 409 VAT_CORRECTION_REQUIRED
// ---------------------------------------------------------------------------
// À la création, le serveur RE-RÉSOUT la TVA de chaque ligne. Si le taux fourni
// est incohérent (ex : 20 % sur une vente intra-UE B2B au lieu de l'autoliquidation)
// ET qu'aucune raison d'override n'est donnée, l'API renvoie un 409 et NE persiste
// PAS la facture. Le builder `createInvoiceLine` émet les champs au bon endroit.
import { createInvoiceLine, VatCorrectionRequiredError } from '@scell/sdk';
try {
await scell.invoices.create({
direction: 'outgoing',
output_format: 'facturx',
issue_date: '2026-06-04',
currency: 'EUR',
// ... seller / buyer (B2B UE avec numéro TVA valide) ...
lines: [
createInvoiceLine({ category: 'REVERSE_CHARGE' })
.description('Prestation de conseil')
.unitPrice(1000)
.supplyType('services') // → AE, art. 283-2 (mention auto sur la facture)
.build(),
],
} as Parameters<typeof scell.invoices.create>[0]);
} catch (e) {
if (e instanceof VatCorrectionRequiredError) {
for (const c of e.corrections) {
console.warn(
`Ligne ${c.line_index} : ${c.provided_rate}% → ${c.suggested_rate}% ` +
`(${c.suggested_category}) — ${c.mention ?? ''}`
);
}
// → Accepter les taux suggérés, OU ajouter .overrideReason('...') sur la ligne.
}
}

Devis

15 méthodes

Cycle complet : création, envoi par email avec lien public signable, signature canvas, conversion en factures d'acompte (type 386) et de solde (type 380 + BG-22). Numérotation DEV-YYYY-NNNN indépendante de la chaîne ISCA. Disponible sur ScellApiClient.

MéthodeDescription
list(options?)Lister les devis avec pagination et filtres
get(id)Obtenir un devis par UUID
create(data)Créer un devis (numérotation DEV-YYYY-NNNN auto)
update(id, data)Mettre à jour un devis en brouillon
delete(id)Supprimer un devis en brouillon
send(id)Envoyer le devis par email au client (lien public signable)
cancel(id)Annuler un devis envoyé
duplicate(id)Dupliquer un devis existant (nouveau brouillon)
convertToDeposit(id, data)Convertir en facture d'acompte (type 386, TVA immédiate)
convertToBalance(id)Convertir en facture de solde (type 380 + BG-22 auto)
auditLog(id)Piste d'audit append-only (hash SHA-256)
regeneratePublicLink(id)Régénérer le lien public signable (token 90j)
revokePublicLink(id)Révoquer le lien public
pdf(id)Télécharger le devis en PDF
preview(data)Aperçu PDF non persisté depuis des données brutes (POST /quotes/preview) — pas d'UUID requis
paymentSchedule.*Échéancier de paiement câblé sur le devis (get / set / patch / delete / summary / convertLine / presets) — voir section dédiée
quotes.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// ── Create a quote with signature ───────────────────────────────────
const { data: quote } = await scell.quotes.create({
issue_date: '2026-06-01',
expiration_date: '2026-09-01', // optional, defaults to +90 days
currency: 'EUR',
title: 'Proposition commerciale — Audit digital',
description: 'Prestation complète d\'audit et accompagnement.',
// Buyer (flat fields or buyer_id)
buyer_name: 'GN IMMO',
buyer_siret: '49438068600076',
buyer_country: 'FR',
buyer_email: 'contact@gnimmo.com',
buyer_address: {
line1: '453 Route Nationale 7',
postal_code: '13670',
city: 'Verquières',
country: 'FR',
},
// Signature options
signature_required: true,
// Callback URL — buyer is redirected here after accept/refuse
callback_url: 'https://myapp.com/quotes/callback',
// Lines
lines: [
{
description: 'Audit transformation digitale',
detail: 'Analyse SI existant + recommandations (5 jours)',
quantity: 5,
unit: 'jour',
unit_price_ht: 800.00,
tax_rate: 20.0,
},
{
description: 'Accompagnement mensuel',
quantity: 3,
unit: 'mois',
unit_price_ht: 1200.00,
tax_rate: 20.0,
},
],
});
// quote.quote_number === 'DEV-2026-000012'
// quote.status === 'draft'
// quote.public_url === 'https://scell.io/q/{token}'
// ── Send by email (generates public signable link) ──────────────────
await scell.quotes.send(quote.id);
// ── Duplicate a quote ───────────────────────────────────────────────
const { data: copy } = await scell.quotes.duplicate(quote.id);
// ── Convert accepted quote to deposit invoice (type 386) ────────────
const { data: deposit } = await scell.quotes.convertToDeposit(quote.id, {
amount: 2000.00, // or use percent: 30
});
// deposit.invoice_type === 'deposit'
// deposit.invoice_number === 'FAC-2026-000043'
// ── Convert to balance invoice (type 380 + BG-22 auto-deduction) ────
const { data: balance } = await scell.quotes.convertToBalance(quote.id);

Échéancier de paiement

7 méthodes

Sous-resource d'un devis : gérez les lignes d'échéancier (acomptes planifiés). Chaque ligne peut être convertie individuellement en facture d'acompte. Accès via client.quotes.paymentSchedule (JS) ou $client->quotes()->paymentSchedule() (PHP).

MéthodeDescription
get(quoteId)Lister les lignes d'échéancier du devis
set(quoteId, lines)Remplacer tout l'échéancier (atomique)
patch(quoteId, lines)Mettre à jour partiellement (ajouter/modifier des lignes)
delete(quoteId)Supprimer toutes les lignes (bloqué si facturées)
summary(quoteId)Résumé agrégé : total, facturé, restant, lignes avec statut
convertLine(quoteId, lineId, data)Facturer une ligne spécifique (acompte depuis l'échéancier)
presets()Lister les modèles d'échéancier prédéfinis

Onboarding & Widget

6 méthodes

Deux flows distincts : OAuth Authorization Code server-to-server (créer une session, récupérer l'URL d'autorisation SuperPDP, échanger le code) ET widget public avec clé pk_* (lookup Sirene, création SubTenant). Le widget v3 inverse le flow Scell-first puis SuperPDP — voir Swagger UI.

MéthodeDescription
createSession(data)Créer une session d'onboarding partenaire (mode server-to-server)
getSession(sessionId)Récupérer le statut courant d'une session
getSuperPDPAuthorizeUrl(sessionId)Obtenir l'URL OAuth SuperPDP avec PKCE + state CSRF
superpdpCallback(sessionId, code, state)Échanger un authorization code SuperPDP contre des credentials tenant
lookupSirene(siret)Lookup Sirene par SIRET (auth pk_*) — retourne CompanyData ou manual_entry
createSubTenant(data)Créer un sub_tenant depuis les données du widget (auth pk_*)

Tarification

3 méthodes

Cascade fonctionnelle : tarifs globaux Scell.io → override par tenant (admin uniquement). Le snapshot est figé dans tenant_invoices.metadata['pricing_snapshot'] au moment de la génération de la facture.

MéthodeDescription
getPublic()Obtenir les tarifs publics (sans auth) — affichage marketing
get()Obtenir les tarifs effectifs du tenant (cascade : global → override tenant)
getForTenant()Variant tenant-scopé — alias de get() côté ScellTenantClient

Sous-tenants

12 méthodes

Gérez les sous-tenants pour les plateformes partenaires multi-tenant. Chaque sous-tenant obtient sa propre clé tenant (tk_live_*) et peut être identifié par votre système d'ID externe. Disponible sur ScellApiClient et ScellTenantClient.

MéthodeDescription
list(options?)Lister tous les sous-tenants (paginé)
get(id)Obtenir les détails d'un sous-tenant par ID
create(data)Créer un sous-tenant avec les données de l'entreprise
update(id, data)Mettre à jour les informations d'un sous-tenant
delete(id, options?)Supprimer un sous-tenant. `options.cascade=true` pour cascade Companies. Retourne 422 SUB_TENANT_HAS_FISCAL_ENTRIES si factures émises (compliance ISCA)
findByExternalId(externalId)Rechercher un sous-tenant par votre ID externe
statsOverview(id)Obtenir les statistiques d'utilisation d'un sous-tenant
getThresholds(id)Jauges de seuils micro-entrepreneur (franchise TVA + plafond du régime micro) : CA HT par catégorie, %, palier atteint et projection de franchissement. Lecture seule. Retourne `{ data, disclaimer }`.
updateFiscalStatus(id, data)Mettre à jour le statut fiscal (fiscal_regime, vat_status, activity_type, activity_start_date). Passer `vat_status: "liable"` (n° TVA requis) bascule la facturation vers la TVA. La démarche URSSAF/INPI reste à charge de l'AE.
getSuperPDPStatus(id)Statut SuperPDP courant + recommended_action i18n (cached)
refreshSuperPDPStatus(id)Forcer un poll frais du statut SuperPDP. 422 MISSING_ACCESS_TOKEN inclut authorize_url
superpdpAuthorize(id)Générer une URL OAuth SuperPDP (lancer/relancer le tunnel). Retourne `{ authorize_url, state }`
getResumeUrl(id)Régénérer une URL signée 7j pour reprendre le tunnel d'onboarding
superpdpDisconnect(id)Révoquer la connexion SuperPDP du sous-tenant et remettre `onboarding_status` à `pending_superpdp`. Les factures déjà émises restent immuables (ISCA) ; les futures B2B repassent en mode papier jusqu'à reconnexion (depuis v3.1.0)
superpdpReconnect(id)Déconnecter puis générer une nouvelle URL OAuth SuperPDP en un seul appel. Retourne `{ authorize_url, state }` (depuis v3.1.0)
superpdpWidgetToken(id, { reset })Émettre un jeton signé 24h pour reprendre l'onboarding dans le widget en mode SuperPDP seul (`<scell-onboarding mode="superpdp" resume-token="…">`). Scopé au sous-tenant (anti-IDOR) (depuis v3.1.0)
sub-tenants.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// Create a sub-tenant
const tenant = await scell.subTenants.create({
name: 'Partner Corp',
external_id: 'partner-001',
email: 'admin@partner-corp.com',
company: {
name: 'Partner Corp',
siren: '111222333',
address: {
street: '20 Boulevard Haussmann',
city: 'Paris',
postal_code: '75009',
country: 'FR',
},
},
});
console.log(tenant.id);
console.log(tenant.tenant_key); // sk_live_... (cle secrete sk_*, pas de format tk_*)
// List all sub-tenants
const list = await scell.subTenants.list();
// Get a specific sub-tenant
const detail = await scell.subTenants.get(tenant.id);
// Find by external ID
const found = await scell.subTenants.findByExternalId('partner-001');
// Update a sub-tenant
await scell.subTenants.update(tenant.id, { name: 'Partner Corp (Updated)' });
// Get sub-tenant stats
const stats = await scell.subTenants.statsOverview(tenant.id);
// Delete a sub-tenant
await scell.subTenants.delete(tenant.id);
// --- Supervision SuperPDP ---
// Path: /api/v1/tenant/sub-tenants/{id}/... (middleware tenant.key).
// Statut OAuth2 + KYB courant (cache 5 min)
const status = await scell.subTenants.getSuperPdpStatus(tenant.id);
// Forcer un poll cote SuperPDP (rate-limit 1/min)
// 422 MISSING_ACCESS_TOKEN -> e.authorize_url a ouvrir dans le navigateur
try {
await scell.subTenants.refreshSuperPdpStatus(tenant.id);
} catch (e) {
if (e.code === 'MISSING_ACCESS_TOKEN') {
window.open(e.authorize_url, '_blank', 'noopener');
}
}
// Generer une URL OAuth fresh (sans passer par refresh)
const { authorize_url, state } = await scell.subTenants.superpdpAuthorize(tenant.id);
// Regenerer une URL signee (7j) pour reprendre le tunnel onboarding
const { resume_url } = await scell.subTenants.getResumeUrl(tenant.id);
// --- Delete avec politique ISCA ---
try {
await scell.subTenants.delete(tenant.id);
} catch (e) {
if (e.code === 'SUB_TENANT_HAS_COMPANIES') {
// Demander confirmation a l'utilisateur, puis cascade
await scell.subTenants.delete(tenant.id, { cascade: true });
} else if (e.code === 'SUB_TENANT_HAS_FISCAL_ENTRIES') {
// Factures emises -> impossible de supprimer. Desactiver a la place.
await scell.subTenants.update(tenant.id, { is_active: false });
}
}
// --- Suivi de seuils micro-entrepreneur (auto-entrepreneur FR) ---
// Jauges de seuils (franchise TVA base/majoree + plafond du regime micro).
// Regles datees (loi 2025-1044). Lecture seule, informational.
const { data, disclaimer } = await scell.subTenants.getThresholds(tenant.id);
for (const g of data.gauges) {
// g.category: 'goods' | 'service' | 'accommodation'
// g.kind: 'vat_franchise_base' | 'vat_franchise_majored' | 'micro_ceiling'
// g.level: null | 'warning_80' | 'warning_90' | 'base_exceeded' | 'majored_exceeded' | 'micro_ceiling_exceeded'
console.log(`${g.category}/${g.kind}: ${g.percent}% (${g.level ?? 'ok'})`);
if (g.actionable) {
console.warn(`Seuil franchi — projection: ${g.projected_crossing_date}`);
}
}
console.info(disclaimer); // toujours afficher le disclaimer (info non contractuelle)
// Declarer le statut fiscal. vat_status='liable' bascule la facturation vers la
// TVA (factures suivantes avec TVA, retrait de la mention art. 293 B).
// vat_number requis (422 sinon). La demarche URSSAF/INPI reste a charge de l'AE.
const res = await scell.subTenants.updateFiscalStatus(tenant.id, {
vat_status: 'liable',
vat_number: 'FR12345678901',
});
console.log(res.message);
// --- Clotures par sous-tenant + telechargement CSV ---
const { data: closings } = await scell.fiscal.closings({
closing_type: 'monthly', // 'daily' | 'monthly' | 'annual'
sub_tenant_id: tenant.id,
});
const csv = await scell.fiscal.downloadClosing(closings[0].id); // ArrayBuffer (CSV)

Statut fiscal — payload & options (PATCH /sub-tenants/{id}/fiscal-status)

Tous les champs sont optionnels (mise à jour partielle). Met à jour l'état fiscal déclaré dans Scell — aucune démarche administrative (URSSAF / INPI) n'est effectuée.

ChampTypeOptionsDescription
fiscal_regimestringmicro | reelRégime fiscal déclaré. Seul `micro` est suivi pour les plafonds.
vat_statusstringfranchise | liable`liable` bascule la facturation vers la TVA (n° TVA requis) et retire la mention 293 B.
activity_typestringgoods | service | accommodation | mixedType d'activité. Défaut de classification des lignes + jauges suivies. `mixed` suit les deux barèmes.
activity_start_datestring (date)YYYY-MM-DDDate de début d'activité. Active le prorata temporis du seuil la 1re année.
vat_numberstringRequis pour passer à `vat_status: "liable"`.
fiscal-status.request.json
json
// PATCH /api/v1/sub-tenants/{id}/fiscal-status
{
"fiscal_regime": "micro",
"vat_status": "liable",
"activity_type": "service",
"activity_start_date": "2026-01-15",
"vat_number": "FR12345678901"
}

Suivi de seuils — schéma de réponse (GET /sub-tenants/{id}/thresholds)

Une jauge par couple (catégorie × type de seuil). level = palier le plus haut atteint ; projected_crossing_date = projection de franchissement au rythme courant.

thresholds.response.json
json
// GET /api/v1/sub-tenants/{id}/thresholds
{
"data": {
"sub_tenant_id": "st_…",
"fiscal_year": 2026,
"generated_at": "2026-06-04T10:00:00+00:00",
"gauges": [
{
"category": "service", // goods | service | accommodation
"kind": "vat_franchise_base", // vat_franchise_base | vat_franchise_majored | micro_ceiling
"revenue": 40000.00, // CA HT net (factures - avoirs)
"threshold": 37500.00, // seuil applicable (résolu par date, prorata 1re année)
"percent": 106.7,
"level": "base_exceeded", // null | warning_80 | warning_90 | base_exceeded | majored_exceeded | micro_ceiling_exceeded
"actionable": true,
"projected_crossing_date": null // sinon "YYYY-MM-DD" au rythme courant
}
],
"new_alerts": []
},
"disclaimer": "Information non contractuelle, ne constitue pas un conseil fiscal ou comptable. …"
}

Échéancier de paiement

v2.13.0

Attachez un échéancier de paiement contractualisé à un devis. Lignes par % ou montant TTC, par date OU jalon textuel (« Livraison MVP », « Mise en prod »). Auto-génération de factures d'acompte à la date prévue. Tracker du solde restant à facturer. Échéancier verrouillé dès la signature (immutable post-acceptation). Accessible via $client->quotes->paymentSchedule (PHP) ou client.quotes.paymentSchedule (JS).

Méthodes: set, list/get, patch, delete, summary, convertLine, presets

Règles métier: somme des lignes ≤ total TTC ; chaque jalon indépendant ; immutable post-signature ; 1 conversion par ligne max.

payment-schedule.ts
typescript
// TypeScript — @scell/sdk v2.13.0
import { ScellClient } from '@scell/sdk';
const client = new ScellClient({ apiKey: 'sk_live_...' });
// Créer / remplacer l'échéancier
await client.quotes.paymentSchedule.set('quote-uuid', [
{ amount_type: 'percent', amount_value: 30,
milestone_label: 'À la commande',
auto_generate: true, due_date: '2026-06-01' },
{ amount_type: 'percent', amount_value: 70,
milestone_label: 'À la livraison' },
]);
// Tracker du solde restant
const summary = await client.quotes.paymentSchedule.summary('quote-uuid');
// → { schedule, invoiced: { gross_ttc, net_ttc, remaining_ttc, remaining_pct }, next_due, overdue, superpdp_status }
// Convertir une ligne en facture d'acompte
const invoice = await client.quotes.paymentSchedule.convertLine(
'quote-uuid', 'line-uuid',
{ send_email: true }
);
// 4 presets disponibles
const presets = await client.quotes.paymentSchedule.presets();

Envoi facture par email

v2.13.0

Envoyez une facture par email Scell.io générique avec PDF Factur-X en pièce jointe. Cascade de résolution du destinataire : override → buyer.billing_emailbuyer.emailquote.buyer_email. Si la facture est en draft, transition automatique vers validated + soumission SUPER PDP. Accessible via client.invoices.sendByEmail().

send-by-email.ts
typescript
// TypeScript
const result = await client.invoices.sendByEmail('invoice-uuid', {
recipient_email: 'compta@buyer.com', // optionnel
cc: ['manager@buyer.com'],
message: 'Merci pour votre confiance',
});
// → { sent_to, sent_at, message_id, cc }

Branding tenant / sub-tenant

v2.35.0

Personnalisez le branding de vos emails (logo, couleur primaire, footer, signature). Par défaut, Scell.io applique son branding générique. Si TOUS les champs (brand_logo_url, brand_primary_color, brand_email_footer) sont renseignés, vos emails utilisent votre branding. Disponible au niveau tenant master et sub-tenant. Upload de logo via URL pré-signée S3. preview() retourne un aperçu HTML de l'email brandé, avant tout envoi (depuis v2.35.0). Depuis v3.2.0 JS / v3.4.0 PHP : upload direct multipart du logo e-mail via uploadLogoFile() (JS) / uploadLogoTenant() / uploadLogoSubTenant() (PHP) — jpeg/png/webp/svg, max 2 Mo, SVG normalisés ; preview(overrides) accepte des overrides non persistés (brand_primary_color, brand_email_footer, brand_email_signature, brand_logo_url) pour un aperçu live ; nouveaux champs brand_email_enabledfalse, les e-mails repartent sur le branding par défaut du canal) et computed_email_footer (lecture seule, pied de page calculé depuis la société, utilisé quand brand_email_footer est vide).

branding.ts
typescript
// TypeScript
// Tenant master
const branding = await client.branding.tenant.get();
// → { is_complete, missing_fields, brand_logo_url, brand_primary_color, ... }
await client.branding.tenant.update({
brand_logo_url: 'https://cdn.scell.io/.../logo.png',
brand_primary_color: '#1A73E8',
brand_email_footer: 'Société XYZ — SIRET 123456789',
});
// Sub-tenant
await client.branding.subTenants.update('sub-tenant-uuid', {
brand_primary_color: '#10B981',
});
// Upload logo (presigned S3)
const signed = await client.branding.tenant.uploadLogo('image/png');
// Then PUT the file to signed.url, then persist signed.public_url
// Preview — render the branded email as HTML (before sending anything)
const html = await client.branding.tenant.preview();
// e.g. show it in <iframe srcDoc={html} /> for a live preview
const subHtml = await client.branding.subTenants.preview('sub-tenant-uuid');
// Since v3.2.0 — direct multipart upload of the email logo (no presign round-trip)
const updated = await client.branding.tenant.uploadLogoFile(file, 'logo.svg');
// jpeg/png/webp/svg, max 2 MB — SVGs are normalized server-side
await client.branding.subTenants.uploadLogoFile('sub-tenant-uuid', file);
// Since v3.2.0 — live preview with NON-persisted overrides (try before saving)
const draft = await client.branding.tenant.preview({
brand_primary_color: '#0066FF',
brand_email_footer: 'Essai de pied de page',
});
// Since v3.2.0 — toggle branding + computed footer
await client.branding.tenant.update({ brand_email_enabled: false });
// branding.computed_email_footer (read-only): footer computed from the company,
// used at render time when brand_email_footer is empty

Callback URL post-signature

v2.13.1

Fournissez une callback_url à la création du devis. Après acceptation ou refus via le viewer public, le buyer est redirigé vers cette URL avec query string : ?status=signed|refused&quote_id=<UUID>&quote_number=<num>&reason=<txt>. Permet d'intégrer la signature dans votre propre flow métier (page de remerciement, dashboard client, automation). Sans callback_url, le buyer voit la page de confirmation Scell.io par défaut.

Format: URL absolue HTTPS, max 500 caractères

Query string ajoutée: status (signed|refused), quote_id, quote_number, reason (si refus)

callback-url.ts
typescript
// TypeScript — @scell/sdk v2.13.1
import { ScellClient } from '@scell/sdk';
const client = new ScellClient({ apiKey: 'sk_live_...' });
await client.quotes.create({
issue_date: '2026-05-24',
valid_until: '2026-06-24',
buyer_id: 'buyer-uuid',
lines: [{ description: 'Mission', quantity: 1, unit_price_ht: 12000, tax_rate: 20 }],
total_ht: 12000, total_tax: 2400, total_ttc: 14400,
callback_url: 'https://mon-site.com/devis-signe',
});
// Buyer signe -> redirige vers :
// https://mon-site.com/devis-signe?status=signed&quote_id=...&quote_number=DEV-2026-0042
//
// Buyer refuse avec motif "Prix trop élevé" -> :
// https://mon-site.com/devis-signe?status=refused&quote_id=...&quote_number=...&reason=Prix+trop+%C3%A9lev%C3%A9

PaymentSummary enrichi + parité SDKs

v2.14.0

Le payload GET /api/v1/quotes/{id}/payment-summary expose désormais le champ lines: PaymentScheduleLine[] en plus des agrégats (schedule, invoiced, next_due, overdue, superpdp_status). Permet d'afficher le tracker visuel complet — highlight de la prochaine échéance, grisé des passées, rouge des overdue — sans seconde requête. Côté MCP, 11 nouveaux tools sont documentés pour atteindre la parité totale avec le backend.

Nouveaux tools MCP: regenerate_quote_public_link, revoke_quote_public_link, get_quote_pdf, preview_quote_pdf, get/set/patch/delete_quote_payment_schedule, get_quote_payment_summary, convert_schedule_line_to_invoice, list_payment_schedule_presets

summary-lines.ts
typescript
// TypeScript — @scell/sdk v2.14.0
const summary = await client.quotes.paymentSchedule.summary('quote-uuid');
// summary.lines est maintenant peuplé : PaymentScheduleLine[]
summary.lines.forEach((line) => {
const isNext = line.id === summary.next_due?.line_id;
const isOverdue = line.is_overdue;
const isPast = line.status === 'invoiced';
// → render tracker visuel avec highlight
});
// summary.invoiced.remaining_ttc = montant restant à facturer
// summary.invoiced.remaining_pct = % restant

Acomptes standalone (sans devis)

v2.15.0

Créez des factures d'acompte directement via POST /invoices sans passer par un devis. Indiquez le montant total du deal (deposit_total_ht) et une référence libre (deposit_reference_text). Liez les acomptes suivants via deposit_group_id. Quand la somme atteint 100%, le dernier acompte est automatiquement converti en facture de solde (type 380 + déductions BG-22 Factur-X).

standalone-deposit.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// ── 1. First deposit: create a new group ────────────────────────
const deposit1 = await scell.invoices.create({
invoice_type: 'deposit',
deposit_total_ht: 10000, // Total deal = 10 000 € HT
deposit_reference_text: 'Proposition commerciale signée le 15/05/2026',
direction: 'outgoing',
output_format: 'facturx',
issue_date: '2026-05-15',
due_date: '2026-05-30',
total_ht: 3000, // 30% deposit
total_tax: 600,
total_ttc: 3600,
seller_siret: '12345678901234',
seller_name: 'Ma Société',
seller_address: { line1: '1 rue Example', postal_code: '75001', city: 'Paris', country: 'FR' },
buyer_name: 'Client SA',
buyer_siret: '98765432109876',
buyer_address: { line1: '2 avenue Test', postal_code: '69001', city: 'Lyon', country: 'FR' },
lines: [{ description: 'Acompte 30%', quantity: 1, unit_price: 3000, tax_rate: 20, total_ht: 3000, total_tax: 600, total_ttc: 3600 }],
});
// deposit1.deposit_group_id = deposit1.id (self-reference)
// ── 2. Second deposit: join the group ───────────────────────────
const deposit2 = await scell.invoices.create({
invoice_type: 'deposit',
deposit_group_id: deposit1.deposit_group_id, // Link to group
// deposit_total_ht and deposit_reference_text inherited from group leader
direction: 'outgoing',
output_format: 'facturx',
issue_date: '2026-06-15',
total_ht: 7000, // Remaining 70% → auto-converted to balance
total_tax: 1400,
total_ttc: 8400,
seller_siret: '12345678901234',
seller_name: 'Ma Société',
seller_address: { line1: '1 rue Example', postal_code: '75001', city: 'Paris', country: 'FR' },
buyer_name: 'Client SA',
buyer_siret: '98765432109876',
buyer_address: { line1: '2 avenue Test', postal_code: '69001', city: 'Lyon', country: 'FR' },
lines: [{ description: 'Solde 70%', quantity: 1, unit_price: 7000, tax_rate: 20, total_ht: 7000, total_tax: 1400, total_ttc: 8400 }],
});
// deposit2.invoice_type === 'balance' (auto-converted: sum = 100%)
// deposit2.parent_invoice_ids === [deposit1.id] (BG-22 deductions)
// ── 3. Check group progress ─────────────────────────────────────
const invoice = await scell.invoices.get(deposit1.id);
console.log(invoice.deposit_group_progress);
// { deposit_total_ht: 10000, sum_deposits_ht: 3000, remaining_ht: 7000,
// progress_percent: 30, has_balance: true, invoices_count: 2 }

Factures récurrentes

10 méthodes

Automatisez l'émission de factures sur une cadence (abonnements, loyers, maintenance). Un profil récurrent est un template éditable : à chaque échéance, Scell.io fige l'état COURANT du profil dans une vraie facture (chaîne ISCA par facture émise). En mode auto_send, la facture est soumise au PDP puis envoyée par email au buyer avec le PDF Factur-X ; en mode draft, un brouillon est créé pour relecture. Notifications bilatérales + rappel J-N. Un cycle en échec n'est jamais sauté silencieusement (occurrence failed). Disponible via client.recurringInvoices.* (JS) ou $client->recurringInvoices()->* (PHP).

MéthodeDescription
list(options?)Lister les profils récurrents (filtres : status, sub_tenant_id, per_page max 100)
get(id)Obtenir un profil récurrent par UUID
create(data)Créer un profil récurrent (template éditable). Chaque émission fige l'état courant dans une vraie facture (ISCA).
update(id, data)Mettre à jour le template / la cadence. N'affecte que les émissions FUTURES.
delete(id)Supprimer un profil récurrent (les factures déjà émises restent inchangées)
occurrences(id)Historique des occurrences (pending | emitted | failed | skipped) + invoice_id émis
pause(id)Mettre en pause (stoppe les émissions futures, conserve la planification)
activate(id)Réactiver un profil en pause
cancel(id)Annuler (terminal — plus aucune émission, profil conservé pour l'audit)
runNow(id)Émettre immédiatement la prochaine occurrence, hors cadence (202 Accepted, async)

Énumérations

ChampValeurs
recurrence.interval_unitday | week | month | year
end_modenever | on_date | after_occurrences
emission_modedraft | auto_send (défaut auto_send)
statusactive | paused | completed | cancelled
occurrence statuspending | emitted | failed | skipped

Schéma de création (POST /recurring-invoices)

recurring-invoice.create.json
json
{
"title": "Abonnement SaaS — Plan Pro", // requis
// Émetteur : sans sub_tenant_id => tenant master ; sinon le sous-tenant
"sub_tenant_id": "uuid", // optionnel
// Acheteur : buyer_id (registre) OU les champs buyer_* à plat
"buyer_id": "uuid", // optionnel (sinon buyer_*)
"buyer_name": "GN IMMO",
"buyer_country": "FR",
"buyer_is_individual": false, // true => B2C (siret/tva optionnels)
"buyer_siret": "49438068600076",
"buyer_vat_number": "FR42494380686",
"buyer_email": "compta@gnimmo.com",
"buyer_address": { "line1": "…", "postal_code": "…", "city": "…", "country": "FR" },
"buyer_shipping_address": { "name": "…", "line1": "…", "postal_code": "…", "city": "…", "country": "FR" },
"currency": "EUR", // optionnel, défaut "EUR"
"output_format": "facturx", // facturx | ubl | cii
"payment_terms": "Paiement à 30 jours.", // optionnel
// Lignes (requis) — même forme qu'une ligne de facture
"lines": [
{
"description": "Abonnement mensuel Plan Pro",
"quantity": 1,
"unit_price": 49.00,
"vat_rate": 20,
"unit": "mois", // optionnel
"discount": 0, // % remise sur la ligne, optionnel
"category": "subscription" // regroupement libre, optionnel
}
],
// Cadence (requis)
"recurrence": {
"interval_unit": "month", // day | week | month | year
"interval_count": 1, // tous les N (défaut 1)
"day_of_month": 1, // 1..31, clampé à la longueur du mois (31 => 28/29/30)
"day_of_week": 1 // 1..7 ISO (lun..dim) — uniquement si interval_unit "week"
},
"start_date": "2026-07-01", // requis (date ISO) — 1re émission
// Condition d'arrêt
"end_mode": "after_occurrences", // never | on_date | after_occurrences
"end_date": "2027-06-30", // requis si end_mode = "on_date"
"max_occurrences": 12, // requis si end_mode = "after_occurrences"
"emission_mode": "auto_send", // draft | auto_send (défaut auto_send)
"notify_before_days": 3, // 0..30 — rappel J-N avant chaque émission
"metadata": { "plan": "pro" } // optionnel
}

Créer un profil

recurring-invoice-create.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
// ── Create a recurring invoice profile (an editable template) ───────
// Each emission snapshots the CURRENT state of this profile into a real
// invoice (ISCA chain per emitted invoice). Editing the profile only
// affects FUTURE emissions, never invoices already issued.
const { data: profile } = await scell.recurringInvoices.create({
title: 'Abonnement SaaS — Plan Pro',
// Buyer: use buyer_id (registry) OR the flat buyer_* fields below.
buyer_id: 'b1f2c3d4-5e6f-7081-92a3-b4c5d6e7f809',
// buyer_name: 'GN IMMO',
// buyer_country: 'FR',
// buyer_is_individual: false,
// buyer_siret: '49438068600076',
// buyer_vat_number: 'FR42494380686',
// buyer_email: 'compta@gnimmo.com',
// buyer_address: { line1: '453 Route Nationale 7', postal_code: '13670', city: 'Verquières', country: 'FR' },
// buyer_shipping_address: { name: 'Entrepôt Lyon', line1: '12 Rue du Dôme', postal_code: '69003', city: 'Lyon', country: 'FR' },
currency: 'EUR', // optional, defaults to 'EUR'
output_format: 'facturx', // 'facturx' | 'ubl' | 'cii'
payment_terms: 'Paiement à 30 jours.',
// Lines — same shape as a standard invoice line
lines: [
{
description: 'Abonnement mensuel Plan Pro',
quantity: 1,
unit_price: 49.0,
vat_rate: 20,
unit: 'mois',
},
{
description: 'Utilisateurs additionnels',
quantity: 5,
unit_price: 9.0,
vat_rate: 20,
discount: 10, // % discount on this line (optional)
category: 'subscription', // free-text grouping (optional)
},
],
// Recurrence cadence
recurrence: {
interval_unit: 'month', // 'day' | 'week' | 'month' | 'year'
interval_count: 1, // every N units (default 1)
day_of_month: 1, // 1..31 — clamped to month length (e.g. 31 → 28/29/30)
// day_of_week: 1, // 1..7 ISO (Mon..Sun) — only for interval_unit 'week'
},
start_date: '2026-07-01', // first emission (ISO date)
// End condition
end_mode: 'after_occurrences', // 'never' | 'on_date' | 'after_occurrences'
max_occurrences: 12, // required when end_mode = 'after_occurrences'
// end_date: '2027-06-30', // required when end_mode = 'on_date'
emission_mode: 'auto_send', // 'draft' | 'auto_send' (default 'auto_send')
notify_before_days: 3, // 0..30 — J-N reminder before each emission
metadata: { plan: 'pro', crm_id: 'sub_9981' },
});
// profile.status === 'active'
// profile.next_occurrence_at === '2026-07-01'
console.log(profile.id, profile.next_occurrence_at);

Piloter : pause / activer / annuler / émettre + historique

recurring-invoice-manage.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
const profileId = 'r1e2c3u4-5r6r-7081-92a3-b4c5d6e7f809';
// ── List recurring invoice profiles ─────────────────────────────────
const { data: profiles } = await scell.recurringInvoices.list({
status: 'active', // 'active' | 'paused' | 'completed' | 'cancelled'
// sub_tenant_id: '…', // scope to one sub-tenant (anti-IDOR: 404 if not yours)
per_page: 25, // default 25, max 100
});
// ── Get one profile + its occurrence history ────────────────────────
const { data: profile } = await scell.recurringInvoices.get(profileId);
// profile.status, profile.next_occurrence_at, profile.occurrences_count
const { data: occurrences } = await scell.recurringInvoices.occurrences(profileId);
for (const occ of occurrences) {
// occ.status: 'pending' | 'emitted' | 'failed' | 'skipped'
// occ.scheduled_for, occ.invoice_id (when emitted), occ.error (when failed)
console.log(occ.scheduled_for, occ.status, occ.invoice_id ?? '—');
}
// ── Pause (stops future emissions, keeps the schedule) ──────────────
await scell.recurringInvoices.pause(profileId);
// ── Activate (resume a paused profile) ──────────────────────────────
await scell.recurringInvoices.activate(profileId);
// ── Run now (emit the next occurrence immediately, out of cadence) ──
// Returns 202 Accepted — the emission is processed asynchronously.
// Honours emission_mode: 'auto_send' submits to the PDP + emails the
// buyer with the Factur-X PDF; 'draft' creates a draft for review.
const { data: run } = await scell.recurringInvoices.runNow(profileId);
// run.occurrence_id, run.status === 'pending'
// ── Cancel (terminal — no further emissions, profile kept for audit) ─
await scell.recurringInvoices.cancel(profileId);

MCP Agent@scell/mcp-client v3.5.0

Utilisez Scell.io directement depuis votre assistant IA. L'agent MCP expose 148 outils permettant à Claude, Cursor ou VS Code Copilot de créer des factures, gérer des signatures, planifier des échéanciers et surveiller la conformité fiscale en langage naturel. La liste exhaustive ci-dessous reprend les noms canoniques (préfixe scell_) tels que déclarés côté serveur dans backend/config/mcp.php.

Configuration

~/.claude/.mcp.json
json
// Coller ce bloc dans le fichier de config MCP de votre client IA.
// Cree le fichier s'il n'existe pas (chemin selon le client) :
//
//   - Claude Code (CLI)   ~/.claude/.mcp.json
//   - Claude Desktop      ~/Library/Application Support/Claude/claude_desktop_config.json   (macOS)
//                         %APPDATA%\\Claude\\claude_desktop_config.json                  (Windows)
//   - Cursor              ~/.cursor/mcp.json
//   - VS Code (Copilot)   ~/.vscode/mcp.json
//
// Remplacer sk_live_xxxx par votre cle Scell.io (sk_live_* en prod, sk_test_* en sandbox).
// Recuperez vos cles depuis le dashboard : https://app.scell.io/dashboard/api-keys

{
  "mcpServers": {
    "scell": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "https://api.scell.io/api/mcp",
        "--header",
        "X-Scell-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      ]
    }
  }
}

Invoices12 outils

OutilDescriptionExemple de prompt
scell_create_invoiceCreate a Factur-X/UBL/CII electronic invoice (optional `parentQuoteId` to link a standard invoice to a source quote)"Create a Factur-X invoice from ACME Corp to Client SA for 10 hours of consulting at 150 EUR/h, linked to quote DEV-2026-0042"
scell_get_invoiceGet details of a specific invoice by ID"Get details for invoice inv_abc123"
scell_list_invoicesList all invoices with optional filters"Show me all invoices from this month"
scell_download_invoiceDownload an invoice as PDF or XML"Download the PDF for invoice inv_abc123"
scell_mark_invoice_paidMark an outgoing invoice as paid (manual)"Mark invoice inv_abc123 as paid"
scell_submit_invoiceSubmit an invoice to the PDP network"Submit invoice inv_abc123 to the PDP"
scell_convert_invoiceConvert an invoice between formats (Factur-X ↔ UBL ↔ CII)"Convert invoice inv_abc123 to UBL"
scell_send_invoice_by_emailEmail the Factur-X invoice to the buyer"Email invoice inv_abc123 to the buyer"
scell_list_deposit_groupsList deposit groups (multi-invoice deals) with progress"List my deposit groups still missing a balance invoice"
scell_get_deposit_groupGet a deposit group: deal total, deposits issued, balance, % invoiced"Show the deposit group for the Dubois renovation deal"
scell_suggest_invoice_mentionsLegal-mentions assistant: suggest per-field footer/terms/notes for an invoice"Suggest the legal mentions for a B2B invoice from my company"
scell_preview_invoice_mentionsPreview the rendered legal mentions (footer / payment terms) before issuing"Preview the legal mentions that would appear on this invoice"

Credit Notes7 outils

OutilDescriptionExemple de prompt
scell_list_credit_notesList all credit notes"Show all credit notes issued this quarter"
scell_get_credit_noteGet a credit note by ID"Get credit note cn_abc123"
scell_download_credit_noteDownload a credit note as PDF or XML"Download the PDF for credit note cn_abc123"
scell_create_credit_noteCreate a credit note (avoir). `type` partial|total. A PARTIAL credit note SELECTS lines of the source invoice via invoice_line_id (price + exact per-line VAT inherited — never invent amounts). Use scell_get_remaining_creditable first."Credit the consulting line of invoice inv_abc123"
scell_send_credit_noteEmail the credit note to the buyer"Send credit note cn_abc123 to the buyer"
scell_delete_credit_noteDelete a draft credit note"Delete draft credit note cn_abc123"
scell_get_remaining_creditableList the invoice lines still creditable (invoice_line_id + remaining quantity + per-line VAT) — discovery step before a partial credit note."Which lines of invoice inv_abc123 can still be credited?"

Quotes22 outils

OutilDescriptionExemple de prompt
scell_create_quoteCreate a quote (auto-numbering DEV-YYYY-NNNN)"Create a quote for Client SA for a 5-day website build at 600 EUR/day"
scell_get_quoteGet a quote by ID"Get quote DEV-2026-0042"
scell_list_quotesList quotes with filters"List all accepted quotes this year"
scell_update_quoteUpdate a draft quote"Add a maintenance line to draft quote qte_abc123"
scell_delete_quoteDelete a draft quote"Delete draft quote qte_abc123"
scell_send_quoteSend the quote by email to the buyer (signable public link)"Send quote qte_abc123 to the client"
scell_cancel_quoteCancel a sent quote"Cancel quote qte_abc123"
scell_duplicate_quoteDuplicate an existing quote (new draft)"Duplicate quote qte_abc123"
scell_convert_quote_to_depositConvert a quote into a deposit invoice (type 386, immediate VAT)"Convert quote qte_abc123 into a 30% deposit invoice"
scell_convert_quote_to_balanceConvert a quote into a balance invoice (type 380 + auto BG-22 deductions)"Issue the balance invoice for quote qte_abc123"
scell_get_quote_pdfDownload the quote as PDF"Download quote qte_abc123 as PDF"
scell_get_quote_audit_logAppend-only audit log of the quote (SHA-256 chain)"Show the audit log for quote qte_abc123"
scell_regenerate_quote_public_linkRegenerate the signable public link (fresh token)"Regenerate the public link for quote qte_abc123"
scell_revoke_quote_public_linkRevoke the public link of a sent quote"Revoke the public link for quote qte_abc123"
scell_preview_quoteNon-persisted PDF preview from raw quote data"Preview a quote PDF for a 3-day audit at 800 EUR/day"
scell_get_quote_payment_scheduleGet the payment schedule lines of a quote"Show the payment schedule for quote qte_abc123"
scell_set_quote_payment_scheduleCreate or replace the full payment schedule (atomic)"Set a 30/40/30 payment schedule on quote qte_abc123"
scell_patch_quote_payment_schedulePartially update the payment schedule (add/update/remove lines)"Push back the second installment of quote qte_abc123 by a month"
scell_delete_quote_payment_scheduleDelete all schedule lines (blocked if any line is invoiced)"Remove the payment schedule on quote qte_abc123"
scell_get_quote_payment_summaryAggregated summary: total, invoiced, remaining, lines with status"How much is left to invoice on quote qte_abc123?"
scell_convert_schedule_line_to_invoiceInvoice a specific schedule line (deposit from the schedule)"Invoice the first milestone of quote qte_abc123"
scell_list_payment_schedule_presetsList predefined payment schedule templates"List the available payment schedule presets"

Recurring Invoices10 outils

OutilDescriptionExemple de prompt
scell_create_recurring_invoiceCreate a recurring invoice profile (subscription / rent / maintenance)"Set up a monthly 99 EUR maintenance invoice for Client SA"
scell_get_recurring_invoiceGet a recurring profile by ID"Show recurring profile rec_abc123"
scell_list_recurring_invoicesList recurring profiles"List all my active recurring invoices"
scell_update_recurring_invoiceUpdate a recurring profile (template)"Raise the monthly amount on profile rec_abc123 to 120 EUR"
scell_delete_recurring_invoiceDelete a recurring profile"Delete recurring profile rec_abc123"
scell_list_recurring_invoice_occurrencesList the emitted/pending/failed occurrences of a profile"Show the occurrences of profile rec_abc123"
scell_pause_recurring_invoicePause a recurring profile"Pause recurring profile rec_abc123"
scell_activate_recurring_invoiceResume a paused recurring profile"Reactivate recurring profile rec_abc123"
scell_cancel_recurring_invoiceCancel a recurring profile (final)"Cancel recurring profile rec_abc123"
scell_run_recurring_invoice_nowTrigger the next occurrence immediately"Issue the next occurrence of profile rec_abc123 now"

Buyers & VAT6 outils

OutilDescriptionExemple de prompt
scell_create_buyerCreate a reusable buyer in the registry (B2B/B2C, billing + shipping address)"Add buyer Client SA, SIRET 12345678900012, to my registry"
scell_get_buyerGet a buyer by ID"Get buyer buy_abc123"
scell_list_buyersList/search buyers (q on name/siret/email, filter is_individual)"Find buyers matching ACME"
scell_update_buyerUpdate a buyer"Update the billing email for buyer buy_abc123"
scell_delete_buyerDelete (soft) a buyer from the registry"Remove buyer buy_abc123 from my registry"
scell_resolve_vat_contextResolve the authoritative VAT context (intracom autoliquidation, franchise, exemptions)"What VAT applies to a B2B service sold to a German company?"

Products5 outils

OutilDescriptionExemple de prompt
scell_create_productCreate a catalog product/service (revenue_category, unit, price, tax/discount defaults)"Add a Consulting day product at 600 EUR HT, 20% VAT, to my catalog"
scell_get_productGet a catalog product by ID"Get product prod_abc123"
scell_list_productsList/search products (q, filter revenue_category / category / is_active)"List my active service products"
scell_update_productUpdate a catalog product"Raise the price of product prod_abc123 to 650 EUR"
scell_delete_productDelete (soft) a catalog product"Delete product prod_abc123"

Product Categories5 outils

OutilDescriptionExemple de prompt
scell_create_product_categoryCreate a custom organisation category (name, color, position)"Create a product category called Subscriptions in blue"
scell_get_product_categoryGet a product category by ID"Get category cat_abc123"
scell_list_product_categoriesList product categories"List my product categories"
scell_update_product_categoryUpdate a product category"Rename category cat_abc123 to Recurring"
scell_delete_product_categoryDelete a product category"Delete category cat_abc123"

Suppliers3 outils

OutilDescriptionExemple de prompt
scell_list_suppliersList suppliers (auto-derived from received invoices)"List my suppliers"
scell_get_supplierGet a supplier by ID"Get supplier sup_abc123"
scell_update_supplierEnrich a supplier (email / phone / notes / metadata only — identity is read-only)"Add a contact email to supplier sup_abc123"

Invoice Templates9 outils

OutilDescriptionExemple de prompt
scell_list_invoice_templatesList templates (system / tenant / sub_tenant scope)"List my invoice templates"
scell_get_invoice_templateGet a template by ID"Get template tpl_abc123"
scell_create_invoice_templateCreate a custom template (logo, colors, footer, mentions)"Create an invoice template with my brand colors"
scell_update_invoice_templateUpdate a template"Change the accent color of template tpl_abc123"
scell_delete_invoice_templateDelete a template"Delete template tpl_abc123"
scell_set_default_invoice_templateMark a template as the default"Make template tpl_abc123 my default"
scell_preview_invoice_templatePreview the PDF render of a template (without persisting)"Preview how invoices look with template tpl_abc123"
scell_derive_template_colors_from_email_logoDerive primary/accent colors from the email logo and apply them to the default template"Use my email logo colors for my invoice template"
scell_derive_template_colors_from_invoice_logoExtract the { primary, accent } palette from the invoice (template) logo (not persisted)"What colors does my invoice logo suggest?"

Branding7 outils

OutilDescriptionExemple de prompt
scell_get_tenant_brandingGet the tenant email/branding settings"Show my branding settings"
scell_update_tenant_brandingUpdate tenant branding (logo URL, colors, footer, brand_email_enabled)"Enable email branding and set my primary color to #0066FF"
scell_preview_tenant_brandingRender the branded email (HTML or PDF) as it will be received, with optional overrides"Preview my branded email before I enable it"
scell_get_tenant_branding_logo_upload_urlGet a presigned URL to upload the tenant email logo"Give me an upload URL for my email logo"
scell_get_sub_tenant_brandingGet a sub-tenant's branding settings"Show the branding for sub-tenant sub_abc123"
scell_update_sub_tenant_brandingUpdate a sub-tenant's branding"Set the footer text for sub-tenant sub_abc123"
scell_preview_sub_tenant_brandingPreview a sub-tenant's branded email with optional overrides"Preview the branded email for sub-tenant sub_abc123"

Documents1 outil

OutilDescriptionExemple de prompt
scell_preview_documentLive HTML preview of a draft document (invoice / credit_note / quote) with the real template + branding + legal mentions"Preview the HTML of an invoice I'm drafting for Client SA"

Signatures6 outils

OutilDescriptionExemple de prompt
scell_create_signatureCreate an eIDAS EU-SES signature request (signature/initials/mentions/date blocks)"Create a signature request for agreement.pdf with 2 signers: Jean Dupont and Marie Martin"
scell_get_signatureGet signature request details"What's the status of signature sig_xyz789?"
scell_list_signaturesList signature requests (tenant scope)"List all pending signature requests"
scell_download_signedDownload the signed document / proof file"Download the signed PDF for signature sig_xyz789"
scell_cancel_signatureCancel a pending signature request"Cancel signature request sig_xyz789"
scell_send_reminderSend a reminder to pending signers"Remind the signers of request sig_xyz789"

Incoming Invoices5 outils

OutilDescriptionExemple de prompt
scell_list_incoming_invoicesList invoices received via the PDP"Show my incoming invoices this month"
scell_get_incoming_invoiceGet an incoming invoice by ID"Get incoming invoice in_abc123"
scell_accept_incoming_invoiceAccept an incoming invoice"Accept incoming invoice in_abc123"
scell_reject_incoming_invoiceReject an incoming invoice with a reason + code"Reject incoming invoice in_abc123 — wrong amount"
scell_mark_incoming_invoice_paidMark an incoming invoice as paid"Mark incoming invoice in_abc123 as paid"

Sub-Tenants & Onboarding17 outils

OutilDescriptionExemple de prompt
scell_list_sub_tenantsList all sub-tenants"Show all my sub-tenants"
scell_create_sub_tenantCreate a new sub-tenant"Create a sub-tenant for Partner Corp with external ID partner-001"
scell_get_sub_tenantGet a sub-tenant by ID"Get sub-tenant sub_abc123"
scell_update_sub_tenantUpdate a sub-tenant (PUT { is_active } to deactivate)"Deactivate sub-tenant sub_abc123"
scell_delete_sub_tenantDelete a sub-tenant (ISCA policy: refused if fiscal entries exist)"Delete sub-tenant sub_abc123 (no invoices yet)"
scell_find_sub_tenant_by_external_idFind a sub-tenant by your external ID (idempotent lookup)"Find the sub-tenant with external ID partner-001"
scell_get_subtenant_superpdp_statusGet the SuperPDP onboarding status of a sub-tenant"Is sub-tenant sub_abc123 connected to SuperPDP?"
scell_refresh_subtenant_superpdp_statusForce a SuperPDP status poll (rate-limited)"Refresh the SuperPDP status of sub-tenant sub_abc123"
scell_authorize_subtenant_superpdpGet a SuperPDP authorize URL (prefilled) for a sub-tenant"Get the SuperPDP authorize link for sub-tenant sub_abc123"
scell_get_subtenant_resume_urlGet a signed resume URL to reopen the onboarding tunnel (7 days)"Give me a resume link for sub-tenant sub_abc123 onboarding"
scell_disconnect_subtenant_superpdpForce-disconnect a sub-tenant from SuperPDP"Disconnect sub-tenant sub_abc123 from SuperPDP"
scell_reconnect_subtenant_superpdpDisconnect + return a fresh SuperPDP authorize URL in one call"Reconnect sub-tenant sub_abc123 to SuperPDP"
scell_mint_subtenant_widget_tokenMint a signed 24h token for the SuperPDP-only embed widget"Mint a SuperPDP widget token for sub-tenant sub_abc123"
scell_lookup_sireneSirene lookup (Etalab + INSEE fallback) by SIRET/SIREN"Look up SIRET 12345678900012 in Sirene"
scell_create_onboarding_sessionCreate a widget onboarding session (Scell-first flow)"Start an onboarding session for a new partner"
scell_get_onboarding_sessionGet an onboarding session status"What's the status of onboarding session ses_abc123?"
scell_authorize_onboarding_superpdpGet the SuperPDP authorize URL for an onboarding session"Get the SuperPDP link for onboarding session ses_abc123"

Thresholds (Micro-Entrepreneur)3 outils

OutilDescriptionExemple de prompt
scell_get_subtenant_thresholdsGet a sub-tenant's VAT-franchise / micro-enterprise threshold tracking"How close is sub-tenant sub_abc123 to the VAT franchise threshold?"
scell_simulate_subtenant_thresholdsPre-issuance simulator: would this invoice cross a threshold?"Would a 5,000 EUR invoice push sub_abc123 over the VAT threshold?"
scell_update_subtenant_fiscal_statusSwitch a sub-tenant's VAT status (franchise ↔ liable)"Switch sub-tenant sub_abc123 to VAT-liable"

Fiscal (ISCA)12 outils

OutilDescriptionExemple de prompt
scell_get_fiscal_complianceGet fiscal compliance status"Am I ISCA compliant?"
scell_check_fiscal_integrityVerify the hash-chain integrity"Verify my fiscal data integrity"
scell_list_fiscal_closingsList daily/monthly closings (tenant and sub-tenant scope)"Show all fiscal closings for March 2026"
scell_get_fiscal_attestationGet the ISCA attestation for a year"Get my ISCA attestation for 2025"
scell_list_fiscal_entriesList immutable ledger entries"Show the last 50 fiscal entries"
scell_get_kill_switch_statusGet kill-switch status (read-only)"Is the kill switch active?"
scell_list_fiscal_rulesList fiscal automation rules"Show all fiscal rules"
scell_export_fecExport the FEC file for the tax authorities"Generate the FEC export for 2025"
scell_perform_daily_closingTrigger a daily fiscal closing"Run the daily fiscal closing now"
scell_activate_kill_switchActivate the emergency kill switch (step-up auth, client allowlist required)"Activate the kill switch"
scell_deactivate_kill_switchDeactivate the kill switch (step-up auth, client allowlist required)"Deactivate the kill switch"
scell_export_forensicExport a forensic bundle of the ledger"Export a forensic bundle for 2025"

Billing & Credit Packs8 outils

OutilDescriptionExemple de prompt
scell_get_balanceGet the current tenant credit balance"What's my current credit balance?"
scell_list_billing_invoicesList Scell.io billing invoices issued to your account"List my Scell.io billing invoices for this year"
scell_get_billing_usageGet current-period usage metrics with projection"How many invoices did I send this month?"
scell_list_billing_transactionsList billing transactions (debits + credits)"Show my last 10 billing transactions"
scell_list_credit_packsList the available credit packs"What credit packs can I buy?"
scell_checkout_credit_packStart a Stripe checkout for a credit pack"Buy the 1,000-credit pack"
scell_topup_balanceTop up the balance with a custom amount (returns Stripe client_secret)"Top up my balance with 50 EUR"
scell_confirm_topupConfirm a top-up after Stripe payment"Confirm my last top-up"

Tenant & Stats5 outils

OutilDescriptionExemple de prompt
scell_get_tenant_profileGet the tenant profile (default company / Factur-X issuer defaults)"Show my tenant profile"
scell_update_tenant_profileUpdate the tenant profile (IBAN, BIC, payment terms, notifications toggle)"Set my default payment terms to 30 days"
scell_get_tenant_statsGet tenant-level statistics"Give me my tenant stats"
scell_get_stats_overviewGet a stats overview (invoices, signatures, revenue)"Show my stats overview"
scell_get_stats_monthlyGet monthly statistics breakdown"Show my monthly stats for 2026"

Validation & System5 outils

OutilDescriptionExemple de prompt
scell_validate_siretValidate a SIRET number (Sirene)"Validate SIRET 12345678900012"
scell_validate_vatValidate an intra-EU VAT number (VIES)"Validate VAT number FR12345678901"
scell_get_audit_trailGet the audit trail for a resource"Show the audit trail for invoice inv_abc123"
scell_health_checkCheck the API health"Is the Scell.io API healthy?"
scell_validate_api_keyValidate the current API key and report its scope"Is my API key valid and what can it do?"

Événements webhook

Liste complète des événements webhook auxquels vous pouvez vous abonner. Utilisez ces noms d'événements lors de la création ou la mise à jour des endpoints webhook.

ÉvénementDescription
invoice.createdFacture créée
invoice.validatedFacture validée (Factur-X/UBL généré)
invoice.transmittedFacture transmise au PDP
invoice.acceptedFacture acceptée par le destinataire
invoice.rejectedFacture rejetée
invoice.errorErreur de traitement de la facture
invoice.refund_status_changedStatut de remboursement modifié (avoir)
signature.createdDemande de signature créée
signature.signedDocument signé par un signataire
signature.completedTous les signataires ont signé
signature.refusedSignature refusée par un signataire
signature.expiredDemande de signature expirée
balance.lowSolde de crédits faible (seuil d'alerte)
balance.criticalSolde de crédits critique

Statuts de facture

Liste complète des statuts possibles sur le champ status du payload Invoice (check constraint PostgreSQL côté backend). Les statuts marqués Auto sont posés automatiquement par le système (workers, observers, webhooks) — vous n'avez pas à les écrire. Les statuts refunded et partially_refunded sont posés par le CreditNoteObserver dès qu'un avoir validé est attaché à une facture — à utiliser côté lecture uniquement.

StatutAutoDescription
draftBrouillon. Modifiable et supprimable. Pas encore validé.
validatingOuiValidation Factur-X/UBL en cours (génération PDF/A-3).
validatedValidé. Hash fiscal posé, ledger ISCA immutable. Soumission PDP possible.
convertingOuiConversion de format en cours (Factur-X ↔ UBL ↔ CII).
convertedOuiFormat cible généré, prêt pour transmission.
transmittingOuiTransmission au PDP/PPF en cours.
transmittedOuiTransmise au réseau, en attente de réponse du destinataire.
acceptedOuiAcceptée par le destinataire via le PDP.
rejectedOuiRejetée par le destinataire ou le PDP.
disputedContestée par le destinataire. Action humaine requise.
paidPayée. Posé par mark-paid ou webhook bancaire.
receivedOuiFacture entrante reçue via le PDP (direction incoming).
completedOuiCycle terminé (paiement confirmé + post-traitement).
errorOuiErreur technique non récupérable. Voir metadata.last_error.
refundedOuiTotalement avoirée. Posé automatiquement par le backend quand la somme des avoirs validés ≥ total TTC.
partially_refundedOuiPartiellement avoirée. Posé automatiquement quand un avoir validé est attaché sans atteindre le total TTC.

Champs liés au remboursement

Deux champs accompagnent les statuts refunded et partially_refunded sur tout payload Invoice retourné par GET /invoices/{id} ou GET /invoices.

  • refund_status'none' | 'partial' | 'full'. Granularité fine de l'état de remboursement, indépendamment du statut principal (une facture paid puis partially_refunded reste en refund_status='partial').
  • total_refundedFloat, montant TTC cumulé remboursé via les avoirs validés. Source de vérité pour le reporting (la somme se reflète sur refund_status automatiquement).
Exemple — Payload Invoice (extrait)
json
{
  "id": "inv_01HXP3K7M2YQ9V8B5N6Z4A1C2D",
  "invoice_number": "QRCOM-202605-00001",
  "status": "partially_refunded",
  "refund_status": "partial",
  "total_refunded": 250.00,
  "total_amount": 1200.00,
  "currency": "EUR",
  "invoice_type": "standard",
  "buyer": { /* ... */ },
  "lines": [ /* ... */ ],
  "metadata": { /* ... */ }
}

Énumérations & statuts

Liste exhaustive des 19 énumérations exposées par l'API au-delà de InvoiceStatus. Les 8 premières sont des BackedEnum PHP synchronisées vers TypeScript via la commande php artisan types:generate (codegen back→front). Les 11 suivantes sont des contraintes CHECK PostgreSQL exposées par les payloads JSON de l'API.

Les SDK TypeScript (@scell/sdk), PHP (scell/sdk) et MCP (@scell/mcp-client) typent strictement ces valeurs côté client. Le ledger ISCA s'appuie sur les valeurs string telles quelles, sans alias.

ÉnumérationValeursDescription
InvoiceTemplateKind
App\Enums\Invoice\InvoiceTemplateKind
invoicequoteboth
Détermine si un template Factur-X est utilisable pour les factures, les devis, ou les deux.
InvoiceType
App\Enums\Invoice\InvoiceType
standarddepositbalance
Type de facture. `deposit` = acompte (TVA exigible immédiatement, CGI 289). `balance` = solde (déduit les acomptes via BG-22 code 80).
PaymentScheduleLineAmountType
App\Enums\Quote\PaymentScheduleLineAmountType
percentamount
Mode d'une ligne d'échéancier de devis : pourcentage du total TTC ou montant fixe en devise.
PaymentScheduleLineStatus
App\Enums\Quote\PaymentScheduleLineStatus
pendinginvoicedcancelled
État d'une ligne d'échéancier de devis. `invoiced` est posé automatiquement lors de la génération de la facture acompte/solde correspondante.
QuoteStatus
App\Enums\Quote\QuoteStatus
draftsentviewedacceptedrefusedexpiredconvertedcancelled
Cycle de vie d'un devis. `viewed` et `accepted/refused` sont posés via l'URL publique signée. `converted` quand un solde a été émis.
QuoteAuditAction
App\Enums\Quote\QuoteAuditAction
createdupdatedline_addedline_removedline_updatedbuyer_changedsentresentviewedsignedacceptedrefusedcancelledexpiredconvertedpublic_link_regeneratedpublic_link_revokedduplicateddeposit_generated_from_scheduleschedule_updatedschedule_deleted
21 actions journalisées dans `quote_audit_logs` (chaîne SHA-256 indépendante du ledger fiscal ISCA).
SubTenantOnboardingStatus
App\Enums\SubTenantOnboardingStatus
pending_superpdpsuperpdp_redirectedsuperpdp_authorizedsuperpdp_pending_reviewactivesuperpdp_failed
Cycle de vie de l'onboarding SuperPDP d'un sub-tenant via le widget `<scell-onboarding>`. `active` = KYB vérifié, B2B en mode Peppol.
VatCategory
App\Enums\Billing\VatCategory
STANDARDINTERMEDIATEREDUCEDSUPER_REDUCEDZERO_RATEDEXEMPTREVERSE_CHARGEOUT_OF_SCOPEINTRACOM_GOODSEXPORTFRANCHISE_BASEEXEMPT_TRAINING
12 catégories alignées EN16931 (codes S/AE/K/G/O/Z/E). `REVERSE_CHARGE` (AE) = autoliquidation services intra-UE (art. 283-2). `INTRACOM_GOODS` (K) = livraison intra-UE de biens (art. 262 ter I). `EXPORT` (G) = biens hors UE (art. 262 I). `OUT_OF_SCOPE` (O) = services hors UE (art. 259-1). `FRANCHISE_BASE` (E) = AE art. 293 B. `EXEMPT_TRAINING` (E) = formation art. 261-4-4°a. La mention ne se déduit PAS du seul code : FRANCHISE_BASE/EXEMPT/EXEMPT_TRAINING partagent E mais portent des mentions distinctes. Voir la section TVA & autoliquidation pour le détail (champs `supply_type`/`vat_override_reason`, 409, builder).
CreditNoteStatus
DB check constraint
draftsent
État d'un avoir. `draft` = modifiable/supprimable. `sent` = irréversible (entrée fiscale ISCA posée).
CreditNoteType
DB check constraint
partialtotal
Type d'avoir. `total` = avoir intégral, met la facture en `refunded`. `partial` = avoir partiel, déclenche `partially_refunded`.
SignatureStatus
DB check constraint
pendingwaiting_signerspartially_signedcompletedrefusedexpirederror
Cycle de vie d'une demande de signature eIDAS EU-SES. `completed` = tous les signataires ont signé, fichier de preuve disponible.
SignatureArchiveStatus
DB check constraint
pendingarchivedglaciererror
État d'archivage long terme d'une signature (10 ans). `glacier` = stockage froid S3 Glacier.
InvoiceArchiveStatus
DB check constraint
pendingarchivedglaciererror
État d'archivage long terme d'une facture (Object Lock COMPLIANCE 11 ans, conformité ISCA).
TenantKybStatus
DB check constraint
pendingdocuments_submittedunder_reviewverifiedrejected
Statut KYB du tenant master. `verified` est requis en production pour émettre des factures B2B.
CompanyStatus
DB check constraint
pending_kycactivesuspended
État d'une Company. `active` est requis pour qu'une Company soit émettrice de factures.
ApiKeyStatus
DB check constraint
activerevoked
État d'une clé API. `revoked` est irréversible (audit trail conservé).
TenantInvoiceStatus
DB check constraint
draftsentpaidoverduecancelled
État d'une facture de facturation Scell.io émise au tenant (consommation, packs, top-up). `overdue` est posé par le cron J+30.
TenantTransactionType
DB check constraint
debitcredit
Type d'une transaction de facturation tenant. `debit` = consommation. `credit` = top-up ou pack.
OnboardingSessionStatus
DB check constraint
initiatedsiret_verifiedvat_verifieddocuments_pendingdocuments_submittedunder_reviewcompletedfailedexpired
État d'une session d'onboarding sub-tenant via le widget public (cycle de vie complet du tunnel KYB).

Synchronisation des SDK

Les nouvelles versions v2.21.0 (PHP), v2.23.0 (TypeScript) et v2.22.0 (MCP) exposent ces 19 énumérations de façon typée. Côté PHP elles vivent dans Scell\\Sdk\\Enums\\* ; côté TypeScript dans des union types exportés ; côté MCP dans les descriptions d'outils consommées par le LLM.

Gestion des erreurs

Toutes les méthodes SDK lèvent des exceptions typées avec des codes de statut HTTP. Gérez les erreurs en fonction du code de statut.

CodeStatutDescription
400Bad RequestCorps de requête malformé ou paramètres invalides
401UnauthorizedIdentifiants d'authentification manquants, invalides ou expirés
402Payment RequiredSolde de crédits insuffisant pour effectuer l'opération
403ForbiddenIdentifiants valides mais permissions insuffisantes sur la ressource
404Not FoundLa ressource demandée n'existe pas
409ConflictRessource déjà existante ou conflit d'état (ex. soumission en doublon)
422Unprocessable EntityErreur de validation. Consultez l'objet errors pour les détails par champ
429Too Many RequestsLimite de taux dépassée. Vérifiez l'en-tête Retry-After
500Server ErrorErreur serveur interne. Réessayez avec un backoff exponentiel
503Service UnavailableService temporairement indisponible. Réessayez après un court délai

Stratégie de relance

  • 1.429 Rate LimitedRespectez l'en-tête Retry-After. Le SDK relance automatiquement jusqu'à 3 fois avec le délai indiqué.
  • 2.500/503 Server ErrorRelancez avec un backoff exponentiel : 1s, 2s, 4s. Max 3 relances. Le SDK gère cela automatiquement.
  • 3.4xx Client ErrorNe relancez pas. Corrigez le payload de la requête ou les identifiants et réessayez.
error-handling.ts
typescript
import { ScellApiClient } from '@scell/sdk';
const scell = new ScellApiClient('sk_live_your_api_key');
try {
const invoice = await scell.invoices.create({ /* ... */ });
} catch (error) {
if (error.status === 422) {
// Validation error — check error.errors for field-level details
console.error('Validation:', error.errors);
// { "seller.siren": ["The siren must be 9 digits."] }
} else if (error.status === 401) {
// Invalid or expired API key
console.error('Authentication failed');
} else if (error.status === 402) {
// Insufficient credits
console.error('Insufficient balance — top up credits');
} else if (error.status === 404) {
// Resource not found
console.error('Resource not found');
} else if (error.status === 429) {
// Rate limited — retry after error.retryAfter seconds
console.error('Rate limited, retry after', error.retryAfter, 'seconds');
} else if (error.status >= 500) {
// Server error — retry with exponential backoff
console.error('Server error, retrying...');
}
}

Prêt à intégrer ?

Créez votre compte et obtenez vos clés API en quelques minutes. Commencez avec 100 crédits offerts.

Vos préférences cookies

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