Quick start
This guide runs an income tax calculation in a single request. The examples target the local development server
(npm run dev, port 3001): no public address is open to developers yet (phase 5 of the roadmap).
The requests and responses of this guide are produced by the documentation itself: each example is run against the
engine by the tests (packages/api/src/openapi/openapi.test.ts), and the blocks between the debut-exemple and
fin-exemple markers are rewritten by npm run docs:api. No figure in them is typed by hand. They are the same
examples as in the French guide, and the API answers them in French: field identifiers, choice values and messages
are French (see Errors and The trace for the parts that exist in English).
1. Find the calculator
GET /v1/calculators lists the calculators served. Each one has a slug (route identifier), a version and, for
income tax, the year of the income (incomeYear). The impot-revenu-2026 calculator computes the tax of the 2026
campaign, that is, the tax on 2025 income.
2. Know its fields
GET /v1/calculators/{slug}/schema returns the JSON Schema of the inputs: identifier of each field, box of the
official form (x-physcal-case), type, bounds, allowed choices with their French labels (x-physcal-libelles) and
default value. A missing field takes its default value; an unknown field is refused. For a calculator with a few fields:
curl -s "http://localhost:3001/v1/calculators/calcul-tva-2025/schema"
GET /v1/calculators/{slug}/fields/search?q=... finds a field from a few words. The search reads the French labels:
query it in French (« revenus fonciers », « garde d'enfant ») or with a box code (« 1AJ »).
3. Calculate
A single person who received wages and salaries (box 1AJ):
curl -s -X POST "http://localhost:3001/v1/calculators/impot-revenu-2026/calculate?trace=false" \
-H "Content-Type: application/json" \
-d '{"filingStatus":"celibataire","salaire1AJ":30000}'
In TypeScript:
const res = await fetch("http://localhost:3001/v1/calculators/impot-revenu-2026/calculate?trace=false", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"filingStatus": "celibataire",
"salaire1AJ": 30000
}),
});
const data = await res.json();
In Python:
import requests
res = requests.post(
"http://localhost:3001/v1/calculators/impot-revenu-2026/calculate?trace=false",
json={
"filingStatus": "celibataire",
"salaire1AJ": 30000
},
)
data = res.json()
Response: status 200, excerpt of result (irFinal, revenuFiscalReference, nombreDeParts, tauxMarginalImposition, tauxMoyenImposition).
{
"result": {
"irFinal": "1564",
"revenuFiscalReference": "27000",
"nombreDeParts": "1",
"tauxMarginalImposition": "11",
"tauxMoyenImposition": "5.79"
}
}
Each output of result is a decimal string (see Amounts and rounding). irFinal is the income tax,
revenuFiscalReference the reference taxable income (revenu fiscal de référence), nombreDeParts the number of tax
units of the income splitting (quotient familial), and the two rates are expressed in points. ?trace=false leaves
out the trace; without this parameter, the response also carries steps, the ordered steps of the calculation with
their formula and their citations (see The trace).
4. Amounts written the French way
An amount can be sent as a JSON number or as a string, with a decimal comma or a decimal point and spaces between the thousands:
curl -s -X POST "http://localhost:3001/v1/calculators/impot-revenu-2026/calculate?trace=false" \
-H "Content-Type: application/json" \
-d '{"filingStatus":"marie_pacs","enfantsAChargeEntiere":2,"salaire1AJ":"42 000","salaire1BJ":"27 500,50"}'
Response: status 200, excerpt of result (irFinal, nombreDeParts, revenuNetImposableCalcule).
{
"result": {
"irFinal": "2951",
"nombreDeParts": "3",
"revenuNetImposableCalcule": "62551"
}
}
5. Errors
A refused input answers 400 with the common error envelope, a stable code and a message in French. The faulty field
is named by field, and the message gives the allowed values:
curl -s -X POST "http://localhost:3001/v1/calculators/impot-revenu-2026/calculate" \
-H "Content-Type: application/json" \
-d '{"filingStatus":"concubinage","salaire1AJ":30000}'
Response: status 400.
{
"error": {
"code": "VALIDATION_ERROR",
"messageFr": "La valeur « concubinage » du champ Situation du foyer fiscal n'est pas autorisée. Valeurs admises : celibataire (Célibataire), marie_pacs (Marié(e) / Pacsé(e)), divorce (Divorcé(e) / Séparé(e)), veuf (Veuf / Veuve).",
"field": "filingStatus",
"requestId": "00000000-0000-0000-0000-000000000000"
}
}
The full catalogue of codes is in Errors.
Disclaimer
The results are those of the engine applied to the input sent; they do not constitute tax advice.