Skip to main content

Patterns

Quotes, deposit and balance invoices

From signed quote to deposit invoice (VAT due) then balance

The quote → deposit → balance cycle is a sensitive fiscal pattern. A quote (`quotes`) lives outside the ISCA chain (separate SHA-256 audit trail). Once accepted, it converts into a deposit invoice (`invoice_type='deposit'`, Factur-X code 386): VAT becomes immediately due (French CGI art. 289). The balance (`invoice_type='balance'`, code 380) automatically deducts emitted deposits via group BG-22 code '80', and its VAT is no longer due. Anti-pattern: emitting the same deposit twice or re-numbering at submit (gap in the ISCA sequence). The SDK assigns a provisional DRAFT- number and only allocates the final number at emission. Convert as many deposits as needed (`convertToDeposit`, N times) but a single balance (`convertToBalance`).

Key facts

  • Quotes: SHA-256 audit chain separate from fiscal ISCA
  • Deposit = Factur-X type 386, VAT due immediately (CGI 289)
  • Balance = type 380, auto deduction of deposits (BG-22 code '80')
  • N deposits possible, a single balance per quote
  • Signable public link: `quotes.send()` / `regeneratePublicLink()` → `public_link`
  • Non-persisted PDF preview: `POST /quotes/preview`

Code example

import { ScellApiClient } from '@scell/sdk'; // v3.5.0

const client = new ScellApiClient({ apiKey: process.env.SCELL_API_KEY! });

// 1. Créer un devis (hors chaîne ISCA)
const { data: quote } = await client.quotes.create({
  issue_date: '2026-06-15',
  valid_until: '2026-07-15',
  currency: 'EUR',
  buyer_name: 'Acme SARL',
  buyer_siret: '98765432109876',
  buyer_country: 'FR',
  buyer_address: { line1: '2 av. Demo', postal_code: '69001', city: 'Lyon', country: 'FR' },
  total_ht: 5000, total_tax: 1000, total_ttc: 6000,
  signature_required: true,
  lines: [{ description: 'Prestation conseil', quantity: 1, unit_price: 5000, vat_rate: 20, total_ht: 5000, total_tax: 1000, total_ttc: 6000 }],
});

// 2. Aperçu PDF non persisté (avant envoi)
const pdf = await client.quotes.preview({
  issue_date: '2026-06-15', valid_until: '2026-07-15',
  buyer_name: 'Acme SARL', buyer_country: 'FR',
  total_ht: 5000, total_tax: 1000, total_ttc: 6000,
  lines: [{ description: 'Conseil', quantity: 1, unit_price: 5000, vat_rate: 20, total_ht: 5000, total_tax: 1000, total_ttc: 6000 }],
});

// 3. Envoyer le devis → lien public signable
const { public_link } = await client.quotes.send(quote.id, { send_email: true });
console.log('Lien client :', public_link);

// 4. Acompte 30 % (TVA exigible — Factur-X 386)
const { data: deposit } = await client.quotes.convertToDeposit(quote.id, {
  deposit_percent: 30,
  output_format: 'facturx',
  due_date: '2026-07-01',
});
console.log('Acompte :', deposit.invoice_number);

// 5. Solde (déduit l'acompte — Factur-X 380)
const { data: balance } = await client.quotes.convertToBalance(quote.id, {
  due_date: '2026-08-01',
  output_format: 'facturx',
});
console.log('Solde :', balance.invoice_number);

See also

Your cookie preferences

We use cookies to improve your experience. Essential cookies are always active. Cookie policy.