Conformite Fiscale ISCA (autocertification)
Version applicative: 1.2.1 Derniere mise a jour: 2026-06-05 Garanties: ISCA (Inalterabilite, Securisation, Conservation, Archivage) Base legale: Article 286-I-3 bis du Code General des Impots (Loi de Finances 2026)
Statut juridique : Scell.io est autocertifie sur la base d'une attestation interne (modele CNIL / DGFiP). La plateforme n'est pas certifiee par un organisme tiers. Le terme "ISCA" designe le concept technique de chaine de hachage immuable ; "autocertification" designe le statut juridique.
Table des matieres
- Introduction
- Architecture Fiscale
- Immutabilite
- Integrite de la Chaine de Hachage
- Clotures
- Ancrage (Timestamping)
- Kill Switch
- Export FEC
- Regles Fiscales
- API Fiscale
- Seuils Auto-Entrepreneur
- Scellement des Devis (PAdES + Bitcoin)
1. Introduction
Qu'est-ce que ISCA ?
ISCA (Inalterabilite, Securisation, Conservation, Archivage) regroupe les exigences de conformite imposees aux logiciels de caisse et de facturation en France. Quatre garanties fondamentales :
| Exigence | Description | Implementation Scell.io |
|---|---|---|
| Inalterabilite | Les donnees fiscales ne peuvent etre modifiees apres validation | Triggers SQL, immutabilite Eloquent, audit log |
| Sécurisation | Les donnees sont protegees contre toute alteration | Chaine SHA-256, ancrage OpenTimestamps / Bitcoin (provider RFC 3161 optionnel, voir ADR-0009) |
| Conservation | Les donnees sont conservees pendant la duree legale | Retention 6 ans minimum, archivage S3 |
| Archivage | Les donnees peuvent etre restituees a l'administration | Export FEC conforme, export forensique |
Pourquoi c'est obligatoire en France ?
Depuis la Loi de Finances 2018 (renforcee en 2026), tout logiciel de facturation utilise par une entreprise assujettie a la TVA doit etre certifie conforme par un organisme tiers ou produire une auto-attestation de conformite de son editeur (modele retabli par l'article 125 de la LF 2026). Le non-respect expose a une amende de 7 500 EUR par logiciel non conforme. Scell.io retient la voie de l'autocertification.
Ce que Scell.io implemente
Scell.io implemente l'integralite des exigences ISCA au niveau applicatif et base de donnees :
- Grand livre fiscal (fiscal ledger) avec chaine de hachage SHA-256
- Triggers PostgreSQL pour l'immutabilite des ecritures
- Clotures journalieres et mensuelles automatiques
- Ancrage RFC 3161 TSA pour preuve d'anteriorite
- Export FEC conforme a l'article A.47 A-1 du LPF
- Kill switch pour arret d'urgence
- Piste d'audit complete de toute tentative de modification
2. Architecture Fiscale
Diagramme du flux complet
graph TD
subgraph "Evenements Source"
INV["Facture creee/validee/transmise"]
CN["Avoir cree/envoye"]
PAY["Paiement recu"]
end
subgraph "Grand Livre Fiscal"
FE["FiscalEntry<br/>Ecriture fiscale"]
FS["FiscalSequence<br/>Compteur atomique"]
HASH["Chaine SHA-256<br/>data_hash + previous_hash = chain_hash"]
end
subgraph "Clotures"
DC["Cloture journaliere<br/>(00:05 UTC)"]
MC["Cloture mensuelle<br/>(1er du mois)"]
ATT["Attestation annuelle"]
end
subgraph "Preuves"
TSA["Ancrage RFC 3161 TSA<br/>(Timestamp Authority)"]
FEC["Export FEC<br/>(DGFIP)"]
FOR["Export forensique"]
end
subgraph "Securite"
KS["Kill Switch<br/>(arret d'urgence)"]
IC["Verification d'integrite<br/>(02:00 UTC)"]
AL["Audit Log<br/>(tentatives de modification)"]
end
INV --> FE
CN --> FE
PAY --> FE
FE --> FS
FS --> HASH
HASH --> DC
DC --> MC
MC --> ATT
DC --> TSA
MC --> TSA
FE --> IC
IC --> AL
FE --> FEC
FE --> FOR
KS -.->|"bloque"| FEModeles de donnees
Le systeme fiscal repose sur 9 modeles interconnectes :
| Modele | Table | Role |
|---|---|---|
FiscalEntry | fiscal_entries | Ecriture fiscale unitaire (append-only) |
FiscalSequence | fiscal_sequences | Compteur de sequence atomique par tenant |
FiscalClosing | fiscal_closings | Cloture journaliere/mensuelle/annuelle |
FiscalAttestation | fiscal_attestations | Attestation de conformite annuelle |
FiscalAnchor | fiscal_anchors | Ancrage TSA (preuve d'anteriorite) |
FiscalKillSwitch | fiscal_kill_switches | Historique des arrets d'urgence |
FiscalIntegrityCheck | fiscal_integrity_checks | Resultats des verifications d'integrite |
FiscalRule | fiscal_rules | Regles fiscales configurables par tenant |
FiscalRuleApplication | fiscal_rule_applications | Journal d'application des regles |
Services
| Service | Fichier | Responsabilite |
|---|---|---|
FiscalLedgerService | Services/Fiscal/FiscalLedgerService.php | Grand livre, enregistrement, verification |
FiscalAnchoringService | Services/Fiscal/FiscalAnchoringService.php | Ancrage TSA, attestations |
FecExportService | Services/Fiscal/FecExportService.php | Export FEC conforme DGFIP |
FiscalForensicExportService | Services/Fiscal/FiscalForensicExportService.php | Export forensique complet |
FiscalVersionChangeDetector | Services/Fiscal/FiscalVersionChangeDetector.php | Detection de changement de version logicielle |
3. Immutabilite
L'immutabilite est la pierre angulaire de la conformite ISCA. Scell.io l'implemente a trois niveaux.
Niveau 1 : Modele Eloquent
Les modeles Invoice et CreditNote definissent des champs fiscaux immutables :
// Invoice.php
const IMMUTABLE_FISCAL_FIELDS = [
'total_ht', 'total_ttc', 'total_tax', 'invoice_number',
'issue_date', 'seller_name', 'seller_siret', 'seller_address',
'buyer_name', 'buyer_siret', 'buyer_address', 'currency',
'user_id', 'company_id',
];Des qu'une facture quitte le statut draft, toute tentative de modification de ces champs :
- Est bloquee par un
RuntimeException - Est enregistree dans
FiscalAuditLogavec la severitecritical - Inclut l'identifiant de l'acteur, l'adresse IP et le user-agent
// Protection dans le modele Invoice (booting)
protected static function booting(): void
{
static::updating(function (Invoice $invoice) {
if ($invoice->status !== 'draft') {
$changedFiscalFields = array_intersect(
array_keys($invoice->getDirty()),
self::IMMUTABLE_FISCAL_FIELDS
);
if (!empty($changedFiscalFields)) {
FiscalAuditLog::record([
'event_type' => 'modification_attempt',
'target_table' => 'invoices',
'target_id' => $invoice->id,
'severity' => 'critical',
'details' => ['fields' => $changedFiscalFields],
]);
throw new \RuntimeException(
'Modification interdite : champs fiscaux immutables.'
);
}
}
});
}Niveau 2 : Triggers PostgreSQL
La migration 2026_02_10_000005_add_fiscal_immutability_triggers installe des triggers SQL qui protegent les donnees directement au niveau de la base de donnees, meme en cas de contournement de l'application :
-- Empecher la modification des ecritures fiscales
CREATE OR REPLACE FUNCTION prevent_fiscal_entry_update()
RETURNS TRIGGER AS $$
BEGIN
RAISE EXCEPTION 'Les ecritures fiscales sont immutables (ISCA)';
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER tr_fiscal_entries_immutable
BEFORE UPDATE ON fiscal_entries
FOR EACH ROW
EXECUTE FUNCTION prevent_fiscal_entry_update();
-- Empecher la suppression des ecritures fiscales
CREATE TRIGGER tr_fiscal_entries_no_delete
BEFORE DELETE ON fiscal_entries
FOR EACH ROW
EXECUTE FUNCTION prevent_fiscal_entry_delete();Niveau 3 : Journal d'audit
Le trait LogsImmutabilityViolation est applique aux modeles fiscaux. Toute tentative de modification est tracee :
FiscalAuditLog::record([
'event_type' => 'modification_attempt', // ou deletion_attempt, deletion_blocked
'event_source' => 'eloquent', // ou sql_trigger, api
'target_table' => 'fiscal_entries',
'target_id' => $entry->id,
'severity' => 'critical',
'actor_type' => 'user', // ou api_key, system
'actor_id' => auth()->id(),
'ip_address' => request()->ip(),
'user_agent' => request()->userAgent(),
'details' => ['attempted_changes' => $dirty],
]);Suppression interdite
Les factures et avoirs valides (statut != draft) ne peuvent pas etre supprimes. Les soft deletes sont desactivees sur les ecritures fiscales (FiscalEntry n'utilise pas SoftDeletes). Le grand livre est strictement en mode append-only.
4. Integrite de la Chaine de Hachage
Principe
Chaque ecriture fiscale (FiscalEntry) est liee a la precedente par un hash cryptographique SHA-256, formant une chaine inalterable :
Entry #1: chain_hash = SHA256(data_hash_1 + "0000...0000")
Entry #2: chain_hash = SHA256(data_hash_2 + chain_hash_1)
Entry #3: chain_hash = SHA256(data_hash_3 + chain_hash_2)
...
Entry #N: chain_hash = SHA256(data_hash_N + chain_hash_N-1)Calcul du hash
// FiscalEntry::record() - methode statique, seul point de creation
public static function record(
?string $tenantId,
string $entryType,
string $entityType,
string $entityId,
string $fiscalDate,
array $dataSnapshot,
string $environment,
string $legalStatus,
string $actorType,
?string $actorId,
?string $ipAddress,
?string $userAgent,
): self {
return DB::transaction(function () use (...) {
// 1. Obtenir le prochain numero de sequence (atomique)
$sequence = FiscalSequence::lockForUpdate()
->where('tenant_id', $tenantId)
->first();
$sequenceNumber = $sequence->last_sequence_number + 1;
// 2. Calculer le hash des donnees
$dataHash = hash('sha256', json_encode($dataSnapshot, JSON_UNESCAPED_UNICODE));
// 3. Recuperer le hash precedent
$previousEntry = self::where('tenant_id', $tenantId)
->orderBy('sequence_number', 'desc')
->first();
$previousHash = $previousEntry?->chain_hash ?? str_repeat('0', 64);
// 4. Calculer le hash de chaine
$chainHash = hash('sha256', $dataHash . $previousHash);
// 5. Creer l'ecriture (append-only)
$entry = self::create([
'tenant_id' => $tenantId,
'sequence_number' => $sequenceNumber,
'entry_type' => $entryType,
'data_hash' => $dataHash,
'previous_hash' => $previousHash,
'chain_hash' => $chainHash,
'data_snapshot' => $dataSnapshot,
// ...
]);
// 6. Mettre a jour la sequence
$sequence->increment('last_sequence_number');
return $entry;
});
}Verification d'integrite
Le FiscalLedgerService::verifyChainIntegrity() rejoue l'integralite de la chaine pour detecter toute falsification :
public function verifyChainIntegrity(Tenant $tenant, ?Carbon $from, ?Carbon $to): array
{
$query = FiscalEntry::forTenant($tenant->id)
->orderBy('sequence_number', 'asc');
if ($from) $query->where('fiscal_date', '>=', $from);
if ($to) $query->where('fiscal_date', '<=', $to);
$entries = $query->get();
$discrepancies = [];
$previousHash = str_repeat('0', 64);
foreach ($entries as $entry) {
// Recalculer le hash des donnees
$expectedDataHash = hash('sha256', json_encode($entry->data_snapshot));
if ($expectedDataHash !== $entry->data_hash) {
$discrepancies[] = [
'type' => 'data_hash_mismatch',
'sequence' => $entry->sequence_number,
];
}
// Verifier la chaine
$expectedChainHash = hash('sha256', $entry->data_hash . $previousHash);
if ($expectedChainHash !== $entry->chain_hash) {
$discrepancies[] = [
'type' => 'chain_break',
'sequence' => $entry->sequence_number,
];
}
$previousHash = $entry->chain_hash;
}
return [
'result' => empty($discrepancies) ? 'valid' : 'invalid',
'entries_checked' => $entries->count(),
'discrepancies' => $discrepancies,
];
}Verification automatique
La commande FiscalIntegrityCheckCommand s'execute automatiquement chaque jour a 02:00 UTC :
# Configuration dans le scheduler Laravel
$schedule->command('fiscal:integrity-check')->dailyAt('02:00');Le resultat est enregistre dans la table fiscal_integrity_checks avec le nombre d'entrees verifiees, le nombre d'anomalies trouvees et le chemin du rapport.
5. Clotures
Cloture journaliere
La cloture journaliere s'execute automatiquement a 00:05 UTC via la commande FiscalDailyClosingCommand :
php artisan fiscal:daily-closingElle produit un enregistrement FiscalClosing contenant :
| Champ | Description |
|---|---|
closing_date | Date cloturee |
closing_type | daily |
entries_count | Nombre d'ecritures de la journee |
opening_balance | Solde d'ouverture |
closing_balance | Solde de cloture |
total_operations | Somme des operations de la journee |
fec_export_path | Chemin du FEC journalier (optionnel) |
closed_at | Horodatage de la cloture |
La cloture est elle-meme enregistree comme une ecriture fiscale dans le grand livre (entry_type: closing), garantissant son inclusion dans la chaine de hachage.
Cloture mensuelle
La cloture mensuelle s'execute le 1er de chaque mois via FiscalMonthlyClosingCommand :
php artisan fiscal:monthly-closingElle agrege les clotures journalieres du mois et genere un enregistrement FiscalClosing de type monthly.
Attestation annuelle
A la fin de chaque exercice fiscal, une FiscalAttestation est generee automatiquement :
FiscalAttestation::create([
'tenant_id' => $tenant->id,
'year' => 2025,
'attestation_type' => 'annual',
'software_name' => 'Scell.io', // config('fiscal.attestation.software_name')
'software_version' => '1.2.1', // config('fiscal.attestation.software_version')
'editor_name' => 'QR Communication SAS', // config('fiscal.attestation.editor')
'editor_siret' => '...', // config('fiscal.attestation.editor_siret')
'license_number' => '...', // config('fiscal.attestation.license_number')
'market_release_date' => '2026-01-01',
'attestation_date' => now(),
]);L'attestation est disponible en PDF via l'API : GET /v1/tenant/fiscal/attestation/{year}/download.
6. Ancrage (Preuve d'anteriorite cryptographique)
Strategie : OpenTimestamps / Bitcoin (mecanisme principal)
Scell.io utilise OpenTimestamps comme mecanisme principal et par defaut de preuve d'anteriorite. Le hash de chaque cloture journaliere est ancre dans la blockchain Bitcoin via 3 calendar servers publics gratuits (alice, bob, finney).
Voir ADR-0009 pour la justification complete du choix Bitcoin vs TSA RFC 3161.
Garantie : preuve d'anteriorite irrefutable — l'altération d'un hash ancré dans Bitcoin est cryptographiquement impossible (preuve de travail, 600+ EH/s de hashrate). Le receipt
.otsest autoportant et vérifiable par tout le monde sans tiers de confiance.
Flux d'ancrage OpenTimestamps
sequenceDiagram
participant S as Scell.io
participant C1 as Calendar alice.btc
participant C2 as Calendar bob.btc
participant C3 as Calendar finney
participant BTC as Blockchain Bitcoin
S->>S: Cloture journaliere generee (closing_hash SHA-256)
S->>C1: POST /digest (hash binaire 32 bytes)
S->>C2: POST /digest (hash binaire 32 bytes)
S->>C3: POST /digest (hash binaire 32 bytes)
C1-->>S: Partial receipt (pending)
C2-->>S: Partial receipt (pending)
C3-->>S: Partial receipt (pending)
Note over C1,C3: ~1-6h plus tard : ancrage OP_RETURN dans un bloc Bitcoin
S->>C1: GET /timestamp/{hash} (upgrade)
C1-->>S: Receipt complete (merkle path + block height)
S->>S: Stockage receipt .ots + verification blockstream.infoImplementation
// config/fiscal.php
'anchoring' => [
'provider' => env('FISCAL_ANCHOR_PROVIDER', 'none'), // TSA désactivé par défaut
'auto_anchor' => env('FISCAL_AUTO_ANCHOR', false),
'tsa_url' => env('FISCAL_TSA_URL', 'https://freetsa.org/tsr'),
'tsa_cert_path' => env('FISCAL_TSA_CERT_PATH'),
],
'opentimestamps' => [
'enabled' => env('FISCAL_OTS_ENABLED', true), // OTS activé par défaut
'calendars' => [
'https://alice.btc.calendar.opentimestamps.org',
'https://bob.btc.calendar.opentimestamps.org',
'https://finney.calendar.eternitywall.com',
],
],Verification
Le receipt .ots peut etre verifie :
- En ligne : via l'API des calendars (upgrade du partial vers proof complete)
- Hors-ligne : avec
opentimestamps-client(Python) sur une copie de la blockchain - Via blockstream.info : le service Scell.io valide le block height + block hash
Le receipt est integre en attachment PDF/A-3 dans les certificats de conformite (TenantComplianceCertificateRenderer).
Provider RFC 3161 TSA (optionnel, non active par defaut)
Le provider Rfc3161TsaProvider est disponible mais desactive par defaut (FISCAL_ANCHOR_PROVIDER=none). Il peut etre active en complement d'OpenTimestamps si un client exige un double ancrage TSA + Bitcoin. Ce n'est pas requis pour l'autocertification ISCA.
Verification d'ancrage
// Verifier qu'un ancrage est valide
$isValid = $anchoringService->verifyAnchor($anchor);
// Rejoue la requete TSA et compare avec le token stocke7. Kill Switch
Mecanisme d'arret d'urgence
Le kill switch fiscal est un mecanisme de securite extreme permettant de bloquer toutes les operations fiscales d'un tenant en cas d'urgence (fraude detectee, faille de securite, incoherence comptable grave).
Fonctionnement
stateDiagram-v2
[*] --> Inactif
Inactif --> Actif: activate_kill_switch<br/>(raison obligatoire)
Actif --> Inactif: deactivate_kill_switch<br/>(raison obligatoire)
state Actif {
[*] --> Bloquer_Factures
[*] --> Bloquer_Avoirs
[*] --> Bloquer_Clotures
}Lorsque le kill switch est actif :
- Creation de factures : bloquee (HTTP 423 Locked)
- Creation d'avoirs : bloquee
- Clotures : bloquees
- Consultation : autorisee (lecture seule)
- Export FEC : autorise
Middleware FiscalKillSwitchGuard
Le middleware FiscalKillSwitchGuard intercepte les operations d'ecriture fiscale :
// Applique aux routes : tenant.balance:invoice, tenant.balance:credit_note
// Verifie le statut du kill switch avant toute creation
public function handle(Request $request, Closure $next): Response
{
$tenant = $request->attributes->get('tenant');
$killSwitch = FiscalKillSwitch::where('tenant_id', $tenant->id)
->where('status', 'active')
->first();
if ($killSwitch) {
return response()->json([
'error' => 'Operations fiscales suspendues',
'code' => 'FISCAL_KILL_SWITCH_ACTIVE',
'reason' => $killSwitch->activation_reason,
'activated_at' => $killSwitch->activated_at,
], 423);
}
return $next($request);
}API Kill Switch
| Endpoint | Methode | Scope requis | Description |
|---|---|---|---|
/v1/tenant/fiscal/kill-switch/status | GET | fiscal:read | Statut actuel |
/v1/tenant/fiscal/kill-switch/activate | POST | fiscal:admin | Activer |
/v1/tenant/fiscal/kill-switch/deactivate | POST | fiscal:admin | Desactiver |
Durcissement (2026-06) — activate / deactivate :
- Scope
fiscal:adminfail-closed : doit etre EXPLICITEMENT present danstenant.settings.fiscal_permissions, sinon403 FISCAL_SCOPE_ADMIN_NOT_GRANTED. reasonobligatoire >= 20 caracteres.- Step-up hors-bande en production : le 1er appel envoie un token a l'email de contact du tenant et retourne
403 OOB_CONFIRMATION_REQUIRED; re-soumettre avecconfirmation_token. Une fuite de clesk_*ne suffit donc plus.
Exemple (production, 2 phases) :
# Phase 1 : declenche l'envoi du token (403)
curl -X POST https://api.scell.io/api/v1/tenant/fiscal/kill-switch/activate \
-H "X-API-Key: sk_live_..." -H "Content-Type: application/json" \
-d '{"reason":"Maintenance critique suite a incident de facturation"}'
# -> 403 {"code":"OOB_CONFIRMATION_REQUIRED", ...}
# Phase 2 : confirmer avec le token recu par email
curl -X POST https://api.scell.io/api/v1/tenant/fiscal/kill-switch/activate \
-H "X-API-Key: sk_live_..." -H "Content-Type: application/json" \
-d '{"reason":"Maintenance critique suite a incident de facturation","confirmation_token":"<token-email>"}'Chaque activation/desactivation est enregistree dans :
- Le modele
FiscalKillSwitch(historique complet) - Le
FiscalAuditLog(piste d'audit) - Le grand-livre fiscal (
FiscalEntry, evenementkill_switch_activated/deactivated)
Voir aussi : backend/docs/runbooks/kill-switch-step-up.md et le point de durcissement docs/dev/security-hardening-2026-06.md.
8. Export FEC
Format FEC (Fichier des Ecritures Comptables)
Le FEC est le format standardise par la DGFIP pour le controle fiscal informatise. Scell.io genere un fichier conforme a l'article A.47 A-1 du Livre des Procedures Fiscales.
Structure du fichier
Le fichier FEC contient 18 colonnes obligatoires, separees par un pipe (|) ou une tabulation :
| # | Colonne | Description | Exemple |
|---|---|---|---|
| 1 | JournalCode | Code du journal | VE (ventes) |
| 2 | JournalLib | Libelle du journal | Journal des ventes |
| 3 | EcritureNum | Numero de l'ecriture | VE-2026-001 |
| 4 | EcritureDate | Date de l'ecriture | 20260303 |
| 5 | CompteNum | Numero de compte | 411000 |
| 6 | CompteLib | Libelle du compte | Clients |
| 7 | CompAuxNum | Compte auxiliaire | CLI-ACME |
| 8 | CompAuxLib | Libelle auxiliaire | ACME SAS |
| 9 | PieceRef | Reference de la piece | FA-2026-001 |
| 10 | PieceDate | Date de la piece | 20260303 |
| 11 | EcritureLib | Libelle de l'ecriture | Facture ACME SAS |
| 12 | Debit | Montant debit | 600.00 |
| 13 | Credit | Montant credit | 0.00 |
| 14 | EcritureLet | Lettrage | |
| 15 | DateLet | Date de lettrage | |
| 16 | ValidDate | Date de validation | 20260303 |
| 17 | Montantdevise | Montant en devise | 600.00 |
| 18 | Idevise | Code devise | EUR |
Comptabilisation en partie double
Le FecExportService genere les ecritures en partie double :
Facture (500 EUR HT, TVA 20%) :
| CompteNum | CompteLib | Debit | Credit |
|---|---|---|---|
411000 | Clients | 600.00 | 0.00 |
701000 | Ventes de produits | 0.00 | 500.00 |
44571 | TVA collectee | 0.00 | 100.00 |
Avoir (extourne) :
| CompteNum | CompteLib | Debit | Credit |
|---|---|---|---|
411000 | Clients | 0.00 | 600.00 |
701000 | Ventes de produits | 500.00 | 0.00 |
44571 | TVA collectee | 100.00 | 0.00 |
Nommage du fichier
Le fichier FEC suit la convention de nommage DGFIP :
{SIREN}FEC{AAAAMMJJ}.txtExemple : 123456789FEC20261231.txt
API d'export
# Export FEC pour l'exercice 2025
curl -X GET "https://api.scell.io/api/v1/tenant/fiscal/fec?year=2025&format=pipe" \
-H "X-API-Key: sk_live_..." \
-o 123456789FEC20251231.txtExport forensique
L'export forensique est un export complet incluant :
- Toutes les ecritures fiscales avec snapshots
- Les clotures et attestations
- Le journal d'audit complet
- Les resultats de verification d'integrite
curl -X GET "https://api.scell.io/api/v1/tenant/fiscal/forensic-export?date_from=2025-01-01&date_to=2025-12-31" \
-H "X-API-Key: sk_live_..."9. Regles Fiscales
Regles configurables par tenant
Le systeme de regles fiscales permet aux tenants de definir des alertes et validations personnalisees :
| Type de regle | Description | Exemple |
|---|---|---|
alert | Notification sans blocage | "Alerte si facture > 10 000 EUR" |
validation | Blocage si condition non remplie | "Refuser si SIRET invalide" |
correction | Application automatique | "Arrondir a 2 decimales" |
Structure d'une regle
{
"rule_key": "max_invoice_amount",
"rule_name": "Montant maximum de facture",
"rule_type": "alert",
"condition_json": {
"field": "total_ttc",
"operator": "greater_than",
"value": 10000
},
"action_json": {
"type": "notify",
"channel": "email",
"message": "Facture de montant eleve detectee"
},
"enabled": true
}API Regles
| Endpoint | Methode | Description |
|---|---|---|
/v1/tenant/fiscal/rules | GET | Lister les regles |
/v1/tenant/fiscal/rules | POST | Creer une regle |
/v1/tenant/fiscal/rules/{id} | PUT | Modifier une regle |
/v1/tenant/fiscal/rules/{key} | GET | Detail d'une regle |
/v1/tenant/fiscal/rules/{key}/history | GET | Historique d'application |
/v1/tenant/fiscal/rules/replay | POST | Rejouer les regles |
/v1/tenant/fiscal/rules/export | GET | Exporter en JSON |
10. API Fiscale
Endpoints complets
Tous les endpoints fiscaux sont sous le prefixe /api/v1/tenant/fiscal/ et necessitent une cle secrete tenant (X-API-Key: sk_live_* / sk_test_*).
| Endpoint | Methode | Scope | Description |
|---|---|---|---|
/fiscal/compliance | GET | fiscal:read | Statut de conformite |
/fiscal/entries | GET | fiscal:read | Ecritures fiscales |
/fiscal/closings | GET | fiscal:read | Liste des clotures |
/fiscal/closings/daily | POST | fiscal:write | Cloture journaliere manuelle |
/fiscal/integrity | GET | fiscal:read | Verification d'integrite |
/fiscal/integrity/history | GET | fiscal:read | Historique des verifications |
/fiscal/integrity/{date} | GET | fiscal:read | Verification pour une date |
/fiscal/attestation/{year} | GET | fiscal:read | Attestation annuelle |
/fiscal/attestation/{year}/download | GET | fiscal:read | Telecharger PDF |
/fiscal/fec | GET | fiscal:read | Export FEC |
/fiscal/forensic-export | GET | fiscal:read | Export forensique |
/fiscal/anchors | GET | fiscal:read | Liste des ancrages TSA |
/fiscal/rules | GET | fiscal:read | Regles fiscales |
/fiscal/rules | POST | fiscal:write | Creer une regle |
/fiscal/rules/{id} | PUT | fiscal:write | Modifier une regle |
/fiscal/rules/replay | POST | fiscal:write | Rejouer les regles |
/fiscal/kill-switch/status | GET | fiscal:read | Statut kill switch |
/fiscal/kill-switch/activate | POST | fiscal:admin | Activer |
/fiscal/kill-switch/deactivate | POST | fiscal:admin | Desactiver |
Scopes de permission
Le systeme fiscal utilise 3 niveaux de permission (configurable par tenant dans settings.fiscal_permissions) :
| Scope | Permissions |
|---|---|
fiscal:read | Consultation du grand livre, clotures, FEC, attestation, integrite, regles |
fiscal:write | Declenchement de clotures, creation/modification de regles |
fiscal:admin | Activation/desactivation du kill switch |
Configuration
# .env
FISCAL_COMPLIANCE_ENABLED=true
FISCAL_EDITOR_NAME="QR Communication SAS"
FISCAL_EDITOR_SIRET="12345678900001"
FISCAL_LICENSE_NUMBER="ISCA-AUTO-2026-001"
FISCAL_MARKET_RELEASE_DATE="2026-01-01"
FISCAL_ANCHOR_PROVIDER=rfc3161_tsa # none | rfc3161_tsa
FISCAL_AUTO_ANCHOR=false
FISCAL_TSA_URL=https://freetsa.org/tsr
FISCAL_RETENTION_YEARS=6Commandes Artisan
# Cloture journaliere (normalement automatique a 00:05 UTC)
php artisan fiscal:daily-closing
# Cloture mensuelle (normalement automatique le 1er du mois)
php artisan fiscal:monthly-closing
# Verification d'integrite (normalement automatique a 02:00 UTC)
php artisan fiscal:integrity-check
# Detection de changement de version logicielle
php artisan fiscal:check-version-change11. Seuils Auto-Entrepreneur (Loi 2025-1044)
Scell.io suit, par sous-tenant auto-entrepreneur, les seuils legaux de franchise en base de TVA et de plafond du micro-regime, definis par la loi 2025-1044. Ces seuils sont des regles fiscales datees (FiscalRule), pas des constantes en dur : ils peuvent etre rejoues a une date passee et evolueront sans redeploiement.
| Seuil | Base | Majore |
|---|---|---|
| Franchise en base de TVA | 37 500 € | 41 250 € |
| Plafond micro-regime (CA) | 83 600 € | 91 900 € |
Le CA HT cumule est suivi par categorie de revenu. Chaque jauge expose un niveau d'alerte (warning_80 … micro_ceiling_exceeded) et une date de franchissement projetee.
Information, pas conseil fiscal. Les reponses incluent un champ
disclaimer: le suivi est purement informatif et ne constitue pas un conseil fiscal.
Endpoints
| Methode | Endpoint | Description |
|---|---|---|
| GET | /api/v1/sub-tenants/{id}/thresholds | Jauges de seuils (lecture) |
| POST | /api/v1/sub-tenants/{id}/thresholds/simulate | Simulateur pre-emission (lecture seule) |
| PATCH | /api/v1/sub-tenants/{id}/fiscal-status | Statut fiscal declare |
Simulateur pre-emission. POST .../thresholds/simulate projette les jauges comme si une facture hypothetique de amount (HT) en categorie category etait emise — sans rien enregistrer. Cela permet d'alerter l'utilisateur AVANT d'emettre s'il franchit un seuil.
Statut fiscal declare. PATCH .../fiscal-status met a jour le regime, le vat_status, le type d'activite, la date de debut et le numero de TVA. Basculer vat_status a liable fait que Scell.io facture la TVA sur les factures suivantes et retire la mention art. 293 B ; un vat_number devient alors requis.
curl https://api.scell.io/api/v1/sub-tenants/{id}/thresholds \
-H "X-API-Key: sk_live_xxx"Les notifications asynchrones de franchissement sont produites par la commande planifiee
ae:monitor-thresholds(distincte du GET, qui est a la demande).
12. Scellement des Devis (PAdES + Bitcoin)
A l'acceptation d'un devis signe, Scell.io scelle le PDF en deux temps, dans la continuite de l'approche ISCA (chaine de hachage + ancrage OpenTimestamps deja utilises pour les clotures fiscales — voir section 6) :
- Signature PAdES : le PDF du devis est signe electroniquement au format PAdES (PDF Advanced Electronic Signatures).
- Ancrage Bitcoin : l'empreinte SHA-256 du PDF scelle est soumise aux calendriers OpenTimestamps, qui l'ancrent dans un bloc Bitcoin — preuve d'integrite et d'anteriorite infalsifiable et verifiable publiquement.
L'objet sealing est expose sur la ressource Devis une fois le sceau pose.
Champ sealing.* | Type | Description |
|---|---|---|
is_sealed | bool | true une fois le devis scelle (seul champ non nullable) |
pades_signed_at | datetime | Date de la signature PAdES |
signed_pdf_sha256 | string | Empreinte SHA-256 du PDF scelle (= valeur ancree Bitcoin) |
ots_status | enum | pending → confirmed (ou failed) |
ots_submitted_at | datetime | Soumission aux calendriers OpenTimestamps |
ots_bitcoin_confirmed_at | datetime | Confirmation de l'ancrage dans un bloc Bitcoin |
bitcoin_block_height | int | Hauteur du bloc Bitcoin d'ancrage |
ots_proof_base64 | string | Receipt OpenTimestamps .ots (BYTEA → base64) |
Cycle de vie du statut d'ancrage :
null (pas encore scelle) → pending (soumis a OTS) → confirmed (bloc Bitcoin)
↘ failed (a rejouer)Le receipt
.ots(ots_proof_base64) suit le meme pattern d'accesseur BYTEA → base64 queFiscalClosing.ots_proof. Un integrateur avance peut le verifier hors-ligne avec le clientots verify.