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:
Executable
+163
@@ -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)
|
||||
})
|
||||
Executable
+158
@@ -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)
|
||||
})
|
||||
Executable
+232
@@ -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)
|
||||
})
|
||||
Executable
+173
@@ -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)
|
||||
})
|
||||
Executable
+193
@@ -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)
|
||||
})
|
||||
Executable
+213
@@ -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)
|
||||
})
|
||||
Executable
+221
@@ -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)
|
||||
})
|
||||
Executable
+214
@@ -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)
|
||||
})
|
||||
Executable
+168
@@ -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)
|
||||
})
|
||||
Executable
+207
@@ -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)
|
||||
})
|
||||
Reference in New Issue
Block a user