Due Diligence
This guide helps you run an in-depth due diligence before an investment, acquisition, or strategic partnership.
Goal
Thoroughly analyze a target company:
- Legal and compliance verification
- Historical financial analysis
- Mapping of officers and beneficial owners
- Risk and background detection
- Asset verification (trademarks, patents)
Due diligence scope
Due Diligence Scope
360° review before any deal, investment, or partnership.
Legal
- Bylaws & statutory acts
- K-bis & registration proofs
- Ultimate beneficial owners
- Corporate structure
Finance
- Financial statements & ratios
- Tax bundles & VAT
- Bank accounts & cashflow
- Sector benchmarks
Compliance
- PEP & sanctions screening
- Adverse media
- Conformity checks
- Background graphs
Governance
- Current & former officers
- Mandates and control links
- Beneficial owner timeline
- Multi-mandate detection
Assets
- Trademarks and IP
- Patents & software
- Real estate footprint
- Other intangible assets
History
- Collective procedures
- Court decisions
- Legal notices & events
- Privileges & liens
Data collected
Legal and structural data
| Type | Description | Endpoint |
|---|---|---|
| Company Profile | Identification details | /users/{userId}/company-profile |
| Articles of Association | Company bylaws | /users/{userId}/articles-of-association |
| Acts | Statutory acts and amendments | /users/{userId}/acts |
| Corporate Offices | Secondary establishments | /users/{userId}/corporate-offices |
| Registration Proof | K-bis extract | /users/{userId}/registration-proof |
| INSEE Registration Proof | INSEE status notice | /users/{userId}/insee-registration-proof |
Governance and control
| Type | Description | Endpoint |
|---|---|---|
| Company Officers | Current and past officers | /users/{userId}/company-officers |
| Beneficial Owners | Ultimate beneficial owners | /users/{userId}/beneficial-owners |
| Background Check V2 | Relationship graph | /users/{userId}/background-check-v2 |
| Conformity Check | Compliance verifications | /users/{userId}/conformity-checks |
Financial data
| Type | Description | Endpoint |
|---|---|---|
| Financial Statement | Published statements | /users/{userId}/financial-statements |
| Tax Return | Tax bundles | /users/{userId}/tax-returns |
| Tax Return Analysis | Financial ratios | /users/{userId}/tax-return-analysis |
| Sector Analysis | Industry benchmark | /users/{userId}/sector-analysis |
| Bank Accounts | Bank accounts | /users/{userId}/bank-accounts |
| Bank Cashflow | Cashflow analysis | /users/{userId}/bank-cashflow |
History and risk
| Type | Description | Endpoint |
|---|---|---|
| Collective Procedure | Insolvency proceedings | /users/{userId}/collective-procedures |
| Court Decision | Court rulings | /users/{userId}/court-decisions |
| Legal Notice | Official legal notices | /users/{userId}/legal-notices |
| Privileges | Liens and pledges | /users/{userId}/privileges |
| Timeline | Event history | /users/{userId}/timeline |
Intangible assets
| Type | Description | Endpoint |
|---|---|---|
| Trademark | Registered trademarks | /users/{userId}/trademarks |
Implementation steps
Step 1: Enable every required provider
PUT /api/v6/providers/company_legal_fr
{
"enable": true
}
PUT /api/v6/providers/company_legal_fr/settings
{
"auto_connect": true
}
PUT /api/v6/providers/infogreffe
{
"enable": true
}
PUT /api/v6/providers/comply_cube
{
"enable": true
}
PUT /api/v6/providers/comply_cube/settings
{
"officers_check": true,
"beneficial_owners_check": true,
"background_check_nodes_check": true
}
Step 2: Create the target user
POST /api/v6/users/legal
{
"name": "Target Acquisition SAS",
"siren": "123456789",
"group": "due-diligence-2024"
}
Step 3: Create the data connections
3.1 Full legal data
POST /api/v6/users/{userId}/data-connections
{
"requested_data_types": [
"COMPANY_PROFILE",
"COMPANY_OFFICER",
"CORPORATE_OFFICE",
"ACT",
"ARTICLES_OF_ASSOCIATION",
"AVIS_SIREN",
"COLLECTIVE_PROCEDURE",
"BENEFICIAL_OWNER",
"BACKGROUND_CHECK",
"BACKGROUND_CHECK_V2",
"CONFORMITY_CHECK",
"BANKING_RELATIONSHIP",
"FINANCIAL_STATEMENT",
"TAX_RETURN",
"TAX_RETURN_ANALYSIS",
"SECTOR_ANALYSIS",
"TIMELINE",
"TRADEMARK",
"LEGAL_NOTICE",
"PRIVILEGES"
],
"provider_name": "company_legal_fr"
}
3.2 Court decisions (Infogreffe)
POST /api/v6/users/{userId}/data-connections
{
"requested_data_types": [
"COURT_DECISION",
"REGISTRATION_PROOF"
],
"provider_name": "infogreffe"
}
Step 4: Launch the full synchronization
POST /api/v6/users/{userId}/sync
{
"data_types": [
"COMPANY_PROFILE",
"COMPANY_OFFICER",
"CORPORATE_OFFICE",
"ACT",
"ARTICLES_OF_ASSOCIATION",
"AVIS_SIREN",
"COLLECTIVE_PROCEDURE",
"BENEFICIAL_OWNER",
"BACKGROUND_CHECK_V2",
"CONFORMITY_CHECK",
"FINANCIAL_STATEMENT",
"TAX_RETURN",
"TAX_RETURN_ANALYSIS",
"SECTOR_ANALYSIS",
"TIMELINE",
"TRADEMARK",
"LEGAL_NOTICE",
"PRIVILEGES",
"COURT_DECISION",
"REGISTRATION_PROOF"
]
}
Synchronization time
A complete due diligence may take several minutes. Set up webhooks so you are notified when the sync ends.
Step 5: Analyze the results
5.1 Legal checklist
async function legalDueDiligence(userId) {
const [profile, articles, officers, beneficialOwners] = await Promise.all([
qardApi.getCompanyProfile(userId),
qardApi.getArticlesOfAssociation(userId),
qardApi.getCompanyOfficers(userId),
qardApi.getBeneficialOwners(userId)
]);
return {
companyActive: !profile.insee_closing_date && !profile.rncs_closing_date,
hasStatutes: articles.length > 0,
statutesUpToDate: articles[0]?.date > '2020-01-01',
hasActiveOfficers: officers.some(o => !o.roles[0]?.end_date),
hasBeneficialOwners: beneficialOwners.length > 0,
legalForm: profile.legal?.form,
capital: profile.capital?.amount
};
}
5.2 Governance analysis
async function governanceDueDiligence(userId) {
const backgroundCheck = await qardApi.getBackgroundCheckV2(userId);
// Analyze links between entities
const nodes = backgroundCheck.details?.nodes || [];
const links = backgroundCheck.details?.links || [];
const naturalPersons = nodes.filter(n => n.type === 'NATURAL');
const legalPersons = nodes.filter(n => n.type === 'LEGAL');
// Detect officers holding too many mandates
const multiMandates = naturalPersons.filter(person => {
const personLinks = links.filter(l => l.to === person.id);
return personLinks.length > 3;
});
// Check linked entities for collective procedures
const entitiesWithProcedures = nodes.filter(n =>
n.pcl?.management_difficulties || n.pcl?.financial_difficulties
);
return {
totalOfficers: naturalPersons.length,
legalOfficers: legalPersons.length,
multiMandatePersons: multiMandates,
entitiesWithProcedures,
riskAcceptable: backgroundCheck.acceptable === 'OK',
riskReasons: backgroundCheck.reasons
};
}
5.3 Compliance risk analysis
async function complianceDueDiligence(userId) {
const [backgroundCheck, conformityChecks] = await Promise.all([
qardApi.getBackgroundCheckV2(userId),
qardApi.getConformityChecks(userId)
]);
const riskFlags = {
pep: backgroundCheck.reasons?.includes('PEP'),
sanctions: backgroundCheck.reasons?.includes('WATCHLIST'),
adverseMedia: backgroundCheck.reasons?.includes('ADVERSE_MEDIA'),
blacklistedNationality: backgroundCheck.reasons?.includes('BENEFICIAL_OWNER_NATIONALITY_BLACKLISTED'),
blacklistedAddress: backgroundCheck.reasons?.includes('COMPANY_ADDRESS_BLACKLISTED')
};
// Person-level details from conformity checks
const personRisks = conformityChecks.map(check => ({
personId: check.entity_id,
entityType: check.entity_type,
status: check.status,
risks: check.risks
}));
return {
globalRisk: backgroundCheck.acceptable === 'NOK' ? 'HIGH' : 'LOW',
riskFlags,
personRisks,
requiresManualReview: Object.values(riskFlags).some(Boolean)
};
}
5.4 Historical financial analysis
async function financialDueDiligence(userId) {
const [taxReturns, analysis, sectorAnalysis] = await Promise.all([
qardApi.getTaxReturns(userId),
qardApi.getTaxReturnAnalysis(userId),
qardApi.getSectorAnalysis(userId)
]);
// 3-year trend
const revenueHistory = taxReturns
.sort((a, b) => b.closing_year - a.closing_year)
.slice(0, 3)
.map(tr => ({
year: tr.closing_year,
revenue: tr.revenue,
netProfit: tr.net_profit,
margin: tr.net_profit / tr.revenue
}));
// Trend calculation
const revenueGrowth = revenueHistory.length >= 2
? (revenueHistory[0].revenue - revenueHistory[1].revenue) / revenueHistory[1].revenue
: null;
return {
revenueHistory,
revenueGrowth,
lastRevenue: revenueHistory[0]?.revenue,
lastNetProfit: revenueHistory[0]?.netProfit,
profitMargin: revenueHistory[0]?.margin,
dataQuality: taxReturns[0]?.warnings?.length === 0 ? 'GOOD' : 'WARNINGS',
sectorPercentile: sectorAnalysis[0]?.percentile
};
}
5.5 Incident history
async function historicalDueDiligence(userId) {
const [procedures, courtDecisions, legalNotices, privileges] = await Promise.all([
qardApi.getCollectiveProcedures(userId),
qardApi.getCourtDecisions(userId),
qardApi.getLegalNotices(userId),
qardApi.getPrivileges(userId)
]);
return {
collectiveProcedures: procedures.map(p => ({
type: p.type,
date: p.date,
status: p.status
})),
courtDecisions: courtDecisions.length,
hasActivePrivileges: privileges.some(p => !p.end_date),
recentLegalNotices: legalNotices
.filter(n => new Date(n.date) > new Date(Date.now() - 365 * 24 * 60 * 60 * 1000))
.length
};
}
Due diligence report
async function generateDueDiligenceReport(userId) {
const [legal, governance, compliance, financial, historical] = await Promise.all([
legalDueDiligence(userId),
governanceDueDiligence(userId),
complianceDueDiligence(userId),
financialDueDiligence(userId),
historicalDueDiligence(userId)
]);
// Compute the overall score
const scores = {
legal: calculateLegalScore(legal),
governance: calculateGovernanceScore(governance),
compliance: calculateComplianceScore(compliance),
financial: calculateFinancialScore(financial),
historical: calculateHistoricalScore(historical)
};
const globalScore = Object.values(scores).reduce((a, b) => a + b, 0) / 5;
return {
userId,
generatedAt: new Date().toISOString(),
globalScore: Math.round(globalScore),
recommendation: globalScore >= 70 ? 'PROCEED' : globalScore >= 50 ? 'CAUTION' : 'DECLINE',
sections: {
legal: { score: scores.legal, details: legal },
governance: { score: scores.governance, details: governance },
compliance: { score: scores.compliance, details: compliance },
financial: { score: scores.financial, details: financial },
historical: { score: scores.historical, details: historical }
},
redFlags: identifyRedFlags({ legal, governance, compliance, financial, historical }),
nextSteps: generateNextSteps(globalScore)
};
}
function identifyRedFlags(data) {
const flags = [];
if (!data.legal.companyActive) flags.push('Inactive or deregistered company');
if (data.governance.riskReasons?.length > 0) flags.push('Governance risks identified');
if (data.compliance.globalRisk === 'HIGH') flags.push('High compliance risk');
if (data.financial.profitMargin < 0) flags.push('Negative net margin');
if (data.historical.collectiveProcedures?.length > 0) flags.push('History of collective procedures');
if (data.historical.hasActivePrivileges) flags.push('Active liens or pledges');
return flags;
}
Due diligence checklist
Documents to collect
- Recent K-bis extract
- Updated bylaws
- Beneficial owner declaration
- Last three financial statements
- Complete tax bundles
- Trademark and patent list
Verification points
- Company is active and not deregistered
- Legal information is consistent
- All officers are identified
- Beneficial owner declaration is complete
- No active collective procedures
- No individuals on sanctions lists
- Satisfactory financial health
- No significant liens or pledges
See also
- KYB / Onboarding - Streamlined onboarding version
- Background Check V2 - Detailed risk analysis
- Conformity Check - Compliance checks
- ComplyCube - Compliance verification provider