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
PUT /api/v6/providers/company_legal_fr
{
"enable": true
}
PUT /api/v6/providers/company_legal_fr/settings
{
"auto_connect": true
}
Create the user and launch the sync
POST /api/v6/users/legal
{
"name": "Entreprise SAS",
"siren": "123456789"
}
POST /api/v6/users/{userId}/data-connections
{
"requested_data_types": ["TAX_RETURN", "TAX_RETURN_ANALYSIS"],
"provider_name": "company_legal_fr"
}
POST /api/v6/users/{userId}/sync
{
"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
PUT /api/v6/providers/infogreffe/credentials
{
"credentials": {
"client_id": "INFOGREFFE_CLIENT_ID",
"password": "INFOGREFFE_PASSWORD"
}
}
PUT /api/v6/providers/infogreffe/settings
{
"auto_connect": true,
"confidential_only": true
}
PUT /api/v6/providers/infogreffe
{
"enable": true
}
Create the connection and sync
POST /api/v6/users/{userId}/data-connections
{
"requested_data_types": ["TAX_RETURN", "TAX_RETURN_ANALYSIS"],
"provider_name": "infogreffe"
}
POST /api/v6/users/{userId}/sync
{
"data_types": ["TAX_RETURN", "TAX_RETURN_ANALYSIS"]
}
info
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
PUT /api/v6/providers/impots_gouv
{
"enable": true
}
Create the connection
POST /api/v6/users/{userId}/data-connections
{
"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
POST /api/v6/users/{userId}/sync
{
"data_types": ["TAX_RETURN", "VAT_DECLARATION"]
}
Option 4: OCR applied to PDF documents
Configuration
PUT /api/v6/providers/ocr_service
{
"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
List tax bundles
GET
/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": "C",
"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
GET
/api/v6/users/{userId}/tax-returns/{taxReturnId}Download the original PDF
GET
/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 |
Full documentation
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:
GET
/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