Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions apps/sim/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ API_ENCRYPTION_KEY=your_api_encryption_key # Use `openssl rand -hex 32` to gener
# COHERE_API_KEY= # Cohere API key for the Knowledge block reranker (rerank-v4.0-pro/-fast, rerank-v3.5). Alternatively set COHERE_API_KEY_1/2/3 for rotation.
# NEXT_PUBLIC_COHERE_CONFIGURED=true # Set when COHERE_API_KEY (or rotation keys) are pre-configured above. Hides the Cohere API Key field on the Knowledge block UI.

# Hosted tool API keys (Optional - lets Sim supply the key so users don't have to bring their own).
# Each provider reads `{PREFIX}_COUNT` then `{PREFIX}_1..N`, distributing requests round-robin across the keys.
# HUNTER_API_KEY_COUNT=2 # Number of Hunter.io keys for hosted Hunter blocks
# HUNTER_API_KEY_1= # Hunter.io API key #1
# HUNTER_API_KEY_2= # Hunter.io API key #2
# PEOPLEDATALABS_API_KEY_COUNT=2 # Number of People Data Labs keys for hosted PDL blocks
# PEOPLEDATALABS_API_KEY_1= # People Data Labs API key #1
# PEOPLEDATALABS_API_KEY_2= # People Data Labs API key #2

# Admin API (Optional - for self-hosted GitOps)
# ADMIN_API_KEY= # Use `openssl rand -hex 32` to generate. Enables admin API for workflow export/import.
# Usage: curl -H "x-admin-key: your_key" https://your-instance/api/v1/admin/workspaces
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ import {
FireworksIcon,
GeminiIcon,
GoogleIcon,
HunterIOIcon,
ImageIcon,
JinaAIIcon,
LinkupIcon,
MistralIcon,
OpenAIIcon,
ParallelIcon,
PeopleDataLabsIcon,
PerplexityIcon,
SerperIcon,
} from '@/components/icons'
Expand Down Expand Up @@ -156,6 +158,20 @@ const PROVIDERS: {
description: 'Brand assets, logos, colors, and company info',
placeholder: 'Enter your Brandfetch API key',
},
{
id: 'hunter',
name: 'Hunter',
icon: HunterIOIcon,
description: 'Email finder, verification, and domain search',
placeholder: 'Enter your Hunter.io API key',
},
{
id: 'peopledatalabs',
name: 'People Data Labs',
icon: PeopleDataLabsIcon,
description: 'Person and company enrichment, search, and identity',
placeholder: 'Enter your People Data Labs API key',
},
]

export function BYOK() {
Expand Down
1 change: 1 addition & 0 deletions apps/sim/blocks/blocks/hunter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ Return ONLY the search query text - no explanations.`,
required: true,
placeholder: 'Enter your Hunter.io API key',
password: true,
hideWhenHosted: true,
},
],
tools: {
Expand Down
1 change: 1 addition & 0 deletions apps/sim/blocks/blocks/peopledatalabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ export const PeopleDataLabsBlock: BlockConfig<PdlPersonEnrichResponse> = {
placeholder: 'Enter your People Data Labs API key',
password: true,
required: true,
hideWhenHosted: true,
},
],

Expand Down
2 changes: 2 additions & 0 deletions apps/sim/lib/api/contracts/byok-keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export const byokProviderIdSchema = z.enum([
'parallel_ai',
'brandfetch',
'cohere',
'hunter',
'peopledatalabs',
])

export const byokKeySchema = z.object({
Expand Down
13 changes: 13 additions & 0 deletions apps/sim/tools/hunter/companies_find.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { HunterEnrichmentParams, HunterEnrichmentResponse } from '@/tools/hunter/types'
import { HUNTER_API_KEY_PREFIX } from '@/tools/hunter/types'
import type { ToolConfig } from '@/tools/types'

export const companiesFindTool: ToolConfig<HunterEnrichmentParams, HunterEnrichmentResponse> = {
Expand All @@ -7,6 +8,18 @@ export const companiesFindTool: ToolConfig<HunterEnrichmentParams, HunterEnrichm
description: 'Enriches company data using domain name.',
version: '1.0.0',

hosting: {
envKeyPrefix: HUNTER_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'hunter',
// Companies Find (enrichment) is free on Hunter — no credits consumed.
pricing: { type: 'per_request', cost: 0 },
rateLimit: {
mode: 'per_request',
requestsPerMinute: 60,
},
},

params: {
domain: {
type: 'string',
Expand Down
14 changes: 13 additions & 1 deletion apps/sim/tools/hunter/discover.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { HunterDiscoverParams, HunterDiscoverResponse } from '@/tools/hunter/types'
import { DISCOVER_RESULTS_OUTPUT } from '@/tools/hunter/types'
import { DISCOVER_RESULTS_OUTPUT, HUNTER_API_KEY_PREFIX } from '@/tools/hunter/types'
import type { ToolConfig } from '@/tools/types'

export const discoverTool: ToolConfig<HunterDiscoverParams, HunterDiscoverResponse> = {
Expand All @@ -8,6 +8,18 @@ export const discoverTool: ToolConfig<HunterDiscoverParams, HunterDiscoverRespon
description: 'Returns companies matching a set of criteria using Hunter.io AI-powered search.',
version: '1.0.0',

hosting: {
envKeyPrefix: HUNTER_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'hunter',
// Discover is free on Hunter — no credits consumed.
pricing: { type: 'per_request', cost: 0 },
rateLimit: {
mode: 'per_request',
requestsPerMinute: 30,
},
},

params: {
query: {
type: 'string',
Expand Down
28 changes: 27 additions & 1 deletion apps/sim/tools/hunter/domain_search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import type {
HunterDomainSearchResponse,
HunterEmail,
} from '@/tools/hunter/types'
import { EMAILS_OUTPUT } from '@/tools/hunter/types'
import {
EMAILS_OUTPUT,
HUNTER_API_KEY_PREFIX,
HUNTER_SEARCH_CREDIT_USD,
} from '@/tools/hunter/types'
import type { ToolConfig } from '@/tools/types'

export const domainSearchTool: ToolConfig<HunterDomainSearchParams, HunterDomainSearchResponse> = {
Expand All @@ -12,6 +16,28 @@ export const domainSearchTool: ToolConfig<HunterDomainSearchParams, HunterDomain
description: 'Returns all the email addresses found using one given domain name, with sources.',
version: '1.0.0',

hosting: {
envKeyPrefix: HUNTER_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'hunter',
pricing: {
type: 'custom',
getCost: (_params, output) => {
const emails = output.emails
if (!Array.isArray(emails)) {
throw new Error('Hunter domain search response missing emails, cannot determine cost')
}
// Hunter counts one search credit only when a call returns at least one result.
const cost = emails.length > 0 ? HUNTER_SEARCH_CREDIT_USD : 0
return { cost, metadata: { credits: cost > 0 ? 1 : 0, emails: emails.length } }
},
},
rateLimit: {
mode: 'per_request',
requestsPerMinute: 60,
},
},

params: {
domain: {
type: 'string',
Expand Down
14 changes: 13 additions & 1 deletion apps/sim/tools/hunter/email_count.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { HunterEmailCountParams, HunterEmailCountResponse } from '@/tools/hunter/types'
import { DEPARTMENT_OUTPUT, SENIORITY_OUTPUT } from '@/tools/hunter/types'
import { DEPARTMENT_OUTPUT, HUNTER_API_KEY_PREFIX, SENIORITY_OUTPUT } from '@/tools/hunter/types'
import type { ToolConfig } from '@/tools/types'

export const emailCountTool: ToolConfig<HunterEmailCountParams, HunterEmailCountResponse> = {
Expand All @@ -8,6 +8,18 @@ export const emailCountTool: ToolConfig<HunterEmailCountParams, HunterEmailCount
description: 'Returns the total number of email addresses found for a domain or company.',
version: '1.0.0',

hosting: {
envKeyPrefix: HUNTER_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'hunter',
// Email Count is free on Hunter — no credits consumed.
pricing: { type: 'per_request', cost: 0 },
rateLimit: {
mode: 'per_request',
requestsPerMinute: 60,
},
},

params: {
domain: {
type: 'string',
Expand Down
26 changes: 25 additions & 1 deletion apps/sim/tools/hunter/email_finder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { HunterEmailFinderParams, HunterEmailFinderResponse } from '@/tools/hunter/types'
import { SOURCES_OUTPUT, VERIFICATION_OUTPUT } from '@/tools/hunter/types'
import {
HUNTER_API_KEY_PREFIX,
HUNTER_SEARCH_CREDIT_USD,
SOURCES_OUTPUT,
VERIFICATION_OUTPUT,
} from '@/tools/hunter/types'
import type { ToolConfig } from '@/tools/types'

export const emailFinderTool: ToolConfig<HunterEmailFinderParams, HunterEmailFinderResponse> = {
Expand All @@ -9,6 +14,25 @@ export const emailFinderTool: ToolConfig<HunterEmailFinderParams, HunterEmailFin
'Finds the most likely email address for a person given their name and company domain.',
version: '1.0.0',

hosting: {
envKeyPrefix: HUNTER_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'hunter',
pricing: {
type: 'custom',
getCost: (_params, output) => {
// Hunter counts one search credit only when an email is found.
const found = typeof output.email === 'string' && output.email.length > 0
const cost = found ? HUNTER_SEARCH_CREDIT_USD : 0
return { cost, metadata: { credits: found ? 1 : 0 } }
},
},
rateLimit: {
mode: 'per_request',
requestsPerMinute: 60,
},
},

params: {
domain: {
type: 'string',
Expand Down
24 changes: 23 additions & 1 deletion apps/sim/tools/hunter/email_verifier.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import type { HunterEmailVerifierParams, HunterEmailVerifierResponse } from '@/tools/hunter/types'
import { SOURCES_OUTPUT } from '@/tools/hunter/types'
import {
HUNTER_API_KEY_PREFIX,
HUNTER_VERIFICATION_CREDIT_USD,
SOURCES_OUTPUT,
} from '@/tools/hunter/types'
import type { ToolConfig } from '@/tools/types'

export const emailVerifierTool: ToolConfig<HunterEmailVerifierParams, HunterEmailVerifierResponse> =
Expand All @@ -10,6 +14,24 @@ export const emailVerifierTool: ToolConfig<HunterEmailVerifierParams, HunterEmai
'Verifies the deliverability of an email address and provides detailed verification status.',
version: '1.0.0',

hosting: {
envKeyPrefix: HUNTER_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'hunter',
pricing: {
type: 'custom',
// The verifier always consumes one verification (0.5 credit), regardless of result.
getCost: () => ({
cost: HUNTER_VERIFICATION_CREDIT_USD,
metadata: { verifications: 1 },
}),
},
rateLimit: {
mode: 'per_request',
requestsPerMinute: 60,
},
},

params: {
email: {
type: 'string',
Expand Down
19 changes: 19 additions & 0 deletions apps/sim/tools/hunter/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
// Common types for Hunter.io tools
import type { OutputProperty, ToolResponse } from '@/tools/types'

/**
* Env var prefix for Sim-hosted Hunter.io keys.
* Resolved at runtime as `HUNTER_API_KEY_COUNT` + `HUNTER_API_KEY_1..N`.
*/
export const HUNTER_API_KEY_PREFIX = 'HUNTER_API_KEY'

/**
* Dollar cost per Hunter.io credit when billing hosted-key usage.
*
* Hunter does not report per-call credit consumption in its responses, so cost is
* derived from the response: a "search" credit is consumed only when a call returns
* at least one result; a verification consumes half a credit.
*
* Estimate based on the Growth plan ($149/mo for 10,000 credits ≈ $0.015/credit) —
* see https://hunter.io/pricing. Tune if Sim's plan rate changes.
*/
export const HUNTER_SEARCH_CREDIT_USD = 0.015
export const HUNTER_VERIFICATION_CREDIT_USD = 0.0075

/**
* Shared output property definitions for Hunter.io API responses.
* These are reusable across all Hunter tools to ensure consistency.
Expand Down
13 changes: 13 additions & 0 deletions apps/sim/tools/peopledatalabs/autocomplete.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { PdlAutocompleteParams, PdlAutocompleteResponse } from '@/tools/peopledatalabs/types'
import { PEOPLEDATALABS_API_KEY_PREFIX } from '@/tools/peopledatalabs/types'
import { buildQueryString } from '@/tools/peopledatalabs/utils'
import type { OutputProperty, ToolConfig } from '@/tools/types'

Expand All @@ -19,6 +20,18 @@ export const autocompleteTool: ToolConfig<PdlAutocompleteParams, PdlAutocomplete
'Get autocomplete suggestions for a PDL field (title, skill, company, industry, location, school, major, role, sub_role).',
version: '1.0.0',

hosting: {
envKeyPrefix: PEOPLEDATALABS_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'peopledatalabs',
// Autocomplete is free on PDL (rate-limited only) — no credits consumed.
pricing: { type: 'per_request', cost: 0 },
rateLimit: {
mode: 'per_request',
requestsPerMinute: 60,
},
},

params: {
apiKey: {
type: 'string',
Expand Down
28 changes: 27 additions & 1 deletion apps/sim/tools/peopledatalabs/bulk_company_enrich.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import type {
PdlBulkCompanyEnrichResponse,
PdlBulkCompanyResultItem,
} from '@/tools/peopledatalabs/types'
import { projectCompany } from '@/tools/peopledatalabs/utils'
import { PDL_CREDIT_USD, PEOPLEDATALABS_API_KEY_PREFIX } from '@/tools/peopledatalabs/types'
import { countBulkMatched, projectCompany } from '@/tools/peopledatalabs/utils'
import type { OutputProperty, ToolConfig } from '@/tools/types'

const BULK_COMPANY_RESULT_PROPERTIES = {
Expand Down Expand Up @@ -32,6 +33,31 @@ export const bulkCompanyEnrichTool: ToolConfig<
'Enrich up to 100 companies in a single call. Provide a JSON array of request objects, each with a `params` object. Reference: https://docs.peopledatalabs.com/docs/bulk-company-enrichment-api',
version: '1.0.0',

hosting: {
envKeyPrefix: PEOPLEDATALABS_API_KEY_PREFIX,
apiKeyParam: 'apiKey',
byokProviderId: 'peopledatalabs',
pricing: {
type: 'custom',
// PDL charges 1 credit per matched record; unmatched records in the batch are free.
getCost: (_params, output) => {
const matched = countBulkMatched(output)
return { cost: matched * PDL_CREDIT_USD, metadata: { credits: matched } }
},
},
rateLimit: {
mode: 'custom',
requestsPerMinute: 10,
dimensions: [
{
name: 'credits',
limitPerMinute: 600,
extractUsage: (_params, response) => countBulkMatched(response),
},
],
},
},

params: {
apiKey: {
type: 'string',
Expand Down
Loading
Loading