Last updated: August 31, 2026

Ben Argeband, Founder & CEO of Heartbeat.ai — a copy/paste-ready template, no fluff.
What’s on this page:
Who this is for
Recruiters and ops teams importing physician contact data into an ATS who need clean records: no duplicate providers, no broken date or boolean fields, and clear provenance for every row. The template below is built around CSV hygiene, NPI-first identity, and recency tracking, because outreach performance quietly decays when a list goes stale.
This page is a supporting template. For enrichment after upload, use the primary workflow: upload a physician list for enrichment.
Quick answer
- Core answer
- Use an NPI-first CSV with normalized phones and emails, an explicit source and refresh date, and strict dedupe keys so your ATS import stays clean and searchable.
- Best for
- Recruiters and ops teams importing physician contact data into an ATS without creating duplicates or broken fields.
- Primary page for this topic
- https://heartbeat.ai/resources/provider-contact-data/upload-a-physician-list-for-enrichment/
Compliance & safety
This method is for legitimate recruiting outreach only. Respect candidate privacy, opt-out requests, and local data laws. Heartbeat does not provide medical advice or legal counsel.
Why most import failures aren’t really CSV problems
Most import failures trace back to one of three root causes: no stable unique key, inconsistent field formats, or no way to tell what’s current. Fix those in order and the rest of the import mostly takes care of itself.
- Unique key: pick one field that represents the provider across systems. For physicians, that’s the NPI.
- Clean fields: normalize names, phones, emails, and addresses so your ATS doesn’t split records or reject rows.
- Log dates: store a refresh date so you can suppress stale contacts and prioritize recent ones.
The trade-off: a few minutes of upfront structure versus a duplicate-riddled ATS you can’t unwind later. The upfront cost is smaller.
Step-by-step method
Step 1) Start with the exact header row
Paste this header row into row 1 of your CSV. Keep the column names exactly as written to reduce mapping mistakes.
Spreadsheet setup tip: set the NPI and postal_code columns to text before you save or export, or leading zeros will silently disappear.
Copy/paste CSV header:
NPI,first_name,last_name,credential,specialty_primary,organization_name,practice_site_name,address_line1,address_line2,city,state,postal_code,country,phone_main,phone_mobile,email_work,email_personal,preferred_contact_channel,do_not_contact,source_system,source_detail,refresh_date,notes
Example row (synthetic):
1234567890,Priya,Shah,MD,Internal Medicine,Northside Medical Group,Northside Clinic – Midtown,123 Main St,Ste 400,Chicago,IL,02110,US,+13125551212,+13125559876,pshah@northside.org,,phone,FALSE,Heartbeat.ai,IM Midwest outreach list,2026-01-05,Prefers calls 12-2pm local
Step 2) Use the field definitions, don’t improvise formats
Imports break when the same type of data shows up in multiple formats across dates, phones, and booleans. Enforce the definitions below before you import, not after.
Field reference table
| Column | Required? | Definition / Allowed values | Example | ATS mapping notes (Bullhorn / Apploi) |
|---|---|---|---|---|
| NPI | Yes | NPI definition: a unique 10-digit identifier for covered health care providers in the U.S., assigned via NPPES. Store as 10 digits, no dashes. | 1234567890 | Map to a custom field if your ATS doesn’t have a native NPI field. Use as your primary dedupe key. |
| first_name | Yes | Given name only. No titles. | Priya | Standard candidate/contact first name. |
| last_name | Yes | Family name only. No suffixes unless your ATS requires them. | Shah | Standard candidate/contact last name. |
| credential | No | Short credential string. | MD | Often maps to “Suffix” or “Credential” custom field. |
| specialty_primary | No | One specialty only (avoid comma-separated lists). | Internal Medicine | Map to specialty field or tags. Keep one value for filtering. |
| organization_name | No | Employer/health system/group name. | Northside Medical Group | Map to “Company” or “Employer” field if available. |
| practice_site_name | No | Clinic/site label (optional). | Northside Clinic – Midtown | Useful for multi-site groups; map to location/site custom field. |
| address_line1 | No | Street address line 1. | 123 Main St | Map to address fields if your ATS supports them; otherwise store in notes. |
| address_line2 | No | Suite/unit. | Ste 400 | Same as above. |
| city | No | City. | Chicago | Standard address mapping. |
| state | No | 2-letter state code if U.S. | IL | Standard address mapping. |
| postal_code | No | ZIP or postal code as text (preserve leading zeros). | 02110 | Import as text, not number. |
| country | No | Country name or ISO code; be consistent. | US | Optional unless you recruit internationally. |
| phone_main | No | Primary office line. Store as E.164 if possible (+1XXXXXXXXXX). If not, digits only. | +13125551212 | Map to “Phone” or “Work Phone.” Avoid mixing extensions into the number field. |
| phone_mobile | No | Mobile number (E.164 preferred). Keep separate from office line. | +13125559876 | Map to “Mobile Phone” if available; otherwise custom field. |
| email_work | No | Work email. Lowercase. One email per field. | pshah@northside.org | Map to primary email if you prioritize work outreach. |
| email_personal | No | Personal email, only with a legitimate recruiting purpose and honoring opt-outs. Lowercase. | priya.shah@gmail.com | Consider mapping to secondary email/custom field; apply suppression rules. |
| preferred_contact_channel | No | One of: phone, email, unknown | phone | Map to a tag or custom field; helps routing and cadence selection. |
| do_not_contact | No | Boolean: TRUE or FALSE (uppercase). Default FALSE. | FALSE | Map to your ATS DNC/opt-out field if available. Never overwrite TRUE with FALSE. |
| source_system | No | Where the row came from (system name). | Heartbeat.ai | Map to “Source” or custom field for auditability. |
| source_detail | No | Free text: list name, campaign, or query used. If it includes commas, ensure proper CSV quoting. | IM Midwest outreach list | Store for traceability when complaints or bounces happen. |
| refresh_date | Yes | Recency definition: the date you last verified/updated the contact row. Use ISO format YYYY-MM-DD. | 2026-01-05 | Map to “Last Updated” custom field. Use it to suppress stale contacts. |
| notes | No | Short notes. If notes include commas, ensure your CSV exporter properly quotes the field. | Prefers calls 12-2pm local | Map to notes/comments field. |
Step 3) Set your dedupe policy before you import
For physicians, the NPI is the strongest primary key available. CMS describes it as a unique, 10-digit, intelligence-free identifier that stays the same even if a provider changes name, address, or employer. Emails and phones don’t behave the same way — people switch employers, domains lapse, numbers get reassigned — so your dedupe policy should treat contact points as volatile and NPI as the anchor.
- Primary dedupe key: NPI
- Secondary match signals (for review, not auto-merge): last_name + first_name + state, or email_work
- Never auto-merge solely on phone or email — both can be shared, forwarded, or recycled
For a deeper walkthrough, link this into your SOP: how to dedupe a provider list by NPI.
Step 4) Map fields into Bullhorn / Apploi (pilot first)
Two rules keep your ATS usable:
- Don’t overload one field — for example, multiple emails in one email field. Keep one value per field.
- Keep structured data structured — dates as YYYY-MM-DD, booleans as TRUE/FALSE, state as a 2-letter code.
Run a 10-row pilot import first, verify how Bullhorn or Apploi actually stored each field, then import the full file. Skipping this step is how small format mismatches turn into a full cleanup project.
| CSV column | Bullhorn target | Apploi target | Field type | Common failure mode |
|---|---|---|---|---|
| NPI | Custom text field (e.g., NPI__c) | Custom field (text) | Text | Imported as number and loses leading zeros (treat as text) |
| refresh_date | Custom date field | Custom field (date) | Date | Rejected due to non-ISO formats (use YYYY-MM-DD) |
| do_not_contact | DNC/opt-out field (or custom boolean) | Opt-out field (or custom boolean) | Boolean | TRUE/FALSE mismatch (don’t use Yes/No) |
| phone_main | Phone (work) | Phone | Text | Extensions included in number field (put ext in notes) |
| phone_mobile | Mobile phone (or custom) | Mobile phone (or custom) | Text | Mobile overwritten by office line due to single phone mapping |
| email_work | Text | Multiple emails in one cell causing parse issues | ||
| source_system | Source/custom | Source/custom | Text | Missing provenance makes complaints hard to investigate |
If you’re using Heartbeat.ai workflows, you can also start from your existing file and upload it for enrichment: upload your file.
Step 5) Run a pre-import validation pass
- Check NPI format: 10 digits, no blanks, for any row you intend to dedupe reliably.
- Normalize emails: lowercase, remove spaces, one email per field.
- Normalize phones: pick E.164 (+1…) or digits-only and stick to it across the file.
- Validate refresh_date: ISO YYYY-MM-DD only.
- Confirm do_not_contact: TRUE/FALSE only; never overwrite TRUE with FALSE on re-import.
Go/no-go checklist before you import
Score each item 0 (missing), 1 (partial), or 2 (clean). If you’re under 12 of 16, fix the file first — don’t import and clean up afterward.
- (2) NPI present and 10-digit for the rows you plan to keep long-term.
- (2) Dedupe rule written: “NPI = unique; never auto-merge on phone/email.”
- (2) refresh_date populated for every row (YYYY-MM-DD).
- (2) Phone split: office vs. mobile in separate columns.
- (2) Email split: work vs. personal in separate columns.
- (2) do_not_contact respected: TRUE never overwritten by FALSE on re-import.
- (2) Source traceability: source_system and source_detail filled in.
- (2) ATS field mapping tested with a 10-row pilot import and a rollback plan.
Common pitfalls
Pitfall 1: Treating email or phone as the unique key
Emails and phones change. Dedupe on them and you’ll either merge the wrong people or create duplicates when a physician changes systems. Use NPI as the stable identity key and treat contact points as attributes that rotate.
Pitfall 2: No refresh_date, so you can’t tell what’s stale
Without a recency field, you can’t suppress old contacts, and your team burns cycles on dead emails and wrong numbers. Add refresh_date to every row and update it whenever you re-verify.
Pitfall 3: Multi-value fields that break parsing
Comma-separated specialties, multiple emails in one cell, or “(312) 555-1212 ext 9” jammed into a phone field will cause import errors or make ATS search unreliable. One value per field; extensions and notes go elsewhere.
Pitfall 4: Importing the full file without a pilot
The fastest way to create a cleanup project is skipping the pilot. Run 10 rows, verify how your ATS actually stored each field, then run the rest.
Pitfall 5: Overwriting opt-outs on re-import
If your ATS has a do-not-contact flag, treat it as write-protected. Your import process should never flip TRUE back to FALSE just because a source file didn’t carry the opt-out forward.
Import error decoder
| Symptom | Likely cause | Fix |
|---|---|---|
| refresh_date rejected | Date not in YYYY-MM-DD | Convert to ISO format; ensure the column is mapped as a date field |
| ZIP/postal_code loses leading zeros | Spreadsheet saved it as a number | Set the column to text before saving; keep postal_code as text in the ATS |
| Duplicates created on re-import | No match key (or ATS match not configured) | Match/update on NPI; quarantine rows missing NPI for review |
| Phone fields look scrambled | Extensions or multiple numbers in one cell | Keep one number per field; put extensions in notes |
| Emails bounce immediately | Stale contacts or typos/spaces | Lowercase + trim; use refresh_date to suppress older rows until re-verified |
Building a quarantine tab into your workflow
Add a second tab to your spreadsheet called QUARANTINE and apply these rules before every import:
- Rule A (identity): if NPI is blank or not exactly 10 digits, move the row to QUARANTINE rather than importing it into the main ATS table.
- Rule B (freshness): if refresh_date is blank or not YYYY-MM-DD, move to QUARANTINE.
- Rule C (opt-out safety): if do_not_contact is TRUE, keep the row, but confirm your import can’t overwrite TRUE with FALSE.
- Rule D (contact hygiene): if email_work or email_personal contains spaces or multiple emails, split into separate fields or move to QUARANTINE.
- Rule E (phone hygiene): if phone fields contain “ext,” “x,” or multiple numbers, move to QUARANTINE and store the extension in notes.
Dedupe decision tree:
- NPI matches an existing record → update contact attributes (phones/emails), update refresh_date, preserve do_not_contact if TRUE.
- NPI doesn’t match any existing record → create a new record.
- NPI missing → don’t auto-merge; quarantine for manual review.
If your ATS can’t update records by NPI
Some ATS setups can import new rows but can’t reliably update existing records against a custom key. In that case, use a staging workflow instead:
- Import the CSV into a staging list or temporary project instead of your main database.
- Match staging rows to existing records using NPI.
- Apply updates (phones, emails, refresh_date, source fields) to the matched records.
- Create new records only for NPIs that don’t already exist.
Tracking outreach performance after import
Run a weekly scorecard on a fixed cohort — for example, the last imported batch — and compare outcomes by refresh_date band and channel. Definitions worth locking down before you compare numbers:
- Deliverability rate = delivered emails / sent emails.
- Bounce rate = bounced emails / sent emails.
- Connect rate = connected calls / total dials.
- Answer rate = human answers / connected calls.
- Reply rate = replies / delivered emails.
How to measure it:
- Tag every imported record with source_system, source_detail, and refresh_date.
- Run outreach on a consistent cadence for 7–14 days, same number of touches per record.
- Export outcomes and compute the rates above using the stated denominators.
- Compare records with a recent refresh_date against older ones to decide when to re-verify or suppress.
Suppression SOP
Keep opt-outs in two places: your ATS record (do_not_contact = TRUE) and a suppression list used by your outreach tools. On every re-import, treat TRUE as write-protected and never overwrite it with FALSE.
Use NPI to keep the ATS clean across repeated imports
If you’re rebuilding lists on a recurring basis, don’t rely on default ATS duplicate detection. Make NPI the anchor, then update contact attributes as they change. For the upstream list-building workflow, see: how to build a physician call list.
Outreach templates
These assume you have NPI, specialty, and a recent refresh_date on the record. Keep them short and operational.
Template 1: Phone opener (office line)
- You: “Hi, this is [Name]. I’m trying to reach Dr. [Last Name] about a physician opportunity. What’s the best way to get a message through — direct line, email, or a good time window?”
- If asked details: “It’s a [specialty] role with [high-level location/setting]. I can send a 3-line summary — what email should I use?”
Template 2: Email (work email)
- Subject: Dr. [Last Name] — quick question
- Body: “Dr. [Last Name], I recruit physicians for [organization/type]. Are you open to a brief call about a [specialty] role in [location]? If not you, who’s best to contact? — [Name], [Phone]”
Template 3: Follow-up (after no response)
- Body: “Circling back, Dr. [Last Name]. If timing’s bad, I can send details and close the loop. Preferred channel: phone or email?”
Ops note: tie each outreach attempt back to refresh_date so you can see whether stale records are dragging down deliverability and connect rates.
Legal and ethical use
Use physician contact data for legitimate recruiting outreach with a clear business purpose. Respect opt-outs immediately, keep suppression lists, and follow applicable privacy and communications laws in the jurisdictions where you operate. If you’re unsure about a specific rule around texting, calling hours, or email compliance, get counsel — this article is operational guidance, not legal advice.
Evidence and trust notes
We treat provider identity and contact hygiene as an operations problem: stable keys, clean fields, and logged recency. For how we evaluate data quality and sourcing practices, see our methodology: trust methodology.
External reference: NPI is defined and maintained via the NPPES system: https://nppes.cms.hhs.gov/.
FAQs
What’s the minimum set of columns I need for a clean import?
At minimum: NPI, first_name, last_name, and refresh_date. Then add at least one contact channel (phone_main or email_work) plus source_system for traceability.
Why is NPI the best dedupe key for physicians?
NPI is a unique, government-issued provider identifier that stays fixed even if a provider changes name, address, or employer. Phones and emails are attributes that change; NPI is the stable identity anchor for dedupe and record updates.
How should I format phone numbers in the CSV?
Pick one standard and enforce it. E.164 (+1XXXXXXXXXX) is the cleanest for systems that support it. Otherwise use digits-only consistently and keep extensions out of the number field.
What should I do when two rows share the same NPI but different phones/emails?
Keep one provider record (by NPI) and treat phones/emails as updatable attributes. Preserve the most recent refresh_date and store older contact points in notes or secondary fields if your ATS supports it.
How do I avoid breaking my ATS with duplicates on re-import?
Write the rule: NPI is unique. Import updates should match on NPI and update fields without creating a new record. Pilot with 10 rows, confirm behavior, then run the full import.
Next steps
- If your goal is enrichment after upload, use the primary workflow: upload a physician list for enrichment.
- If you already have a file, run the QUARANTINE validation rules above, then upload your CSV for enrichment.
- If you want to test the workflow end-to-end, start free search & preview data and export using the header above.
About the Author
Ben Argeband is the Founder and CEO of Swordfish.ai and Heartbeat.ai. With deep expertise in data and SaaS, he has built two successful platforms trusted by over 50,000 sales and recruitment professionals. Ben’s mission is to help teams find direct contact information for hard-to-reach professionals and decision-makers, providing the shortest route to their next win. Connect with Ben on LinkedIn.