Patterns
Factures récurrentes et abonnements
Cadence mensuelle/annuelle, brouillon vs auto-envoi, idempotence d'occurrence
Un profil de facture récurrente (`recurring_invoices`) décrit un acheteur, des lignes et une cadence (`recurrence`: jour/semaine/mois/année + `day_of_month`/`day_of_week`). À chaque échéance, le scheduler émet une occurrence. Deux modes : `emission_mode='draft'` stage chaque occurrence en brouillon (révision manuelle avant envoi) ; `auto_send` émet ET envoie automatiquement. La terminaison se contrôle via `end_mode` (`never`, `on_date` + `end_date`, `after_occurrences` + `max_occurrences`). Le pattern fiscal critique : chaque occurrence est une facture ISCA pleine et entière (chaîne de hash, numérotation séquentielle). L'idempotence de l'émission empêche qu'un re-run du scheduler ne double une occurrence le même jour. `runNow()` force une émission immédiate (test/rattrapage) ; `pause()`/`activate()` suspendent la cadence sans perdre l'historique.
À retenir
- Cadence : `recurrence.interval_unit` (day/week/month/year) + day_of_*
- `emission_mode` : `draft` (révision) ou `auto_send`
- `end_mode` : never / on_date / after_occurrences
- Chaque occurrence = facture ISCA pleine (hash + séquence)
- Idempotence : un re-run du scheduler ne double pas l'occurrence
- Endpoints : `/api/v1/recurring-invoices` + `/{id}/run-now`, `/pause`, `/activate`
Exemple de code
import { ScellApiClient } from '@scell/sdk'; // v3.5.0
const client = new ScellApiClient({ apiKey: process.env.SCELL_API_KEY! });
// 1. Profil d'abonnement mensuel auto-envoyé, le 1er de chaque mois
const profile = await client.recurringInvoices.create({
title: 'Abonnement mensuel — Acme',
buyer_id: 'buyer-uuid', // ou champs buyer_* inline
currency: 'EUR',
output_format: 'facturx',
emission_mode: 'auto_send',
start_date: '2026-07-01',
recurrence: { interval_unit: 'month', interval_count: 1, day_of_month: 1 },
end_mode: 'never',
notify_before_days: 3,
lines: [{ description: 'Abonnement SaaS', quantity: 1, unit_price: 99, vat_rate: 20 }],
});
// 2. Lister les occurrences déjà émises
const { data: occurrences } = await client.recurringInvoices.occurrences(profile.id, { per_page: 12 });
console.log(`${occurrences.length} occurrences émises`);
// 3. Émission immédiate (rattrapage / test)
const run = await client.recurringInvoices.runNow(profile.id);
console.log('Occurrence forcée :', run);
// 4. Suspendre puis réactiver sans perdre l'historique
await client.recurringInvoices.pause(profile.id);
await client.recurringInvoices.activate(profile.id);