@signaliz/sdk 1.0.1 → 1.0.3

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.
package/README.md CHANGED
@@ -2,32 +2,313 @@
2
2
 
3
3
  The official Signaliz SDK for JavaScript/TypeScript — GTM intelligence for AI agents.
4
4
 
5
+ Current surfaces include the GTM Kernel, Campaign Builder, provider routing,
6
+ Nango-managed customer API connections, MCP/Ops control-plane methods, and
7
+ enrichment primitives. Available data is returned before fresh enrichment;
8
+ live email verification is 0.02 fresh enrichment credits when a new verification is needed.
9
+
5
10
  ## Installation
6
11
 
7
12
  ```bash
8
13
  npm install @signaliz/sdk
9
14
  ```
10
15
 
11
- ## Quick Start
16
+ ## Quick Start — Campaign Builder
17
+
18
+ Build a targeted lead list, wait for completion, then retrieve rows and CSV:
12
19
 
13
20
  ```typescript
14
21
  import { Signaliz } from '@signaliz/sdk';
15
22
 
16
- const signaliz = new Signaliz({
17
- apiKey: process.env.SIGNALIZ_API_KEY,
23
+ const signaliz = new Signaliz({ apiKey: process.env.SIGNALIZ_API_KEY });
24
+
25
+ // 1. Start a campaign build
26
+ const { campaignBuildId } = await signaliz.campaigns.build({
27
+ name: 'Q3 SaaS Outbound',
28
+ prompt: 'Series A-C SaaS companies in fintech hiring SDRs',
29
+ targetCount: 500,
30
+ confirmSpend: true,
31
+ delivery: { destinationType: 'csv' },
32
+ });
33
+
34
+ // 2. Wait for completion with progress updates
35
+ const final = await signaliz.campaigns.wait(campaignBuildId, {
36
+ onProgress: (s) => console.log(`${s.recordsProcessed}/${s.recordsTotal} rows`),
37
+ });
38
+
39
+ // 3. Retrieve structured rows
40
+ const { rows } = await signaliz.campaigns.rows(campaignBuildId, { limit: 100 });
41
+ rows.forEach((r) => console.log(r.data.email, r.data.company_name));
42
+
43
+ // 4. Download CSV artifact
44
+ const artifacts = await signaliz.campaigns.artifacts(campaignBuildId);
45
+ const csv = artifacts.find((a) => a.artifactType === 'csv');
46
+ console.log('Download:', csv?.signedUrl);
47
+ ```
48
+
49
+ > **Downstream routing:** Signaliz outputs JSON, CSV, and webhook. Your agent routes rows to CRMs, outreach tools, or warehouses using their own APIs/MCPs.
50
+
51
+ ## GTM Kernel + Brain
52
+
53
+ Use `signaliz.gtm` when an agent needs the substrate directly: workspace context, first-class campaign objects, ranked memory, Brain patterns/defaults, and provider routes.
54
+
55
+ ```typescript
56
+ const context = await signaliz.gtm.context({
57
+ includeCampaigns: true,
58
+ includeMemory: true,
59
+ includeBrain: true,
60
+ includeConnections: true,
61
+ });
62
+
63
+ const campaign = await signaliz.gtm.createCampaign({
64
+ name: 'Series B Engineering Leaders',
65
+ targetIcp: { personas: ['VP Engineering'], segment: 'Series B SaaS' },
66
+ leadListRefs: [{ source: 'signaliz_cache' }],
67
+ sendConfig: { daily_cap: 50 },
68
+ providerLinks: [{ provider: 'instantly', providerCampaignId: 'instantly_123' }],
69
+ });
70
+
71
+ const seed = await signaliz.gtm.seedBrainDefaults({
72
+ campaignId: campaign.campaign?.id,
73
+ campaignBrief: 'Heads of engineering at Series B SaaS',
74
+ layers: ['icp', 'lead_generation', 'copy_enrichment'],
75
+ includeGlobal: true,
76
+ });
77
+
78
+ const failures = await signaliz.gtm.failurePatterns({
79
+ campaignId: campaign.campaign?.id,
80
+ dimensions: ['provider_chain', 'icp_shape', 'copy_pattern'],
81
+ days: 90,
82
+ });
83
+
84
+ const aggregate = await signaliz.gtm.aggregateBrainPatterns({
85
+ patternTypes: ['icp', 'provider_chain', 'failure'],
86
+ minWorkspaceCount: 3,
87
+ minPrivacyK: 20,
88
+ dryRun: true,
89
+ });
90
+
91
+ const calibrationAggregate = await signaliz.gtm.aggregateBrainCalibrations({
92
+ dimensionTypes: ['email_domain', 'verification_source', 'provider_chain'],
93
+ minWorkspaceCount: 3,
94
+ minPrivacyK: 20,
95
+ dryRun: true,
96
+ });
97
+
98
+ const learningCycle = await signaliz.gtm.learningCyclePlan({
99
+ campaignId: campaign.campaign?.id,
100
+ campaignBrief: 'Heads of engineering at Series B SaaS',
101
+ includeNetwork: true,
102
+ writeMode: 'dry_run',
103
+ });
104
+
105
+ const campaignLearning = await signaliz.gtm.campaignLearningStatus({
106
+ campaignId: campaign.campaign?.id,
107
+ campaignBuildId: campaign.campaign?.campaign_build_id,
108
+ writeMode: 'dry_run',
109
+ });
110
+
111
+ const readyLanes = campaignLearning.learning_lanes?.filter((lane) => lane.state === 'ready') ?? [];
112
+ const networkLane = campaignLearning.learning_lanes?.find((lane) => lane.id === 'network_patterns');
113
+
114
+ await signaliz.gtm.createIntegrationRecipe({
115
+ providerId: 'clay_webhook',
116
+ providerName: 'Clay Webhook',
117
+ layerCapabilities: ['find_company', 'find_people', 'lead_generation'],
118
+ invocationType: 'webhook',
119
+ authStrategy: 'webhook_secret',
120
+ endpointUrl: 'https://hooks.example.com/clay',
121
+ status: 'active',
122
+ });
123
+
124
+ const routeProof = await signaliz.gtm.previewLayerRoute({
125
+ layer: 'lead_generation',
126
+ campaignId: campaign.campaign?.id,
127
+ sampleRecords: [{ email: 'buyer@example.com' }],
128
+ context: { source: 'sdk_quickstart' },
129
+ });
130
+
131
+ console.log(routeProof.next_action);
132
+ console.log(failures.failure_patterns?.[0]?.recommendation?.next_step);
133
+ console.log({ readyLanes: readyLanes.length, networkPolicy: networkLane?.raw_data_policy });
134
+ ```
135
+
136
+ Provider routes can point to Signaliz native tools, Clay webhooks, Airbyte,
137
+ Nango-managed customer APIs, Apollo, AI Ark, Octave, Instantly, HeyReach,
138
+ Smartlead, custom APIs, custom MCP servers, or manual review gates. Nango routes
139
+ keep customer credentials in Nango while Signaliz stores only the workspace
140
+ connection reference and approval/audit context.
141
+
142
+ ### GTM Kernel Smoke Test
143
+
144
+ After CMM imports or Campaign Builder backfills, run the read-only/dry-run
145
+ smoke harness before launching spendful provider work:
146
+
147
+ ```bash
148
+ SIGNALIZ_API_KEY=sk_... node scripts/cmm-kernel-smoke.mjs \
149
+ --campaign-build-id <campaign_build_id>
150
+ ```
151
+
152
+ The receipt includes campaign/build/workspace IDs, execution stage, feedback and
153
+ memory counts, Brain phase readiness, blockers/warnings, the next safe MCP
154
+ action, and explicit no-spend/no-write/no-sender/no-delivery confirmation.
155
+
156
+ ## MCP/Ops Control Plane
157
+
158
+ Fresh-enrichment throughput is now higher across every plan: Free 60/min,
159
+ Builder 300/min, Team 600/min, Agency 1,000/min, and Pay-As-You-Go 1,000/min,
160
+ with a 5,000/hour per-workspace safety cap. Cache hits, API/MCP reads, and
161
+ included standard data do not count against those fresh-enrichment ceilings.
162
+
163
+ ```typescript
164
+ // Workspace and platform health
165
+ const workspace = await signaliz.getWorkspace();
166
+ const health = await signaliz.getPlatformHealth();
167
+
168
+ // Tool/capability discovery
169
+ const tools = await signaliz.listTools();
170
+ const opsMatches = await signaliz.discover('campaign build with webhook delivery', 'ops');
171
+
172
+ // Prompt-first Ops loop
173
+ const plan = await signaliz.ops.plan(
174
+ 'Monitor stripe.com and plaid.com every day and Slack me new hiring signals',
175
+ );
176
+ const op = await signaliz.ops.create({
177
+ prompt: plan.goal,
178
+ blueprint: plan.blueprint,
179
+ target_count: plan.target_count,
180
+ cadence: plan.cadence,
181
+ confirm_spend: true,
18
182
  });
183
+ await signaliz.ops.run(op.op_id);
184
+ const status = await signaliz.ops.status(op.op_id);
185
+ const results = await signaliz.ops.results({ op_id: op.op_id, limit: 100 });
19
186
 
187
+ // Spendful lead generation requires explicit approval
188
+ try {
189
+ await signaliz.leads.generate({
190
+ prompt: 'VP Sales at B2B SaaS companies, 50-500 employees',
191
+ maxLeads: 100,
192
+ });
193
+ } catch (error) {
194
+ // APPROVAL_REQUIRED includes estimated_credits and retry_arguments in details.
195
+ }
196
+
197
+ const leadJob = await signaliz.leads.generate({
198
+ prompt: 'VP Sales at B2B SaaS companies, 50-500 employees',
199
+ maxLeads: 100,
200
+ confirmSpend: true,
201
+ });
202
+ const leadStatus = await signaliz.leads.checkStatus(leadJob.jobId);
203
+ ```
204
+
205
+ ## Custom AI Enrichment - Multi Model
206
+
207
+ Use OpenRouter model IDs directly and attach images, PDFs, audio, or video when the selected model supports them. OpenRouter Fusion handles web search/fetch inside the deliberation step, so there is no separate search toggle.
208
+
209
+ ```typescript
210
+ const result = await signaliz.ai.multiModel({
211
+ model: 'google/gemini-2.5-flash',
212
+ prompt: 'Research {{company_name}} and score whether they match our ICP.',
213
+ records: [{ company_name: 'Stripe', company_domain: 'stripe.com' }],
214
+ outputFields: [
215
+ { name: 'fit_score', type: 'number', description: 'ICP fit from 1-10' },
216
+ { name: 'reasoning', type: 'text', description: 'Short evidence-backed rationale' },
217
+ ],
218
+ fusion: {
219
+ analysis_models: ['~google/gemini-flash-latest', '~openai/gpt-latest'],
220
+ judge_model: '~anthropic/claude-opus-latest',
221
+ },
222
+ });
223
+
224
+ console.log(result.results);
225
+ ```
226
+
227
+ ## Campaigns API
228
+
229
+ ### `campaigns.build(request, options?)`
230
+
231
+ Start an async campaign build. Returns immediately with a `campaignBuildId`.
232
+
233
+ ```typescript
234
+ const result = await signaliz.campaigns.build(
235
+ {
236
+ name: 'Test',
237
+ prompt: 'Find CFOs at mid-market healthcare companies',
238
+ dryRun: true,
239
+ allowDownscale: true,
240
+ confirmSpend: true,
241
+ },
242
+ { idempotencyKey: 'my-unique-key-123' } // prevent duplicate builds
243
+ );
244
+ ```
245
+
246
+ When `dryRun: true` is passed, the result is a plan (`status: 'dry_run'`) with
247
+ `campaignBuildId: null`, planned target count, estimated credits, and duration.
248
+
249
+ ### `campaigns.status(id)`
250
+
251
+ Get a concise status snapshot — ideal for polling.
252
+
253
+ ### `campaigns.get(id)`
254
+
255
+ Get the full campaign build record including delivery details.
256
+
257
+ ### `campaigns.rows(id, options?)`
258
+
259
+ Retrieve paginated rows from a completed build.
260
+
261
+ ```typescript
262
+ const page = await signaliz.campaigns.rows(buildId, {
263
+ limit: 50,
264
+ segment: 'signal',
265
+ qualified: true,
266
+ });
267
+ // page.rows, page.nextCursor, page.hasMore
268
+ ```
269
+
270
+ ### `campaigns.artifacts(id)`
271
+
272
+ List all artifacts (CSV exports, signed URLs).
273
+
274
+ ### `campaigns.cancel(id, reason?)`
275
+
276
+ Cancel a queued or running build.
277
+
278
+ ### `campaigns.wait(id, options?)`
279
+
280
+ Poll until completed, failed, or canceled.
281
+
282
+ ```typescript
283
+ const final = await signaliz.campaigns.wait(buildId, {
284
+ intervalMs: 3000,
285
+ timeoutMs: 300_000,
286
+ onProgress: (s) => console.log(s.status, s.recordsProcessed),
287
+ });
288
+ ```
289
+
290
+ ## Other Resources
291
+
292
+ ```typescript
20
293
  // Find and verify an email
21
294
  const email = await signaliz.emails.find({
22
295
  fullName: 'Jane Smith',
23
296
  companyDomain: 'stripe.com',
24
297
  });
25
- console.log(email);
26
- // → { email: 'jane.smith@stripe.com', verificationStatus: 'valid', confidence: 0.95 }
27
298
 
28
- // Verify an email
29
- const result = await signaliz.emails.verify('jane@stripe.com');
30
- // → { isValid: true, isDeliverable: true, isCatchAll: false, confidenceScore: 0.98 }
299
+ // Submit batch email jobs at scale, then poll status
300
+ const job = await signaliz.emails.verifyBatch([
301
+ 'jane@example.com',
302
+ { email: 'sam@example.com' },
303
+ ]);
304
+ const status = await signaliz.emails.checkStatus(job.jobId);
305
+
306
+ // Local-business lead generation
307
+ const localJob = await signaliz.leads.generateLocal({
308
+ prompt: 'dentists in Phoenix, AZ',
309
+ targetVerified: 50,
310
+ confirmSpend: true,
311
+ });
31
312
 
32
313
  // Company signals
33
314
  const signals = await signaliz.signals.enrich({
@@ -40,28 +321,28 @@ const system = await signaliz.systems.create({
40
321
  name: 'Email Pipeline',
41
322
  capabilities: ['mcp_input', 'find_emails_with_verification', 'mcp_output'],
42
323
  });
43
- const run = await signaliz.systems.run(system.id, { data: [...] });
44
-
45
- // Stream progress
46
- for await (const event of signaliz.runs.stream(run.runId)) {
47
- console.log(`${event.completedRows}/${event.totalRows} — ${event.status}`);
48
- }
49
324
 
50
325
  // HTTP proxy
51
326
  const response = await signaliz.http.request({
52
327
  url: 'https://api.example.com/data',
53
328
  method: 'GET',
54
329
  });
330
+
331
+ // Ops routines and output sinks
332
+ const sinks = await signaliz.ops.listOutputSinks();
333
+ const routines = await signaliz.ops.listRoutines({ status: 'active' });
55
334
  ```
56
335
 
57
336
  ## MCP Setup
58
337
 
59
- Connect Signaliz to your AI agent in one command:
60
-
61
338
  ```bash
62
- npx @signaliz/mcp
339
+ npx -p @signaliz/sdk signaliz-mcp
63
340
  ```
64
341
 
342
+ The setup helper writes a local stdio MCP config that runs `@signaliz/mcp-server`
343
+ with `SIGNALIZ_API_KEY` in the environment. It does not put API keys in a
344
+ query-string URL.
345
+
65
346
  ## Authentication
66
347
 
67
348
  ### API Key (simplest)
@@ -83,12 +364,12 @@ const signaliz = new Signaliz({
83
364
  import { Signaliz, SignalizError } from '@signaliz/sdk';
84
365
 
85
366
  try {
86
- await signaliz.emails.find({ fullName: 'Test', companyDomain: 'example.com' });
367
+ await signaliz.campaigns.build({ name: 'Test', prompt: '...' });
87
368
  } catch (e) {
88
369
  if (e instanceof SignalizError) {
89
- console.log(e.errorType); // 'rate_limited' | 'validation' | 'timeout' | ...
90
- console.log(e.retryAfter); // seconds to wait (for 429s)
91
- console.log(e.isRetryable); // boolean
370
+ console.log(e.errorType); // 'rate_limited' | 'validation' | 'timeout' | ...
371
+ console.log(e.retryAfter); // seconds to wait (for 429s)
372
+ console.log(e.isRetryable); // boolean — SDK retries 429 and 5xx automatically
92
373
  }
93
374
  }
94
375
  ```