Oppora in Clay
Use Clay's built-in HTTP API enrichment column to call Oppora directly from any table. Save your API key once as a workspace-level HTTP API account, then drop the recipes below into any column.
Before you start
- 1An Oppora API key (Integrations → Oppora API in the app). You'll see one secret starting with opp_live_… — copy it once; it's never shown again.
- 2A paid Oppora plan (Pro or Max). API keys can't be generated on Free.
- 3A Clay workspace with at least one table containing the input columns the recipe expects (e.g. first_name, last_name, company_domain).
Save your Oppora credentials once
Clay's HTTP API (Headers) account stores your Bearer token encrypted at the workspace level. Set it up once and every enrichment column reuses it — no pasting the key into every cell.
- In Clay, click your workspace name (top-left) → Settings → Connections.
- Click Add connection → pick HTTP API (Headers).
- Name it
Oppora. In the headers section, add a single row:
Authorization: Bearer YOUR_KEY
Save. Now every recipe below picks Oppora from the "Account" dropdown instead of asking for headers each time.
Recipes
Each recipe is one Oppora endpoint. In Clay: Add enrichment → HTTP API → Configure tab → paste the URL, method, and body below. Reference your table columns inside the body with {{ column_name }}.
POST /email/searchFind email by name + domain
Resolves a verified work email when you have a person's name and their company's website domain.
{
"first_name": "Alice",
"last_name": "Chen",
"domain": "stripe.com"
}{
"email": "[email protected]",
"status": "valid",
"source": "oppora",
"credit_charged": 1,
"credits_remaining": 4823
}- •`domain` is required — free-text company names are not accepted (they cause wrong-company matches).
- •Credit is charged only when an email is returned with status `valid` or `risky`. Misses are free.
Set Method = POST, URL = https://api.oppora.ai/api/v1/public/email/search, Body type = JSON. Paste the body and swap the values for column refs:
{
"first_name": "{{ first_name }}",
"last_name": "{{ last_name }}",
"domain": "{{ company_domain }}"
}On the response, map $.email and $.status into new columns. Free on misses (no credit charged when status is unknown).
POST /email/verifyVerify an email
Check deliverability before sending. Use `mode: "advanced"` for catch-all domains where `standard` returns `risky` or `unknown`.
{
"email": "[email protected]",
"mode": "standard"
}{
"email": "[email protected]",
"mode": "standard",
"status": "valid",
"credit_charged": 1,
"credits_remaining": 4822
}- •`mode` is `standard` (fast) or `advanced` (deep SMTP, catch-all aware). Both charge on result.
Useful as a second column right after email_search for catch-all domains. Use "mode": "advanced" in a third column for risky / unknown rows.
{
"email": "{{ email }}",
"mode": "standard"
}POST /phone/searchLookup phone from LinkedIn URL
Best with a LinkedIn URL. Falls back to (name + company) or (name + domain). DB-cache hits are free; external provider hits charge 1 phone credit on success.
{
"linkedin_url": "https://www.linkedin.com/in/alice-chen-vp"
}{
"phone": "+14155551234",
"status": "valid",
"source": "oppora_db",
"credit_charged": 0,
"credits_remaining": 1200
}- •`source: "oppora_db"` = pulled from cache (free). External provider sources (wiza, dropcontact, etc.) charge 1 credit per resolved phone.
LinkedIn URL is the strongest signal. For rows that don't have one, fall back to name + company/domain:
{
"linkedin_url": "{{ linkedin_url }}"
}{
"first_name": "{{ first_name }}",
"last_name": "{{ last_name }}",
"domain": "{{ company_domain }}"
}POST /discover/companiesDiscover companies matching ICP filters
Search the global company DB by industry, size, location, revenue, funding, growth. Returns up to 100 rows per page with cursor pagination. Every row carries an Oppora `id` so you can chain into add-to-list flows.
{
"industry": ["Software Development"],
"hq_country": "USA",
"size": ["51-200", "201-500"],
"revenue_range_min": 5000000,
"limit": 25
}{
"data": [
{
"id": 8421,
"name": "Stripe",
"domain": "stripe.com",
"industry": "Financial Services",
"size": "5001-10000",
"employee_count": 8200,
"year_founded": 2010,
"total_funding_usd": 8700000000,
"country": "USA"
}
],
"count": 25,
"total": 1842,
"next_cursor": "eyJjdXJzb3IiOiIuLi4ifQ",
"has_more": true,
"credit_charged": 1,
"credits_remaining": 4821
}- •Resolve exact filter values via `GET /filters/industries` and `GET /filters/countries` first — wrong strings match zero rows.
- •`hq_country` is a single ISO 3-alpha code ("USA", "GBR", "IND").
Use Clay's "Use as source" option (instead of enrichment) to populate a new table from Oppora's company database. Map $.data[*] as the row source — each item becomes a row.
For pagination: store $.next_cursor and re-run with it in "next_cursor": "..." until has_more is false.
POST /discover/peopleDiscover people by title, department, company
Search the global people DB by title, department, management level, company, industry, skills, location, years of experience. Returns the same row shape your AI/list tools expect.
{
"title": ["VP Sales", "Head of Sales"],
"departments": ["Sales"],
"management_levels": ["VP", "Director"],
"company_name": ["Stripe", "Plaid"],
"years_experience": ["6 to 10 years", "More than 10 years"],
"limit": 25
}{
"data": [
{
"id": 42818,
"first_name": "Alice",
"last_name": "Chen",
"full_name": "Alice Chen",
"title": "VP of Sales",
"department": "Sales",
"management_level": "VP",
"linkedin_url": "https://www.linkedin.com/in/alice-chen-vp",
"location": "San Francisco",
"years_experience": "More than 10 years",
"company": {
"id": 8421,
"name": "Stripe",
"domain": "stripe.com"
}
}
],
"count": 25,
"total": 412,
"next_cursor": "eyJjdXJzb3IiOiIuLi4ifQ",
"has_more": true,
"credit_charged": 1,
"credits_remaining": 4820
}- •Resolve exact `departments` and `management_levels` values via `GET /filters/departments` and `GET /filters/management-levels` first.
- •`years_experience` must use the exact bucket labels: "Less than 1 year", "1 to 2 years", "3 to 5 years", "6 to 10 years", "More than 10 years".
- •No email or phone in the response — chain into `/email/search` or `/phone/search` for that.
Two patterns:
- Find decision-makers at a list of companies — start with a company table, add HTTP API as enrichment, pass
{{ company_name }}intocompany_nameand the column filters from your row. - Build a people table from scratch — use "Use as source"; each row of
$.data[*]becomes a person.
{
"title": ["VP Sales", "Head of Sales"],
"departments": ["Sales"],
"management_levels": ["VP", "Director"],
"company_name": ["{{ company_name }}"],
"limit": 10
}Need more endpoints?
The recipes above are the most common flows — Oppora exposes 17 REST endpoints in total (discovery, bulk async jobs, filter helpers, account info). See the full REST API reference for the complete surface.