Lire et synchroniser
Parcourir une liste avec le curseur, ne relire que ce qui a changé, et comprendre la forme des données
Les endpoints de lecture
| Endpoint | Réponse |
|---|---|
GET /crm/entities | les entités que la clé peut utiliser, { data } |
GET /crm/entities/{name} | une entité et ses champs |
GET /crm/entities/{name}/records | une page de fiches |
GET /crm/entities/{name}/records/{id} | une fiche |
GET /facture/invoices | une page de factures |
GET /facture/invoices/{id} | une facture et ses lignes |
GET /facture/quotes | une page de devis |
GET /facture/quotes/{id} | un devis et ses lignes |
GET /facture/legal-entities | les entités légales émettrices, { data } |
Les listes de factures et de devis renvoient tous les statuts, brouillons et
archives compris : utilisez status pour filtrer.
Pagination
Une liste renvoie une page et un curseur :
{ "data": [ … ], "nextCursor": "eyJ1Ijoi…" }Pour lire la page suivante, repassez nextCursor tel quel dans le paramètre
cursor. Quand nextCursor vaut null, la liste est terminée. Il n'y a pas
de total : compter à chaque page ralentirait toutes les lectures.
limit: de 1 à 200, 50 par défaut.- Le curseur est opaque : ne le construisez pas, ne le modifiez pas. Un curseur
que l'API n'a pas émis reçoit
400 bad-request, jamais un retour silencieux à la première page. - L'ordre est fixe : du plus ancien changement au plus récent (
updatedAtcroissant, puisid).
Ne relire que ce qui a changé
Gardez le updatedAt du dernier élément lu, et repassez-le dans
updatedSince à la synchronisation suivante :
curl "https://acme.deltia.co/api/v1/crm/entities/societes/records?updatedSince=2026-09-21T08:00:00.000Z" \
-H "Authorization: Bearer dlt_…"updatedSince est inclusif : l'élément modifié à cet instant exact revient.
Un doublon se dédoublonne sur id ; une modification perdue ne se rattrape pas.
La date suit RFC 3339 : en UTC (2026-09-21T08:00:00.000Z) ou avec un décalage
(2026-09-21T10:00:00.000+02:00). Dans l'URL, encodez le + en %2B, sinon
il est lu comme une espace et la requête répond 400.
Factures et devis synchronisés avec la plateforme de facturation
électronique : un document mis à jour par la plateforme prend l'instant de
mise à jour de la plateforme, qui peut être antérieur à votre dernière
synchronisation. Relisez une petite marge (quelques heures) plutôt que de vous
fier au seul dernier updatedAt.
Suppressions, désactivations et sorties de périmètre
Par défaut, une liste de fiches ne renvoie que les fiches actives et non
supprimées. Une synchronisation qui ne passe que updatedSince ne voit donc
ni une suppression ni une désactivation : la fiche disparaît de la liste sans
laisser de trace, et votre copie la garde.
- Suppression : passez
includeDeleted=true. Une fiche supprimée revient alors comme une pierre tombale, réduite à trois propriétés :id,deletedAt, qui porte l'instant de la suppression, etupdatedAt, qui prend la même valeur, si bien qu'elle ressort à la synchronisation suivante. Elle ne porte nifieldValues, nidisplayName, ni périmètres, ni fichiers : le contenu d'une fiche supprimée ne sort pas. Sur une fiche vivante,deletedAtvautnull; c'est lui qui distingue les deux formes. La rechercheqne porte que sur les fiches non supprimées : combinée àincludeDeleted=true, elle ne renvoie aucune pierre tombale. Une fusion de deux fiches supprime la fiche absorbée : elle revient aussi en pierre tombale. La lecture d'une fiche supprimée par son identifiant (GET /crm/entities/{name}/records/{id}) répond404 not-found. - Désactivation : passez
includeInactive=true. Une fiche désactivée revient avecisActive: false. - Sortie des périmètres de la clé : une fiche déplacée vers un périmètre que
la clé ne voit pas sort de toutes les listes, sans pierre tombale. L'API ne peut
pas vous la signaler sans révéler qu'elle existe. Seule une
resynchronisation complète périodique (une liste parcourue sans
updatedSince, avecincludeInactive=true) la rattrape : toute fiche de votre copie absente de ce parcours n'est plus visible par la clé. Une fréquence quotidienne ou hebdomadaire suffit en général ; elle dépend de l'importance, pour votre usage, d'une fiche restée en trop.
curl "https://acme.deltia.co/api/v1/crm/entities/societes/records?updatedSince=2026-09-21T08:00:00.000Z&includeDeleted=true&includeInactive=true" \
-H "Authorization: Bearer dlt_…"Filtres
| Liste | Paramètres |
|---|---|
| Fiches CRM | q (recherche comme dans l'application), updatedSince, includeInactive et includeDeleted (true ou false, false par défaut) |
| Factures et devis | q (numéro, titre, acheteur, description, notes, montant TTC — comme dans l'application), status (liste séparée par des virgules), legalEntityId, updatedSince |
| Entités légales | includeArchived (true ou false, false par défaut) |
Un statut inconnu reçoit 400 validation, avec la
liste des statuts acceptés dans errors[].allowed. Les booléens n'acceptent
que true et false.
La forme d'une fiche
{
"id": "8f2…",
"scopeIds": ["…"],
"displayName": "Acme",
"isActive": true,
"fieldValues": {
"raison_sociale": "Acme",
"effectif": 42,
"contact_principal": { "id": "c41…", "displayName": "Marie Curie" }
},
"createdAt": "2026-09-01T10:00:00.000Z",
"updatedAt": "2026-09-21T08:12:44.000Z",
"deletedAt": null
}fieldValues ne contient que les champs que la clé peut lire. Selon le type du
champ :
| Type de champ | Valeur |
|---|---|
| texte, email, téléphone, URL | chaîne |
| nombre, montant, pourcentage, formule, somme | nombre |
| date | AAAA-MM-JJ ; date et heure : ISO 8601 |
| case à cocher | booléen |
| liste | la valeur de l'option ; liste multiple : tableau de valeurs |
| lien vers une fiche | { id, displayName } ; lien multiple : tableau |
| produit du catalogue | { id, displayName: null } : la clé n'a pas accès au catalogue |
| utilisateur | l'identifiant, ou un tableau d'identifiants |
| crédit | { balance, entries }, chaque mouvement { id, date, amount, note } |
| journal | tableau d'entrées { id, date, values, doneAt, dueAt } |
| fichier, image | tableau de descripteurs (voir Fichiers et PDF) |
Un champ non renseigné est absent ou null. Deux cas sont volontairement
absents de l'API : les champs de service web, et les listes inverses d'une
relation (« les contacts de cette société »). Lisez une relation depuis
l'autre bout : le champ lien de la fiche liée.
Le displayName d'une fiche liée vaut null quand cette fiche est hors des
périmètres de la clé : son identifiant reste, son nom ne sort pas.
Les montants d'une facture ou d'un devis
Les montants sont des nombres, arrondis au centime. subtotalHt est la somme
des lignes avant la remise globale. Le total se reconstitue ainsi :
totalTtc = subtotalHt − globalDiscountAmount + totalTax + shippingAmount + otherCharges| Champ | Sens |
|---|---|
subtotalHt | somme HT des lignes, remises de ligne déduites |
globalDiscountAmount | remise globale appliquée au HT |
globalDiscountPercentage | le pourcentage saisi, à titre indicatif : seul globalDiscountAmount compte |
totalTax | TVA après remise globale |
shippingAmount | frais de port |
otherCharges | autres frais |
totalTtc | total TTC du document |
La base HT réellement taxée vaut subtotalHt − globalDiscountAmount.
Factures et avoirs
GET /facture/invoices renvoie aussi les avoirs. Le champ type les
distingue : invoice ou credit_note. Sur un avoir, creditedInvoiceId
désigne la facture qu'il annule ; il vaut null sur une facture.
Les montants d'un avoir sont toujours exposés en valeur absolue (positive) :
lignes, totaux, remise globale, frais, montants payé et restant. C'est vrai
que l'avoir soit en brouillon ou déjà synchronisé avec la plateforme de
facturation électronique ; subtotalHt reste la somme HT de ses lignes. Le
sens est porté par type seul : pour un credit_note, comptabilisez ces
montants au crédit du client (en négatif si votre logiciel attend un signe).