PhynanxPhynanx

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.