Enrich Google Sheets with DataLedger using N8N - automatically
Add a company number to your sheet and let N8N fill the rest: name, local authority, employees, assets, liabilities, equity, and SIC. No PDFs. No manual copy-paste.

Intro
What you'll learn (5 minutes setup, ~10 minutes mapping):
Trigger an N8N workflow when a company_number is added in Google Sheets
Call the DataLedger API securely with your API key
Update the same row with profile + balance-sheet fields
Add a status column to make troubleshooting easy
What you need:
Google account + a simple Google Sheet
N8N account (cloud or self-hosted)
DataLedger API key (from your account area)
Set up your Google Sheet
Option A (quick start):
👉 Download the Google Sheets template (preloaded with all DataLedger fields)
This template includes every available column (profile, officers, SICs, balance sheet, profit & loss, ratios). Perfect if you want the full dataset ready to go.
Option B (custom setup):
If you’d rather start small, create a sheet with these minimum columns:
company_number
(your input column)dl_status
(optional, to track success/errors)A few target fields such as:
company_name
local_authority
sic1_description
c_calculated_total_assets
c_calculated_total_liabilities
c_calculated_equity
You can add more columns later as you need them.
Create the N8N workflow trigger
In N8N, create a new workflow and add:
Node: Google Sheets Trigger
Operation: On Row Added/Updated
Credential: Connect your Google account
Document: Choose your spreadsheet
Sheet: Choose your worksheet
Trigger Column:
company_number
Tip: Add an IF node after the trigger — continue only if company_number
is not empty.
Add a filter to prevent a loop
⚙️ Important filter: Add a FILTER node straight after the trigger:
Condition: {{ $json.dl_status }}
is empty/undefined
This means the workflow will only fire on fresh company numbers. Once the row has been updated and dl_status
is set to "fetched"
(or "error"
), it won't run again — avoiding an endless loop.
Call the DataLedger API (Webhooks)
Node: HTTP Request
Method: GET
URL:
https://api.dataledger.uk/v1/companies/{{ $json.company_number }}
Headers:
Key:
x-api-key
Value:
YOUR_API_KEY
Authentication: None (we use the header instead)
cURL reference:
curl -X GET \ "https://api.dataledger.uk/v1/companies/12345678" \ -H "x-api-key: YOUR_API_KEY"
Common mistake to avoid: Don't append the entire row as query params. Only pass company_number
in the URL path.
Map API response fields to your row
Now we tell N8N how to update the same row that triggered the workflow:
Node: Google Sheets → Update
Operation: Append or Update Row in Sheet
Document: Same spreadsheet as trigger
Sheet: Same worksheet as trigger
Row Number:
{{ $('Google Sheets Trigger').item.json["__rowNumber"] }}
Field mapping: For each column in your sheet, select the matching property from the HTTP Request response.
Example mappings:
company_name
←{{ $json.companyName }}
local_authority
←{{ $json.registeredAddress.localAuthority }}
c_calculated_total_assets
←{{ $json.financials.cCalculatedTotalAssets }}
c_calculated_total_liabilities
←{{ $json.financials.cCalculatedTotalLiabilities }}
c_calculated_equity
←{{ $json.financials.cCalculatedEquity }}
dl_status
: Set this manually to"fetched"
This is essential — it marks the row as complete so the workflow won't keep re-triggering when the row changes.
Test end-to-end
Enter a real company_number
in the next empty row
Watch the workflow run (N8N Executions tab)
Confirm the row fills with data;
dl_status = "fetched"
Troubleshooting
403 Forbidden
Check that
x-api-key
is added as a header in the HTTP Request nodeEnsure only
company_number
is added to the URL pathVerify you have DataLedger credits available
Row didn't update
Confirm Row Number from the trigger is mapped correctly in Update node
Use
{{ $('Google Sheets Trigger').item.json["__rowNumber"] }}
Verify JSON keys exist in the HTTP Request test output
Re-test the HTTP Request node and remap any changed keys
Workflow keeps running in a loop
Make sure you have a
dl_status
columnAdd an IF node → only continue if
dl_status
is emptyWhen updating the row, always set
dl_status
to"fetched"
(or"error"
if the API fails)
Data comes back blank or unexpected
Double-check the company number is valid and active
Some fields may not exist for smaller companies (e.g. turnover, P&L)
Use
c_
for current year values,p_
for previous yearIf a field is missing, the API will return
null
Workflow runs but Google Sheets isn't updating
Ensure you've selected the correct Document and Sheet in the update node
Check that column headers in your sheet exactly match what you're mapping
Avoid hidden rows or merged cells — they can break the row mapping
N8N-specific tips
Expression editor
Use N8N's expression editor for dynamic values:
{{ $json.company_number }}
- gets company number from current node{{ $('HTTP Request').item.json.companyName }}
- gets data from specific node{{ $('Google Sheets Trigger').item.json["__rowNumber"] }}
- gets triggered row number
Error handling
Add an IF node after the HTTP Request to handle API errors:
Condition:
{{ $json.error }}
existsTrue branch: Update
dl_status
to"error"
False branch: Continue with normal field mapping
Multiple sheets
If you have multiple sheets, create separate workflows or use a Switch node to route based on sheet name.
Frequently Asked Questions
What does the dl_status
column do?
It prevents loops. When you first add a company number, dl_status
is empty, so the workflow runs. When updating, N8N sets dl_status
to "fetched"
. That stops it re-triggering when the row changes.
Can I enrich multiple company numbers at once?
Yes. Paste or import several company numbers into the sheet. N8N will process each new row individually. For bulk jobs, add a Wait node or use N8N's built-in rate limiting.
Which DataLedger fields can I get in Google Sheets?
All major profile, balance sheet, and P&L fields are available, including:
Company name, address, SIC codes, officers
Assets, liabilities, equity (current and previous years)
Turnover and profit/loss (where disclosed)
Growth rates and ratios (debt-to-asset, debt-to-equity)
Download the template sheet to see the full column list.
Why are some values empty in the returned row?
Some companies file abbreviated accounts. Smaller companies often don't disclose revenue, profit, or detailed breakdowns. In those cases, the API returns null
.
Can I filter for companies with specific assets or liabilities directly in N8N?
N8N just handles the enrichment. To filter companies by assets/liabilities, use DataLedger's Chat or API search endpoints to get the relevant company numbers, then push results into Sheets.
Is my API key safe in N8N?
Yes — keep it in the x-api-key
header. Never paste it into the sheet or URL. N8N encrypts credentials. If a key leaks, contact us and we will reset it for you.
How often is the data updated?
DataLedger syncs with Companies House the day after the accounts are submitted. Balance sheet and P&L fields update as soon as filings are available.
Can I use this workflow for lead generation?
Yes. Many users enrich lists of company numbers (from LinkedIn, CRM exports, or other sources) to pull structured financials and employee counts directly into Sheets.
N8N Cloud vs Self-hosted?
Both work identically. N8N Cloud is easier to set up, while self-hosted gives you more control. The workflow JSON is compatible between both.
