Workflows

Each workflow includes full code and credit cost estimates.

The credit estimates in the workflows below are illustrative — see Credits for your plan's exact rates.

1. Find prospects and get their emails#

Goal: Search for 200 VP of Sales at B2B SaaS companies similar to your best customer, then reveal their verified email addresses.

Endpoints used: Search People → Reveal Emails

Credit cost:

  • 200 search results × 0.2 credits = 40 credits
  • ~79% email find rate → 158 emails × 1 credit = 158 credits
  • Total: 198 credits

Step 1 — Search for people#

curl -X POST "https://api.ocean.io/v3/search/people" \
  -H "X-Api-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 200,
    "peopleFilters": {
      "seniorities": ["VP", "C-Level"],
      "departments": ["Sales"],
      "jobTitleKeywords": { "anyOf": ["Sales", "Revenue", "Commercial"] }
    },
    "companiesFilters": {
      "lookalikeDomains": ["your-best-customer.com"],
      "companySizes": ["51-200", "201-500"],
      "industries": { "industries": ["B2B", "SaaS"] }
    }
  }'
import requests

response = requests.post(
    'https://api.ocean.io/v3/search/people',
    headers={'X-Api-Token': 'YOUR_API_TOKEN'},
    json={
        'size': 200,
        'peopleFilters': {
            'seniorities': ['VP', 'C-Level'],
            'departments': ['Sales'],
            'jobTitleKeywords': {'anyOf': ['Sales', 'Revenue', 'Commercial']},
        },
        'companiesFilters': {
            'lookalikeDomains': ['your-best-customer.com'],
            'companySizes': ['51-200', '201-500'],
            'industries': {'industries': ['B2B', 'SaaS']},
        },
    },
).json()
person_ids = [p['id'] for p in response['people']]
const response = await fetch('https://api.ocean.io/v3/search/people', {
  method: 'POST',
  headers: { 'X-Api-Token': 'YOUR_API_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    size: 200,
    peopleFilters: {
      seniorities: ['VP', 'C-Level'],
      departments: ['Sales'],
      jobTitleKeywords: { anyOf: ['Sales', 'Revenue', 'Commercial'] },
    },
    companiesFilters: {
      lookalikeDomains: ['your-best-customer.com'],
      companySizes: ['51-200', '201-500'],
      industries: { industries: ['B2B', 'SaaS'] },
    },
  }),
}).then(r => r.json());
const personIds = response.people.map(p => p.id);

The response includes an id field on each person. Collect these IDs.

Step 2 — Reveal emails#

Pass the IDs to Reveal Emails. Results arrive asynchronously to your webhookUrl.

curl -X POST "https://api.ocean.io/v2/reveal/emails" \
  -H "X-Api-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "personIds": ["abc123", "def456", "...up to 500 IDs"],
    "webhookUrl": "https://yourapp.com/webhooks/ocean-emails"
  }'
response = requests.post(
    'https://api.ocean.io/v2/reveal/emails',
    headers={'X-Api-Token': 'YOUR_API_TOKEN'},
    json={
        'personIds': person_ids,  # from Step 1
        'webhookUrl': 'https://yourapp.com/webhooks/ocean-emails',
    },
).json()
# {"status": "in progress"} — results arrive at your webhook
const response = await fetch('https://api.ocean.io/v2/reveal/emails', {
  method: 'POST',
  headers: { 'X-Api-Token': 'YOUR_API_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    personIds,  // from Step 1
    webhookUrl: 'https://yourapp.com/webhooks/ocean-emails',
  }),
}).then(r => r.json());
// {"status": "in progress"} — results arrive at your webhook

Step 3 — Handle the webhook#

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/webhooks/ocean-emails", methods=["POST"])
def receive_emails():
    data = request.json
    for result in data["results"]:
        person_id = result["personId"]
        email = result["email"]["address"]
        status = result["email"]["status"]

        if status in ("verified", "guessed") and email:
            # Add to your outreach sequence
            add_to_crm(person_id, email)

    return jsonify({"status": "ok"}), 200
// Express.js
app.post('/webhooks/ocean-emails', (req, res) => {
  for (const result of req.body.results) {
    const { personId, email } = result;
    if (['verified', 'guessed'].includes(email.status) && email.address) {
      addToCrm(personId, email.address);
    }
  }
  res.json({ status: 'ok' });
});

Note

For cold outreach, prefer verified emails. guessed emails are high-confidence but not SMTP-confirmed. Avoid catchAll addresses in high-volume campaigns.

Reference: Search People · Reveal Emails · Webhooks

2. Build a lookalike company segment#

Goal: You have 5 customers in a specific vertical. Find 500 similar companies to use as your next outreach segment.

Endpoints used: Search Companies (with lookalikeDomains)

Credit cost: 500 results × 0.2 credits = 100 credits

Step 1 — Search with lookalike domains#

curl -X POST "https://api.ocean.io/v3/search/companies" \
  -H "X-Api-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 500,
    "companiesFilters": {
      "lookalikeDomains": [
        "customer1.com",
        "customer2.com",
        "customer3.com"
      ],
      "companySizes": ["51-200", "201-500"],
      "primaryLocations": {
        "includeCountries": ["us", "gb", "de"]
      },
      "excludeDomains": ["customer1.com", "customer2.com", "customer3.com"]
    }
  }'
import requests

response = requests.post(
    'https://api.ocean.io/v3/search/companies',
    headers={'X-Api-Token': 'YOUR_API_TOKEN'},
    json={
        'size': 500,
        'companiesFilters': {
            'lookalikeDomains': ['customer1.com', 'customer2.com', 'customer3.com'],
            'companySizes': ['51-200', '201-500'],
            'primaryLocations': {'includeCountries': ['us', 'gb', 'de']},
            'excludeDomains': ['customer1.com', 'customer2.com', 'customer3.com'],
        },
    },
).json()
const response = await fetch('https://api.ocean.io/v3/search/companies', {
  method: 'POST',
  headers: { 'X-Api-Token': 'YOUR_API_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    size: 500,
    companiesFilters: {
      lookalikeDomains: ['customer1.com', 'customer2.com', 'customer3.com'],
      companySizes: ['51-200', '201-500'],
      primaryLocations: { includeCountries: ['us', 'gb', 'de'] },
      excludeDomains: ['customer1.com', 'customer2.com', 'customer3.com'],
    },
  }),
}).then(r => r.json());

Tip: Diverse seeds cast a wider net

Using multiple different companies as lookalikeDomains broadens the results. Using similar companies narrows them. Start with 3–5 of your best-fit customers.

Step 2 — Paginate to get all results#

import requests

def fetch_lookalike_companies(seed_domains, api_token, target_count=500):
    url = "https://api.ocean.io/v3/search/companies"
    headers = {"X-Api-Token": api_token, "Content-Type": "application/json"}
    companies = []
    search_after = None

    while len(companies) < target_count:
        payload = {
            "size": min(100, target_count - len(companies)),
            "companiesFilters": {
                "lookalikeDomains": seed_domains,
                "companySizes": ["51-200", "201-500"],
                "excludeDomains": seed_domains
            }
        }
        if search_after:
            payload["searchAfter"] = search_after

        response = requests.post(url, headers=headers, json=payload).json()
        companies.extend(response["companies"])
        search_after = response.get("searchAfter")
        if not search_after:
            break

    return companies
async function fetchLookalikeCompanies(seedDomains, apiToken, targetCount = 500) {
  const url = 'https://api.ocean.io/v3/search/companies';
  const headers = { 'X-Api-Token': apiToken, 'Content-Type': 'application/json' };
  const companies = [];
  let searchAfter;

  while (companies.length < targetCount) {
    const body = {
      size: Math.min(100, targetCount - companies.length),
      companiesFilters: {
        lookalikeDomains: seedDomains,
        companySizes: ['51-200', '201-500'],
        excludeDomains: seedDomains,
      },
    };
    if (searchAfter) body.searchAfter = searchAfter;

    const data = await fetch(url, {
      method: 'POST',
      headers,
      body: JSON.stringify(body),
    }).then(r => r.json());

    companies.push(...data.companies);
    searchAfter = data.searchAfter;
    if (!searchAfter) break;
  }

  return companies;
}

Step 3 — Use the results#

Each company object includes domain, name, companySize, industries, technologies, revenue, and more — enough to qualify accounts before reaching out.

Reference: Search Companies · Pagination

3. Enrich your CRM with missing company data#

Goal: You have 1,000 company domains in your CRM with incomplete firmographic data. Enrich them all with company size, industry, technology stack, and revenue.

Endpoints used: Warmup Companies → Enrich Companies (Batch)

Credit cost: 1,000 enriched companies × 0.1 credits = 100 credits

Before enriching, check which domains are already in Ocean.io's database. Triggered domains need 2–5 minutes to index.

curl -X POST "https://api.ocean.io/v2/warmup/companies" \
  -H "X-Api-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "domains": ["company1.com", "company2.com", "...up to 500 domains"]
  }'
import requests

response = requests.post(
    'https://api.ocean.io/v2/warmup/companies',
    headers={'X-Api-Token': 'YOUR_API_TOKEN'},
    json={'domains': ['company1.com', 'company2.com']},
).json()
# response["successfulDomains"] — ready now
# response["triggeredDomains"] — wait 2–5 min
const response = await fetch('https://api.ocean.io/v2/warmup/companies', {
  method: 'POST',
  headers: { 'X-Api-Token': 'YOUR_API_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({ domains: ['company1.com', 'company2.com'] }),
}).then(r => r.json());
// response.successfulDomains — ready now
// response.triggeredDomains — wait 2–5 min

The response splits domains into successfulDomains (ready now) and triggeredDomains (wait 2–5 min).

Step 2 — Enrich in batches#

The Enrich Companies (Batch) endpoint takes up to 10,000 domains at once. Results are delivered to your webhook.

curl -X POST "https://api.ocean.io/v2/enrich/companies" \
  -H "X-Api-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "companyDataMapping": {
      "crm-account-001": { "company": { "domain": "company1.com" } },
      "crm-account-002": { "company": { "domain": "company2.com" } }
    },
    "webhookUrl": "https://yourapp.com/webhooks/ocean-enrich"
  }'
response = requests.post(
    'https://api.ocean.io/v2/enrich/companies',
    headers={'X-Api-Token': 'YOUR_API_TOKEN'},
    json={
        'companyDataMapping': {
            'crm-account-001': {'company': {'domain': 'company1.com'}},
            'crm-account-002': {'company': {'domain': 'company2.com'}},
        },
        'webhookUrl': 'https://yourapp.com/webhooks/ocean-enrich',
    },
).json()
# {"status": "in progress"} — results arrive at your webhook
const response = await fetch('https://api.ocean.io/v2/enrich/companies', {
  method: 'POST',
  headers: { 'X-Api-Token': 'YOUR_API_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    companyDataMapping: {
      'crm-account-001': { company: { domain: 'company1.com' } },
      'crm-account-002': { company: { domain: 'company2.com' } },
    },
    webhookUrl: 'https://yourapp.com/webhooks/ocean-enrich',
  }),
}).then(r => r.json());
// {"status": "in progress"} — results arrive at your webhook

The keys in companyDataMapping are your CRM IDs — they come back in the webhook payload so you can match enriched data to the right record.

Step 3 — Handle the webhook#

@app.route("/webhooks/ocean-enrich", methods=["POST"])
def receive_enrichment():
    data = request.json
    for crm_id, result in data["results"].items():
        if result["status"] == "found":
            company = result["company"]
            update_crm_account(crm_id, {
                "industry": company.get("industries", []),
                "employee_count": company.get("employeeCountOcean"),
                "revenue": company.get("revenue"),
                "technologies": company.get("technologies", [])
            })
        elif result["status"] == "triggered":
            # Re-enrich this one in 5 minutes
            schedule_retry(crm_id, delay_minutes=5)

    return jsonify({"status": "ok"}), 200
// Express.js
app.post('/webhooks/ocean-enrich', (req, res) => {
  for (const [crmId, result] of Object.entries(req.body.results)) {
    if (result.status === 'found') {
      updateCrmAccount(crmId, {
        industry: result.company.industries ?? [],
        employeeCount: result.company.employeeCountOcean,
        revenue: result.company.revenue,
        technologies: result.company.technologies ?? [],
      });
    } else if (result.status === 'triggered') {
      scheduleRetry(crmId, { delayMinutes: 5 });
    }
  }
  res.json({ status: 'ok' });
});

Reference: Enrich Companies (Batch) · Warmup Companies · Webhooks

4. Find decision-makers at a list of target accounts#

Goal: You have 50 target account domains. Find all VP+ in Sales and Marketing at those companies, one contact per company.

Endpoints used: Search People (with includeDomains + peoplePerCompany)

Credit cost: Up to 50 results × 0.2 credits = ≤10 credits

curl -X POST "https://api.ocean.io/v3/search/people" \
  -H "X-Api-Token: YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "size": 50,
    "peoplePerCompany": 1,
    "peopleFilters": {
      "seniorities": ["VP", "C-Level", "Head", "Director"],
      "departments": ["Sales", "Marketing and Advertising"]
    },
    "companiesFilters": {
      "includeDomains": [
        "targetaccount1.com",
        "targetaccount2.com",
        "targetaccount3.com"
      ]
    }
  }'
import requests

response = requests.post(
    'https://api.ocean.io/v3/search/people',
    headers={'X-Api-Token': 'YOUR_API_TOKEN'},
    json={
        'size': 50,
        'peoplePerCompany': 1,
        'peopleFilters': {
            'seniorities': ['VP', 'C-Level', 'Head', 'Director'],
            'departments': ['Sales', 'Marketing and Advertising'],
        },
        'companiesFilters': {
            'includeDomains': [
                'targetaccount1.com',
                'targetaccount2.com',
                'targetaccount3.com',
            ],
        },
    },
).json()
const response = await fetch('https://api.ocean.io/v3/search/people', {
  method: 'POST',
  headers: { 'X-Api-Token': 'YOUR_API_TOKEN', 'Content-Type': 'application/json' },
  body: JSON.stringify({
    size: 50,
    peoplePerCompany: 1,
    peopleFilters: {
      seniorities: ['VP', 'C-Level', 'Head', 'Director'],
      departments: ['Sales', 'Marketing and Advertising'],
    },
    companiesFilters: {
      includeDomains: ['targetaccount1.com', 'targetaccount2.com', 'targetaccount3.com'],
    },
  }),
}).then(r => r.json());

peoplePerCompany: 1 ensures you get at most one contact per company, choosing the highest-matched person. Combine with seniorities to get the most senior person in your target department.

Want emails too?

Collect the returned id values and pass them to Reveal Emails. With 50 contacts and a ~79% find rate, expect around 40 verified emails for roughly 40 credits.

Reference: Search People · Reveal Emails