feat: add 10 new CLI tools and integration guides from Claude connectors

New tools: Clay, Outreach, ZoomInfo, Close, Pendo, Similarweb,
Supermetrics, AirOps, Crossbeam, and Coupler.io. Each includes a
zero-dependency Node.js CLI and an integration guide.

Updates REGISTRY.md with new tool index entries, categories, and
MCP-enabled tools list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Corey Haines
2026-03-02 21:59:51 -08:00
parent edd613d33f
commit 4ff486a702
21 changed files with 3637 additions and 2 deletions
+163
View File
@@ -0,0 +1,163 @@
#!/usr/bin/env node
const API_KEY = process.env.AIROPS_API_KEY
const WORKSPACE_ID = process.env.AIROPS_WORKSPACE_ID
const BASE_URL = 'https://api.airops.com/v1'
if (!API_KEY) {
console.error(JSON.stringify({ error: 'AIROPS_API_KEY environment variable required' }))
process.exit(1)
}
if (!WORKSPACE_ID) {
console.error(JSON.stringify({ error: 'AIROPS_WORKSPACE_ID environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
const url = `${BASE_URL}${path}`
if (args['dry-run']) {
return { _dry_run: true, method, url, headers: { 'Authorization': 'Bearer ***', 'Content-Type': 'application/json' }, body: body || undefined }
}
const res = await fetch(url, {
method,
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
switch (cmd) {
case 'flows':
switch (sub) {
case 'list': {
result = await api('GET', `/workspaces/${WORKSPACE_ID}/flows`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/workspaces/${WORKSPACE_ID}/flows/${id}`)
break
}
case 'execute': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
const inputs = args.inputs
let parsedInputs = {}
if (inputs) {
try {
parsedInputs = JSON.parse(inputs)
} catch {
result = { error: '--inputs must be valid JSON' }
break
}
}
result = await api('POST', `/workspaces/${WORKSPACE_ID}/flows/${id}/execute`, { inputs: parsedInputs })
break
}
case 'runs': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/workspaces/${WORKSPACE_ID}/flows/${id}/runs`)
break
}
case 'run-status': {
const runId = args['run-id']
if (!runId) { result = { error: '--run-id required' }; break }
result = await api('GET', `/workspaces/${WORKSPACE_ID}/runs/${runId}`)
break
}
default:
result = { error: 'Unknown flows subcommand. Use: list, get, execute, runs, run-status' }
}
break
case 'workflows':
switch (sub) {
case 'list': {
result = await api('GET', `/workspaces/${WORKSPACE_ID}/workflows`)
break
}
case 'execute': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
const inputs = args.inputs
let parsedInputs = {}
if (inputs) {
try {
parsedInputs = JSON.parse(inputs)
} catch {
result = { error: '--inputs must be valid JSON' }
break
}
}
result = await api('POST', `/workspaces/${WORKSPACE_ID}/workflows/${id}/execute`, { inputs: parsedInputs })
break
}
default:
result = { error: 'Unknown workflows subcommand. Use: list, execute' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
flows: {
list: 'flows list',
get: 'flows get --id <id>',
execute: 'flows execute --id <id> --inputs <json>',
runs: 'flows runs --id <id>',
'run-status': 'flows run-status --run-id <id>',
},
workflows: {
list: 'workflows list',
execute: 'workflows execute --id <id> --inputs <json>',
},
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env node
const API_KEY = process.env.CLAY_API_KEY
const BASE_URL = 'https://api.clay.com/v3'
if (!API_KEY) {
console.error(JSON.stringify({ error: 'CLAY_API_KEY environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
if (args['dry-run']) {
return { _dry_run: true, method, url: `${BASE_URL}${path}`, headers: { 'Authorization': 'Bearer ***', 'Content-Type': 'application/json' }, body: body || undefined }
}
const options = {
method,
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
}
if (body) options.body = JSON.stringify(body)
const res = await fetch(`${BASE_URL}${path}`, options)
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
const page = args.page ? Number(args.page) : 1
const perPage = args['per-page'] ? Number(args['per-page']) : 25
switch (cmd) {
case 'tables':
switch (sub) {
case 'list': {
result = await api('GET', `/tables?page=${page}&per_page=${perPage}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/tables/${id}`)
break
}
case 'rows': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/tables/${id}/rows?page=${page}&per_page=${perPage}`)
break
}
case 'add-row': {
const id = args.id
const data = args.data
if (!id) { result = { error: '--id required' }; break }
if (!data) { result = { error: '--data required (JSON string)' }; break }
let parsed
try {
parsed = JSON.parse(data)
} catch {
result = { error: 'Invalid JSON in --data' }
break
}
result = await api('POST', `/tables/${id}/rows`, parsed)
break
}
default:
result = { error: 'Unknown tables subcommand. Use: list, get, rows, add-row' }
}
break
case 'people':
switch (sub) {
case 'enrich': {
const body = {}
if (args.email) body.email = args.email
if (args.linkedin) body.linkedin_url = args.linkedin
if (args['first-name']) body.first_name = args['first-name']
if (args['last-name']) body.last_name = args['last-name']
if (!args.email && !args.linkedin) {
result = { error: '--email or --linkedin required' }
break
}
result = await api('POST', '/people/enrich', body)
break
}
default:
result = { error: 'Unknown people subcommand. Use: enrich' }
}
break
case 'companies':
switch (sub) {
case 'enrich': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
result = await api('POST', '/companies/enrich', { domain })
break
}
default:
result = { error: 'Unknown companies subcommand. Use: enrich' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
tables: {
list: 'tables list [--page <n>] [--per-page <n>]',
get: 'tables get --id <table_id>',
rows: 'tables rows --id <table_id> [--page <n>] [--per-page <n>]',
'add-row': 'tables add-row --id <table_id> --data <json>',
},
people: {
enrich: 'people enrich --email <email> | --linkedin <url>',
},
companies: {
enrich: 'companies enrich --domain <domain>',
},
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+232
View File
@@ -0,0 +1,232 @@
#!/usr/bin/env node
const API_KEY = process.env.CLOSE_API_KEY
const BASE_URL = 'https://api.close.com/api/v1'
if (!API_KEY) {
console.error(JSON.stringify({ error: 'CLOSE_API_KEY environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
const url = `${BASE_URL}${path}`
if (args['dry-run']) {
return { _dry_run: true, method, url, headers: { 'Content-Type': 'application/json', 'Authorization': 'Basic ***' }, body: body || undefined }
}
const res = await fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Basic ${btoa(API_KEY + ':')}`,
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
switch (cmd) {
case 'leads':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args.query) params.set('query', args.query)
if (args.page) params.set('_skip', (parseInt(args.page) - 1) * 100)
const qs = params.toString()
result = await api('GET', `/lead/${qs ? '?' + qs : ''}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/lead/${id}/`)
break
}
case 'create': {
const name = args.name
if (!name) { result = { error: '--name required' }; break }
const body = { name }
if (args.url) body.url = args.url
if (args.description) body.description = args.description
result = await api('POST', '/lead/', body)
break
}
default:
result = { error: 'Unknown leads subcommand. Use: list, get, create' }
}
break
case 'contacts':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args['lead-id']) params.set('lead_id', args['lead-id'])
const qs = params.toString()
result = await api('GET', `/contact/${qs ? '?' + qs : ''}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/contact/${id}/`)
break
}
case 'create': {
const leadId = args['lead-id']
const name = args.name
if (!leadId) { result = { error: '--lead-id required' }; break }
if (!name) { result = { error: '--name required' }; break }
const body = { lead_id: leadId, name }
if (args.email) {
body.emails = [{ email: args.email, type: 'office' }]
}
if (args.phone) {
body.phones = [{ phone: args.phone, type: 'office' }]
}
result = await api('POST', '/contact/', body)
break
}
default:
result = { error: 'Unknown contacts subcommand. Use: list, get, create' }
}
break
case 'opportunities':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args.status) params.set('status', args.status)
const qs = params.toString()
result = await api('GET', `/opportunity/${qs ? '?' + qs : ''}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/opportunity/${id}/`)
break
}
case 'create': {
const leadId = args['lead-id']
const value = args.value
if (!leadId) { result = { error: '--lead-id required' }; break }
if (!value) { result = { error: '--value required (in cents)' }; break }
const body = { lead_id: leadId, value: parseInt(value) }
if (args.status) body.status_type = args.status
result = await api('POST', '/opportunity/', body)
break
}
default:
result = { error: 'Unknown opportunities subcommand. Use: list, get, create' }
}
break
case 'activities':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args['lead-id']) params.set('lead_id', args['lead-id'])
if (args.type) params.set('_type__type', args.type)
const qs = params.toString()
result = await api('GET', `/activity/${qs ? '?' + qs : ''}`)
break
}
default:
result = { error: 'Unknown activities subcommand. Use: list' }
}
break
case 'tasks':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args['assigned-to']) params.set('assigned_to', args['assigned-to'])
if (args['is-complete']) params.set('is_complete', args['is-complete'])
const qs = params.toString()
result = await api('GET', `/task/${qs ? '?' + qs : ''}`)
break
}
case 'create': {
const leadId = args['lead-id']
const text = args.text
if (!leadId) { result = { error: '--lead-id required' }; break }
if (!text) { result = { error: '--text required' }; break }
const body = { lead_id: leadId, text, _type: 'lead' }
if (args['assigned-to']) body.assigned_to = args['assigned-to']
if (args.date) body.date = args.date
result = await api('POST', '/task/', body)
break
}
default:
result = { error: 'Unknown tasks subcommand. Use: list, create' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
leads: {
list: 'leads list [--query <q>] [--page <n>]',
get: 'leads get --id <id>',
create: 'leads create --name <name> [--url <url>] [--description <desc>]',
},
contacts: {
list: 'contacts list [--lead-id <id>]',
get: 'contacts get --id <id>',
create: 'contacts create --lead-id <id> --name <name> [--email <email>] [--phone <phone>]',
},
opportunities: {
list: 'opportunities list [--status <status>]',
get: 'opportunities get --id <id>',
create: 'opportunities create --lead-id <id> --value <cents> [--status <status>]',
},
activities: {
list: 'activities list [--lead-id <id>] [--type <type>]',
},
tasks: {
list: 'tasks list [--assigned-to <user-id>] [--is-complete <bool>]',
create: 'tasks create --lead-id <id> --text <text> [--assigned-to <user-id>] [--date <date>]',
},
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+173
View File
@@ -0,0 +1,173 @@
#!/usr/bin/env node
const API_KEY = process.env.COUPLER_API_KEY
const BASE_URL = 'https://api.coupler.io/v1'
if (!API_KEY) {
console.error(JSON.stringify({ error: 'COUPLER_API_KEY environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
if (args['dry-run']) {
return { _dry_run: true, method, url: `${BASE_URL}${path}`, headers: { 'Authorization': '***', 'Content-Type': 'application/json' }, body: body || undefined }
}
const res = await fetch(`${BASE_URL}${path}`, {
method,
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
switch (cmd) {
case 'importers':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args.limit) params.set('limit', args.limit)
if (args.offset) params.set('offset', args.offset)
const qs = params.toString()
result = await api('GET', `/importers${qs ? '?' + qs : ''}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/importers/${id}`)
break
}
case 'run': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('POST', `/importers/${id}/run`)
break
}
case 'create': {
const source = args.source
const destination = args.destination
const name = args.name
if (!source) { result = { error: '--source required' }; break }
if (!destination) { result = { error: '--destination required' }; break }
if (!name) { result = { error: '--name required' }; break }
const body = { source_type: source, destination_type: destination, name }
if (args.schedule) body.schedule = args.schedule
result = await api('POST', '/importers', body)
break
}
case 'delete': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('DELETE', `/importers/${id}`)
break
}
default:
result = { error: 'Unknown importers subcommand. Use: list, get, run, create, delete' }
}
break
case 'runs':
switch (sub) {
case 'list': {
const importerId = args['importer-id']
if (!importerId) { result = { error: '--importer-id required' }; break }
const params = new URLSearchParams()
if (args.limit) params.set('limit', args.limit)
if (args.offset) params.set('offset', args.offset)
const qs = params.toString()
result = await api('GET', `/importers/${importerId}/runs${qs ? '?' + qs : ''}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/runs/${id}`)
break
}
default:
result = { error: 'Unknown runs subcommand. Use: list, get' }
}
break
case 'sources':
switch (sub) {
case 'list':
result = await api('GET', '/sources')
break
default:
result = { error: 'Unknown sources subcommand. Use: list' }
}
break
case 'destinations':
switch (sub) {
case 'list':
result = await api('GET', '/destinations')
break
default:
result = { error: 'Unknown destinations subcommand. Use: list' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
importers: {
list: 'importers list [--limit <n>] [--offset <n>]',
get: 'importers get --id <id>',
run: 'importers run --id <id>',
create: 'importers create --source <source-type> --destination <dest-type> --name <name> [--schedule <schedule>]',
delete: 'importers delete --id <id>',
},
runs: {
list: 'runs list --importer-id <id> [--limit <n>] [--offset <n>]',
get: 'runs get --id <id>',
},
sources: 'sources list',
destinations: 'destinations list',
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env node
const API_KEY = process.env.CROSSBEAM_API_KEY
const BASE_URL = 'https://api.crossbeam.com/v1'
if (!API_KEY) {
console.error(JSON.stringify({ error: 'CROSSBEAM_API_KEY environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
const url = `${BASE_URL}${path}`
if (args['dry-run']) {
return { _dry_run: true, method, url, headers: { 'Authorization': 'Bearer ***', 'Content-Type': 'application/json' }, body: body || undefined }
}
const res = await fetch(url, {
method,
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
switch (cmd) {
case 'partners':
switch (sub) {
case 'list': {
result = await api('GET', '/partners')
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/partners/${id}`)
break
}
default:
result = { error: 'Unknown partners subcommand. Use: list, get' }
}
break
case 'populations':
switch (sub) {
case 'list': {
result = await api('GET', '/populations')
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/populations/${id}`)
break
}
default:
result = { error: 'Unknown populations subcommand. Use: list, get' }
}
break
case 'overlaps':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args['partner-id']) params.set('partner_id', args['partner-id'])
if (args['population-id']) params.set('population_id', args['population-id'])
const qs = params.toString()
result = await api('GET', `/overlaps${qs ? '?' + qs : ''}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/overlaps/${id}`)
break
}
default:
result = { error: 'Unknown overlaps subcommand. Use: list, get' }
}
break
case 'reports':
switch (sub) {
case 'list': {
result = await api('GET', '/reports')
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/reports/${id}`)
break
}
default:
result = { error: 'Unknown reports subcommand. Use: list, get' }
}
break
case 'threads':
switch (sub) {
case 'list': {
result = await api('GET', '/threads')
break
}
default:
result = { error: 'Unknown threads subcommand. Use: list' }
}
break
case 'accounts':
switch (sub) {
case 'search': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
const params = new URLSearchParams({ domain })
result = await api('GET', `/accounts/search?${params.toString()}`)
break
}
default:
result = { error: 'Unknown accounts subcommand. Use: search' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
partners: {
list: 'partners list',
get: 'partners get --id <id>',
},
populations: {
list: 'populations list',
get: 'populations get --id <id>',
},
overlaps: {
list: 'overlaps list [--partner-id <id>] [--population-id <id>]',
get: 'overlaps get --id <id>',
},
reports: {
list: 'reports list',
get: 'reports get --id <id>',
},
threads: {
list: 'threads list',
},
accounts: {
search: 'accounts search --domain <domain>',
},
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+213
View File
@@ -0,0 +1,213 @@
#!/usr/bin/env node
const ACCESS_TOKEN = process.env.OUTREACH_ACCESS_TOKEN
const BASE_URL = 'https://api.outreach.io/api/v2'
if (!ACCESS_TOKEN) {
console.error(JSON.stringify({ error: 'OUTREACH_ACCESS_TOKEN environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
const url = `${BASE_URL}${path}`
if (args['dry-run']) {
return { _dry_run: true, method, url, headers: { 'Authorization': 'Bearer ***', 'Content-Type': 'application/vnd.api+json', 'Accept': 'application/vnd.api+json' }, body: body || undefined }
}
const res = await fetch(url, {
method,
headers: {
'Authorization': `Bearer ${ACCESS_TOKEN}`,
'Content-Type': 'application/vnd.api+json',
'Accept': 'application/vnd.api+json',
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
switch (cmd) {
case 'prospects':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args.page) params.set('page[number]', args.page)
if (args['per-page']) params.set('page[size]', args['per-page'])
const qs = params.toString()
result = await api('GET', `/prospects${qs ? '?' + qs : ''}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/prospects/${id}`)
break
}
case 'create': {
const email = args.email
if (!email) { result = { error: '--email required' }; break }
const attributes = { emails: [email] }
if (args['first-name']) attributes.firstName = args['first-name']
if (args['last-name']) attributes.lastName = args['last-name']
const body = { data: { type: 'prospect', attributes } }
result = await api('POST', '/prospects', body)
break
}
default:
result = { error: 'Unknown prospects subcommand. Use: list, get, create' }
}
break
case 'sequences':
switch (sub) {
case 'list': {
result = await api('GET', '/sequences')
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/sequences/${id}`)
break
}
default:
result = { error: 'Unknown sequences subcommand. Use: list, get' }
}
break
case 'sequence-states':
switch (sub) {
case 'create': {
const sequenceId = args['sequence-id']
const prospectId = args['prospect-id']
if (!sequenceId) { result = { error: '--sequence-id required' }; break }
if (!prospectId) { result = { error: '--prospect-id required' }; break }
const body = {
data: {
type: 'sequenceState',
relationships: {
prospect: { data: { type: 'prospect', id: parseInt(prospectId) } },
sequence: { data: { type: 'sequence', id: parseInt(sequenceId) } },
},
},
}
result = await api('POST', '/sequenceStates', body)
break
}
default:
result = { error: 'Unknown sequence-states subcommand. Use: create' }
}
break
case 'mailings':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args['sequence-id']) params.set('filter[sequence][id]', args['sequence-id'])
const qs = params.toString()
result = await api('GET', `/mailings${qs ? '?' + qs : ''}`)
break
}
default:
result = { error: 'Unknown mailings subcommand. Use: list' }
}
break
case 'accounts':
switch (sub) {
case 'list': {
result = await api('GET', '/accounts')
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/accounts/${id}`)
break
}
default:
result = { error: 'Unknown accounts subcommand. Use: list, get' }
}
break
case 'tasks':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args.status) params.set('filter[status]', args.status)
const qs = params.toString()
result = await api('GET', `/tasks${qs ? '?' + qs : ''}`)
break
}
default:
result = { error: 'Unknown tasks subcommand. Use: list' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
prospects: {
list: 'prospects list [--page <n>] [--per-page <n>]',
get: 'prospects get --id <id>',
create: 'prospects create --email <email> [--first-name <name>] [--last-name <name>]',
},
sequences: {
list: 'sequences list',
get: 'sequences get --id <id>',
},
'sequence-states': {
create: 'sequence-states create --sequence-id <id> --prospect-id <id>',
},
mailings: {
list: 'mailings list [--sequence-id <id>]',
},
accounts: {
list: 'accounts list',
get: 'accounts get --id <id>',
},
tasks: {
list: 'tasks list [--status <status>]',
},
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+221
View File
@@ -0,0 +1,221 @@
#!/usr/bin/env node
const API_KEY = process.env.PENDO_INTEGRATION_KEY
const BASE_URL = 'https://app.pendo.io/api/v1'
if (!API_KEY) {
console.error(JSON.stringify({ error: 'PENDO_INTEGRATION_KEY environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
const url = `${BASE_URL}${path}`
if (args['dry-run']) {
return { _dry_run: true, method, url, headers: { 'Content-Type': 'application/json', 'x-pendo-integration-key': '***' }, body: body || undefined }
}
const res = await fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
'x-pendo-integration-key': API_KEY,
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
switch (cmd) {
case 'features':
switch (sub) {
case 'list':
result = await api('GET', '/feature')
break
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/feature/${id}`)
break
}
default:
result = { error: 'Unknown features subcommand. Use: list, get' }
}
break
case 'pages':
switch (sub) {
case 'list':
result = await api('GET', '/page')
break
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/page/${id}`)
break
}
default:
result = { error: 'Unknown pages subcommand. Use: list, get' }
}
break
case 'guides':
switch (sub) {
case 'list': {
const params = new URLSearchParams()
if (args.state) params.set('state', args.state)
const qs = params.toString()
result = await api('GET', `/guide${qs ? '?' + qs : ''}`)
break
}
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/guide/${id}`)
break
}
default:
result = { error: 'Unknown guides subcommand. Use: list, get' }
}
break
case 'visitors':
switch (sub) {
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/visitor/${id}`)
break
}
case 'search': {
const query = args.query
if (!query) { result = { error: '--query <json> required' }; break }
let body
try { body = JSON.parse(query) } catch { result = { error: 'Invalid JSON in --query' }; break }
result = await api('POST', '/aggregation', body)
break
}
default:
result = { error: 'Unknown visitors subcommand. Use: get, search' }
}
break
case 'accounts':
switch (sub) {
case 'get': {
const id = args.id
if (!id) { result = { error: '--id required' }; break }
result = await api('GET', `/account/${id}`)
break
}
case 'search': {
const query = args.query
if (!query) { result = { error: '--query <json> required' }; break }
let body
try { body = JSON.parse(query) } catch { result = { error: 'Invalid JSON in --query' }; break }
result = await api('POST', '/aggregation', body)
break
}
default:
result = { error: 'Unknown accounts subcommand. Use: get, search' }
}
break
case 'reports':
switch (sub) {
case 'funnel': {
const pipeline = args.pipeline
if (!pipeline) { result = { error: '--pipeline <json> required' }; break }
let body
try { body = JSON.parse(pipeline) } catch { result = { error: 'Invalid JSON in --pipeline' }; break }
result = await api('POST', '/aggregation', body)
break
}
default:
result = { error: 'Unknown reports subcommand. Use: funnel' }
}
break
case 'metadata':
switch (sub) {
case 'list': {
const kind = args.kind
if (!kind) { result = { error: '--kind <visitor|account|parentAccount> required' }; break }
result = await api('GET', `/metadata/schema/${kind}`)
break
}
default:
result = { error: 'Unknown metadata subcommand. Use: list' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
features: {
list: 'features list',
get: 'features get --id <id>',
},
pages: {
list: 'pages list',
get: 'pages get --id <id>',
},
guides: {
list: 'guides list [--state <state>]',
get: 'guides get --id <id>',
},
visitors: {
get: 'visitors get --id <id>',
search: 'visitors search --query <json>',
},
accounts: {
get: 'accounts get --id <id>',
search: 'accounts search --query <json>',
},
reports: {
funnel: 'reports funnel --pipeline <json>',
},
metadata: {
list: 'metadata list --kind <visitor|account|parentAccount>',
},
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+214
View File
@@ -0,0 +1,214 @@
#!/usr/bin/env node
const API_KEY = process.env.SIMILARWEB_API_KEY
const BASE_URL = 'https://api.similarweb.com/v1'
if (!API_KEY) {
console.error(JSON.stringify({ error: 'SIMILARWEB_API_KEY environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
const separator = path.includes('?') ? '&' : '?'
const url = `${BASE_URL}${path}${separator}api_key=${API_KEY}`
if (args['dry-run']) {
return { _dry_run: true, method, url: url.replace(API_KEY, '***'), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: body || undefined }
}
const res = await fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
switch (cmd) {
case 'traffic':
switch (sub) {
case 'visits': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
if (args.country) params.set('country', args.country)
if (args.granularity) params.set('granularity', args.granularity)
result = await api('GET', `/website/${domain}/total-traffic-and-engagement/visits?${params.toString()}`)
break
}
case 'pages-per-visit': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
if (args.country) params.set('country', args.country)
if (args.granularity) params.set('granularity', args.granularity)
result = await api('GET', `/website/${domain}/total-traffic-and-engagement/pages-per-visit?${params.toString()}`)
break
}
case 'avg-duration': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
if (args.country) params.set('country', args.country)
if (args.granularity) params.set('granularity', args.granularity)
result = await api('GET', `/website/${domain}/total-traffic-and-engagement/average-visit-duration?${params.toString()}`)
break
}
case 'bounce-rate': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
if (args.country) params.set('country', args.country)
if (args.granularity) params.set('granularity', args.granularity)
result = await api('GET', `/website/${domain}/total-traffic-and-engagement/bounce-rate?${params.toString()}`)
break
}
case 'sources': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
if (args.country) params.set('country', args.country)
result = await api('GET', `/website/${domain}/traffic-sources/overview?${params.toString()}`)
break
}
default:
result = { error: 'Unknown traffic subcommand. Use: visits, pages-per-visit, avg-duration, bounce-rate, sources' }
}
break
case 'referrals': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
if (args.country) params.set('country', args.country)
result = await api('GET', `/website/${domain}/traffic-sources/referrals?${params.toString()}`)
break
}
case 'search':
switch (sub) {
case 'keywords-organic': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
if (args.country) params.set('country', args.country)
if (args.limit) params.set('limit', args.limit)
result = await api('GET', `/website/${domain}/search/organic-search-keywords?${params.toString()}`)
break
}
case 'keywords-paid': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
if (args.country) params.set('country', args.country)
if (args.limit) params.set('limit', args.limit)
result = await api('GET', `/website/${domain}/search/paid-search-keywords?${params.toString()}`)
break
}
default:
result = { error: 'Unknown search subcommand. Use: keywords-organic, keywords-paid' }
}
break
case 'competitors': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
result = await api('GET', `/website/${domain}/similar-sites/similarsites`)
break
}
case 'category-rank': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
result = await api('GET', `/website/${domain}/category-rank/category-rank`)
break
}
case 'geography': {
const domain = args.domain
if (!domain) { result = { error: '--domain required' }; break }
if (!args.start) { result = { error: '--start required (YYYY-MM)' }; break }
if (!args.end) { result = { error: '--end required (YYYY-MM)' }; break }
const params = new URLSearchParams({ start_date: args.start, end_date: args.end })
result = await api('GET', `/website/${domain}/geo/traffic-by-country?${params.toString()}`)
break
}
default:
result = {
error: 'Unknown command',
usage: {
traffic: {
visits: 'traffic visits --domain <domain> --start <YYYY-MM> --end <YYYY-MM> [--country <cc>] [--granularity <monthly|weekly|daily>]',
'pages-per-visit': 'traffic pages-per-visit --domain <domain> --start <YYYY-MM> --end <YYYY-MM>',
'avg-duration': 'traffic avg-duration --domain <domain> --start <YYYY-MM> --end <YYYY-MM>',
'bounce-rate': 'traffic bounce-rate --domain <domain> --start <YYYY-MM> --end <YYYY-MM>',
sources: 'traffic sources --domain <domain> --start <YYYY-MM> --end <YYYY-MM>',
},
referrals: 'referrals --domain <domain> --start <YYYY-MM> --end <YYYY-MM>',
search: {
'keywords-organic': 'search keywords-organic --domain <domain> --start <YYYY-MM> --end <YYYY-MM>',
'keywords-paid': 'search keywords-paid --domain <domain> --start <YYYY-MM> --end <YYYY-MM>',
},
competitors: 'competitors --domain <domain>',
'category-rank': 'category-rank --domain <domain>',
geography: 'geography --domain <domain> --start <YYYY-MM> --end <YYYY-MM>',
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+168
View File
@@ -0,0 +1,168 @@
#!/usr/bin/env node
const API_KEY = process.env.SUPERMETRICS_API_KEY
const BASE_URL = 'https://api.supermetrics.com/enterprise/v2'
if (!API_KEY) {
console.error(JSON.stringify({ error: 'SUPERMETRICS_API_KEY environment variable required' }))
process.exit(1)
}
async function api(method, path, body) {
const separator = path.includes('?') ? '&' : '?'
const url = `${BASE_URL}${path}${separator}api_key=${API_KEY}`
if (args['dry-run']) {
return { _dry_run: true, method, url: url.replace(API_KEY, '***'), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, body: body || undefined }
}
const res = await fetch(url, {
method,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
switch (cmd) {
case 'query': {
const dsId = args['ds-id']
const dsAccounts = args['ds-accounts']
const dateRange = args['date-range']
const fields = args.fields
if (!dsId) { result = { error: '--ds-id required (e.g., GA4, AW, FB, LI, GSC)' }; break }
if (!dsAccounts) { result = { error: '--ds-accounts required' }; break }
if (!dateRange) { result = { error: '--date-range required (e.g., last_28_days, last_month, this_month, custom)' }; break }
if (!fields) { result = { error: '--fields required (comma-separated field names)' }; break }
const body = {
ds_id: dsId,
ds_accounts: dsAccounts,
date_range_type: dateRange,
fields: fields.split(',').map(f => ({ name: f.trim() })),
}
if (args.filter) body.filter = args.filter
if (args['max-rows']) body.max_rows = parseInt(args['max-rows'], 10)
if (args['start-date']) body.start_date = args['start-date']
if (args['end-date']) body.end_date = args['end-date']
result = await api('POST', '/query', body)
break
}
case 'sources':
switch (sub) {
case 'list':
result = await api('GET', '/datasources')
break
default:
result = { error: 'Unknown sources subcommand. Use: list' }
}
break
case 'accounts':
switch (sub) {
case 'list': {
const dsId = args['ds-id']
if (!dsId) { result = { error: '--ds-id required (e.g., GA4, AW, FB)' }; break }
const params = new URLSearchParams({ ds_id: dsId })
result = await api('GET', `/datasources/accounts?${params.toString()}`)
break
}
default:
result = { error: 'Unknown accounts subcommand. Use: list' }
}
break
case 'teams':
switch (sub) {
case 'list':
result = await api('GET', '/teams')
break
default:
result = { error: 'Unknown teams subcommand. Use: list' }
}
break
case 'users':
switch (sub) {
case 'list':
result = await api('GET', '/users')
break
default:
result = { error: 'Unknown users subcommand. Use: list' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
query: 'query --ds-id <data-source> --ds-accounts <account-id> --date-range <range> --fields <f1,f2> [--filter <filter>] [--max-rows <n>] [--start-date <date>] [--end-date <date>]',
sources: {
list: 'sources list',
},
accounts: {
list: 'accounts list --ds-id <data-source>',
},
teams: {
list: 'teams list',
},
users: {
list: 'users list',
},
'data-source-ids': {
'GA4': 'Google Analytics 4',
'GA4_PAID': 'Google Analytics (paid)',
'AW': 'Google Ads',
'FB': 'Facebook Ads',
'LI': 'LinkedIn Ads',
'TW_ADS': 'Twitter Ads',
'IG_IA': 'Instagram',
'FB_IA': 'Facebook Pages',
'GSC': 'Google Search Console',
'SE': 'Semrush',
'MC': 'Mailchimp',
},
'date-ranges': ['last_28_days', 'last_month', 'this_month', 'custom'],
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})
+207
View File
@@ -0,0 +1,207 @@
#!/usr/bin/env node
const BASE_URL = 'https://api.zoominfo.com'
let ACCESS_TOKEN = process.env.ZOOMINFO_ACCESS_TOKEN
if (!ACCESS_TOKEN && !process.env.ZOOMINFO_USERNAME) {
console.error(JSON.stringify({ error: 'ZOOMINFO_ACCESS_TOKEN or ZOOMINFO_USERNAME + ZOOMINFO_PRIVATE_KEY environment variables required' }))
process.exit(1)
}
async function authenticate() {
if (ACCESS_TOKEN) return ACCESS_TOKEN
const username = process.env.ZOOMINFO_USERNAME
const password = process.env.ZOOMINFO_PRIVATE_KEY
if (!username || !password) {
throw new Error('ZOOMINFO_USERNAME and ZOOMINFO_PRIVATE_KEY required for authentication')
}
const res = await fetch(`${BASE_URL}/authenticate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password }),
})
const text = await res.text()
try {
const data = JSON.parse(text)
ACCESS_TOKEN = data.jwt
return ACCESS_TOKEN
} catch {
throw new Error(`Authentication failed: ${text}`)
}
}
async function api(method, path, body) {
if (args['dry-run']) {
return { _dry_run: true, method, url: `${BASE_URL}${path}`, headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ***' }, body }
}
const token = await authenticate()
const res = await fetch(`${BASE_URL}${path}`, {
method,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: body ? JSON.stringify(body) : undefined,
})
const text = await res.text()
try {
return JSON.parse(text)
} catch {
return { status: res.status, body: text }
}
}
function parseArgs(args) {
const result = { _: [] }
for (let i = 0; i < args.length; i++) {
const arg = args[i]
if (arg.startsWith('--')) {
const key = arg.slice(2)
const next = args[i + 1]
if (next && !next.startsWith('--')) {
result[key] = next
i++
} else {
result[key] = true
}
} else {
result._.push(arg)
}
}
return result
}
const args = parseArgs(process.argv.slice(2))
const [cmd, sub, ...rest] = args._
async function main() {
let result
const page = args.page ? Number(args.page) : 1
const perPage = args['per-page'] ? Number(args['per-page']) : 25
switch (cmd) {
case 'auth': {
const token = await authenticate()
result = { jwt: token }
break
}
case 'contacts':
switch (sub) {
case 'search': {
const body = { rpp: perPage, page }
if (args['job-title']) body.jobTitle = [args['job-title']]
if (args.company) body.companyName = [args.company]
if (args.location) body.locationSearchType = 'PersonLocation', body.personLocationCity = [args.location]
if (args.seniority) body.managementLevel = [args.seniority]
if (args.department) body.department = [args.department]
result = await api('POST', '/search/contact', body)
break
}
case 'enrich': {
const body = {}
if (args.email) body.matchEmail = [args.email]
if (args['person-id']) body.personId = [args['person-id']]
if (!args.email && !args['person-id']) {
result = { error: '--email or --person-id required' }
break
}
result = await api('POST', '/enrich/contact', body)
break
}
default:
result = { error: 'Unknown contacts subcommand. Use: search, enrich' }
}
break
case 'companies':
switch (sub) {
case 'search': {
const body = { rpp: perPage, page }
if (args.name) body.companyName = [args.name]
if (args.industry) body.industry = [args.industry]
if (args['revenue-min']) body.revenueMin = Number(args['revenue-min'])
if (args['revenue-max']) body.revenueMax = Number(args['revenue-max'])
if (args['employees-min']) body.employeeCountMin = Number(args['employees-min'])
if (args['employees-max']) body.employeeCountMax = Number(args['employees-max'])
result = await api('POST', '/search/company', body)
break
}
case 'enrich': {
const body = {}
if (args.domain) body.matchCompanyWebsite = [args.domain]
if (args['company-id']) body.companyId = [args['company-id']]
if (!args.domain && !args['company-id']) {
result = { error: '--domain or --company-id required' }
break
}
result = await api('POST', '/enrich/company', body)
break
}
default:
result = { error: 'Unknown companies subcommand. Use: search, enrich' }
}
break
case 'intent':
switch (sub) {
case 'search': {
if (!args.topic) {
result = { error: '--topic required' }
break
}
const body = { topicId: [args.topic] }
if (args['company-id']) body.companyId = [args['company-id']]
result = await api('POST', '/lookup/intent', body)
break
}
default:
result = { error: 'Unknown intent subcommand. Use: search' }
}
break
case 'scoops':
switch (sub) {
case 'search': {
const body = { rpp: perPage, page }
if (args['company-id']) body.companyId = [args['company-id']]
if (args.topic) body.topicId = [args.topic]
result = await api('POST', '/lookup/scoops', body)
break
}
default:
result = { error: 'Unknown scoops subcommand. Use: search' }
}
break
default:
result = {
error: 'Unknown command',
usage: {
auth: 'auth — authenticate and get JWT token',
contacts: {
search: 'contacts search [--job-title <t>] [--company <c>] [--location <l>] [--seniority <s>] [--department <d>] [--page <n>]',
enrich: 'contacts enrich --email <email> | --person-id <id>',
},
companies: {
search: 'companies search [--name <n>] [--industry <i>] [--revenue-min <n>] [--employees-min <n>] [--page <n>]',
enrich: 'companies enrich --domain <domain> | --company-id <id>',
},
intent: {
search: 'intent search --topic <topic> [--company-id <id>]',
},
scoops: {
search: 'scoops search [--company-id <id>] [--topic <topic>] [--page <n>]',
},
}
}
}
console.log(JSON.stringify(result, null, 2))
}
main().catch(err => {
console.error(JSON.stringify({ error: err.message }))
process.exit(1)
})