Skip to main content
Each example chains two to four tools to complete one task. Every example includes the CLI, Node.js, and Python.

1. Lead Research & Enrichment

Goal: Research a target company and build a complete profile of key contacts. Tools used: LinkUp (AI search) → Hunter (email finding) → Apollo (enrichment)
# 1. Research the company with AI search
orth run linkup /search --body '{"q": "stripe company funding valuation news 2026", "depth": "standard"}'

# 2. Find contacts at the company
orth run hunter /domain-search --body '{"domain": "stripe.com"}'

# 3. Enrich the top contact (use an email from step 2)
orth run apollo /v1/people/match --body '{"email": "founder@stripe.com"}'
const ORTH_KEY = process.env.ORTHOGONAL_API_KEY;

async function run(api, path, body) {
  const res = await fetch('https://api.orthogonal.com/v1/run', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${ORTH_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ api, path, body })
  });
  return res.json();
}

async function researchLead(company) {
  // Step 1: Research the company with AI search
  const research = await run('linkup', '/search', {
    q: `${company} company funding valuation news 2026`,
    depth: 'standard'
  });
  
  // Step 2: Find contacts at the company
  const contacts = await run('hunter', '/domain-search', {
    domain: `${company}.com`
  });
  
  // Step 3: Enrich the top contact
  const topContact = contacts.data?.data?.emails?.[0];
  if (topContact?.value) {
    const enriched = await run('apollo', '/v1/people/match', {
      email: topContact.value
    });
    return { research: research.data, contact: enriched.data };
  }
  
  return { research: research.data, contacts: contacts.data };
}


const result = await researchLead('stripe');
import requests
import os

ORTH_KEY = os.environ['ORTHOGONAL_API_KEY']

def run(api, path, body):
    return requests.post(
        'https://api.orthogonal.com/v1/run',
        headers={'Authorization': f'Bearer {ORTH_KEY}'},
        json={'api': api, 'path': path, 'body': body}
    ).json()

def research_lead(company):
    # Step 1: Research the company with AI search
    research = run('linkup', '/search', {
        'q': f'{company} company funding valuation news 2026',
        'depth': 'standard'
    })
    
    # Step 2: Find contacts at the company
    contacts = run('hunter', '/domain-search', {
        'domain': f'{company}.com'
    })
    
    # Step 3: Enrich the top contact
    emails = contacts.get('data', {}).get('data', {}).get('emails', [])
    if emails:
        enriched = run('apollo', '/v1/people/match', {
            'email': emails[0]['value']
        })
        return {'research': research['data'], 'contact': enriched['data']}
    
    return {'research': research['data'], 'contacts': contacts['data']}


result = research_lead('stripe')

2. Competitor Social Intelligence

Goal: Monitor a competitor’s social media presence and extract brand assets. Tools used: Shofo (social scraping) → Brand.dev (brand extraction) → Olostep (web scraping)
# 1. Recent LinkedIn posts
orth run shofo /linkedin/company-posts --body '{"company_url": "https://linkedin.com/company/notionhq"}'

# 2. Brand assets - logos, colors
orth run brand-dev /v1/brand/retrieve --body '{"domain": "notion.so"}'

# 3. Scrape the pricing page
orth run olostep /v1/scrapes --body '{"url_to_scrape": "https://notion.so/pricing", "formats": ["markdown"]}'
async function analyzeCompetitor(domain, linkedinSlug) {
  // Step 1: Get their recent LinkedIn posts
  const posts = await run('shofo', '/linkedin/company-posts', {
    company_url: `https://linkedin.com/company/${linkedinSlug}`
  });
  
  // Step 2: Extract brand assets - logos, colors
  const brand = await run('brand-dev', '/v1/brand/retrieve', {
    domain: domain
  });
  
  // Step 3: Scrape their pricing page
  const pricing = await run('olostep', '/v1/scrapes', {
    url_to_scrape: `https://${domain}/pricing`,
    formats: ['markdown']
  });
  
  return {
    socialActivity: posts.data,
    brandAssets: brand.data,
    pricingInfo: pricing.data
  };
}


const intel = await analyzeCompetitor('notion.so', 'notionhq');
def analyze_competitor(domain, linkedin_slug):
    # Step 1: Get their recent LinkedIn posts
    posts = run('shofo', '/linkedin/company-posts', {
        'company_url': f'https://linkedin.com/company/{linkedin_slug}'
    })
    
    # Step 2: Extract brand assets - logos, colors
    brand = run('brand-dev', '/v1/brand/retrieve', {
        'domain': domain
    })
    
    # Step 3: Scrape their pricing page
    pricing = run('olostep', '/v1/scrapes', {
        'url_to_scrape': f'https://{domain}/pricing',
        'formats': ['markdown']
    })
    
    return {
        'social_activity': posts['data'],
        'brand_assets': brand['data'],
        'pricing_info': pricing['data']
    }


intel = analyze_competitor('notion.so', 'notionhq')

3. Event-Based Prospecting

Goal: Find people who recently engaged with relevant content and enrich them for outreach. Tools used: Fiber (people search) → Shofo (social activity) → Tomba (email finding)
# 1. Find people matching your ICP
orth run fiber /v1/natural-language-search/profiles --body '{"query": "VP of Sales at Series B SaaS companies in San Francisco", "limit": 10}'

# For each profile from step 1, plug in its linkedin_url:
# 2. Check recent LinkedIn activity
orth run shofo /linkedin/user-posts --body '{"profile_url": "<linkedin_url>"}'

# 3. Find their email
orth run tomba /v1/linkedin --body '{"url": "<linkedin_url>"}'
async function findEngagedProspects(criteria) {
  // Step 1: Find people matching your ICP
  const prospects = await run('fiber', '/v1/natural-language-search/profiles', {
    query: criteria,
    limit: 10
  });
  
  const enrichedProspects = [];
  
  for (const person of prospects.data?.profiles || []) {
    // Step 2: Check their recent LinkedIn activity
    const activity = await run('shofo', '/linkedin/user-posts', {
      profile_url: person.linkedin_url
    });
    
    // Step 3: Find their email
    const email = await run('tomba', '/v1/linkedin', {
      url: person.linkedin_url
    });
    
    enrichedProspects.push({
      ...person,
      recentPosts: activity.data?.posts?.slice(0, 3),
      email: email.data?.data?.email
    });
  }
  
  return enrichedProspects;
}


const prospects = await findEngagedProspects(
  'VP of Sales at Series B SaaS companies in San Francisco'
);
def find_engaged_prospects(criteria):
    # Step 1: Find people matching your ICP
    prospects = run('fiber', '/v1/natural-language-search/profiles', {
        'query': criteria,
        'limit': 10
    })
    
    enriched_prospects = []
    
    for person in prospects.get('data', {}).get('profiles', []):
        # Step 2: Check their recent LinkedIn activity
        activity = run('shofo', '/linkedin/user-posts', {
            'profile_url': person['linkedin_url']
        })
        
        # Step 3: Find their email
        email = run('tomba', '/v1/linkedin', {
            'url': person['linkedin_url']
        })
        
        enriched_prospects.append({
            **person,
            'recent_posts': activity.get('data', {}).get('posts', [])[:3],
            'email': email.get('data', {}).get('data', {}).get('email')
        })
    
    return enriched_prospects


prospects = find_engaged_prospects(
    'VP of Sales at Series B SaaS companies in San Francisco'
)

4. Account-Based Marketing Research

Goal: Deep-dive on a target account - company intel, key people, and their social presence. Tools used: Brand.dev (company data) → Fiber (find employees) → Apollo (enrich contacts)
# 1. Company brand info and products
orth run brand-dev /v1/brand/retrieve --body '{"domain": "figma.com"}'

# 2. Find decision makers
orth run fiber /v1/natural-language-search/profiles --body '{"query": "executives and VPs at figma.com company", "limit": 5}'

# For each profile from step 2, plug in its linkedin_url:
# 3. Enrich with contact details
orth run apollo /v1/people/match --body '{"linkedin_url": "<linkedin_url>"}'
async function abmResearch(targetDomain) {
  // Step 1: Get company brand info and products
  const company = await run('brand-dev', '/v1/brand/retrieve', {
    domain: targetDomain
  });
  
  // Step 2: Find decision makers
  const people = await run('fiber', '/v1/natural-language-search/profiles', {
    query: `executives and VPs at ${targetDomain} company`,
    limit: 5
  });
  
  // Step 3: Enrich each person with contact details
  const enrichedPeople = [];
  for (const person of people.data?.profiles || []) {
    const enriched = await run('apollo', '/v1/people/match', {
      linkedin_url: person.linkedin_url
    });
    enrichedPeople.push({
      ...person,
      contact: enriched.data?.person
    });
  }
  
  return {
    company: company.data,
    decisionMakers: enrichedPeople
  };
}


const account = await abmResearch('figma.com');
def abm_research(target_domain):
    # Step 1: Get company brand info and products
    company = run('brand-dev', '/v1/brand/retrieve', {
        'domain': target_domain
    })
    
    # Step 2: Find decision makers
    people = run('fiber', '/v1/natural-language-search/profiles', {
        'query': f'executives and VPs at {target_domain} company',
        'limit': 5
    })
    
    # Step 3: Enrich each person with contact details
    enriched_people = []
    for person in people.get('data', {}).get('profiles', []):
        enriched = run('apollo', '/v1/people/match', {
            'linkedin_url': person['linkedin_url']
        })
        enriched_people.append({
            **person,
            'contact': enriched.get('data', {}).get('person')
        })
    
    return {
        'company': company['data'],
        'decision_makers': enriched_people
    }


account = abm_research('figma.com')

5. Content & Trigger Monitoring

Goal: Monitor social channels for buying signals and company news. Tools used: Shofo (X/Twitter monitoring) → LinkUp (news search) → Riveter (structured extraction)
# 1. Recent tweets from the company
orth run shofo /x/user-posts --body '{"username": "stripe"}'

# 2. Recent news and announcements
orth run linkup /search --body '{"q": "stripe.com announcement funding launch 2026", "depth": "standard"}'

# 3. Extract structured triggers from the news text (paste content from step 2)
orth run riveter /v1/run --body '{"input": "<news text>", "output_schema": {"type": "object", "properties": {"funding_events": {"type": "array", "items": {"type": "string"}}, "product_launches": {"type": "array", "items": {"type": "string"}}, "hiring_signals": {"type": "array", "items": {"type": "string"}}, "expansion_news": {"type": "array", "items": {"type": "string"}}}}}'
async function monitorTriggers(companyHandle, domain) {
  // Step 1: Get recent tweets mentioning the company
  const tweets = await run('shofo', '/x/user-posts', {
    username: companyHandle
  });
  
  // Step 2: Search for recent news/announcements
  const news = await run('linkup', '/search', {
    q: `${domain} announcement funding launch 2026`,
    depth: 'standard'
  });
  
  // Step 3: Extract structured triggers from the news
  const triggers = await run('riveter', '/v1/run', {
    input: news.data?.results?.map(r => r.content).join('\n\n'),
    output_schema: {
      type: 'object',
      properties: {
        funding_events: { type: 'array', items: { type: 'string' } },
        product_launches: { type: 'array', items: { type: 'string' } },
        hiring_signals: { type: 'array', items: { type: 'string' } },
        expansion_news: { type: 'array', items: { type: 'string' } }
      }
    }
  });
  
  return {
    socialActivity: tweets.data,
    news: news.data,
    triggers: triggers.data
  };
}


const signals = await monitorTriggers('stripe', 'stripe.com');
def monitor_triggers(company_handle, domain):
    # Step 1: Get recent tweets mentioning the company
    tweets = run('shofo', '/x/user-posts', {
        'username': company_handle
    })
    
    # Step 2: Search for recent news/announcements
    news = run('linkup', '/search', {
        'q': f'{domain} announcement funding launch 2026',
        'depth': 'standard'
    })
    
    # Step 3: Extract structured triggers from the news
    content = '\n\n'.join([r.get('content', '') for r in news.get('data', {}).get('results', [])])
    triggers = run('riveter', '/v1/run', {
        'input': content,
        'output_schema': {
            'type': 'object',
            'properties': {
                'funding_events': {'type': 'array', 'items': {'type': 'string'}},
                'product_launches': {'type': 'array', 'items': {'type': 'string'}},
                'hiring_signals': {'type': 'array', 'items': {'type': 'string'}},
                'expansion_news': {'type': 'array', 'items': {'type': 'string'}}
            }
        }
    })
    
    return {
        'social_activity': tweets['data'],
        'news': news['data'],
        'triggers': triggers['data']
    }


signals = monitor_triggers('stripe', 'stripe.com')