Tax Bundles
This guide explains how to collect and analyze a company’s tax bundles from multiple sources and formats.
Goal
Collect detailed tax bundles:
- From public sources (INPI via
company_legal_fr) - From Infogreffe for confidential tax bundles
- From the impots.gouv professional space (private data)
- Via OCR performed on uploaded PDF documents
Data sources
Tax bundle pipelines
Mix public filings, secure OAuth flows, and OCR uploads for maximum coverage.
INPI (Public)
- Automatic sync
- Published bundles (≈6-month lag)
- No OAuth needed
- Free access
Infogreffe
- Confidential tax bundles
- Requires Infogreffe account
- Automatic sync
- Last 2 tax returns by default
Impots.gouv
- OAuth redirect (pro space)
- Real-time tax data + VAT
- Corporate tax & tax account
- User-level consent required
OCR Service
- Manual PDF uploads
- Automatic data extraction
- Works with scans or exports
- Quality depends on document
| Source | Provider | Advantages | Drawbacks |
|---|---|---|---|
| INPI | company_legal_fr | Automatic, free | Publication delay (~6 months) |
| Infogreffe | infogreffe | Confidential tax bundles | Requires Infogreffe account |
| Impots.gouv | impots_gouv | Real-time data, VAT | Requires user OAuth |
| OCR | ocr_service | Any PDF document | Quality depends on the scan |
Structure of a tax bundle
Bundle types
| Code | Type | Description |
|---|---|---|
C | Full | Standard regime - 2050 to 2059 bundle |
S | Simplified | Simplified regime - 2033 bundle |
K | Consolidated | Consolidated accounts |
Main forms (Standard Regime)
| Form | Content |
|---|---|
| 2050-SD | Balance sheet - Assets |
| 2051-SD | Balance sheet - Liabilities |
| 2052-SD | Income statement (I) |
| 2053-SD | Income statement (II) |
| 2054-SD | Fixed assets |
| 2055-SD | Depreciation |
| 2056-SD | Provisions |
| 2057-SD | Receivables and payables |
Main forms (Simplified Regime)
| Form | Content |
|---|---|
| 2033-A-SD | Simplified balance sheet |
| 2033-B-SD | Simplified income statement |
| 2033-C-SD | Fixed assets |
Implementation
Option 1: INPI public data
Configuration
{
"enable": true
}
{
"auto_connect": true
}
Create the user and launch the sync
{
"name": "Entreprise SAS",
"siren": "123456789"
}
{
"requested_data_types": ["TAX_RETURN", "TAX_RETURN_ANALYSIS"],
"provider_name": "company_legal_fr"
}
{
"data_types": ["TAX_RETURN", "TAX_RETURN_ANALYSIS"]
}
Option 2: Infogreffe confidential data
Infogreffe gives access to confidential tax bundles that are not available via INPI.
Configuration
{
"credentials": {
"client_id": "INFOGREFFE_CLIENT_ID",
"password": "INFOGREFFE_PASSWORD"
}
}
{
"auto_connect": true,
"confidential_only": true
}
{
"enable": true
}
Create the connection and sync
{
"requested_data_types": ["TAX_RETURN", "TAX_RETURN_ANALYSIS"],
"provider_name": "infogreffe"
}
{
"data_types": ["TAX_RETURN", "TAX_RETURN_ANALYSIS"]
}
By default, Infogreffe returns the last 2 available tax bundles regardless of the year. You can adjust this through the month history setting.
Option 3: Impots.gouv private data
Configuration
{
"enable": true
}
Create the connection
{
"requested_data_types": [
"TAX_RETURN",
"VAT_DECLARATION",
"CORPORATE_TAX",
"TAX_ACCOUNT"
],
"provider_name": "impots_gouv"
}
Authentication flow
- Retrieve the user
redirect_url - Redirect the user to that link
- The user signs in on impots.gouv.fr
- They grant access to their data
- They are redirected back to your
return_url - You can now trigger the synchronization
{
"data_types": ["TAX_RETURN", "VAT_DECLARATION"]
}
Option 4: OCR applied to PDF documents
Configuration
{
"enable": true
}
Upload and processing
The OCR service extracts tax bundle data from scanned or exported PDFs. See the OCR Service provider documentation for implementation details.
Retrieve the data
Check which tax bundles exist
Before triggering a synchronization (or to explain why a fiscal year is missing), list every tax bundle
known for the company, all sources confounded. This works for any legal user, without any data connection:
INPI (filed documents and the figures INPI entered) and BODACC (the filing notices) are read from public
data, Infogreffe from Qard's own account. Infogreffe lists the confidential filings that INPI never
publishes, so this is the way to know they exist before purchasing them through the infogreffe provider;
BODACC reveals deposits INPI holds nothing about (confidential filings of small companies, the most recent
exercises). Tax bundles already fetched from a private source (impots.gouv, OCR, user input) are listed
under their provider's name.
/api/v6/users/{userId}/tax-returns/availableRegistries are a stored snapshot, refreshed at most once a week per source; add ?refresh=true to force it.
exercises is the short answer — one entry per fiscal year, newest first, with what exists for it.
Response:
{
"items": [
{
"source": "BODACC",
"closing_date": "2024-07-31",
"submitted_at": null,
"type": "COMPLETE",
"privacy": "CONFIDENTIAL",
"reference": "1893",
"already_fetched": false,
"document_available": false,
"figures_available": false,
"revenue": null,
"published_at": "2025-03-25"
},
{
"source": "INFOGREFFE",
"closing_date": "2025-12-31",
"submitted_at": "2026-08-21",
"type": "STANDALONE",
"privacy": "CONFIDENTIAL",
"reference": "2026/5649",
"already_fetched": false,
"document_available": true,
"figures_available": false,
"revenue": null,
"published_at": null
},
{
"source": "INPI",
"closing_date": "2021-12-31",
"submitted_at": "2022-12-19",
"type": "COMPLETE",
"privacy": "PUBLISHED",
"reference": "6734",
"already_fetched": true,
"document_available": true,
"figures_available": true,
"revenue": 12480000,
"published_at": null
}
],
"exercises": [
{ "closing_date": "2025-12-31", "sources": ["INFOGREFFE"], "type": "STANDALONE", "privacy": "CONFIDENTIAL", "submitted_at": "2026-08-21", "document_available": true, "figures_available": false, "already_fetched": false, "revenue": null },
{ "closing_date": "2024-07-31", "sources": ["BODACC"], "type": "COMPLETE", "privacy": "CONFIDENTIAL", "submitted_at": null, "document_available": false, "figures_available": false, "already_fetched": false, "revenue": null },
{ "closing_date": "2021-12-31", "sources": ["INPI"], "type": "COMPLETE", "privacy": "PUBLISHED", "submitted_at": "2022-12-19", "document_available": true, "figures_available": true, "already_fetched": true, "revenue": 12480000 }
],
"sources": {
"INPI": { "refreshed_at": "2026-09-07 11:14:29", "refreshed": false, "error": null },
"INFOGREFFE": { "refreshed_at": "2026-09-07 11:14:37", "refreshed": true, "error": null },
"BODACC": { "refreshed_at": "2026-09-07 11:14:38", "refreshed": true, "error": null }
}
}
already_fetched is true when a tax bundle with the same closing date already exists for the user.
revenue (chiffre d'affaires net, euros) is filled as soon as a source knows the figures — INPI entered
accounts, the key figures Infogreffe publishes for its public filings, or a tax bundle already fetched for
that closing date — and stays null for a confidential filing or a BODACC notice: it tells you whether a
fetch is worth it before you pay for one.
Field reference: Available tax return and
List tax bundles
/api/v6/users/{userId}/tax-returnsResponse:
{
"total": 0,
"per_page": 0,
"current_page": 0,
"last_page": 0,
"result": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"type": "COMPLETE",
"privacy": "PUBLISHED",
"closing_year": 2023,
"closing_date": "2023-12-31",
"millesime": 2024,
"duration": 12,
"submitted_date": "2024-05-15",
"revenue": 2500000,
"net_profit": 180000,
"file_id": "abc123...",
"provider_name": "company_legal_fr",
"data_connection_id": "...",
"warnings": [],
"tax_return_values": [
{ "code": "AA", "values": [1200000, 0, 0, 0] },
{ "code": "FL", "values": [2500000, 0, 0, 0] },
{ "code": "HN", "values": [180000, 0, 0, 0] }
]
}
]
}
Tax bundle detail
/api/v6/users/{userId}/tax-returns/{taxReturnId}Download the original PDF
/api/v6/files/{fileId}Tax cell codes
Key codes (Balance sheet)
| Code | Description | Formulaire |
|---|---|---|
| AA | Intangible assets - Start-up costs | 2050 |
| AB | Intangible assets - Development costs | 2050 |
| CJ | Total fixed assets (net) | 2050 |
| CO | Total current assets (net) | 2050 |
| EE | Total assets (net) | 2050 |
| DA | Share capital | 2051 |
| DL | Total equity | 2051 |
| EC | Total liabilities | 2051 |
| EE | Total liabilities & equity | 2051 |
Key codes (Income statement)
| Code | Description | Formulaire |
|---|---|---|
| FA | Goods sold (France) | 2052 |
| FJ | Production sold - Goods | 2052 |
| FL | Net revenue | 2052 |
| FR | Total operating income | 2052 |
| GF | Payroll expenses | 2052 |
| GW | Total operating expenses | 2052 |
| GG | Operating profit | 2052 |
| GV | Financial result | 2053 |
| HI | Exceptional result | 2053 |
| HK | Corporate tax | 2053 |
| HN | Net income | 2053 |
For the exhaustive list of codes, see the INPI technical document: Document Technique Comptes annuels
Tax bundle analysis
Extract key indicators
function extractKeyIndicators(taxReturn) {
const values = taxReturn.tax_return_values.reduce((acc, v) => {
acc[v.code] = v.values[0];
return acc;
}, {});
return {
// Activity
revenue: values['FL'] || 0,
revenueGrowth: null, // À calculer avec N-1
// Profitability
operatingResult: values['GG'] || 0,
netProfit: values['HN'] || 0,
profitMargin: (values['HN'] || 0) / (values['FL'] || 1),
// Balance sheet structure
equity: values['DL'] || 0,
totalAssets: values['EE'] || 0,
totalDebt: values['EC'] || 0,
// Ratios
debtToEquityRatio: (values['EC'] || 0) / (values['DL'] || 1),
returnOnEquity: (values['HN'] || 0) / (values['DL'] || 1),
returnOnAssets: (values['HN'] || 0) / (values['EE'] || 1)
};
}
Compute multi-year trends
function calculateTrends(taxReturns) {
// Sort by descending closing year
const sorted = taxReturns.sort((a, b) => b.closing_year - a.closing_year);
if (sorted.length < 2) return null;
const current = extractKeyIndicators(sorted[0]);
const previous = extractKeyIndicators(sorted[1]);
return {
revenueGrowth: (current.revenue - previous.revenue) / previous.revenue,
profitGrowth: (current.netProfit - previous.netProfit) / Math.abs(previous.netProfit || 1),
marginEvolution: current.profitMargin - previous.profitMargin,
years: {
current: sorted[0].closing_year,
previous: sorted[1].closing_year
}
};
}
Use the Tax Return Analysis
The API automatically computes ratios:
/api/v6/users/{userId}/tax-return-analysisChecking data quality
Completeness warnings
| Code | Message | Impact |
|---|---|---|
| 01 | Absence BILAN- Actif - 2050-SD | Bilan incomplet |
| 02 | Absence BILAN-Passif - 2051-SD | Bilan incomplet |
| 03 | Absence COMPTE DE RESULTAT - 2052-SD | CR incomplet |
| 04 | Absence COMPTE DE RESULTAT - 2053-SD | CR incomplet |
Consistency warnings
| Code | Message | Meaning |
|---|---|---|
| 26 | Controle ACTIF= PASSIF | Total assets ≠ total liabilities |
| 41 | Profit or loss control | Profit or loss inconsistency |
Data validation
function validateTaxReturn(taxReturn) {
const issues = [];
// Check warnings
if (taxReturn.warnings?.length > 0) {
issues.push({
severity: 'WARNING',
message: 'Tax bundle incomplete or inconsistent',
details: taxReturn.warnings
});
}
// Check fiscal year duration
if (taxReturn.duration !== 12) {
issues.push({
severity: 'INFO',
message: `Fiscal year lasting ${taxReturn.duration} months (non standard)`
});
}
// Check revenue vs. net result consistency
if (taxReturn.revenue > 0 && Math.abs(taxReturn.net_profit) > taxReturn.revenue) {
issues.push({
severity: 'WARNING',
message: 'Net result is higher than revenue (verify)'
});
}
return {
valid: issues.filter(i => i.severity === 'ERROR').length === 0,
issues
};
}
Source comparison
| Criterion | INPI | Infogreffe | Impots.gouv | OCR |
|---|---|---|---|---|
| Availability delay | ~6 months | ~6 months | Real-time | Immediate |
| Authorization required | No | Infogreffe account | OAuth | No |
| Cost | Included | Included | Included | Depends on volume |
| VAT included | No | No | Yes | Depends on document |
| Data reliability | High | High | Very high | Variable |
| Coverage | Published filings only | Published + confidential | All declarations | Any document |
Combined use cases
Fetch the freshest data
async function getLatestTaxReturn(userId) {
// Synchronize all sources
await Promise.all([
qardApi.sync(userId, { data_types: ['TAX_RETURN'], provider: 'company_legal_fr' }),
qardApi.sync(userId, { data_types: ['TAX_RETURN'], provider: 'infogreffe' }),
qardApi.sync(userId, { data_types: ['TAX_RETURN'], provider: 'impots_gouv' })
]);
// Retrieve every tax bundle
const taxReturns = await qardApi.getTaxReturns(userId);
// Sort by closing date and take the newest
return taxReturns.sort((a, b) =>
new Date(b.closing_date) - new Date(a.closing_date)
)[0];
}
Fill missing data
async function enrichTaxData(userId, closingYear) {
// Public data (INPI)
const publicData = await qardApi.getTaxReturns(userId, {
filter: { closing_year: closingYear, provider_name: 'company_legal_fr' }
});
// Confidential data (Infogreffe)
const infogreffeData = await qardApi.getTaxReturns(userId, {
filter: { closing_year: closingYear, provider_name: 'infogreffe' }
});
// Private data (Impots.gouv, if available)
const privateData = await qardApi.getTaxReturns(userId, {
filter: { closing_year: closingYear, provider_name: 'impots_gouv' }
});
// Merge while prioritizing private data (most complete)
return {
year: closingYear,
public: publicData[0] || null,
infogreffe: infogreffeData[0] || null,
private: privateData[0] || null,
best: privateData[0] || infogreffeData[0] || publicData[0] || null
};
}
See also
- Tax Return - Detailed data format
- Tax Return Analysis - Computed ratios
- Infogreffe - Confidential tax bundles provider
- Impots Gouv - Provider configuration
- Financial Analysis - Full financial analysis use case