orangeslice 2.2.0 → 2.3.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of orangeslice might be problematic. Click here for more details.
- package/README.md +17 -0
- package/dist/cli.js +12 -1
- package/dist/index.d.ts +27 -0
- package/dist/index.js +10 -2
- package/dist/integrations.d.ts +60 -0
- package/dist/integrations.js +106 -0
- package/dist/ocean.d.ts +2 -8
- package/dist/skills.d.ts +57 -0
- package/dist/skills.js +33 -0
- package/docs/lookalike-search/index.md +24 -12
- package/docs/prospecting/index.md +2 -2
- package/docs/services/index.md +3 -1
- package/docs/services/integrations/index.md +128 -0
- package/docs/services/ocean/search/companies.ts +122 -119
- package/docs/services/predictLeads/companyJobOpenings.ts +168 -94
- package/docs/services/skills/index.md +87 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,6 +52,21 @@ pnpm add orangeslice
|
|
|
52
52
|
yarn add orangeslice
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
## Integrations & Skills
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { integrations, skills } from "orangeslice";
|
|
59
|
+
|
|
60
|
+
// Connect a third-party service (opens browser for OAuth)
|
|
61
|
+
const hubspot = await integrations.connect("hubspot");
|
|
62
|
+
|
|
63
|
+
// List connected integrations
|
|
64
|
+
const { integrations: list } = await integrations.list();
|
|
65
|
+
|
|
66
|
+
// Create a knowledge skill
|
|
67
|
+
await skills.create({ name: "ICP", content: "B2B SaaS, 50-500 employees..." });
|
|
68
|
+
```
|
|
69
|
+
|
|
55
70
|
## Public API (services-first)
|
|
56
71
|
|
|
57
72
|
Use `services.*` as the primary API surface.
|
|
@@ -103,6 +118,8 @@ const startups = await services.crunchbase.search({
|
|
|
103
118
|
- `services.googleMaps.scrape`
|
|
104
119
|
- `services.geo.parseAddress`
|
|
105
120
|
- `services.builtWith.lookupDomain/relationships/searchByTech`
|
|
121
|
+
- `integrations.connect/list/get/create/update/delete`
|
|
122
|
+
- `skills.list/get/create/update/delete`
|
|
106
123
|
|
|
107
124
|
## How routing works today
|
|
108
125
|
|
package/dist/cli.js
CHANGED
|
@@ -179,6 +179,7 @@ Use these docs as the source of truth. If there is any conflict between your pri
|
|
|
179
179
|
## Package Setup (Do Not Guess)
|
|
180
180
|
- Import from the package name, not a local file path:
|
|
181
181
|
- \`import { services } from "orangeslice"\`
|
|
182
|
+
- \`import { integrations, skills } from "orangeslice"\` for integration and skill management
|
|
182
183
|
- \`import { configure, services } from "orangeslice"\` when setting API key programmatically
|
|
183
184
|
- Do NOT use \`import { services } from "./orangeslice"\` unless the user explicitly has a local wrapper file at that path.
|
|
184
185
|
- The orangeslice bootstrap commands (\`npx orangeslice\`, \`bunx orangeslice\`, \`pnpm dlx orangeslice\`, \`yarn dlx orangeslice\`) sync docs, install the package, and handle auth. They do NOT execute user app scripts.
|
|
@@ -192,7 +193,9 @@ Use these docs as the source of truth. If there is any conflict between your pri
|
|
|
192
193
|
## Mandatory Read Order (Before writing code)
|
|
193
194
|
1. \`./services/index.md\` - service map and capabilities
|
|
194
195
|
2. Relevant docs under \`./services/**\` for every service you plan to call
|
|
195
|
-
3. \`./
|
|
196
|
+
3. \`./services/integrations/index.md\` when connecting or managing third-party integrations
|
|
197
|
+
4. \`./services/skills/index.md\` when managing knowledge skills
|
|
198
|
+
5. \`./prospecting/index.md\` when doing discovery or lead generation tasks
|
|
196
199
|
|
|
197
200
|
Do not call a service before reading its documentation.
|
|
198
201
|
|
|
@@ -203,6 +206,12 @@ Do not call a service before reading its documentation.
|
|
|
203
206
|
- For broad scraping by URL, use \`services.scrape.website\`.
|
|
204
207
|
- Use \`services.ai.generateObject\` for structured extraction/classification with a JSON schema.
|
|
205
208
|
|
|
209
|
+
## Integration & Skill Management
|
|
210
|
+
- To connect a third-party service, use \`integrations.connect(provider)\`. This opens the browser for OAuth (HubSpot, Salesforce, Attio, Gmail, Slack) or prompts for an API key (Instantly, HeyReach).
|
|
211
|
+
- To list connected integrations, use \`integrations.list()\`.
|
|
212
|
+
- To manage knowledge skills (ICP descriptions, templates, etc.), use \`skills.create/list/update/delete\`.
|
|
213
|
+
- Read \`./services/integrations/index.md\` and \`./services/skills/index.md\` for full API details.
|
|
214
|
+
|
|
206
215
|
## Execution Rules
|
|
207
216
|
- Parallelize independent async calls with \`Promise.all\`.
|
|
208
217
|
- Avoid serial \`await\` inside loops when calls can run concurrently.
|
|
@@ -246,6 +255,8 @@ This project includes orangeslice for B2B sales operations, lead generation, enr
|
|
|
246
255
|
- Structured AI generation
|
|
247
256
|
- Website scraping and browser execution
|
|
248
257
|
- PredictLeads and BuiltWith-backed discovery
|
|
258
|
+
- Integration management — connect HubSpot, Salesforce, Attio, Gmail, Slack, Instantly, HeyReach via \`integrations.connect(provider)\`
|
|
259
|
+
- Knowledge skills — create and manage reusable knowledge snippets via \`skills.create/list/update/delete\`
|
|
249
260
|
`;
|
|
250
261
|
fs.writeFileSync(CLAUDE_GUIDE_FILE, content, "utf8");
|
|
251
262
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export { configure } from "./api";
|
|
2
2
|
export type { OrangesliceConfig } from "./api";
|
|
3
|
+
export { integrations } from "./integrations";
|
|
4
|
+
export type { Integration, IntegrationProvider, IntegrationListParams, IntegrationCreateParams, IntegrationUpdateParams, IntegrationConnectOptions } from "./integrations";
|
|
5
|
+
export { skills } from "./skills";
|
|
6
|
+
export type { Skill, SkillListParams, SkillCreateParams, SkillUpdateParams } from "./skills";
|
|
3
7
|
export { findCareersPage, scrapeCareersPage } from "./careers";
|
|
4
8
|
export type { FindCareersPageParams, FindCareersPageResult, ScrapeCareersPageParams, ScrapeCareersPageResult, ScrapeCareersPageJob } from "./careers";
|
|
5
9
|
export { ctx } from "./ctx";
|
|
@@ -95,5 +99,28 @@ export declare const services: {
|
|
|
95
99
|
searchByTech: typeof builtWithSearchByTech;
|
|
96
100
|
};
|
|
97
101
|
predictLeads: Readonly<import("./predictLeads").PredictLeadsServiceMap>;
|
|
102
|
+
integrations: {
|
|
103
|
+
connect: (provider: import("./integrations").IntegrationProvider, opts?: import("./integrations").IntegrationConnectOptions) => Promise<import("./integrations").Integration>;
|
|
104
|
+
list: (opts?: import("./integrations").IntegrationListParams) => Promise<{
|
|
105
|
+
integrations: import("./integrations").Integration[];
|
|
106
|
+
}>;
|
|
107
|
+
get: (id: string) => Promise<import("./integrations").Integration>;
|
|
108
|
+
create: (opts: import("./integrations").IntegrationCreateParams) => Promise<import("./integrations").Integration>;
|
|
109
|
+
update: (id: string, fields: import("./integrations").IntegrationUpdateParams) => Promise<import("./integrations").Integration>;
|
|
110
|
+
delete: (id: string) => Promise<{
|
|
111
|
+
success: boolean;
|
|
112
|
+
}>;
|
|
113
|
+
};
|
|
114
|
+
skills: {
|
|
115
|
+
list: (opts?: import("./skills").SkillListParams) => Promise<{
|
|
116
|
+
skills: import("./skills").Skill[];
|
|
117
|
+
}>;
|
|
118
|
+
get: (id: string) => Promise<import("./skills").Skill>;
|
|
119
|
+
create: (opts: import("./skills").SkillCreateParams) => Promise<import("./skills").Skill>;
|
|
120
|
+
update: (id: string, fields: import("./skills").SkillUpdateParams) => Promise<import("./skills").Skill>;
|
|
121
|
+
delete: (id: string) => Promise<{
|
|
122
|
+
success: boolean;
|
|
123
|
+
}>;
|
|
124
|
+
};
|
|
98
125
|
};
|
|
99
126
|
export default services;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.services = exports.builtWithSearchByTech = exports.builtWithRelationships = exports.builtWithLookupDomain = exports.geoParseAddress = exports.companyGetEmployeesFromLinkedin = exports.companyLinkedinFindUrl = exports.companyLinkedinEnrich = exports.personContactGet = exports.personLinkedinFindUrl = exports.personLinkedinEnrich = exports.PREDICT_LEADS_OPERATION_IDS = exports.predictLeads = exports.executePredictLeads = exports.googleMapsScrape = exports.runApifyActor = exports.browserExecute = exports.scrapeWebsite = exports.generateObject = exports.webBatchSearch = exports.webSearch = exports.OCEAN_OPERATION_IDS = exports.oceanSearchPeople = exports.oceanSearchCompanies = exports.executeOcean = exports.crunchbaseSearch = exports.linkedinSearch = exports.ctx = exports.scrapeCareersPage = exports.findCareersPage = exports.configure = void 0;
|
|
3
|
+
exports.services = exports.builtWithSearchByTech = exports.builtWithRelationships = exports.builtWithLookupDomain = exports.geoParseAddress = exports.companyGetEmployeesFromLinkedin = exports.companyLinkedinFindUrl = exports.companyLinkedinEnrich = exports.personContactGet = exports.personLinkedinFindUrl = exports.personLinkedinEnrich = exports.PREDICT_LEADS_OPERATION_IDS = exports.predictLeads = exports.executePredictLeads = exports.googleMapsScrape = exports.runApifyActor = exports.browserExecute = exports.scrapeWebsite = exports.generateObject = exports.webBatchSearch = exports.webSearch = exports.OCEAN_OPERATION_IDS = exports.oceanSearchPeople = exports.oceanSearchCompanies = exports.executeOcean = exports.crunchbaseSearch = exports.linkedinSearch = exports.ctx = exports.scrapeCareersPage = exports.findCareersPage = exports.skills = exports.integrations = exports.configure = void 0;
|
|
4
4
|
var api_1 = require("./api");
|
|
5
5
|
Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return api_1.configure; } });
|
|
6
|
+
var integrations_1 = require("./integrations");
|
|
7
|
+
Object.defineProperty(exports, "integrations", { enumerable: true, get: function () { return integrations_1.integrations; } });
|
|
8
|
+
var skills_1 = require("./skills");
|
|
9
|
+
Object.defineProperty(exports, "skills", { enumerable: true, get: function () { return skills_1.skills; } });
|
|
6
10
|
var careers_1 = require("./careers");
|
|
7
11
|
Object.defineProperty(exports, "findCareersPage", { enumerable: true, get: function () { return careers_1.findCareersPage; } });
|
|
8
12
|
Object.defineProperty(exports, "scrapeCareersPage", { enumerable: true, get: function () { return careers_1.scrapeCareersPage; } });
|
|
@@ -50,6 +54,8 @@ const b2b_2 = require("./b2b");
|
|
|
50
54
|
const browser_2 = require("./browser");
|
|
51
55
|
const careers_2 = require("./careers");
|
|
52
56
|
const crunchbase_2 = require("./crunchbase");
|
|
57
|
+
const integrations_2 = require("./integrations");
|
|
58
|
+
const skills_2 = require("./skills");
|
|
53
59
|
const expansion_2 = require("./expansion");
|
|
54
60
|
const firecrawl_2 = require("./firecrawl");
|
|
55
61
|
const generateObject_2 = require("./generateObject");
|
|
@@ -114,6 +120,8 @@ exports.services = {
|
|
|
114
120
|
relationships: expansion_2.builtWithRelationships,
|
|
115
121
|
searchByTech: expansion_2.builtWithSearchByTech
|
|
116
122
|
},
|
|
117
|
-
predictLeads: predictLeads_2.predictLeads
|
|
123
|
+
predictLeads: predictLeads_2.predictLeads,
|
|
124
|
+
integrations: integrations_2.integrations,
|
|
125
|
+
skills: skills_2.skills
|
|
118
126
|
};
|
|
119
127
|
exports.default = exports.services;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integrations API for the orangeslice SDK.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { integrations } from "orangeslice";
|
|
6
|
+
*
|
|
7
|
+
* // Connect an OAuth provider (opens browser)
|
|
8
|
+
* const hubspot = await integrations.connect("hubspot");
|
|
9
|
+
*
|
|
10
|
+
* // List connected integrations
|
|
11
|
+
* const { integrations: list } = await integrations.list();
|
|
12
|
+
*
|
|
13
|
+
* // Programmatic API-key create (no browser)
|
|
14
|
+
* await integrations.create({ provider: "instantly", apiKey: "inst_..." });
|
|
15
|
+
*/
|
|
16
|
+
export type IntegrationProvider = "hubspot" | "salesforce" | "attio" | "gmail" | "slack" | "instantly" | "heyreach";
|
|
17
|
+
export interface Integration {
|
|
18
|
+
id: string;
|
|
19
|
+
provider: string;
|
|
20
|
+
displayName: string;
|
|
21
|
+
isActive: boolean;
|
|
22
|
+
hasApiKey: boolean;
|
|
23
|
+
hasOauthToken: boolean;
|
|
24
|
+
createdAt: string;
|
|
25
|
+
updatedAt: string;
|
|
26
|
+
scope: "account" | "spreadsheet";
|
|
27
|
+
spreadsheetId?: string | null;
|
|
28
|
+
}
|
|
29
|
+
export interface IntegrationListParams {
|
|
30
|
+
spreadsheetId?: string;
|
|
31
|
+
provider?: IntegrationProvider;
|
|
32
|
+
}
|
|
33
|
+
export interface IntegrationCreateParams {
|
|
34
|
+
provider: IntegrationProvider;
|
|
35
|
+
apiKey: string;
|
|
36
|
+
displayName?: string;
|
|
37
|
+
config?: Record<string, string>;
|
|
38
|
+
spreadsheetId?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface IntegrationUpdateParams {
|
|
41
|
+
apiKey?: string;
|
|
42
|
+
displayName?: string;
|
|
43
|
+
isActive?: boolean;
|
|
44
|
+
config?: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
export interface IntegrationConnectOptions {
|
|
47
|
+
noBrowser?: boolean;
|
|
48
|
+
}
|
|
49
|
+
export declare const integrations: {
|
|
50
|
+
connect: (provider: IntegrationProvider, opts?: IntegrationConnectOptions) => Promise<Integration>;
|
|
51
|
+
list: (opts?: IntegrationListParams) => Promise<{
|
|
52
|
+
integrations: Integration[];
|
|
53
|
+
}>;
|
|
54
|
+
get: (id: string) => Promise<Integration>;
|
|
55
|
+
create: (opts: IntegrationCreateParams) => Promise<Integration>;
|
|
56
|
+
update: (id: string, fields: IntegrationUpdateParams) => Promise<Integration>;
|
|
57
|
+
delete: (id: string) => Promise<{
|
|
58
|
+
success: boolean;
|
|
59
|
+
}>;
|
|
60
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Integrations API for the orangeslice SDK.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* import { integrations } from "orangeslice";
|
|
7
|
+
*
|
|
8
|
+
* // Connect an OAuth provider (opens browser)
|
|
9
|
+
* const hubspot = await integrations.connect("hubspot");
|
|
10
|
+
*
|
|
11
|
+
* // List connected integrations
|
|
12
|
+
* const { integrations: list } = await integrations.list();
|
|
13
|
+
*
|
|
14
|
+
* // Programmatic API-key create (no browser)
|
|
15
|
+
* await integrations.create({ provider: "instantly", apiKey: "inst_..." });
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.integrations = void 0;
|
|
19
|
+
const api_1 = require("./api");
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Constants
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const AUTH_BASE_URL = "https://www.orangeslice.ai";
|
|
24
|
+
const CONNECT_POLL_TIMEOUT_MS = 600000;
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Browser helper (same as cli.ts)
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
function openBrowser(url) {
|
|
29
|
+
if (!process?.versions?.node) {
|
|
30
|
+
console.log(` Open this URL in your browser:\n ${url}\n`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const { execFileSync } = require("child_process");
|
|
35
|
+
if (process.platform === "darwin") {
|
|
36
|
+
execFileSync("open", [url], { stdio: "ignore" });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (process.platform === "win32") {
|
|
40
|
+
execFileSync("cmd.exe", ["/c", "start", "", url], { stdio: "ignore" });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
execFileSync("xdg-open", [url], { stdio: "ignore" });
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
console.log(` Open this URL in your browser:\n ${url}\n`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function sleep(ms) {
|
|
50
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Connect (device flow via Next.js)
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
async function connectIntegration(provider, opts) {
|
|
56
|
+
const startRes = await fetch(`${AUTH_BASE_URL}/api/orangeslice/integrations/connect/start`, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify({ provider })
|
|
60
|
+
});
|
|
61
|
+
if (!startRes.ok) {
|
|
62
|
+
const data = (await startRes.json().catch(() => ({})));
|
|
63
|
+
throw new Error(`[orangeslice] integrations.connect: ${data.error || "Failed to start connect flow"}`);
|
|
64
|
+
}
|
|
65
|
+
const start = (await startRes.json());
|
|
66
|
+
if (opts?.noBrowser) {
|
|
67
|
+
console.log(` Open this URL to connect ${provider}:\n ${start.verificationUrl}\n`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
openBrowser(start.verificationUrl);
|
|
71
|
+
console.log(` Browser opened. Complete ${provider} authorization there, then return here.\n`);
|
|
72
|
+
}
|
|
73
|
+
const timeoutAt = Date.now() + CONNECT_POLL_TIMEOUT_MS;
|
|
74
|
+
let pollInterval = start.pollIntervalMs > 0 ? start.pollIntervalMs : 1000;
|
|
75
|
+
while (Date.now() < timeoutAt) {
|
|
76
|
+
await sleep(pollInterval);
|
|
77
|
+
const pollRes = await fetch(`${AUTH_BASE_URL}/api/orangeslice/integrations/connect/poll?deviceCode=${encodeURIComponent(start.deviceCode)}`, { method: "GET", headers: { "Content-Type": "application/json" } });
|
|
78
|
+
const data = (await pollRes.json());
|
|
79
|
+
if (data.status === "pending")
|
|
80
|
+
continue;
|
|
81
|
+
if (data.status === "approved" && data.integration) {
|
|
82
|
+
return data.integration;
|
|
83
|
+
}
|
|
84
|
+
if (data.status === "expired") {
|
|
85
|
+
throw new Error(`[orangeslice] integrations.connect: Device code expired. Please try again.`);
|
|
86
|
+
}
|
|
87
|
+
if (data.status === "consumed") {
|
|
88
|
+
throw new Error(`[orangeslice] integrations.connect: Device code already used.`);
|
|
89
|
+
}
|
|
90
|
+
if (!pollRes.ok) {
|
|
91
|
+
throw new Error(`[orangeslice] integrations.connect: ${data.error || "Polling failed"}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`[orangeslice] integrations.connect: Timed out waiting for authorization.`);
|
|
95
|
+
}
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// CRUD (via batch-service)
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
exports.integrations = {
|
|
100
|
+
connect: (provider, opts) => connectIntegration(provider, opts),
|
|
101
|
+
list: (opts) => (0, api_1.post)("/ctx/integrations/list", (opts ?? {})),
|
|
102
|
+
get: (id) => (0, api_1.post)("/ctx/integrations/get", { id }),
|
|
103
|
+
create: (opts) => (0, api_1.post)("/ctx/integrations/create", opts),
|
|
104
|
+
update: (id, fields) => (0, api_1.post)("/ctx/integrations/update", { id, ...fields }),
|
|
105
|
+
delete: (id) => (0, api_1.post)("/ctx/integrations/delete", { id })
|
|
106
|
+
};
|
package/dist/ocean.d.ts
CHANGED
|
@@ -5,14 +5,9 @@ export declare const OCEAN_OPERATION_IDS: {
|
|
|
5
5
|
export type OceanOperationId = (typeof OCEAN_OPERATION_IDS)[keyof typeof OCEAN_OPERATION_IDS];
|
|
6
6
|
export interface OceanCompaniesFilters {
|
|
7
7
|
lookalikeDomains?: string[];
|
|
8
|
-
minScore?: number;
|
|
9
8
|
companySizes?: Array<"0-1" | "2-10" | "11-50" | "51-200" | "201-500" | "501-1000" | "1001-5000" | "5001-10000" | "10001+">;
|
|
10
9
|
countries?: string[];
|
|
11
10
|
industries?: string[];
|
|
12
|
-
technologies?: string[];
|
|
13
|
-
technologyCategories?: string[];
|
|
14
|
-
keywords?: string[];
|
|
15
|
-
revenueRanges?: string[];
|
|
16
11
|
ecommerce?: boolean;
|
|
17
12
|
}
|
|
18
13
|
export interface OceanPeopleFilters {
|
|
@@ -24,11 +19,9 @@ export interface OceanPeopleFilters {
|
|
|
24
19
|
}
|
|
25
20
|
export interface OceanCompaniesSearchParams {
|
|
26
21
|
companiesFilters?: OceanCompaniesFilters;
|
|
22
|
+
peopleFilters?: OceanPeopleFilters;
|
|
27
23
|
size?: number;
|
|
28
|
-
from?: number;
|
|
29
24
|
searchAfter?: string;
|
|
30
|
-
includeDomains?: string[];
|
|
31
|
-
excludeDomains?: string[];
|
|
32
25
|
}
|
|
33
26
|
export interface OceanPhone {
|
|
34
27
|
country?: string;
|
|
@@ -97,6 +90,7 @@ export interface OceanCompanyMatch {
|
|
|
97
90
|
relevance?: string;
|
|
98
91
|
}
|
|
99
92
|
export interface OceanCompaniesSearchResponse {
|
|
93
|
+
detail?: string;
|
|
100
94
|
total: number;
|
|
101
95
|
searchAfter?: string;
|
|
102
96
|
companies: OceanCompanyMatch[];
|
package/dist/skills.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge Skills API for the orangeslice SDK.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { skills } from "orangeslice";
|
|
6
|
+
*
|
|
7
|
+
* // Create a skill
|
|
8
|
+
* const skill = await skills.create({
|
|
9
|
+
* title: "CRM Mapping",
|
|
10
|
+
* description: "Maps company fields to HubSpot properties",
|
|
11
|
+
* content: "When pushing to HubSpot, map ...",
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* // List all skills
|
|
15
|
+
* const { skills: list } = await skills.list();
|
|
16
|
+
*
|
|
17
|
+
* // Update a skill
|
|
18
|
+
* await skills.update(skill.id, { autoInject: true });
|
|
19
|
+
*/
|
|
20
|
+
export interface Skill {
|
|
21
|
+
id: string;
|
|
22
|
+
title: string;
|
|
23
|
+
description: string;
|
|
24
|
+
content: string;
|
|
25
|
+
autoInject: boolean;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
updatedAt: string;
|
|
28
|
+
scope: "account" | "spreadsheet";
|
|
29
|
+
spreadsheetId?: string | null;
|
|
30
|
+
}
|
|
31
|
+
export interface SkillListParams {
|
|
32
|
+
spreadsheetId?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface SkillCreateParams {
|
|
35
|
+
title: string;
|
|
36
|
+
description: string;
|
|
37
|
+
content: string;
|
|
38
|
+
autoInject?: boolean;
|
|
39
|
+
spreadsheetId?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface SkillUpdateParams {
|
|
42
|
+
title?: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
content?: string;
|
|
45
|
+
autoInject?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export declare const skills: {
|
|
48
|
+
list: (opts?: SkillListParams) => Promise<{
|
|
49
|
+
skills: Skill[];
|
|
50
|
+
}>;
|
|
51
|
+
get: (id: string) => Promise<Skill>;
|
|
52
|
+
create: (opts: SkillCreateParams) => Promise<Skill>;
|
|
53
|
+
update: (id: string, fields: SkillUpdateParams) => Promise<Skill>;
|
|
54
|
+
delete: (id: string) => Promise<{
|
|
55
|
+
success: boolean;
|
|
56
|
+
}>;
|
|
57
|
+
};
|
package/dist/skills.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Knowledge Skills API for the orangeslice SDK.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* import { skills } from "orangeslice";
|
|
7
|
+
*
|
|
8
|
+
* // Create a skill
|
|
9
|
+
* const skill = await skills.create({
|
|
10
|
+
* title: "CRM Mapping",
|
|
11
|
+
* description: "Maps company fields to HubSpot properties",
|
|
12
|
+
* content: "When pushing to HubSpot, map ...",
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* // List all skills
|
|
16
|
+
* const { skills: list } = await skills.list();
|
|
17
|
+
*
|
|
18
|
+
* // Update a skill
|
|
19
|
+
* await skills.update(skill.id, { autoInject: true });
|
|
20
|
+
*/
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.skills = void 0;
|
|
23
|
+
const api_1 = require("./api");
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
// CRUD (via batch-service)
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
exports.skills = {
|
|
28
|
+
list: (opts) => (0, api_1.post)("/ctx/skills/list", (opts ?? {})),
|
|
29
|
+
get: (id) => (0, api_1.post)("/ctx/skills/get", { id }),
|
|
30
|
+
create: (opts) => (0, api_1.post)("/ctx/skills/create", opts),
|
|
31
|
+
update: (id, fields) => (0, api_1.post)("/ctx/skills/update", { id, ...fields }),
|
|
32
|
+
delete: (id) => (0, api_1.post)("/ctx/skills/delete", { id })
|
|
33
|
+
};
|
|
@@ -51,20 +51,32 @@ const results = await services.ocean.search.companies({
|
|
|
51
51
|
|
|
52
52
|
**Key filters:**
|
|
53
53
|
|
|
54
|
-
| Filter | Example
|
|
55
|
-
| ------------------ |
|
|
56
|
-
| `lookalikeDomains` | `["stripe.com", "plaid.com"]`
|
|
57
|
-
| `companySizes` | `["51-200", "201-500"]`
|
|
58
|
-
| `countries` | `["us", "gb", "de"]`
|
|
59
|
-
| `industries` | `["SaaS", "Fintech"]`
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `keywords` | `["payments", "infrastructure"]` | Keyword filter |
|
|
63
|
-
| `ecommerce` | `true` | E-commerce companies only |
|
|
64
|
-
| `minScore` | `0.5` | Minimum similarity score (0–1) |
|
|
54
|
+
| Filter | Example | Notes |
|
|
55
|
+
| ------------------ | ------------------------------ | ------------------------------------------------------------ |
|
|
56
|
+
| `lookalikeDomains` | `["stripe.com", "plaid.com"]` | Core input — seed domains to find lookalikes for |
|
|
57
|
+
| `companySizes` | `["51-200", "201-500"]` | Filter by employee count range |
|
|
58
|
+
| `countries` | `["us", "gb", "de"]` | Two-letter ISO country codes |
|
|
59
|
+
| `industries` | `["SaaS", "Fintech"]` | Industry category names |
|
|
60
|
+
| `ecommerce` | `true` | E-commerce companies only |
|
|
61
|
+
| `peopleFilters` | `{ seniorities: ["C-Level"] }` | Top-level filter. Only return companies with matching people |
|
|
65
62
|
|
|
66
63
|
**Pagination:** Use `searchAfter` from the previous response for efficient cursor-based pagination. Max `size` per request is 100.
|
|
67
64
|
|
|
65
|
+
**Do not send these fields to `services.ocean.search.companies`:**
|
|
66
|
+
|
|
67
|
+
- `excludeDomains`
|
|
68
|
+
- `includeDomains`
|
|
69
|
+
- `from`
|
|
70
|
+
- `minScore`
|
|
71
|
+
- `technologyCategories`
|
|
72
|
+
- `revenueRanges`
|
|
73
|
+
|
|
74
|
+
Ocean v3 rejects each of those with `422`.
|
|
75
|
+
|
|
76
|
+
**Fields that are not safe as simple string arrays:** `technologies` and `keywords`.
|
|
77
|
+
|
|
78
|
+
When sent as string arrays, Ocean v3 returns `422` with `Input should be a valid dictionary or object to extract fields from`. Until we document the exact upstream shape, do not have the agent generate them.
|
|
79
|
+
|
|
68
80
|
### 2. `services.ocean.search.people` — Find People at Companies
|
|
69
81
|
|
|
70
82
|
Combine company filters with people filters to find the right contacts.
|
|
@@ -150,5 +162,5 @@ for (let page = 0; page < 5; page++) {
|
|
|
150
162
|
|
|
151
163
|
- **More seed domains = better results.** 3-5 seeds produce much better lookalikes than a single domain.
|
|
152
164
|
- **Combine with enrichment.** Ocean.io returns firmographic data, but you can enrich further with LinkedIn, BuiltWith, or PredictLeads.
|
|
153
|
-
- **
|
|
165
|
+
- **Exclude seed domains client-side.** Ocean v3 rejects `excludeDomains`, so filter out seed domains after the response if needed.
|
|
154
166
|
- **Credits:** 5 credits per result. A search returning 50 companies = 250 credits. Reserve is based on the requested `size`.
|
|
@@ -87,7 +87,7 @@ When using qualification columns, think Circle & Star:
|
|
|
87
87
|
| **Web Search (Default)** | **ALL prospecting/discovery** — keywords, niche, fuzzy, specific, LinkedIn profiles & companies via `site:linkedin.com` | Requires verification columns for false positives. |
|
|
88
88
|
| **Crunchbase (Funding Default)** | Funding-focused prospecting: stage, round type, amount, recency, investors | Best for funding intelligence; use other sources for non-funding discovery criteria. |
|
|
89
89
|
| **Ocean.io (Lookalike Default)** | User has seed domains and wants similar companies/people. "Find companies like X." | Needs seed domains as input. Not for keyword/niche discovery from scratch. See [guide](../lookalike-search/). |
|
|
90
|
-
| **PredictLeads** | Company intelligence, buying signals, and structured company events at scale | Coverage varies by company/market
|
|
90
|
+
| **PredictLeads** | Company intelligence, buying signals, and structured company events at scale | Coverage varies by company/market. Treat it as a prospecting/enrichment signal, not source-of-truth validation for whether a known company currently has an opening. |
|
|
91
91
|
| **Niche Directory Scrape** | Well-defined categories with existing lists (see below) | Requires finding the right directory first. |
|
|
92
92
|
| **LinkedIn B2B DB** | **Almost never for prospecting.** Only for: (1) lookups by known identifier (URL/domain/ID), (2) employees at a single known company, (3) trivially simple single-indexed-column filters like `industry_code` or `country_code`. | **Any query with keywords, descriptions, names, ILIKE, skills, or multi-criteria = web search.** The bar is extremely high — if in doubt, use web search. |
|
|
93
93
|
| **Google Maps** | Local/SMB, physical locations, restaurants, retail | Limited to businesses with physical presence. |
|
|
@@ -99,7 +99,7 @@ Use PredictLeads first when the user needs **high-quality structured company dat
|
|
|
99
99
|
|
|
100
100
|
PredictLeads is usually the best choice for:
|
|
101
101
|
- Tracking **company signals over time** (news, financing, hiring, tech detections, product changes, website evolution)
|
|
102
|
-
- Pulling **normalized lists** (job openings, technologies, investors/connections, similar companies) without custom scraping
|
|
102
|
+
- Pulling **normalized lists** (job openings, technologies, investors/connections, similar companies) for prospecting/enrichment without custom scraping
|
|
103
103
|
- Building qualification columns where consistency matters more than recall
|
|
104
104
|
- Workflows that need stable structured fields instead of parsing search snippets
|
|
105
105
|
|
package/docs/services/index.md
CHANGED
|
@@ -9,5 +9,7 @@
|
|
|
9
9
|
- **email**: send transactional notification emails through Orange Slice's managed sender.
|
|
10
10
|
- **scrape**: website scraper, sitemap scraper
|
|
11
11
|
- **web**: SERP
|
|
12
|
-
- **predictLeads**: company intelligence datasets (financing events, technologies, products, job openings, news, and related company data).
|
|
12
|
+
- **predictLeads**: company intelligence datasets (financing events, technologies, products, job openings, news, and related company data). Use these as prospecting/enrichment signals, not source-of-truth validation for whether a known company is hiring right now.
|
|
13
|
+
- **integrations**: connect and manage third-party integrations (HubSpot, Salesforce, Attio, Gmail, Slack, Instantly, HeyReach). Use `integrations.connect(provider)` to open the browser OAuth flow from a script, or `integrations.create(...)` for API-key providers.
|
|
14
|
+
- **skills**: create and manage knowledge skills — reusable knowledge snippets (ICP, templates, product info) that guide AI agents.
|
|
13
15
|
- **guides**: agent notes & operational docs (see [Error Handling Cheatsheet](../error-handling-cheatsheet.md))
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Connect and manage third-party integrations (HubSpot, Salesforce, Attio, Gmail, Slack, Instantly, HeyReach)
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# integrations — Integration Management
|
|
6
|
+
|
|
7
|
+
Connect, list, and manage third-party service integrations. Supports both OAuth providers (HubSpot, Salesforce, Attio, Gmail, Slack) and API-key providers (Instantly, HeyReach).
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { integrations } from "orangeslice";
|
|
13
|
+
|
|
14
|
+
// Connect an OAuth provider (opens browser for authorization)
|
|
15
|
+
const hubspot = await integrations.connect("hubspot");
|
|
16
|
+
console.log(`Connected: ${hubspot.displayName}`);
|
|
17
|
+
|
|
18
|
+
// List all connected integrations
|
|
19
|
+
const { integrations: list } = await integrations.list();
|
|
20
|
+
console.log(list.map(i => `${i.provider}: ${i.displayName}`));
|
|
21
|
+
|
|
22
|
+
// Connect an API-key provider programmatically (no browser)
|
|
23
|
+
await integrations.create({
|
|
24
|
+
provider: "instantly",
|
|
25
|
+
apiKey: "inst_abc123...",
|
|
26
|
+
displayName: "My Instantly"
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Methods
|
|
31
|
+
|
|
32
|
+
### `integrations.connect(provider, opts?)`
|
|
33
|
+
|
|
34
|
+
Opens the user's browser to complete OAuth authorization (or API key entry for Instantly/HeyReach). Polls until the user finishes, then returns the connected integration.
|
|
35
|
+
|
|
36
|
+
This is the recommended way to connect any integration from a script or agent.
|
|
37
|
+
|
|
38
|
+
**Parameters:**
|
|
39
|
+
- `provider` — One of: `"hubspot"`, `"salesforce"`, `"attio"`, `"gmail"`, `"slack"`, `"instantly"`, `"heyreach"`
|
|
40
|
+
- `opts.noBrowser` — If `true`, prints the URL instead of auto-opening the browser
|
|
41
|
+
|
|
42
|
+
**Returns:** `Integration` object
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const salesforce = await integrations.connect("salesforce");
|
|
46
|
+
// Browser opens -> user authorizes -> returns when complete
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### `integrations.list(opts?)`
|
|
50
|
+
|
|
51
|
+
List connected integrations for the current account.
|
|
52
|
+
|
|
53
|
+
**Parameters:**
|
|
54
|
+
- `opts.spreadsheetId` — Filter to a specific spreadsheet's integrations
|
|
55
|
+
- `opts.provider` — Filter by provider name
|
|
56
|
+
|
|
57
|
+
**Returns:** `{ integrations: Integration[] }`
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const { integrations: all } = await integrations.list();
|
|
61
|
+
const { integrations: crms } = await integrations.list({ provider: "hubspot" });
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `integrations.get(id)`
|
|
65
|
+
|
|
66
|
+
Get a single integration by ID.
|
|
67
|
+
|
|
68
|
+
**Returns:** `Integration`
|
|
69
|
+
|
|
70
|
+
### `integrations.create(opts)`
|
|
71
|
+
|
|
72
|
+
Programmatically create an API-key integration without opening a browser. Only works for API-key providers (`instantly`, `heyreach`). For OAuth providers, use `connect()` instead.
|
|
73
|
+
|
|
74
|
+
**Parameters:**
|
|
75
|
+
- `opts.provider` — `"instantly"` or `"heyreach"`
|
|
76
|
+
- `opts.apiKey` — The provider API key
|
|
77
|
+
- `opts.displayName` — Optional display name
|
|
78
|
+
- `opts.config` — Optional key-value config
|
|
79
|
+
- `opts.spreadsheetId` — Optional, scope to a specific spreadsheet
|
|
80
|
+
|
|
81
|
+
**Returns:** `Integration`
|
|
82
|
+
|
|
83
|
+
### `integrations.update(id, fields)`
|
|
84
|
+
|
|
85
|
+
Update an existing integration.
|
|
86
|
+
|
|
87
|
+
**Parameters:**
|
|
88
|
+
- `fields.apiKey` — New API key
|
|
89
|
+
- `fields.displayName` — New display name
|
|
90
|
+
- `fields.isActive` — Enable/disable
|
|
91
|
+
- `fields.config` — New config object
|
|
92
|
+
|
|
93
|
+
**Returns:** `Integration`
|
|
94
|
+
|
|
95
|
+
### `integrations.delete(id)`
|
|
96
|
+
|
|
97
|
+
Delete an integration by ID.
|
|
98
|
+
|
|
99
|
+
**Returns:** `{ success: boolean }`
|
|
100
|
+
|
|
101
|
+
## Integration object
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
{
|
|
105
|
+
id: string;
|
|
106
|
+
provider: string; // "hubspot", "salesforce", etc.
|
|
107
|
+
displayName: string; // "HubSpot portal acme.hubspot.com"
|
|
108
|
+
isActive: boolean;
|
|
109
|
+
hasApiKey: boolean; // true if API key is set (key itself is never returned)
|
|
110
|
+
hasOauthToken: boolean; // true if OAuth token is set
|
|
111
|
+
createdAt: string;
|
|
112
|
+
updatedAt: string;
|
|
113
|
+
scope: "account" | "spreadsheet";
|
|
114
|
+
spreadsheetId: string | null;
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Supported providers
|
|
119
|
+
|
|
120
|
+
| Provider | Auth Type | Connect method |
|
|
121
|
+
| ----------- | --------- | ---------------------- |
|
|
122
|
+
| HubSpot | OAuth | `connect("hubspot")` |
|
|
123
|
+
| Salesforce | OAuth | `connect("salesforce")`|
|
|
124
|
+
| Attio | OAuth | `connect("attio")` |
|
|
125
|
+
| Gmail | OAuth | `connect("gmail")` |
|
|
126
|
+
| Slack | OAuth | `connect("slack")` |
|
|
127
|
+
| Instantly | API Key | `connect("instantly")` or `create(...)` |
|
|
128
|
+
| HeyReach | API Key | `connect("heyreach")` or `create(...)` |
|
|
@@ -1,130 +1,133 @@
|
|
|
1
1
|
interface OceanCompaniesFilters {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
/** Array of domains to find lookalike companies for (e.g., ["stripe.com", "shopify.com"]) */
|
|
3
|
+
lookalikeDomains?: string[];
|
|
4
|
+
/** Company size ranges to filter by */
|
|
5
|
+
companySizes?: Array<
|
|
6
|
+
"0-1" | "2-10" | "11-50" | "51-200" | "201-500" | "501-1000" | "1001-5000" | "5001-10000" | "10001+"
|
|
7
|
+
>;
|
|
8
|
+
/** Two-letter country codes to filter by (e.g., ["us", "gb"]) */
|
|
9
|
+
countries?: string[];
|
|
10
|
+
/** Industry names to filter by */
|
|
11
|
+
industries?: string[];
|
|
12
|
+
/** Filter for e-commerce companies */
|
|
13
|
+
ecommerce?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface OceanPeopleFilters {
|
|
17
|
+
/** Seniority levels to filter by (e.g., ["C-Level", "VP", "Director", "Manager"]) */
|
|
18
|
+
seniorities?: string[];
|
|
19
|
+
/** Departments to filter by (e.g., ["Engineering", "Sales", "Marketing"]) */
|
|
20
|
+
departments?: string[];
|
|
21
|
+
/** Job title keywords to search for */
|
|
22
|
+
jobTitleKeywords?: string[];
|
|
23
|
+
/** Two-letter country codes to filter by */
|
|
24
|
+
countries?: string[];
|
|
25
|
+
/** Array of Ocean.io people IDs to find lookalikes for */
|
|
26
|
+
lookalikePeopleIds?: string[];
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
interface OceanCompanyResult {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
30
|
+
/** Company domain */
|
|
31
|
+
domain: string;
|
|
32
|
+
/** Company name */
|
|
33
|
+
name?: string;
|
|
34
|
+
/** Legal company name */
|
|
35
|
+
legalName?: string;
|
|
36
|
+
/** Company description */
|
|
37
|
+
description?: string;
|
|
38
|
+
/** Two-letter country codes where the company operates */
|
|
39
|
+
countries?: string[];
|
|
40
|
+
/** Primary country code */
|
|
41
|
+
primaryCountry?: string;
|
|
42
|
+
/** Company size range (e.g., "51-200") */
|
|
43
|
+
companySize?: string;
|
|
44
|
+
/** Industry categories */
|
|
45
|
+
industryCategories?: string[];
|
|
46
|
+
/** Industries */
|
|
47
|
+
industries?: string[];
|
|
48
|
+
/** LinkedIn industry classification */
|
|
49
|
+
linkedinIndustry?: string;
|
|
50
|
+
/** Whether the company is an e-commerce business */
|
|
51
|
+
ecommerce?: boolean;
|
|
52
|
+
/** Company keywords */
|
|
53
|
+
keywords?: string[];
|
|
54
|
+
/** Ocean.io employee count estimate */
|
|
55
|
+
employeeCountOcean?: number;
|
|
56
|
+
/** LinkedIn employee count */
|
|
57
|
+
employeeCountLinkedin?: number;
|
|
58
|
+
/** Revenue range (e.g., "1M-10M") */
|
|
59
|
+
revenue?: string;
|
|
60
|
+
/** Year founded */
|
|
61
|
+
yearFounded?: number;
|
|
62
|
+
/** Company email addresses */
|
|
63
|
+
emails?: string[];
|
|
64
|
+
/** Phone numbers with country and primary flag */
|
|
65
|
+
phones?: Array<{ country?: string; number: string; primary?: boolean }>;
|
|
66
|
+
/** Company logo URL */
|
|
67
|
+
logo?: string;
|
|
68
|
+
/** Technologies used */
|
|
69
|
+
technologies?: string[];
|
|
70
|
+
/** Technology categories */
|
|
71
|
+
technologyCategories?: string[];
|
|
72
|
+
/** Company website root URL */
|
|
73
|
+
rootUrl?: string;
|
|
74
|
+
/** Social media profiles */
|
|
75
|
+
medias?: Record<string, { url?: string; handle?: string; name?: string }>;
|
|
76
|
+
/** Office locations */
|
|
77
|
+
locations?: Array<{
|
|
78
|
+
primary?: boolean;
|
|
79
|
+
latitude?: number;
|
|
80
|
+
longitude?: number;
|
|
81
|
+
country?: string;
|
|
82
|
+
locality?: string;
|
|
83
|
+
region?: string;
|
|
84
|
+
postalCode?: string;
|
|
85
|
+
streetAddress?: string;
|
|
86
|
+
state?: string;
|
|
87
|
+
}>;
|
|
88
|
+
/** Department sizes */
|
|
89
|
+
departmentSizes?: Array<{ department: string; size: number }>;
|
|
90
|
+
/** Headcount growth metrics */
|
|
91
|
+
headcountGrowth?: {
|
|
92
|
+
threeMonths?: number;
|
|
93
|
+
threeMonthsPercentage?: number;
|
|
94
|
+
sixMonths?: number;
|
|
95
|
+
sixMonthsPercentage?: number;
|
|
96
|
+
twelveMonths?: number;
|
|
97
|
+
twelveMonthsPercentage?: number;
|
|
98
|
+
};
|
|
99
|
+
/** Last update timestamp */
|
|
100
|
+
updatedAt?: string;
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
/**
|
|
99
104
|
* Search for lookalike companies using Ocean.io.
|
|
100
105
|
* Provide seed domains via companiesFilters.lookalikeDomains to find similar companies.
|
|
101
|
-
*
|
|
102
|
-
*
|
|
106
|
+
* Verified v3 filters: companySizes, countries, industries, ecommerce, and top-level peopleFilters.
|
|
107
|
+
* Use `searchAfter` for pagination. Do not send `from`, `includeDomains`, `excludeDomains`, or `minScore` because Ocean v3 rejects them with 422 errors.
|
|
103
108
|
*/
|
|
104
109
|
type companies = (params: {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
redirectMap?: Record<string, string>;
|
|
130
|
-
}>;
|
|
110
|
+
/** Filters for company search (lookalike domains, size, country, industry, ecommerce) */
|
|
111
|
+
companiesFilters?: OceanCompaniesFilters;
|
|
112
|
+
/** Optional people filters. Returns companies that have at least one matching person. */
|
|
113
|
+
peopleFilters?: OceanPeopleFilters;
|
|
114
|
+
/** Number of results to return (default 10, max 100) */
|
|
115
|
+
size?: number;
|
|
116
|
+
/** Cursor token from a previous response for efficient pagination */
|
|
117
|
+
searchAfter?: string;
|
|
118
|
+
}) => Promise<{
|
|
119
|
+
/** Ocean.io status detail (typically "OK") */
|
|
120
|
+
detail?: string;
|
|
121
|
+
/** Total matching companies */
|
|
122
|
+
total: number;
|
|
123
|
+
/** Cursor for next page (pass as searchAfter) */
|
|
124
|
+
searchAfter?: string;
|
|
125
|
+
/** Matched companies with relevance scores */
|
|
126
|
+
companies: Array<{
|
|
127
|
+
company: OceanCompanyResult;
|
|
128
|
+
/** Relevance grade (A = best match) */
|
|
129
|
+
relevance?: string;
|
|
130
|
+
}>;
|
|
131
|
+
/** Domains that were redirected to canonical domains */
|
|
132
|
+
redirectMap?: Record<string, string>;
|
|
133
|
+
}>;
|
|
@@ -1,102 +1,176 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Retrieve company's Job Openings
|
|
3
3
|
* Returns a list of company's Job Openings.
|
|
4
|
+
*
|
|
5
|
+
* Use this as a prospecting/enrichment signal, not as source-of-truth validation
|
|
6
|
+
* that a known company is currently hiring. For current validation, prefer the
|
|
7
|
+
*
|
|
8
|
+
* company's official careers page / ATS via services.company.findCareersPage and
|
|
9
|
+
* services.company.scrapeCareersPage.
|
|
4
10
|
* HTTP GET /companies/{company_id_or_domain}/job_openings
|
|
5
11
|
*/
|
|
6
12
|
type companyJobOpenings = (params: {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
13
|
+
/** Company's ID or domain. */
|
|
14
|
+
company_id_or_domain: string;
|
|
15
|
+
/** Set to true if you'd like to receive JobOpenings that are not closed, have last_seen_at more recent than 5 days and were found in the last year. */
|
|
16
|
+
active_only?: boolean;
|
|
17
|
+
/** Similar to `active_only`, but without considering `last_seen_at` timestamp. */
|
|
18
|
+
not_closed?: boolean;
|
|
19
|
+
/** Only return `JobOpenings` first seen after given date (ISO 8601). */
|
|
20
|
+
first_seen_at_from?: string;
|
|
21
|
+
/** Only return `JobOpenings` first seen before given date (ISO 8601). */
|
|
22
|
+
first_seen_at_until?: string;
|
|
23
|
+
/** Only return `JobOpenings` last seen after given date (ISO 8601). */
|
|
24
|
+
last_seen_at_from?: string;
|
|
25
|
+
/** Only return `JobOpenings` last seen before given date (ISO 8601). */
|
|
26
|
+
last_seen_at_until?: string;
|
|
27
|
+
/** Only return JobOpenings that have description. */
|
|
28
|
+
with_description_only?: boolean;
|
|
29
|
+
/** Only return JobOpenings that have location. */
|
|
30
|
+
with_location_only?: boolean;
|
|
31
|
+
/** Comma-separated (,) `JobOpening` categories. */
|
|
32
|
+
categories?: Array<
|
|
33
|
+
| "administration"
|
|
34
|
+
| "consulting"
|
|
35
|
+
| "data_analysis"
|
|
36
|
+
| "design"
|
|
37
|
+
| "directors"
|
|
38
|
+
| "education"
|
|
39
|
+
| "engineering"
|
|
40
|
+
| "finance"
|
|
41
|
+
| "healthcare_services"
|
|
42
|
+
| "human_resources"
|
|
43
|
+
| "information_technology"
|
|
44
|
+
| "internship"
|
|
45
|
+
| "legal"
|
|
46
|
+
| "management"
|
|
47
|
+
| "marketing"
|
|
48
|
+
| "military_and_protective_services"
|
|
49
|
+
| "operations"
|
|
50
|
+
| "purchasing"
|
|
51
|
+
| "product_management"
|
|
52
|
+
| "quality_assurance"
|
|
53
|
+
| "real_estate"
|
|
54
|
+
| "research"
|
|
55
|
+
| "sales"
|
|
56
|
+
| "software_development"
|
|
57
|
+
| "support"
|
|
58
|
+
| "manual_work"
|
|
59
|
+
| "food"
|
|
60
|
+
>;
|
|
61
|
+
/** Page number of shown items. **NOTE**: If the parameter is not provided, the meta property `count` will be omitted from response for performance reasons. */
|
|
62
|
+
page?: number;
|
|
63
|
+
/** Limit the number of shown items per page. */
|
|
64
|
+
limit?: number;
|
|
31
65
|
}) => Promise<{
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
66
|
+
data: Array<{
|
|
67
|
+
id: string;
|
|
68
|
+
type: "job_opening";
|
|
69
|
+
attributes: {
|
|
70
|
+
title: string;
|
|
71
|
+
description: string | null;
|
|
72
|
+
url: string;
|
|
73
|
+
first_seen_at: string;
|
|
74
|
+
last_seen_at: string;
|
|
75
|
+
last_processed_at: string;
|
|
76
|
+
contract_types: Array<Record<string, unknown>>;
|
|
77
|
+
categories: Array<
|
|
78
|
+
| "administration"
|
|
79
|
+
| "consulting"
|
|
80
|
+
| "data_analysis"
|
|
81
|
+
| "design"
|
|
82
|
+
| "directors"
|
|
83
|
+
| "education"
|
|
84
|
+
| "engineering"
|
|
85
|
+
| "finance"
|
|
86
|
+
| "healthcare_services"
|
|
87
|
+
| "human_resources"
|
|
88
|
+
| "information_technology"
|
|
89
|
+
| "internship"
|
|
90
|
+
| "legal"
|
|
91
|
+
| "management"
|
|
92
|
+
| "marketing"
|
|
93
|
+
| "military_and_protective_services"
|
|
94
|
+
| "operations"
|
|
95
|
+
| "purchasing"
|
|
96
|
+
| "product_management"
|
|
97
|
+
| "quality_assurance"
|
|
98
|
+
| "real_estate"
|
|
99
|
+
| "research"
|
|
100
|
+
| "sales"
|
|
101
|
+
| "software_development"
|
|
102
|
+
| "support"
|
|
103
|
+
| "manual_work"
|
|
104
|
+
| "food"
|
|
105
|
+
>;
|
|
106
|
+
onet_data: {
|
|
107
|
+
code: string | null;
|
|
108
|
+
family: string | null;
|
|
109
|
+
occupation_name: string | null;
|
|
110
|
+
};
|
|
111
|
+
posted_at: string | null;
|
|
112
|
+
recruiter_data: {
|
|
113
|
+
name: string | null;
|
|
114
|
+
title: string | null;
|
|
115
|
+
contact: string | null;
|
|
116
|
+
};
|
|
117
|
+
salary: string | null;
|
|
118
|
+
salary_data: {
|
|
119
|
+
salary_low: number | null;
|
|
120
|
+
salary_high: number | null;
|
|
121
|
+
salary_currency: string | null;
|
|
122
|
+
salary_low_usd: number | null;
|
|
123
|
+
salary_high_usd: number | null;
|
|
124
|
+
salary_time_unit: "hour" | "day" | "week" | "month" | "year" | null;
|
|
125
|
+
};
|
|
126
|
+
seniority:
|
|
127
|
+
| "not_set"
|
|
128
|
+
| "founder"
|
|
129
|
+
| "c_level"
|
|
130
|
+
| "partner"
|
|
131
|
+
| "president"
|
|
132
|
+
| "vice_president"
|
|
133
|
+
| "head"
|
|
134
|
+
| "director"
|
|
135
|
+
| "manager"
|
|
136
|
+
| "mid_senior"
|
|
137
|
+
| "junior"
|
|
138
|
+
| "non_manager";
|
|
139
|
+
status: "closed" | null;
|
|
140
|
+
language: string | null;
|
|
141
|
+
location: string | null;
|
|
142
|
+
location_data: Array<{
|
|
143
|
+
city: unknown;
|
|
144
|
+
state: unknown;
|
|
145
|
+
zip_code: unknown;
|
|
146
|
+
country: unknown;
|
|
147
|
+
region: unknown;
|
|
148
|
+
continent: unknown;
|
|
149
|
+
fuzzy_match: unknown;
|
|
150
|
+
}>;
|
|
151
|
+
tags: Array<Record<string, unknown>>;
|
|
152
|
+
};
|
|
153
|
+
relationships: {
|
|
154
|
+
company: {
|
|
155
|
+
data: {
|
|
156
|
+
id: string;
|
|
157
|
+
type: "company";
|
|
158
|
+
};
|
|
159
|
+
};
|
|
160
|
+
};
|
|
161
|
+
}>;
|
|
162
|
+
included: Array<{
|
|
163
|
+
id: string;
|
|
164
|
+
type: "company";
|
|
165
|
+
attributes: {
|
|
166
|
+
domain: string;
|
|
167
|
+
company_name: string | null;
|
|
168
|
+
ticker: string | null;
|
|
169
|
+
};
|
|
170
|
+
}>;
|
|
171
|
+
meta?: {
|
|
172
|
+
schema_version: string;
|
|
173
|
+
record_state: "active";
|
|
174
|
+
count?: number;
|
|
175
|
+
};
|
|
76
176
|
}>;
|
|
77
|
-
tags: Array<Record<string, unknown>>;
|
|
78
|
-
};
|
|
79
|
-
relationships: {
|
|
80
|
-
company: {
|
|
81
|
-
data: {
|
|
82
|
-
id: string;
|
|
83
|
-
type: "company";
|
|
84
|
-
};
|
|
85
|
-
};
|
|
86
|
-
};
|
|
87
|
-
}>;
|
|
88
|
-
included: Array<{
|
|
89
|
-
id: string;
|
|
90
|
-
type: "company";
|
|
91
|
-
attributes: {
|
|
92
|
-
domain: string;
|
|
93
|
-
company_name: string | null;
|
|
94
|
-
ticker: string | null;
|
|
95
|
-
};
|
|
96
|
-
}>;
|
|
97
|
-
meta?: {
|
|
98
|
-
schema_version: string;
|
|
99
|
-
record_state: "active";
|
|
100
|
-
count?: number;
|
|
101
|
-
};
|
|
102
|
-
}>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Create and manage knowledge skills — reusable knowledge snippets that guide AI agents
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# skills — Knowledge Skills
|
|
6
|
+
|
|
7
|
+
Create, read, update, and delete knowledge skills. Skills are reusable knowledge snippets (company context, ICP descriptions, email templates, product info) that agents reference during research and outreach.
|
|
8
|
+
|
|
9
|
+
## Quick start
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { skills } from "orangeslice";
|
|
13
|
+
|
|
14
|
+
// Create a skill
|
|
15
|
+
const skill = await skills.create({
|
|
16
|
+
name: "ICP description",
|
|
17
|
+
content: "We sell to B2B SaaS companies, 50-500 employees, Series A-C..."
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// List all skills
|
|
21
|
+
const { skills: all } = await skills.list();
|
|
22
|
+
console.log(all.map(s => `${s.name}: ${s.content.slice(0, 50)}...`));
|
|
23
|
+
|
|
24
|
+
// Update a skill
|
|
25
|
+
await skills.update(skill.id, { content: "Updated ICP: ..." });
|
|
26
|
+
|
|
27
|
+
// Delete a skill
|
|
28
|
+
await skills.delete(skill.id);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Methods
|
|
32
|
+
|
|
33
|
+
### `skills.list(opts?)`
|
|
34
|
+
|
|
35
|
+
List knowledge skills for the current account.
|
|
36
|
+
|
|
37
|
+
**Parameters:**
|
|
38
|
+
- `opts.spreadsheetId` — Filter to a specific spreadsheet's skills
|
|
39
|
+
|
|
40
|
+
**Returns:** `{ skills: Skill[] }`
|
|
41
|
+
|
|
42
|
+
### `skills.get(id)`
|
|
43
|
+
|
|
44
|
+
Get a single skill by ID.
|
|
45
|
+
|
|
46
|
+
**Returns:** `Skill`
|
|
47
|
+
|
|
48
|
+
### `skills.create(opts)`
|
|
49
|
+
|
|
50
|
+
Create a new knowledge skill.
|
|
51
|
+
|
|
52
|
+
**Parameters:**
|
|
53
|
+
- `opts.name` — Skill name (e.g. "ICP description", "Email template")
|
|
54
|
+
- `opts.content` — The knowledge content
|
|
55
|
+
- `opts.spreadsheetId` — Optional, scope to a specific spreadsheet
|
|
56
|
+
|
|
57
|
+
**Returns:** `Skill`
|
|
58
|
+
|
|
59
|
+
### `skills.update(id, fields)`
|
|
60
|
+
|
|
61
|
+
Update an existing skill.
|
|
62
|
+
|
|
63
|
+
**Parameters:**
|
|
64
|
+
- `fields.name` — New name
|
|
65
|
+
- `fields.content` — New content
|
|
66
|
+
|
|
67
|
+
**Returns:** `Skill`
|
|
68
|
+
|
|
69
|
+
### `skills.delete(id)`
|
|
70
|
+
|
|
71
|
+
Delete a skill by ID.
|
|
72
|
+
|
|
73
|
+
**Returns:** `{ success: boolean }`
|
|
74
|
+
|
|
75
|
+
## Skill object
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
{
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
content: string;
|
|
82
|
+
createdAt: string;
|
|
83
|
+
updatedAt: string;
|
|
84
|
+
scope: "account" | "spreadsheet";
|
|
85
|
+
spreadsheetId: string | null;
|
|
86
|
+
}
|
|
87
|
+
```
|