RB2B → TwentyCRM Import Pipeline
Download RB2B → TwentyCRM Import Pipeline — zip containing the script and README.
Scripts for importing an RB2B visitor-identification CSV export into a TwentyCRM workspace. Creates companies, people, scored opportunities, and "Next Steps" checklist notes.
See tools/rb2b.md for full context on RB2B, the data model, and automation opportunities.
Prerequisites
Python 3.11+ — no third-party packages required (stdlib only).
Add to the root .env file:
RB2B_TWENTYCRM_API_KEY=your-client-workspace-token
RB2B_TWENTYCRM_API_BASE=https://your-twenty-instance.com/rest
Get the API key from Settings → Playground in the target TwentyCRM workspace.
Important: Use the client workspace token — not the Pacing agency workspace token. Each TwentyCRM workspace has its own isolated API keys.
Scripts
1. rb2b-import.py — Import companies and people
Reads the RB2B CSV and creates all companies and people in TwentyCRM. Custom fields are created automatically on the first run.
python3 scripts/resources/rb2b/rb2b-import.py \
--csv ~/Downloads/filtered_custom_report_XXXXXXXXX.csv
What it does:
- Reads
ProfileTypeto split rows into Company and Person groups - Creates 9 custom fields on both
companyandpersonobjects (idempotent — skips fields that already exist):industry,estimatedRevenue(Text)allTimeViews,recentPageViews(Number)lastSeenAt,firstSeenAt(DateTime)leadTags,leadReferrer,visitedPages(Text)
- Creates all Company rows first — maps standard fields (
name,domainName,linkedinLink,employees,address) plus custom fields - Creates stub companies for any company referenced by a Person row but not present as a Company row
- Creates all Person rows — maps
name,emails,jobTitle,linkedinLink,city, links to company
Field mapping:
| CSV | TwentyCRM field | Notes |
|---|---|---|
CompanyName | name | Company and person |
Website | domainName.primaryLinkUrl | Company |
LinkedInUrl | linkedinLink.primaryLinkUrl | Both |
EstimatedEmployeeCount | employees | Converted from range to midpoint integer |
City + State + Zipcode | address | Company |
WorkEmail | emails.primaryEmail | Person |
FirstName + LastName | name.firstName / name.lastName | Person |
Title | jobTitle | Person |
Industry | industry (custom) | Both |
EstimateRevenue | estimatedRevenue (custom) | Both |
AllTimePageViews | allTimeViews (custom) | Both |
RecentPageCount | recentPageViews (custom) | Both |
LastSeenAt | lastSeenAt (custom) | Both |
FirstSeenAt | firstSeenAt (custom) | Both |
Tags | leadTags (custom) | Both |
MostRecentReferrer | leadReferrer (custom) | Both |
RecentPageUrls | visitedPages (custom) | Deduplicated, newline-separated |
Output: Writes rb2b-import-log.json alongside the script with every created record's CRM UUID.
2. rb2b-opportunities.py — Create scored opportunities
Reads the import log and CSV, scores every lead, then creates the top N opportunities with stage, score, and a "Next Steps" checklist note.
python3 scripts/resources/rb2b/rb2b-opportunities.py \
--csv ~/Downloads/filtered_custom_report_XXXXXXXXX.csv \
--top 10
Scoring (1-10):
| Signal | Points |
|---|---|
| Base | 2 |
| All-time views ≥ 5 / ≥ 15 / ≥ 30 / ≥ 50 | +1 / +2 / +3 / +4 |
| Recent views ≥ 3 / ≥ 10 | +1 / +2 |
| "Hot page" tag | +2 |
| Has work email | +1 |
Stages assigned:
| Stage | Condition |
|---|---|
MEETING | "Hot page" AND (has email OR views ≥ 20) |
SCREENING | Has email OR views ≥ 10 |
NEW | Everything else |
What it creates per opportunity:
- Opportunity record linked to company, with
scoreandstageset pointOfContactset to linked person (if one exists)- One "Next Steps" note with a BlockNote checklist attached via
noteTargets
Checklist items generated per lead:
- Research [name]: industry, size, product & background
- Find key decision makers (CMO / VP Marketing / Head of Growth)
- Send personalised cold outreach email (if has email)
- Follow up after 3 business days (if has email)
- Review visited pages for intent signals (if has page data)
- HIGH PRIORITY fast-track note (if score ≥ 7)
Output: Writes rb2b-opportunities-log.json with each created opportunity's ID, stage, score, and tasks.
3. rb2b-notes.py — Add notes to existing opportunities
Idempotent script that adds a "Next Steps" checklist note to any opportunity that doesn't already have one. Useful after manually creating opportunities in the UI.
python3 scripts/resources/rb2b/rb2b-notes.py \
--csv ~/Downloads/filtered_custom_report_XXXXXXXXX.csv
Skips opportunities that already have a note linked via noteTargets.
Typical Run Order
# 1. Import all companies and people
python3 scripts/resources/rb2b/rb2b-import.py \
--csv ~/Downloads/your-export.csv
# 2. Review the score ranking (printed to console) and pick top N
# 3. Create top 10 opportunities with notes
python3 scripts/resources/rb2b/rb2b-opportunities.py \
--csv ~/Downloads/your-export.csv \
--top 10
# 4. If you created additional opportunities manually in the UI, add notes to them
python3 scripts/resources/rb2b/rb2b-notes.py \
--csv ~/Downloads/your-export.csv
Re-running / Idempotency
| Script | Safe to re-run? | Notes |
|---|---|---|
rb2b-import.py | ⚠ Partial | Custom field creation is idempotent; company/person creation will create duplicates if run twice. Check CRM before re-running. |
rb2b-opportunities.py | ⚠ Partial | Will create duplicate opportunities if run twice on the same leads. Delete existing opps first if re-running. |
rb2b-notes.py | ✅ Yes | Checks for existing noteTargets before creating. |
Logs
All scripts write JSON logs to their working directory:
rb2b-import-log.json— company and person CRM IDsrb2b-opportunities-log.json— opportunity CRM IDs, stages, scores
Keep these logs alongside the source CSV — you'll need the IDs if you want to update or delete records later.
Automation (Future)
The current pipeline is manual. See tools/rb2b.md for a full breakdown of automation options, including:
- RB2B webhook → n8n → TwentyCRM (no CSV step)
- Automated email sequences via Resend for high-scoring leads
- LinkedIn Matched Audiences export for retargeting
- Slack alerts for score-10 leads