Stable Pro

Stable Pro API · v1

Conventions

Montants, dates, codes, taxes, listes et filtres, langues, versions.

Requêtes et réponses

GET lit. Les réponses sont en JSON, avec des noms de champs en anglais et en snake_case. Chaque réponse porte Cache-Control: no-store. Chaque objet a un champ object qui dit ce qu'il est (charge, payment, event…).

Montants

Les montants sont des entiers dans l'unité mineure de leur devise (ISO 4217), avec la devise à côté : 300,00 € s'écrit 30000 avec currency: "EUR" ; 3 000 ¥ s'écrit 3000 ; 25,500 KWD s'écrit 25500.

Chaque montant est le total que paie le client (amount_basis: "gross") : quand Stable Pro calcule la TVA, le total l'inclut, et Stable Pro donne à côté le hors taxe et la taxe. Un logiciel qui applique sa propre taxe à un montant de Stable Pro la déduit de ce total, il ne l'ajoute pas.

Les montants sont signés quand le sens compte : une correction qui réduit un débit est négative, un remboursement est négatif.

Dates

  • Les dates de calendrier (échéances, périodes, la date d'un encaissement) sont au format YYYY-MM-DD ; les mois au format YYYY-MM.
  • Les instants (created_at, issued_at, occurred_at…) sont en RFC 3339, en UTC : 2026-11-10T14:32:05.120Z.
  • Le mois comptable (accounting_month) est calculé par Stable Pro dans le fuseau horaire de l'écurie : c'est le plus tardif entre le mois de rattachement et le mois où le fait a été enregistré. Vous n'avez jamais de calcul de fuseau horaire à faire.

Le fuseau horaire, la devise, le pays et la langue de l'écurie sont dans GET /organization.

Des codes, pas des textes

Le contrat expose des codes — action, reason, category, origin, les types de débit, les types d'événement — jamais des phrases dans une langue. Les noms destinés aux personnes viennent du dictionnaire, dans la langue demandée :

curl "https://app.stable-pro.com/api/v1/codes?lang=de" -H "Authorization: Bearer sp_live_…"

GET /codes liste chaque famille de codes, où chaque famille apparaît (fields, par exemple adjustment.reason) et un name par code. Le nom d'un reason dépend de son action : cherchez-le avec les deux.

Les listes de codes sont ouvertes : une nouvelle valeur peut arriver au sein de la v1. Votre intégration doit accepter un code qu'elle ne connaît pas encore (et peut lire son nom dans /codes). taxonomy_version indique quelle version de la taxonomie des corrections a produit une ligne.

Là où une liste standard existe, c'est elle qui est utilisée : devise ISO 4217, pays ISO 3166-1 et subdivision ISO 3166-2 (IT-MI, US-OH), identifiants fiscaux avec un schéma ISO 6523, catégorie de taxe UNCL 5305 (S, Z, E, AE, K, G, O), unités UNECE Rec. 20 (MON, ANN, C62).

Taxes

Chaque débit et chaque correction indiquent :

  • tax_calculated_by : stable_pro (Stable Pro calcule la TVA et la donne), ou external — ce qui signifie seulement que Stable Pro ne la calcule pas : cela ne veut pas dire que la taxe est nulle ;
  • tax_treatment : standard_rated, zero_rated, not_calculated, ou undetermined (un fait plus ancien pour lequel on ne le sait pas) ;
  • taxable_amount et taxes[] : une liste, même avec un seul élément — { type, jurisdiction, category, rate_bp, amount }. Les taux sont en points de base : 22 % s'écrit 2200.

Un débit se lit tel qu'il est maintenant : son montant et ses taxes sont sa naissance, plus ses corrections, plus tout changement de taxe ultérieur.

Listes

Une liste contient tous les faits de son type, payés ou non : GET /charges, ce sont tous les débits aux clients (jamais la rémunération du personnel) ; GET /customers, tous ceux qui ont au moins un débit, membres ou personnel.

Les listes fonctionnent par curseur :

GET /charges?limit=100&starting_after=<id du dernier élément que vous avez lu>
  • limit de 1 à 100 (25 s'il manque) ;
  • l'enveloppe est { "object": "list", "data": [...], "has_more": true } ; redemandez avec starting_after = l'id du dernier élément ;
  • l'ordre part toujours du plus ancien : created_at, puis id (reçus : issued_at, puis id).

Filtres

Certaines listes se restreignent avec des filtres, qui s'appliquent ensemble, avec limit et avec le curseur. Par exemple, les débits d'un client sur un mois :

GET /charges?customer=<id du client>&accounting_month=2026-10
ListeFiltres
GET /chargescustomer, accounting_month
GET /adjustmentscharge, accounting_month
GET /paymentscustomer
GET /credit-entriescustomer
GET /receiptscustomer, payment

customer, charge et payment attendent un identifiant ; accounting_month attend YYYY-MM : c'est le mois comptable, le mois où le fait compte (voir « Dates » plus haut).

Paramètres inconnus et valeurs non valides

Un paramètre que l'endpoint ne connaît pas n'est jamais ignoré : la réponse est 400 invalid-request, et invalid_param indique lequel. Ainsi, un filtre mal écrit (accountingmonth au lieu de accounting_month) ne renvoie jamais la liste entière. Il en va de même pour un limit, un curseur ou un filtre dont la valeur n'est pas valide. La clé et les autorisations sont contrôlées d'abord : sans clé, la réponse reste 401 ; sans l'autorisation, 403.

Les listes servent à chercher et à vérifier ; pour rester synchronisé, lisez les événements (Événements).

Langues

Le contrat est en anglais et ne change jamais avec la langue. Les phrases destinées aux personnes — le detail d'une erreur, les noms dans /codes — arrivent dans la langue demandée : ?lang= l'emporte sur Accept-Language ; sans l'un ni l'autre, anglais. Disponibles : en, it, fr, de, es. La réponse indique la langue dans Content-Language.

Versions

La version est dans le chemin : /api/v1/. Au sein de la v1, il n'y a que des ajouts : un nouveau champ, un nouvel endpoint, une nouvelle valeur d'une liste de codes. Tout ce qui casserait une intégration est une v2, avec au moins un an de coexistence et les en-têtes Deprecation et Sunset.

Les reçus ne sont pas des documents fiscaux

Les reçus de Stable Pro confirment un paiement (fiscal_document: false). Le document fiscal est émis par votre logiciel. L'écurie peut choisir de ne pas donner les reçus de Stable Pro à ses clients tant que votre logiciel est connecté : GET /organization l'indique dans receipts_shown_to_customers. Les reçus existent quand même, numérotés, et vous pouvez les lire.