Skip to main content

Patterns

Reusable buyers registry

Reference a buyer by `buyer_id` without breaking fiscal immutability

The `buyers` registry stores a buyer (SIRET, VAT, billing and shipping addresses) and reuses it via `buyer_id` on each invoice. Scope is strict per `(tenant_id, sub_tenant_id)` pair: a tenant never sees another's buyers (anti-IDOR via 404). Key compliance point: the `invoices.buyer_id` link is a soft UUID, WITHOUT cascade FK. The denormalised `buyer_*` columns snapshotted on the invoice remain the immutable source of truth — editing a buyer later NEVER affects already-emitted invoices (ISCA). On invoice creation, supply either `buyer_id` (the API re-snapshots the current state) or flat `buyer_*` fields (the API upserts a buyer by SIRET then email). The shipping address (BG-13) is emitted in Factur-X only when it differs from the billing address.

Key facts

  • Strict scope (tenant_id, sub_tenant_id) — anti-IDOR 404
  • `invoices.buyer_id` soft UUID, no cascade FK
  • Denormalised `buyer_*` columns = immutable ISCA truth
  • Deterministic upsert by SIRET (B2B) then email (B2C)
  • BG-13 shipping address omitted when identical to billing
  • Endpoints: `GET/POST/PATCH/DELETE /api/v1/buyers`

Code example

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

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

// 1. Enregistrer un acheteur réutilisable
const { data: buyer } = await client.buyers.create({
  name: 'Acme SARL',
  country: 'FR',
  siret: '98765432109876',
  vat_number: 'FR98765432109',
  email: 'compta@acme.fr',
  billing_address: { line1: '2 av. Demo', postal_code: '69001', city: 'Lyon', country: 'FR' },
  // Adresse de livraison distincte → BG-13 émise dans le Factur-X
  shipping_address: { name: 'Entrepôt Lyon', line1: '10 rue du Stock', postal_code: '69007', city: 'Lyon', country: 'FR' },
});

// 2. Facturer en référençant l'acheteur (snapshot immutable côté facture)
const invoice = await client.invoices.create({
  format: 'factur-x',
  profile: 'EN16931',
  currency: 'EUR',
  buyer_id: buyer.id,
  lines: [{ description: 'Licence annuelle', quantity: 1, unit_price: 1200, vat_rate: 20 }],
});
console.log('Facture :', invoice.id, '→ buyer figé sur la facture');

// 3. Modifier le buyer plus tard n'altère PAS les factures déjà émises (ISCA)
await client.buyers.update(buyer.id, { email: 'finance@acme.fr' });

See also

Your cookie preferences

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