You get a Power Automate flow that finds Dynamics 365 contacts with a LinkedIn URL and no email, asks LeadOcean for each one, and writes the result back to Dataverse. The link is one HTTP action calling POST /v1/people/enrich. It runs on a schedule, skips contacts that already have an email, and never overwrites a value you typed.
This recipe uses Power Automate and the Dataverse connector, which offers List rows and Update a row (Microsoft Learn, September 2026). LeadOcean needs a free key.
How it works
- Create a LeadOcean key. Sign up at app.leadocean.io/register. The free plan has 1,000 records, one-off, no card.
- Add a LinkedIn column to Contact. Dynamics holds no standard LinkedIn field, so add a text column such as
new_linkedinurland fill it from your list. - Create a scheduled cloud flow. Add a Recurrence trigger. Daily at night suits a backlog.
- Add List rows on Contacts. Filter to contacts that need data, and set Top Count to 100 so each run stays small.
- Add an Apply to each loop with an HTTP action. POST the LinkedIn URL to LeadOcean with the
x-api-keyheader. - Gate on email status. Continue only when the first email is
verifiedorcatch_all_valid. A 404 means LeadOcean holds nothing and costs nothing. - Add Update a row. Write email, phone and job title to the contact.
- Test on five contacts. Set Top Count to 5, run the flow once, and open each record.
Licensing: a Power Automate Premium licence covers standard, premium and custom connectors. Dynamics 365 licences include only a limited set of Power Automate capabilities, listed in Microsoft's Power Platform Licensing Guide (Microsoft Learn, October 2026). Check yours before you build.
Configuration
Set the List rows filter in OData so only blank, enrichable contacts come back. emailaddress1 is the standard email column on Contact.
Table name: Contacts
Filter rows: emailaddress1 eq null and new_linkedinurl ne null
Top Count: 100The HTTP action sends one identifier per call. The expression in the body is Power Automate's dynamic content for the new_linkedinurl column.
Method: POST
URI: https://api.leadocean.io/v1/people/enrich
Headers: x-api-key: <your LeadOcean key>
content-type: application/json
Body: {
"linkedin_url": "@{items('Apply_to_each')?['new_linkedinurl']}",
"reveal_email": true
}Store the key in an environment variable or Azure Key Vault, not in the flow text. Test the same request from a terminal first.
curl -X POST "https://api.leadocean.io/v1/people/enrich" \
-H "x-api-key: $LEADOCEAN_API_KEY" \
-H "content-type: application/json" \
-d '{"linkedin_url":"https://www.linkedin.com/in/jane-doe","reveal_email":true}'Send exactly one identifier. Two is a 400. reveal_email costs no extra record (LeadOcean docs, September 2026). Addresses come back best first, so the first entry is the one to write:
first(body('HTTP')?['data']?['contact_data']?['contact_emails'])?['email']Field mapping
The response nests data under data.contact_data. Map these into Contact columns.
| LeadOcean field | Dynamics 365 column | Note |
|---|---|---|
data.contact_data.contact_emails[0].email | emailaddress1 | Write only when the status is verified or catch_all_valid. |
data.contact_data.email_status | custom text column | Keep it. It tells you which contacts are safe to email. |
data.contact_data.contact_phones[0].phone | mobilephone | Returned because reveal_email is true. |
data.contact_data.contact_current_experiences[0].job_title | jobtitle | The current role. Update it only if the field is blank. |
data.contact_data.contact_current_experiences[0].company_domain | custom text column | Use it to match the parent account. |
Dedupe: Dynamics 365 ships default duplicate detection rules for accounts and contacts, and you can add rules for other tables (Microsoft Learn, September 2026). This flow only updates existing rows, so it creates no new duplicates. Two habits keep it clean.
- Filter on
emailaddress1 eq null. A contact with an email is never touched. - Match by
new_linkedinurl, one URL per contact. Two contacts sharing a URL will both be enriched, so clean the column first.
Cost at 10,000 rows
At 10,000 contacts, LeadOcean costs $0 for the first 1,000 records and $97 on Solo for the rest. Power Automate adds its own licence cost.
LeadOcean. A hit counts as one record. A miss is a 404 and costs nothing. The Free plan covers 1,000 records, once. Solo is $97 a month with no per-record price and a pace of 10k enrichments every 5 hours, so 10,000 rows fit in one run (LeadOcean pricing). The Free rate limit is 5 requests a second, so keep the loop's concurrency low.
Dynamics 365 and Power Automate. Power Automate Premium is $15 per user a month, paid yearly; the page shows no monthly-billed rate (Microsoft, October 2026). Dataverse reads and updates count toward Power Platform request limits. A licensed Dynamics 365 Sales Enterprise user gets 40,000 requests per 24 hours (Microsoft Learn, September 2026). A run that lists, updates and calls out for 10,000 rows is roughly 20,000 or more requests, so batch over two nights on a small tenant.
| Item | 10,000 contacts |
|---|---|
| LeadOcean on Free | First 1,000 free, then 402 |
| LeadOcean on Solo | $97 for the month |
| Power Automate Premium, one user | $15 a month, billed yearly |
The request count is arithmetic from the limits above, not a measured run.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Flow will not save or run, licence error | The flow uses a capability outside the owner's licence | Assign a Power Automate Premium licence to the flow owner. |
| 401 from LeadOcean | Missing or wrong x-api-key header | Re-paste the key. The header is x-api-key, not Authorization. |
| 400 from LeadOcean | Blank or malformed new_linkedinurl | Add new_linkedinurl ne null to the filter and trim spaces. |
| 404 on some contacts | LeadOcean holds nothing for that person | Expected. It costs nothing. Add a branch that tags the contact. |
| 402 after a while | The free 1,000 records are spent | Move to Solo, or stop the flow. |
| 429 errors | Requests above 5 a second on Free | Set Apply to each concurrency to 1 and honor Retry-After. |
| Run stops at the daily cap | Dataverse request limit reached | Lower Top Count or split the run across days. |
FAQ
Can I enrich Leads and Accounts too?
Yes. Leads work the same way with POST /v1/people/enrich. For Accounts, POST /v1/companies/enrich takes a domain. Add a text column for the domain and repeat the flow.
Will it overwrite what my reps typed?
Not with the filter above. It only picks contacts whose email is empty. For job title, add a condition that writes only when jobtitle is empty.
Do I need a card to test this?
No. The free plan needs no card and gives the same API as Solo. Your 1,000 records last until you spend them.
Does LeadOcean keep my Dynamics data in sync?
No. It answers per call. The flow decides what to ask and when. Related recipes: Retool, Notion, Folk. Back to all integrations, or see pricing.
Enrich your Dynamics 365 contacts. Start free.
Free to start. No credit card. 1,000 records to spend whenever you like.
Get your free API key →