Salary gross to net
The net pay left from a gross, with the breakdown by component: every contribution separately, with its own computation base, the rate applied and the legislation behind that rate. An accountant cannot use a number they cannot justify.
⚠️ POST, not GET, and with zero retention. The input is somebody's salary: in a GET it would end up in access logs, in the browser history and in the Referer header. Nothing you send is written anywhere — not to the database, not to a cache, not to a log.
⚠️ Order matters and so does rounding. Pension and health contributions are computed on the whole gross, each rounded separately to the leu; only then is the personal allowance deducted and the income tax applied. Rounded only at the end, the figure comes out a leu away from the payslip for a share of salaries.
⚠️ The personal allowance is covered across the whole scale in art. 77(4) — all 41 bands, across five columns of dependants, transcribed from the legislative portal. The band is chosen by how far the gross exceeds the minimum wage, and the percentage is applied to the minimum wage, not to the gross. Above the minimum wage plus 2,000 lei the allowance is zero by law.
⚠️ If a band were nevertheless missing — today none is — the response does not assume zero but returns an interval: net comes back null and beside it net_interval carries the bounds, which remain exact. The mechanism is kept as a safety net, not because it is needed.
⚠️ If any rate used is flagged de_verificat, the response says so at response level, not buried inside the breakdown.
Request body
Sent as JSON in the request body (Content-Type: application/json) — not in the query string.
YYYY-MM-DD; defaults to today. Determines every rate used.
intreaga (default) or partiala.
intreagapartiala
it, constructii, agroalimentar. Must be active at the requested date.
{
"brut": 5000
}
{
"brut": 4000,
"persoane_intretinere": 2
}
{
"brut": 4050
}
{
"brut": 15000,
"facilitate": "it",
"la_data": "2023-06-15"
}
{
"brut": 2500,
"norma": "partiala"
}
Query parameters
How it behaves
- The net remaining from a gross, with a component breakdown: each contribution separately, with its calculation base, the rate applied and the legal act behind that rate. An accountant cannot use a number they cannot justify, so the breakdown is not optional.
- ⚠️ POST, not GET, and with zero retention. The input is someone salary: in a
GETit would land in the server access logs, in the browser history and in theRefererheader of the next page. Nothing you send is written anywhere — not to the database, not to the cache, not to a log. - ⚠️ Order matters, and so does rounding. Pension and health contributions are computed on the full gross, each rounded to the leu separately; only then is the personal deduction subtracted and the income tax applied to what remains. Rounded only at the end, the figure comes out one leu off the payslip for some salaries.
- ⚠️ The personal deduction is covered across the whole grid. The table in art. 77 para. (4) — one row for income up to the minimum wage plus 41 brackets of 50 lei above it, across five columns for dependants — is transcribed from the official legislative portal. The bracket is chosen by how far the gross exceeds the minimum wage, and the percentage applies to the minimum wage, not to the gross. Above the minimum wage plus 2,000 lei the deduction is zero by law. A worked example you can check by hand: a gross of 4,500 lei on 1 March 2025, minimum wage 4,050, so 450 lei above it → bracket +401..+450 → 15.5% × 4,050 = 628 lei deduction, giving a net of 2,695 lei.
- ⚠️ Should a bracket ever be missing — none is today — the response does not assume zero but returns an interval:
netcomes backnullwithnet_intervalbeside it, the bounds staying exact and the contributions staying single figures. The mechanism is kept as a safety net. - ⚠️ If any value used is flagged
de_verificat, the response says so at response level, inmeta, not buried in the breakdown. - ⚠️ Relief with a ceiling (IT, construction and agri-food, from January 2023): the law says "the part of the monthly gross income above the ceiling does not benefit from tax reliefs" — plural. So the part above is taxed and carries the general pension and health rates, while the part below keeps the reduced rate or the exemption. The interpretation applied to the taxable base of the part above is flagged in the response, because it is an interpretation, not a quoted text.
- ⚠️ The non-taxable part of the minimum wage (200 or 300 lei, depending on the period) is deducted from EVERY base — income tax, pension and health — not only from the taxable one. Without it, the net at the minimum wage came out about 80 lei too low. The conditions in the law are about the contract (base wage exactly at the guaranteed minimum, full time, main job), while the request carries only the monthly gross: the route applies the rule when the gross sits between the minimum wage and the period ceiling, and says in
meta.avertismentewhat it assumed. Checkable: at 4,050 lei gross in March 2025 the net is 2,574 lei; at 4,325 lei in September 2026, 2,699 lei.
What it is for
- The net of a salary at a past date, with every deduction justified.
- Checking a payslip, component by component.
- The effect of a sectoral relief on the net, at the same gross.
Response structure
meta.total_e_limita_de_jos is the word to switch on in code.
net is null.
scade_din_baza_impozabila for the personal deduction, scade_din_toate_bazele for the non-taxable part of the minimum wage.
data is null and this says why. The rates do not cover the requested date; the response says what is missing. The sector has no active relief then.
fara_date is prose and may be rephrased, this is not.
Response examples
body: {"brut": 5000}
{
"data": {
"brut": 5000,
"net": 2981,
"la_data": "2026-10-07",
"facilitate": null,
"componente": [
{
"cod": "cas",
"denumire": "Contribuţia de asigurări sociale",
"baza_de_calcul": 5000,
"cota": "25%",
"valoare": 1250,
"act_normativ": "Codul Fiscal art.138",
"de_verificat": false
}
]
},
"meta": {
"sursa": "Cotele vin din registrul comun `business_indicatori_fiscali`; facilităţile şi grila deducerii, din `Modules/Financiar/resources/fiscal`, cu act normativ pe fiecare valoare.",
"retentie": "Zero. Intrarea nu se scrie nicăieri — nici în bază, nici în cache, nici în log.",
"nota_acoperire": "Ce e acoperit şi ce nu: /financiar/v1/fiscal/acoperire."
}
}
body: {"brut": 4000, "persoane_intretinere": 2}
{
"data": {
"brut": 4000,
"net": 2470,
"la_data": "2026-10-07",
"facilitate": null,
"componente": [
{
"cod": "cas",
"denumire": "Contribuţia de asigurări sociale",
"baza_de_calcul": 4000,
"cota": "25%",
"valoare": 1000,
"act_normativ": "Codul Fiscal art.138",
"de_verificat": false
}
]
},
"meta": {
"sursa": "Cotele vin din registrul comun `business_indicatori_fiscali`; facilităţile şi grila deducerii, din `Modules/Financiar/resources/fiscal`, cu act normativ pe fiecare valoare.",
"retentie": "Zero. Intrarea nu se scrie nicăieri — nici în bază, nici în cache, nici în log.",
"nota_acoperire": "Ce e acoperit şi ce nu: /financiar/v1/fiscal/acoperire."
}
}
body: {"brut": 4050}
{
"data": {
"brut": 4050,
"net": 2455,
"la_data": "2026-10-07",
"facilitate": null,
"componente": [
{
"cod": "cas",
"denumire": "Contribuţia de asigurări sociale",
"baza_de_calcul": 4050,
"cota": "25%",
"valoare": 1013,
"act_normativ": "Codul Fiscal art.138",
"de_verificat": false
}
]
},
"meta": {
"sursa": "Cotele vin din registrul comun `business_indicatori_fiscali`; facilităţile şi grila deducerii, din `Modules/Financiar/resources/fiscal`, cu act normativ pe fiecare valoare.",
"retentie": "Zero. Intrarea nu se scrie nicăieri — nici în bază, nici în cache, nici în log.",
"nota_acoperire": "Ce e acoperit şi ce nu: /financiar/v1/fiscal/acoperire."
}
}
body: {"brut": 15000, "facilitate": "it", "la_data": "2023-06-15"}
{
"data": {
"brut": 15000,
"net": 9425,
"la_data": "2023-06-15",
"facilitate": {
"sector": "it",
"denumire": "Scutire de impozit pe venit pentru crearea de programe pentru calculator",
"act_normativ": "OG 16/2022, art. I pct. 24 (modifică art. 60 pct. 2 din Legea 227/2015), aplicabil veniturilor din ianuarie 2023",
"de_verificat": false
},
"componente": [
{
"cod": "cas",
"denumire": "Contribuţia de asigurări sociale",
"baza_de_calcul": 15000,
"cota": "25%",
"valoare": 3750,
"act_normativ": "Codul Fiscal art.138",
"de_verificat": false
}
]
},
"meta": {
"sursa": "Cotele vin din registrul comun `business_indicatori_fiscali`; facilităţile şi grila deducerii, din `Modules/Financiar/resources/fiscal`, cu act normativ pe fiecare valoare.",
"retentie": "Zero. Intrarea nu se scrie nicăieri — nici în bază, nici în cache, nici în log.",
"avertismente": [
"Brutul depăşeşte plafonul facilităţii (10000 lei). Partea de deasupra nu beneficiază de nicio facilitate: se impozitează şi poartă cotele generale de CAS şi CASS, în timp ce partea de dedesubt păstrează cotele facilităţii. Baza impozabilă a părţii de deasupra e calculată scăzând contribuţiile aferente ei — interpretare a textului, nu citat din el."
],
"nota_acoperire": "Ce e acoperit şi ce nu: /financiar/v1/fiscal/acoperire."
}
}
body: {"brut": 2500, "norma": "partiala"}
{
"data": {
"brut": 2500,
"net": 1549,
"la_data": "2026-10-07",
"facilitate": null,
"componente": [
{
"cod": "cas",
"denumire": "Contribuţia de asigurări sociale",
"baza_de_calcul": 2500,
"cota": "25%",
"valoare": 625,
"act_normativ": "Codul Fiscal art.138",
"de_verificat": false
}
]
},
"meta": {
"sursa": "Cotele vin din registrul comun `business_indicatori_fiscali`; facilităţile şi grila deducerii, din `Modules/Financiar/resources/fiscal`, cu act normativ pe fiecare valoare.",
"retentie": "Zero. Intrarea nu se scrie nicăieri — nici în bază, nici în cache, nici în log.",
"avertismente": [
"Norma parţială e declarată, dar brutul trimis e luat ca atare: sursa nu dă o regulă de proratare a deducerii personale pe fracţiune de normă, aşa că nu inventăm una."
],
"nota_acoperire": "Ce e acoperit şi ce nu: /financiar/v1/fiscal/acoperire."
}
}
Error codes
| Code | Slug | When it occurs |
|---|---|---|
| 401 | neautentificat | Missing or invalid token. |
| 403 | feature_indisponibil | financiar.fiscal_calcul is not in the current plan. |
| 422 | deducere_neacoperita | Only for a la_data before 2023, where the deduction regime is not transcribed. From 2023 onwards the grid is complete. brut_lipsa. Plus values outside the expected shape. |
| 429 | cota_depasita | The plan's monthly quota has been exceeded (see Retry-After). |
All errors share the same shape. eroare.cod is stable and is the value you should branch on in code — not the text in mesaj, which may change.
{
"eroare": {
"cod": "deducere_neacoperita",
"mesaj": "Only for a la_data before 2023, where the deduction regime is not transcribed. From 2023 onwards the grid is complete. brut_lipsa. Plus values outside the expected shape."
}
}