A comprehensive INPI API Python Client for accessing French company data from INPI (Institut national de la propriété industrielle).
- Features
- Data Sources
- Installation
- Quick Start
- Configuration
- Usage Examples
- API Reference
- Project Structure
- Contributing
- License
- 🔒 Secure: Environment variable configuration, no hard-coded credentials
- 🏗️ Clean Architecture: Modular, maintainable, and well-documented code
- 🛡️ Robust: Comprehensive error handling and input validation
- 📝 Type Safe: Full type hints throughout the codebase
- 🔄 Context Managers: Automatic resource cleanup
- 🧪 Testable: Demonstration module included
This client accesses data from INPI - Institut national de la propriété industrielle:
- Company information and legal data
- Financial statements (comptes annuels)
- Official documents (actes)
- API Documentation:
- Documentations techniques
- Python 3.8 or higher
- Valid INPI account credentials
pip install -r requirements.txtrequirements.txt:
requests>=2.31.0
python-dotenv>=1.0.0
- Copy the example environment file:
cp .env.EXAMPLE .env- Edit
.envwith your credentials:
# .env
[email protected]
INPI_PASSWORD=your_password- Get your API credentials here.
The included main.py module processes multiple companies from a text file:
# 1. Create a text file with SIREN/SIRET codes (one per line)
echo "552032534" > sirens.txt
echo "542051180" >> sirens.txt
# 2. Run the demonstration module
python main.pyWorkflow:
- Place SIREN/SIRET codes in a text file (e.g.,
sirens.txt) - The module reads codes line by line
- For each code, it fetches:
- INPI company data (name, legal form, directors)
- INPI financial statements (revenue, profits, balance sheets)
- Results are displayed with formatted output and status indicators
- Summary statistics are shown at the end
You can call the API clients directly without using main.py:
from dotenv import load_dotenv
import os
load_dotenv()
from inpi import InpiCompaniesClient, ComptesAnnuelsClient
from config import Config
# Get credentials
username, password = Config.get_inpi_credentials()
# INPI: Get company information
with InpiCompaniesClient(username, password, siren="552032534") as client:
print(f"Company: {client.nom_societe()}")
print(f"Legal form: {client.forme_juridique()}")
print(f"Location: {client.ville()}")
# INPI: Get financial statements
with ComptesAnnuelsClient(username, password, siren="552032534") as client:
if client.bilans_saisis_len() > 0:
ca = client.chiffre_affaires_tbc(position=0)
print(f"Revenue: {ca:,.2f} €")Key Points:
main.pyis a demonstration tool for batch processing- For production integration, import and use the clients directly in your code
- Both approaches use the same underlying API clients
- Direct usage gives you more control and flexibility
| Variable | Required | Description |
|---|---|---|
INPI_USERNAME |
Yes | Your INPI account email |
INPI_PASSWORD |
Yes | Your INPI account password |
Get your API credentials here.
Check your configuration:
from api_client_inpi import Config
# Validate configuration
status = Config.validate_configuration()
print(status)
# Get credentials
username, password = Config.get_inpi_credentials()from config import Config
from api_client_inpi import InpiCompaniesClient
# Get credentials
username, password = Config.get_inpi_credentials()
# With context manager (recommended)
with InpiCompaniesClient(username, password, siren="552032534") as client:
# Basic information
nom_societe = client.nom_societe()
forme_juridique = client.forme_juridique()
code_ape = client.code_ape()
capital = client.montant_capital()
# Address
ville = client.ville()
code_postal = client.code_postal()
adresse = client.numero_voie()
# Directors (dirigeants)
individus = client.nombre_individus()
for idx in individus:
nom_dirigeant = client.nom_dirigeant(idx)
prenom_dirigeant = client.prenom_dirigeant(idx)
role = client.role_dirigeant(idx)
print(f"Director: {prenom_dirigeant} {nom_dirigeant} - {role}")
# Without context manager (manual):
client = InpiCompaniesClient(username, password, siren="552032534")
try:
nom_societe = client.nom_societe()
print(nom_societe)
finally:
client.close()from config import Config
from api_client_inpi import ComptesAnnuelsClient, BilanType
from api_client_inpi import FinancialDataExtractor
# Get credentials
username, password = Config.get_inpi_credentials()
with ComptesAnnuelsClient(username, password, siren="552032534") as client:
# Check availability
count = client.bilans_saisis_len()
print(f"Financial statements available: {count}")
if count > 0:
# Most recent statement (position 0)
date_cloture = client.date_cloture(position=0)
type_bilan = client.type_bilan_saisi(position=0)
print(f"Statement type: {type_bilan}") # e.g., "C", "S", "K", "B"
# ⚠️ IMPORTANT: Use the correct BilanType for accurate data extraction
# Each company files a specific type of financial statement:
# - BilanType.TBC: Complete accounts (most common)
# - BilanType.TBS: Simplified accounts
# - BilanType.TBK: Consolidated accounts
# - BilanType.TBB: Bank accounts
# The bilan_type parameter MUST match the actual statement type
# returned by type_bilan_saisi() to get correct financial data.
# Determine the correct BilanType based on type_bilan
if type_bilan == "C":
bilan_type = BilanType.TBC
elif type_bilan == "S":
bilan_type = BilanType.TBS
elif type_bilan == "K":
bilan_type = BilanType.TBK
elif type_bilan == "B":
bilan_type = BilanType.TBB
else:
print(f"Unsupported bilan type: {type_bilan}")
bilan_type = None
if bilan_type:
# Extract financial data using the correct bilan type
# Most recent statement (position 0)
capitaux = FinancialDataExtractor.get_capitaux_propres(
bilan_data=client.documents_associes_entreprise,
position=0,
bilan_type=bilan_type # ← Must match actual statement type!
)
chiffre_affaires = FinancialDataExtractor.get_chiffre_affaires(
bilan_data=client.documents_associes_entreprise,
position=0,
bilan_type=bilan_type
)
benefice_perte = FinancialDataExtractor.get_benefice_perte(
bilan_data=client.documents_associes_entreprise,
position=0,
bilan_type=bilan_type
)
print(f"Equity: {capitaux:,} €")
print(f"Revenue: {chiffre_affaires:,} €")
print(f"Profit/Loss: {benefice_perte:,} €")
⚠️ Note: Financial data extraction is currently limited to key metrics (revenue, profit loss, equity, employee count). Additional financial fields and support for agricultural bilan types (TBAC/TBAS) will be added in future releases. For more details about bilan types and financial fields click here to download Documentation technique Comptes annuels or read Data sources
from config import Config
from api_client_inpi import ActesClient
# Get credentials
username, password = Config.get_inpi_credentials()
with ActesClient(username, password, siren="552032534") as client:
# Check how many actes are available
actes_count = client.actes_len()
print(f"Number of actes: {actes_count}")
if actes_count > 0:
# Get list of all actes with metadata
actes_list = client.acte_depot_id()
# Returns: [(position, date_depot, id, type_rdd), ...]
for position, date_depot, acte_id, type_acte in actes_list:
print(f"Acte #{position + 1}:")
print(f" Date: {date_depot}")
print(f" ID: {acte_id}")
print(f" Type: {type_acte}")
# Get metadata for a specific acte
acte_id = actes_list[0][2] # Get ID of first acte
metadata = client.recherche_acte_pdf(id_acte=acte_id)
print(f"Acte details: {metadata}")
# Download acte PDF
result = client.telecharger_acte_pdf(
id_acte=acte_id,
file_path="/path/to/download/folder",
file_name="acte_document" # Will be saved as "acte_document.pdf"
)
print(result) # "PDF acte downloaded successfully"from api_client_inpi import SirenSiretValidator, InvalidSirenError
try:
# Validate SIREN
siren = SirenSiretValidator.validate_siren("552032534")
# Validate SIRET
siret = SirenSiretValidator.validate_siret("55203253400054")
# Extract SIREN from SIRET
siren_from_siret = SirenSiretValidator.extract_siren_from_siret(siret)
# Check without raising exception
is_valid = SirenSiretValidator.is_valid_siren("552032534")
except InvalidSirenError as e:
print(f"Invalid format: {e}")from api_client_inpi import (
InpiCompaniesClient,
AuthenticationError,
ApiRequestError,
InvalidSirenError
)
try:
with InpiCompaniesClient(username, password, siren="552032534") as client:
data = client.nom_societe()
except AuthenticationError as e:
print(f"Authentication failed: {e}")
except InvalidSirenError as e:
print(f"Invalid SIREN format: {e}")
except ApiRequestError as e:
print(f"API request failed: {e.status_code}")
print(f"Response: {e.response_text}")
except Exception as e:
print(f"Unexpected error: {e}")- Company information and directors
- Methods:
nom_societe(),forme_juridique(),code_ape(),dirigeants_box(), etc.
- Financial statements (PDF and JSON)
- Methods:
bilans_saisis_len(),chiffre_affaires_tbc(),benefice_perte_tbc(), etc.
- Official documents
- Methods:
actes_len(),telecharger_acte_pdf(), etc.
- Configuration management
- Methods:
get_inpi_credentials(),validate_configuration()
- Input validation
- Methods:
validate_siren(),validate_siret(),extract_siren_from_siret()
- Financial data extraction
- Methods:
get_capitaux_propres(),get_benefice_perte(),get_chiffre_affaires()
ApiClientError- Base exceptionAuthenticationError- Authentication failuresApiRequestError- API request failuresValidationError- Input validation errorsInvalidSirenError- Invalid SIREN formatInvalidSiretError- Invalid SIRET formatDataNotFoundError- Data not found in API response
api-client-inpi/
├── __init__.py # Main package entry point
├── config.py # Configuration management
├── exceptions.py # Custom exception classes
├── main.py # Demonstration module
├── base/ # Base classes
│ ├── http_client.py # Base HTTP client
│ └── authenticator.py # Base authenticator
├── utils/ # Utilities
│ └── validators.py # SIREN/SIRET validation
└── inpi/ # INPI API modules
├── authenticator.py # INPI authentication
├── companies.py # Company data
├── financials.py # Financial statements
├── documents.py # Documents
└── financial_extractor.py # Financial data extraction
Documentation/
├── README.md # This file
├── .env.EXAMPLE # Environment variables template
└── CONTRIBUTING.md # Development Setup
Contributions are welcome !
Feel free to submit a Pull Request !
- Clone the repository
- Create a virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
- Install dependencies:
pip install -r requirements.txt
- Set up your
.envfile with test credentials - Run the demonstration module to verify setup
- Follow PEP 8 guidelines
- Use type hints
- Document all public methods with docstrings
- Handle errors gracefully
- This project is licensed under the MIT License - see the LICENSE file for details.
- This INPI API Python Client accesses datasets from INPI (Institut National de la Propriété Industrielle). The data reuse is governed by INPI's homologated reuse licences (for RNE and industrial property). See INPI licence page for details.
For questions, bug reports, or feature requests, please use the GitHub Issues page.
⚠️ When reporting an issue, please include:
- Your Python version and environment
- Steps to reproduce the problem
- Any error messages or stack traces
- Complete architecture refactoring
- Added environment variable configuration
- Comprehensive error handling
- Full type hints
- Modular, maintainable codebase
- Initial release with basic functionality
- Intended for internal use by professionals in the M&A sector in France
Made with ❤️ for the French business data community