@synterai/sdk-js 0.1.2 → 0.2.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.
- package/CHANGELOG.md +11 -0
- package/README.md +63 -1
- package/dist/index.d.mts +186 -8
- package/dist/index.d.ts +186 -8
- package/dist/index.js +206 -8
- package/dist/index.mjs +201 -8
- package/package.json +9 -8
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 — 2026-10-02
|
|
4
|
+
|
|
5
|
+
Metadata: public repo link (Synter-Media-AI/synter-docs), synterai.com homepage, hello@synterai.com author, and the official-packages provenance line in the README.
|
|
6
|
+
|
|
7
|
+
Default production URLs and documentation links now use synterai.com. The artifact API uses api.synterai.com where applicable.
|
|
8
|
+
|
|
9
|
+
Explicit `baseUrl` and `artifactBaseUrl` options take precedence over `SYNTER_API_URL` and `SYNTER_ARTIFACT_API_URL` in Node.js. Browser clients can use the options without a `process` global.
|
|
10
|
+
|
|
11
|
+
The syntermedia.ai machine endpoints remain dual-served for previously published versions and explicit overrides.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
TypeScript SDK for the [Synter](https://syntermedia.ai) advertising API — manage campaigns across 27 ad platforms (Google Ads, Meta, LinkedIn, Microsoft, Reddit, TikTok, X, Amazon DSP, Amazon Ads, Pinterest, Snap, Spotify, OpenAI Ads, The Trade Desk, FreeWheel, DV360, CM360, Walmart Connect, Instacart Ads, Target Roundel, Criteo) from your own code, with full types and IDE autocomplete.
|
|
4
4
|
|
|
5
|
-
> **`0.1.2` — live on npm.** Pre-1.0: the surface may change before a stable `1.0`. Pin a version in production. `0.1.2` fixes `analytics.getPerformance({ platform: "google" | "linkedin" })`, which in `0.1.0`/`0.1.1` sent the script *filename* (`pull_google_ads_data`) instead of the canonical script name (`pull_google_ads`); the backend rejected it with `400 UNKNOWN_TOOL` until it gained an alias on 2026-08-27.
|
|
5
|
+
> **`0.1.2` — live on npm.** Pre-1.0: the surface may change before a stable `1.0`. Pin a version in production. `0.1.2` fixes `analytics.getPerformance({ platform: "google" | "linkedin" })`, which in `0.1.0`/`0.1.1` sent the script *filename* (`pull_google_ads_data`) instead of the canonical script name (`pull_google_ads`); the backend rejected it with `400 UNKNOWN_TOOL` until it gained an alias on 2026-08-27 (synter-media PR #9684).
|
|
6
6
|
|
|
7
7
|
## What this actually talks to
|
|
8
8
|
|
|
@@ -64,6 +64,68 @@ const image = await synter.creative.generateImage({ prompt: 'a running shoe on a
|
|
|
64
64
|
await synter.execute('google_ads_list_audiences', { status: 'ENABLED' }, 'google');
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
## Post-Write Readback Verification (Agent Safety Pattern)
|
|
68
|
+
|
|
69
|
+
When coding agents or automated scripts modify campaign state (such as pausing overspending campaigns or halving daily budgets), **never trust an HTTP 200 `{success: true}` alone**. Always execute an explicit post-write readback to verify that the upstream ad platform actually persisted and confirmed the state change:
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { Synter } from '@synterai/sdk-js';
|
|
73
|
+
|
|
74
|
+
const synter = new Synter(process.env.SYNTER_API_KEY!);
|
|
75
|
+
|
|
76
|
+
async function optimizeCampaignBudget(campaignId: string, targetCpa: number, isDryRun = true) {
|
|
77
|
+
// 1. Fetch 7-day performance
|
|
78
|
+
const perf = await synter.analytics.getPerformance({ platform: 'google', date_range: 'LAST_7_DAYS' });
|
|
79
|
+
const campaign = (perf.campaigns as any[])?.find(c => c.id === campaignId || c.campaign_id === campaignId);
|
|
80
|
+
|
|
81
|
+
if (!campaign) throw new Error(`Campaign ${campaignId} not found`);
|
|
82
|
+
|
|
83
|
+
const cost = Number(campaign.cost || 0);
|
|
84
|
+
const conversions = Number(campaign.conversions || 0);
|
|
85
|
+
|
|
86
|
+
// Handle missing or zero conversions explicitly — never guess a CPA
|
|
87
|
+
if (conversions <= 0) {
|
|
88
|
+
console.log(`[SKIP] Campaign ${campaignId}: 0 conversions recorded, CPA is undefined.`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const cpa = cost / conversions;
|
|
93
|
+
if (cpa <= targetCpa) {
|
|
94
|
+
console.log(`[OK] Campaign ${campaignId}: CPA $${cpa.toFixed(2)} <= threshold $${targetCpa}. No action needed.`);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const currentBudget = Number(campaign.daily_budget || campaign.budget || 50);
|
|
99
|
+
const newBudget = Math.max(1, Math.round(currentBudget * 0.5));
|
|
100
|
+
|
|
101
|
+
console.log(`[ACTION] Campaign ${campaignId}: CPA $${cpa.toFixed(2)} > threshold $${targetCpa}. Target: PAUSE and cut budget to $${newBudget}/day.`);
|
|
102
|
+
|
|
103
|
+
if (isDryRun) {
|
|
104
|
+
console.log(`[DRY RUN] Would pause campaign ${campaignId} and reduce daily budget from $${currentBudget} to $${newBudget}.`);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 2. Execute mutations in apply mode
|
|
109
|
+
const pauseResult = await synter.campaigns.pause({ campaign_id: campaignId, platform: 'google' });
|
|
110
|
+
const budgetResult = await synter.campaigns.updateBudget({ campaign_id: campaignId, platform: 'google', daily_budget: newBudget });
|
|
111
|
+
|
|
112
|
+
// 3. MANDATORY POST-WRITE READBACK VERIFICATION
|
|
113
|
+
// Re-read campaign state from Google Ads to verify provider applied the mutations
|
|
114
|
+
const refreshed = await synter.campaigns.list({ platform: 'google' });
|
|
115
|
+
const verified = (refreshed.campaigns as any[])?.find(c => c.id === campaignId || c.campaign_id === campaignId);
|
|
116
|
+
|
|
117
|
+
if (!verified) {
|
|
118
|
+
throw new Error(`Readback verification failed: Campaign ${campaignId} not returned in refreshed list.`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (verified.status !== 'PAUSED') {
|
|
122
|
+
throw new Error(`Readback verification failed: Campaign ${campaignId} status is '${verified.status}', expected 'PAUSED'.`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
console.log(`[VERIFIED] Campaign ${campaignId} successfully paused and daily budget reduced to $${newBudget}. Confirmed on live platform.`);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
67
129
|
## API surface
|
|
68
130
|
|
|
69
131
|
Methods are grouped by category, matching the tool catalog:
|
package/dist/index.d.mts
CHANGED
|
@@ -153,6 +153,34 @@ declare class CampaignsResource {
|
|
|
153
153
|
* dispatches with `platform=google` regardless of input.
|
|
154
154
|
*/
|
|
155
155
|
updateBudget(input: UpdateCampaignBudgetInput): Promise<Record<string, unknown>>;
|
|
156
|
+
/**
|
|
157
|
+
* Update campaign budget with deterministic readback verification.
|
|
158
|
+
*
|
|
159
|
+
* Executes the budget update, waits for propagation, and reads back
|
|
160
|
+
* campaign status from the platform to verify the update succeeded on the wire.
|
|
161
|
+
*/
|
|
162
|
+
updateBudgetAndVerify(input: UpdateCampaignBudgetInput & {
|
|
163
|
+
maxWaitMs?: number;
|
|
164
|
+
pollIntervalMs?: number;
|
|
165
|
+
}): Promise<{
|
|
166
|
+
mutation: Record<string, unknown>;
|
|
167
|
+
verified: boolean;
|
|
168
|
+
readback?: Record<string, unknown>;
|
|
169
|
+
}>;
|
|
170
|
+
/**
|
|
171
|
+
* Pause a campaign with deterministic readback verification.
|
|
172
|
+
*
|
|
173
|
+
* Executes the pause command, waits for propagation, and reads back
|
|
174
|
+
* campaign status from the platform to verify status === 'PAUSED' on the wire.
|
|
175
|
+
*/
|
|
176
|
+
pauseAndVerify(input: PauseCampaignInput & {
|
|
177
|
+
maxWaitMs?: number;
|
|
178
|
+
pollIntervalMs?: number;
|
|
179
|
+
}): Promise<{
|
|
180
|
+
mutation: Record<string, unknown>;
|
|
181
|
+
verified: boolean;
|
|
182
|
+
readback?: Record<string, unknown>;
|
|
183
|
+
}>;
|
|
156
184
|
}
|
|
157
185
|
|
|
158
186
|
/**
|
|
@@ -217,7 +245,8 @@ declare class KeywordsResource {
|
|
|
217
245
|
|
|
218
246
|
/**
|
|
219
247
|
* `conversions` category — catalog.json tools: create_conversion,
|
|
220
|
-
* list_conversions, diagnose_tracking
|
|
248
|
+
* list_conversions, diagnose_tracking, get_pixel_health,
|
|
249
|
+
* list_event_deliveries, get_click_attribution.
|
|
221
250
|
*/
|
|
222
251
|
|
|
223
252
|
interface CreateConversionInput {
|
|
@@ -232,6 +261,21 @@ interface DiagnoseTrackingInput {
|
|
|
232
261
|
/** Website URL to check. */
|
|
233
262
|
url: string;
|
|
234
263
|
}
|
|
264
|
+
interface GetPixelHealthInput {
|
|
265
|
+
site_key?: string;
|
|
266
|
+
}
|
|
267
|
+
interface ListEventDeliveriesInput {
|
|
268
|
+
site_key?: string;
|
|
269
|
+
status?: 'PENDING' | 'SUCCESS' | 'RETRYING' | 'FAILED';
|
|
270
|
+
platform?: string;
|
|
271
|
+
limit?: number;
|
|
272
|
+
}
|
|
273
|
+
interface GetClickAttributionInput {
|
|
274
|
+
site_key?: string;
|
|
275
|
+
user_id?: number;
|
|
276
|
+
email?: string;
|
|
277
|
+
limit?: number;
|
|
278
|
+
}
|
|
235
279
|
declare class ConversionsResource {
|
|
236
280
|
private readonly client;
|
|
237
281
|
constructor(client: Synter);
|
|
@@ -250,6 +294,9 @@ declare class ConversionsResource {
|
|
|
250
294
|
* credentials (SPEC.md's "Platform resolution" rule 3).
|
|
251
295
|
*/
|
|
252
296
|
diagnoseTracking(input: DiagnoseTrackingInput): Promise<Record<string, unknown>>;
|
|
297
|
+
getPixelHealth(input?: GetPixelHealthInput): Promise<Record<string, unknown>>;
|
|
298
|
+
listEventDeliveries(input?: ListEventDeliveriesInput): Promise<Record<string, unknown>>;
|
|
299
|
+
getClickAttribution(input?: GetClickAttributionInput): Promise<Record<string, unknown>>;
|
|
253
300
|
}
|
|
254
301
|
|
|
255
302
|
/**
|
|
@@ -419,7 +466,7 @@ declare class AudiencesResource {
|
|
|
419
466
|
* identifiers inline when over ~500 entries.
|
|
420
467
|
*
|
|
421
468
|
* Bypasses the primary `tools/run` dispatcher: different host
|
|
422
|
-
* (`https://api.
|
|
469
|
+
* (`https://api.synterai.com`) and a different auth header
|
|
423
470
|
* (`X-Synter-Key`, not `Authorization: Bearer`) — see SPEC.md/catalog.json
|
|
424
471
|
* `transport.special`.
|
|
425
472
|
*/
|
|
@@ -442,6 +489,127 @@ declare class AudiencesResource {
|
|
|
442
489
|
manage(input: ManageAudienceInput): Promise<Record<string, unknown>>;
|
|
443
490
|
}
|
|
444
491
|
|
|
492
|
+
/**
|
|
493
|
+
* `shield` category — Agent Shield spend limits, burst thresholds,
|
|
494
|
+
* circuit breakers, and kill-switch inspection.
|
|
495
|
+
*/
|
|
496
|
+
|
|
497
|
+
interface InspectShieldInput {
|
|
498
|
+
platform?: AdPlatform;
|
|
499
|
+
}
|
|
500
|
+
interface AgentShieldPolicy {
|
|
501
|
+
policy_id: string;
|
|
502
|
+
name: string;
|
|
503
|
+
enforced: boolean;
|
|
504
|
+
max_daily_spend_usd: number;
|
|
505
|
+
max_hourly_spend_usd: number;
|
|
506
|
+
burst_threshold_multiplier: number;
|
|
507
|
+
circuit_breaker_active: boolean;
|
|
508
|
+
kill_switch_engaged: boolean;
|
|
509
|
+
}
|
|
510
|
+
declare class ShieldResource {
|
|
511
|
+
private readonly client;
|
|
512
|
+
constructor(client: Synter);
|
|
513
|
+
/**
|
|
514
|
+
* Inspect Agent Shield velocity limits, burst thresholds, circuit breakers,
|
|
515
|
+
* and kill-switch status before executing ad-spend mutations.
|
|
516
|
+
*/
|
|
517
|
+
inspect(input?: InspectShieldInput): Promise<{
|
|
518
|
+
status: 'ACTIVE' | 'TRIPPED' | 'PAUSED';
|
|
519
|
+
policies: AgentShieldPolicy[];
|
|
520
|
+
kill_switch_engaged: boolean;
|
|
521
|
+
notice: string;
|
|
522
|
+
}>;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* `angstrom` category — Synter Ångström attribution claim verification.
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
interface VerifyAngstromClaimInput {
|
|
530
|
+
platform?: AdPlatform;
|
|
531
|
+
claimed_conversions?: number;
|
|
532
|
+
claimed_revenue_usd?: number;
|
|
533
|
+
touchpoint_ids?: string[];
|
|
534
|
+
}
|
|
535
|
+
interface AngstromVerificationResult {
|
|
536
|
+
confidence_score: number;
|
|
537
|
+
verdict: 'VERIFIED' | 'DISPUTED' | 'UNVERIFIABLE';
|
|
538
|
+
incremental_lift_multiplier: number;
|
|
539
|
+
deterministic_touchpoints_verified: number;
|
|
540
|
+
rubric: {
|
|
541
|
+
single_touch_discount: number;
|
|
542
|
+
cross_network_dedup_factor: number;
|
|
543
|
+
latency_decay_score: number;
|
|
544
|
+
};
|
|
545
|
+
explanation: string;
|
|
546
|
+
}
|
|
547
|
+
declare class AngstromResource {
|
|
548
|
+
private readonly client;
|
|
549
|
+
constructor(client: Synter);
|
|
550
|
+
/**
|
|
551
|
+
* Verify attribution claims against Synter Ångström's deterministic confidence rubric.
|
|
552
|
+
*/
|
|
553
|
+
verify(input?: VerifyAngstromClaimInput): Promise<AngstromVerificationResult>;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* `skills` category — Core autonomous growth playbooks.
|
|
558
|
+
*/
|
|
559
|
+
|
|
560
|
+
type GrowthSkillId = 'pmax-brand-cannibalization' | 'search-hygiene-shield' | 'marginal-cpa-budget-rebalancer' | 'meta-asc-dark-pool-auditor' | 'single-truth-attribution';
|
|
561
|
+
interface GrowthSkillPlaybook {
|
|
562
|
+
skill_id: GrowthSkillId;
|
|
563
|
+
name: string;
|
|
564
|
+
category: string;
|
|
565
|
+
description: string;
|
|
566
|
+
required_tools: string[];
|
|
567
|
+
execution_steps: string[];
|
|
568
|
+
safety_checks: string[];
|
|
569
|
+
expected_outcome: string;
|
|
570
|
+
}
|
|
571
|
+
declare class SkillsResource {
|
|
572
|
+
private readonly client;
|
|
573
|
+
constructor(client: Synter);
|
|
574
|
+
/**
|
|
575
|
+
* Load an autonomous growth runbook by ID.
|
|
576
|
+
*/
|
|
577
|
+
get(skillId: GrowthSkillId): Promise<GrowthSkillPlaybook>;
|
|
578
|
+
/**
|
|
579
|
+
* List available autonomous growth runbook IDs.
|
|
580
|
+
*/
|
|
581
|
+
list(): GrowthSkillId[];
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* `visibility` category — LLM search brand visibility and AEO share of voice.
|
|
586
|
+
*/
|
|
587
|
+
|
|
588
|
+
interface GetVisibilityInput {
|
|
589
|
+
query?: string;
|
|
590
|
+
competitor_domains?: string[];
|
|
591
|
+
}
|
|
592
|
+
interface EngineVisibilityScore {
|
|
593
|
+
engine: 'chatgpt' | 'claude' | 'perplexity' | 'gemini';
|
|
594
|
+
share_of_voice_pct: number;
|
|
595
|
+
mention_count: number;
|
|
596
|
+
ranking_position_avg: number;
|
|
597
|
+
}
|
|
598
|
+
interface VisibilityReportResult {
|
|
599
|
+
brand: string;
|
|
600
|
+
overall_aeo_score: number;
|
|
601
|
+
engines: EngineVisibilityScore[];
|
|
602
|
+
recommendations: string[];
|
|
603
|
+
}
|
|
604
|
+
declare class VisibilityResource {
|
|
605
|
+
private readonly client;
|
|
606
|
+
constructor(client: Synter);
|
|
607
|
+
/**
|
|
608
|
+
* Read AI search brand visibility and AEO share of voice across ChatGPT, Claude, Perplexity, and Gemini.
|
|
609
|
+
*/
|
|
610
|
+
get(input?: GetVisibilityInput): Promise<VisibilityReportResult>;
|
|
611
|
+
}
|
|
612
|
+
|
|
445
613
|
/**
|
|
446
614
|
* Amp Custom Advertising Toolbox
|
|
447
615
|
*
|
|
@@ -961,19 +1129,22 @@ declare class SynterValidationError extends Error {
|
|
|
961
1129
|
* Main Synter SDK client.
|
|
962
1130
|
*
|
|
963
1131
|
* Transport per SPEC.md: nearly every tool dispatches through
|
|
964
|
-
* `POST /api/v1/tools/run` on `https://
|
|
1132
|
+
* `POST /api/v1/tools/run` on `https://synterai.com` with
|
|
965
1133
|
* `{ script_name, args, platform? }`, auth via `Authorization: Bearer <key>`.
|
|
966
1134
|
* Two tools bypass that dispatcher (`list_landing_pages`, `stage_audience_artifact`)
|
|
967
1135
|
* — see `resources/audiences.ts` and `listLandingPages` below.
|
|
968
1136
|
*/
|
|
969
1137
|
|
|
970
1138
|
/** Real, production base URL — see SPEC.md's "Transport" section. */
|
|
971
|
-
declare const DEFAULT_BASE_URL = "https://
|
|
1139
|
+
declare const DEFAULT_BASE_URL = "https://synterai.com";
|
|
1140
|
+
declare const DEFAULT_ARTIFACT_BASE_URL = "https://api.synterai.com";
|
|
972
1141
|
interface SynterConfig {
|
|
973
|
-
/** `syn_` + 32 base64url characters, issued at
|
|
1142
|
+
/** `syn_` + 32 base64url characters, issued at synterai.com/developer. */
|
|
974
1143
|
apiKey: string;
|
|
975
|
-
/**
|
|
1144
|
+
/** Primary API URL. Takes precedence over SYNTER_API_URL in Node.js. */
|
|
976
1145
|
baseUrl?: string;
|
|
1146
|
+
/** Artifact API URL. Takes precedence over SYNTER_ARTIFACT_API_URL in Node.js. */
|
|
1147
|
+
artifactBaseUrl?: string;
|
|
977
1148
|
/** Request timeout in ms. Default 30000 (30s), per SPEC.md. */
|
|
978
1149
|
timeout?: number;
|
|
979
1150
|
/** Max retry attempts for 429s and network/timeout errors. Default 3, per SPEC.md. */
|
|
@@ -998,6 +1169,7 @@ interface UploadImageInput {
|
|
|
998
1169
|
declare class Synter {
|
|
999
1170
|
private readonly apiKey;
|
|
1000
1171
|
private readonly baseUrl;
|
|
1172
|
+
private readonly artifactBaseUrl;
|
|
1001
1173
|
private readonly timeout;
|
|
1002
1174
|
private readonly maxRetries;
|
|
1003
1175
|
private readonly fetchImpl;
|
|
@@ -1010,6 +1182,10 @@ declare class Synter {
|
|
|
1010
1182
|
readonly linkedin: LinkedInResource;
|
|
1011
1183
|
readonly reddit: RedditResource;
|
|
1012
1184
|
readonly audiences: AudiencesResource;
|
|
1185
|
+
readonly shield: ShieldResource;
|
|
1186
|
+
readonly angstrom: AngstromResource;
|
|
1187
|
+
readonly skills: SkillsResource;
|
|
1188
|
+
readonly visibility: VisibilityResource;
|
|
1013
1189
|
/** AI-powered advertising toolbox for Amp integration — unchanged, out of scope for the transport rewrite. */
|
|
1014
1190
|
readonly amp: AmpToolbox;
|
|
1015
1191
|
constructor(config: SynterConfig | string, ampConfig?: AmpToolboxConfig);
|
|
@@ -1043,7 +1219,9 @@ declare class Synter {
|
|
|
1043
1219
|
*/
|
|
1044
1220
|
listLandingPages(): Promise<Record<string, unknown>>;
|
|
1045
1221
|
private authHeaders;
|
|
1046
|
-
/**
|
|
1222
|
+
/** Artifact host used by audience staging. */
|
|
1223
|
+
getArtifactBaseUrl(): string;
|
|
1224
|
+
/** The raw API key, for tools that need a non-Bearer header. */
|
|
1047
1225
|
getApiKey(): string;
|
|
1048
1226
|
/**
|
|
1049
1227
|
* Low-level generic HTTP helper retained for `AmpToolbox` and any other
|
|
@@ -1255,4 +1433,4 @@ declare function normalizeConversionEvent(params: {
|
|
|
1255
1433
|
metadata?: Record<string, any>;
|
|
1256
1434
|
}): AnalyticsEvent;
|
|
1257
1435
|
|
|
1258
|
-
export { type AdPlatform, type AddKeywordsInput, type AddNegativeKeywordsInput, AmpToolbox, type AmpToolboxConfig, type AnalyticsEvent, type AnalyticsIntegration, type AnalyticsIntegrationConfig, AnalyticsIntegrationManager, type AnalyticsPlatform, AnalyticsResource, AudiencesResource, type CampaignBriefInput, CampaignsResource, type ConversionPayload, ConversionsResource, type CreateConversionInput, type CreateDisplayCampaignInput, type CreateLinkedInCampaignInput, type CreateMetaCampaignInput, type CreatePmaxCampaignInput, type CreateRedditCampaignInput, type CreateSearchCampaignInput, CreativeResource, type CreativeVariant, DEFAULT_BASE_URL, type DateRange, type DiagnoseTrackingInput, type GenerateImageInput, type GenerateVideoInput, type GeneratedCampaign, type GetDailySpendInput, type GetPerformanceInput, KeywordsResource, LinkedInResource, type ListCampaignsInput, type ManageAudienceInput, MetaResource, type OptimizationRecommendation, type PauseCampaignInput, type Platform, type PlatformConnection, type PlatformStatus, RedditResource, type StageAudienceArtifactInput, type StageAudienceArtifactResult, type SyncAudienceInput, Synter, type SynterConfig, SynterError, SynterValidationError, type TrackingParams, type UTMParameters, type UTMTemplate, type UpdateCampaignBudgetInput, type UploadImageInput, buildConversionPayload, buildTrackingURL, buildUTMParameters, Synter as default, detectClickId, extractTrackingParams, extractUTMParameters, generateDefaultUTMTemplate, normalizeAdClickEvent, normalizeConversionEvent, normalizeEventName, validateClickId, validateUTMTemplate };
|
|
1436
|
+
export { type AdPlatform, type AddKeywordsInput, type AddNegativeKeywordsInput, type AgentShieldPolicy, AmpToolbox, type AmpToolboxConfig, type AnalyticsEvent, type AnalyticsIntegration, type AnalyticsIntegrationConfig, AnalyticsIntegrationManager, type AnalyticsPlatform, AnalyticsResource, AngstromResource, type AngstromVerificationResult, AudiencesResource, type CampaignBriefInput, CampaignsResource, type ConversionPayload, ConversionsResource, type CreateConversionInput, type CreateDisplayCampaignInput, type CreateLinkedInCampaignInput, type CreateMetaCampaignInput, type CreatePmaxCampaignInput, type CreateRedditCampaignInput, type CreateSearchCampaignInput, CreativeResource, type CreativeVariant, DEFAULT_ARTIFACT_BASE_URL, DEFAULT_BASE_URL, type DateRange, type DiagnoseTrackingInput, type EngineVisibilityScore, type GenerateImageInput, type GenerateVideoInput, type GeneratedCampaign, type GetDailySpendInput, type GetPerformanceInput, type GetVisibilityInput, type GrowthSkillId, type GrowthSkillPlaybook, type InspectShieldInput, KeywordsResource, LinkedInResource, type ListCampaignsInput, type ManageAudienceInput, MetaResource, type OptimizationRecommendation, type PauseCampaignInput, type Platform, type PlatformConnection, type PlatformStatus, RedditResource, ShieldResource, SkillsResource, type StageAudienceArtifactInput, type StageAudienceArtifactResult, type SyncAudienceInput, Synter, type SynterConfig, SynterError, SynterValidationError, type TrackingParams, type UTMParameters, type UTMTemplate, type UpdateCampaignBudgetInput, type UploadImageInput, type VerifyAngstromClaimInput, type VisibilityReportResult, VisibilityResource, buildConversionPayload, buildTrackingURL, buildUTMParameters, Synter as default, detectClickId, extractTrackingParams, extractUTMParameters, generateDefaultUTMTemplate, normalizeAdClickEvent, normalizeConversionEvent, normalizeEventName, validateClickId, validateUTMTemplate };
|
package/dist/index.d.ts
CHANGED
|
@@ -153,6 +153,34 @@ declare class CampaignsResource {
|
|
|
153
153
|
* dispatches with `platform=google` regardless of input.
|
|
154
154
|
*/
|
|
155
155
|
updateBudget(input: UpdateCampaignBudgetInput): Promise<Record<string, unknown>>;
|
|
156
|
+
/**
|
|
157
|
+
* Update campaign budget with deterministic readback verification.
|
|
158
|
+
*
|
|
159
|
+
* Executes the budget update, waits for propagation, and reads back
|
|
160
|
+
* campaign status from the platform to verify the update succeeded on the wire.
|
|
161
|
+
*/
|
|
162
|
+
updateBudgetAndVerify(input: UpdateCampaignBudgetInput & {
|
|
163
|
+
maxWaitMs?: number;
|
|
164
|
+
pollIntervalMs?: number;
|
|
165
|
+
}): Promise<{
|
|
166
|
+
mutation: Record<string, unknown>;
|
|
167
|
+
verified: boolean;
|
|
168
|
+
readback?: Record<string, unknown>;
|
|
169
|
+
}>;
|
|
170
|
+
/**
|
|
171
|
+
* Pause a campaign with deterministic readback verification.
|
|
172
|
+
*
|
|
173
|
+
* Executes the pause command, waits for propagation, and reads back
|
|
174
|
+
* campaign status from the platform to verify status === 'PAUSED' on the wire.
|
|
175
|
+
*/
|
|
176
|
+
pauseAndVerify(input: PauseCampaignInput & {
|
|
177
|
+
maxWaitMs?: number;
|
|
178
|
+
pollIntervalMs?: number;
|
|
179
|
+
}): Promise<{
|
|
180
|
+
mutation: Record<string, unknown>;
|
|
181
|
+
verified: boolean;
|
|
182
|
+
readback?: Record<string, unknown>;
|
|
183
|
+
}>;
|
|
156
184
|
}
|
|
157
185
|
|
|
158
186
|
/**
|
|
@@ -217,7 +245,8 @@ declare class KeywordsResource {
|
|
|
217
245
|
|
|
218
246
|
/**
|
|
219
247
|
* `conversions` category — catalog.json tools: create_conversion,
|
|
220
|
-
* list_conversions, diagnose_tracking
|
|
248
|
+
* list_conversions, diagnose_tracking, get_pixel_health,
|
|
249
|
+
* list_event_deliveries, get_click_attribution.
|
|
221
250
|
*/
|
|
222
251
|
|
|
223
252
|
interface CreateConversionInput {
|
|
@@ -232,6 +261,21 @@ interface DiagnoseTrackingInput {
|
|
|
232
261
|
/** Website URL to check. */
|
|
233
262
|
url: string;
|
|
234
263
|
}
|
|
264
|
+
interface GetPixelHealthInput {
|
|
265
|
+
site_key?: string;
|
|
266
|
+
}
|
|
267
|
+
interface ListEventDeliveriesInput {
|
|
268
|
+
site_key?: string;
|
|
269
|
+
status?: 'PENDING' | 'SUCCESS' | 'RETRYING' | 'FAILED';
|
|
270
|
+
platform?: string;
|
|
271
|
+
limit?: number;
|
|
272
|
+
}
|
|
273
|
+
interface GetClickAttributionInput {
|
|
274
|
+
site_key?: string;
|
|
275
|
+
user_id?: number;
|
|
276
|
+
email?: string;
|
|
277
|
+
limit?: number;
|
|
278
|
+
}
|
|
235
279
|
declare class ConversionsResource {
|
|
236
280
|
private readonly client;
|
|
237
281
|
constructor(client: Synter);
|
|
@@ -250,6 +294,9 @@ declare class ConversionsResource {
|
|
|
250
294
|
* credentials (SPEC.md's "Platform resolution" rule 3).
|
|
251
295
|
*/
|
|
252
296
|
diagnoseTracking(input: DiagnoseTrackingInput): Promise<Record<string, unknown>>;
|
|
297
|
+
getPixelHealth(input?: GetPixelHealthInput): Promise<Record<string, unknown>>;
|
|
298
|
+
listEventDeliveries(input?: ListEventDeliveriesInput): Promise<Record<string, unknown>>;
|
|
299
|
+
getClickAttribution(input?: GetClickAttributionInput): Promise<Record<string, unknown>>;
|
|
253
300
|
}
|
|
254
301
|
|
|
255
302
|
/**
|
|
@@ -419,7 +466,7 @@ declare class AudiencesResource {
|
|
|
419
466
|
* identifiers inline when over ~500 entries.
|
|
420
467
|
*
|
|
421
468
|
* Bypasses the primary `tools/run` dispatcher: different host
|
|
422
|
-
* (`https://api.
|
|
469
|
+
* (`https://api.synterai.com`) and a different auth header
|
|
423
470
|
* (`X-Synter-Key`, not `Authorization: Bearer`) — see SPEC.md/catalog.json
|
|
424
471
|
* `transport.special`.
|
|
425
472
|
*/
|
|
@@ -442,6 +489,127 @@ declare class AudiencesResource {
|
|
|
442
489
|
manage(input: ManageAudienceInput): Promise<Record<string, unknown>>;
|
|
443
490
|
}
|
|
444
491
|
|
|
492
|
+
/**
|
|
493
|
+
* `shield` category — Agent Shield spend limits, burst thresholds,
|
|
494
|
+
* circuit breakers, and kill-switch inspection.
|
|
495
|
+
*/
|
|
496
|
+
|
|
497
|
+
interface InspectShieldInput {
|
|
498
|
+
platform?: AdPlatform;
|
|
499
|
+
}
|
|
500
|
+
interface AgentShieldPolicy {
|
|
501
|
+
policy_id: string;
|
|
502
|
+
name: string;
|
|
503
|
+
enforced: boolean;
|
|
504
|
+
max_daily_spend_usd: number;
|
|
505
|
+
max_hourly_spend_usd: number;
|
|
506
|
+
burst_threshold_multiplier: number;
|
|
507
|
+
circuit_breaker_active: boolean;
|
|
508
|
+
kill_switch_engaged: boolean;
|
|
509
|
+
}
|
|
510
|
+
declare class ShieldResource {
|
|
511
|
+
private readonly client;
|
|
512
|
+
constructor(client: Synter);
|
|
513
|
+
/**
|
|
514
|
+
* Inspect Agent Shield velocity limits, burst thresholds, circuit breakers,
|
|
515
|
+
* and kill-switch status before executing ad-spend mutations.
|
|
516
|
+
*/
|
|
517
|
+
inspect(input?: InspectShieldInput): Promise<{
|
|
518
|
+
status: 'ACTIVE' | 'TRIPPED' | 'PAUSED';
|
|
519
|
+
policies: AgentShieldPolicy[];
|
|
520
|
+
kill_switch_engaged: boolean;
|
|
521
|
+
notice: string;
|
|
522
|
+
}>;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* `angstrom` category — Synter Ångström attribution claim verification.
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
interface VerifyAngstromClaimInput {
|
|
530
|
+
platform?: AdPlatform;
|
|
531
|
+
claimed_conversions?: number;
|
|
532
|
+
claimed_revenue_usd?: number;
|
|
533
|
+
touchpoint_ids?: string[];
|
|
534
|
+
}
|
|
535
|
+
interface AngstromVerificationResult {
|
|
536
|
+
confidence_score: number;
|
|
537
|
+
verdict: 'VERIFIED' | 'DISPUTED' | 'UNVERIFIABLE';
|
|
538
|
+
incremental_lift_multiplier: number;
|
|
539
|
+
deterministic_touchpoints_verified: number;
|
|
540
|
+
rubric: {
|
|
541
|
+
single_touch_discount: number;
|
|
542
|
+
cross_network_dedup_factor: number;
|
|
543
|
+
latency_decay_score: number;
|
|
544
|
+
};
|
|
545
|
+
explanation: string;
|
|
546
|
+
}
|
|
547
|
+
declare class AngstromResource {
|
|
548
|
+
private readonly client;
|
|
549
|
+
constructor(client: Synter);
|
|
550
|
+
/**
|
|
551
|
+
* Verify attribution claims against Synter Ångström's deterministic confidence rubric.
|
|
552
|
+
*/
|
|
553
|
+
verify(input?: VerifyAngstromClaimInput): Promise<AngstromVerificationResult>;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* `skills` category — Core autonomous growth playbooks.
|
|
558
|
+
*/
|
|
559
|
+
|
|
560
|
+
type GrowthSkillId = 'pmax-brand-cannibalization' | 'search-hygiene-shield' | 'marginal-cpa-budget-rebalancer' | 'meta-asc-dark-pool-auditor' | 'single-truth-attribution';
|
|
561
|
+
interface GrowthSkillPlaybook {
|
|
562
|
+
skill_id: GrowthSkillId;
|
|
563
|
+
name: string;
|
|
564
|
+
category: string;
|
|
565
|
+
description: string;
|
|
566
|
+
required_tools: string[];
|
|
567
|
+
execution_steps: string[];
|
|
568
|
+
safety_checks: string[];
|
|
569
|
+
expected_outcome: string;
|
|
570
|
+
}
|
|
571
|
+
declare class SkillsResource {
|
|
572
|
+
private readonly client;
|
|
573
|
+
constructor(client: Synter);
|
|
574
|
+
/**
|
|
575
|
+
* Load an autonomous growth runbook by ID.
|
|
576
|
+
*/
|
|
577
|
+
get(skillId: GrowthSkillId): Promise<GrowthSkillPlaybook>;
|
|
578
|
+
/**
|
|
579
|
+
* List available autonomous growth runbook IDs.
|
|
580
|
+
*/
|
|
581
|
+
list(): GrowthSkillId[];
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* `visibility` category — LLM search brand visibility and AEO share of voice.
|
|
586
|
+
*/
|
|
587
|
+
|
|
588
|
+
interface GetVisibilityInput {
|
|
589
|
+
query?: string;
|
|
590
|
+
competitor_domains?: string[];
|
|
591
|
+
}
|
|
592
|
+
interface EngineVisibilityScore {
|
|
593
|
+
engine: 'chatgpt' | 'claude' | 'perplexity' | 'gemini';
|
|
594
|
+
share_of_voice_pct: number;
|
|
595
|
+
mention_count: number;
|
|
596
|
+
ranking_position_avg: number;
|
|
597
|
+
}
|
|
598
|
+
interface VisibilityReportResult {
|
|
599
|
+
brand: string;
|
|
600
|
+
overall_aeo_score: number;
|
|
601
|
+
engines: EngineVisibilityScore[];
|
|
602
|
+
recommendations: string[];
|
|
603
|
+
}
|
|
604
|
+
declare class VisibilityResource {
|
|
605
|
+
private readonly client;
|
|
606
|
+
constructor(client: Synter);
|
|
607
|
+
/**
|
|
608
|
+
* Read AI search brand visibility and AEO share of voice across ChatGPT, Claude, Perplexity, and Gemini.
|
|
609
|
+
*/
|
|
610
|
+
get(input?: GetVisibilityInput): Promise<VisibilityReportResult>;
|
|
611
|
+
}
|
|
612
|
+
|
|
445
613
|
/**
|
|
446
614
|
* Amp Custom Advertising Toolbox
|
|
447
615
|
*
|
|
@@ -961,19 +1129,22 @@ declare class SynterValidationError extends Error {
|
|
|
961
1129
|
* Main Synter SDK client.
|
|
962
1130
|
*
|
|
963
1131
|
* Transport per SPEC.md: nearly every tool dispatches through
|
|
964
|
-
* `POST /api/v1/tools/run` on `https://
|
|
1132
|
+
* `POST /api/v1/tools/run` on `https://synterai.com` with
|
|
965
1133
|
* `{ script_name, args, platform? }`, auth via `Authorization: Bearer <key>`.
|
|
966
1134
|
* Two tools bypass that dispatcher (`list_landing_pages`, `stage_audience_artifact`)
|
|
967
1135
|
* — see `resources/audiences.ts` and `listLandingPages` below.
|
|
968
1136
|
*/
|
|
969
1137
|
|
|
970
1138
|
/** Real, production base URL — see SPEC.md's "Transport" section. */
|
|
971
|
-
declare const DEFAULT_BASE_URL = "https://
|
|
1139
|
+
declare const DEFAULT_BASE_URL = "https://synterai.com";
|
|
1140
|
+
declare const DEFAULT_ARTIFACT_BASE_URL = "https://api.synterai.com";
|
|
972
1141
|
interface SynterConfig {
|
|
973
|
-
/** `syn_` + 32 base64url characters, issued at
|
|
1142
|
+
/** `syn_` + 32 base64url characters, issued at synterai.com/developer. */
|
|
974
1143
|
apiKey: string;
|
|
975
|
-
/**
|
|
1144
|
+
/** Primary API URL. Takes precedence over SYNTER_API_URL in Node.js. */
|
|
976
1145
|
baseUrl?: string;
|
|
1146
|
+
/** Artifact API URL. Takes precedence over SYNTER_ARTIFACT_API_URL in Node.js. */
|
|
1147
|
+
artifactBaseUrl?: string;
|
|
977
1148
|
/** Request timeout in ms. Default 30000 (30s), per SPEC.md. */
|
|
978
1149
|
timeout?: number;
|
|
979
1150
|
/** Max retry attempts for 429s and network/timeout errors. Default 3, per SPEC.md. */
|
|
@@ -998,6 +1169,7 @@ interface UploadImageInput {
|
|
|
998
1169
|
declare class Synter {
|
|
999
1170
|
private readonly apiKey;
|
|
1000
1171
|
private readonly baseUrl;
|
|
1172
|
+
private readonly artifactBaseUrl;
|
|
1001
1173
|
private readonly timeout;
|
|
1002
1174
|
private readonly maxRetries;
|
|
1003
1175
|
private readonly fetchImpl;
|
|
@@ -1010,6 +1182,10 @@ declare class Synter {
|
|
|
1010
1182
|
readonly linkedin: LinkedInResource;
|
|
1011
1183
|
readonly reddit: RedditResource;
|
|
1012
1184
|
readonly audiences: AudiencesResource;
|
|
1185
|
+
readonly shield: ShieldResource;
|
|
1186
|
+
readonly angstrom: AngstromResource;
|
|
1187
|
+
readonly skills: SkillsResource;
|
|
1188
|
+
readonly visibility: VisibilityResource;
|
|
1013
1189
|
/** AI-powered advertising toolbox for Amp integration — unchanged, out of scope for the transport rewrite. */
|
|
1014
1190
|
readonly amp: AmpToolbox;
|
|
1015
1191
|
constructor(config: SynterConfig | string, ampConfig?: AmpToolboxConfig);
|
|
@@ -1043,7 +1219,9 @@ declare class Synter {
|
|
|
1043
1219
|
*/
|
|
1044
1220
|
listLandingPages(): Promise<Record<string, unknown>>;
|
|
1045
1221
|
private authHeaders;
|
|
1046
|
-
/**
|
|
1222
|
+
/** Artifact host used by audience staging. */
|
|
1223
|
+
getArtifactBaseUrl(): string;
|
|
1224
|
+
/** The raw API key, for tools that need a non-Bearer header. */
|
|
1047
1225
|
getApiKey(): string;
|
|
1048
1226
|
/**
|
|
1049
1227
|
* Low-level generic HTTP helper retained for `AmpToolbox` and any other
|
|
@@ -1255,4 +1433,4 @@ declare function normalizeConversionEvent(params: {
|
|
|
1255
1433
|
metadata?: Record<string, any>;
|
|
1256
1434
|
}): AnalyticsEvent;
|
|
1257
1435
|
|
|
1258
|
-
export { type AdPlatform, type AddKeywordsInput, type AddNegativeKeywordsInput, AmpToolbox, type AmpToolboxConfig, type AnalyticsEvent, type AnalyticsIntegration, type AnalyticsIntegrationConfig, AnalyticsIntegrationManager, type AnalyticsPlatform, AnalyticsResource, AudiencesResource, type CampaignBriefInput, CampaignsResource, type ConversionPayload, ConversionsResource, type CreateConversionInput, type CreateDisplayCampaignInput, type CreateLinkedInCampaignInput, type CreateMetaCampaignInput, type CreatePmaxCampaignInput, type CreateRedditCampaignInput, type CreateSearchCampaignInput, CreativeResource, type CreativeVariant, DEFAULT_BASE_URL, type DateRange, type DiagnoseTrackingInput, type GenerateImageInput, type GenerateVideoInput, type GeneratedCampaign, type GetDailySpendInput, type GetPerformanceInput, KeywordsResource, LinkedInResource, type ListCampaignsInput, type ManageAudienceInput, MetaResource, type OptimizationRecommendation, type PauseCampaignInput, type Platform, type PlatformConnection, type PlatformStatus, RedditResource, type StageAudienceArtifactInput, type StageAudienceArtifactResult, type SyncAudienceInput, Synter, type SynterConfig, SynterError, SynterValidationError, type TrackingParams, type UTMParameters, type UTMTemplate, type UpdateCampaignBudgetInput, type UploadImageInput, buildConversionPayload, buildTrackingURL, buildUTMParameters, Synter as default, detectClickId, extractTrackingParams, extractUTMParameters, generateDefaultUTMTemplate, normalizeAdClickEvent, normalizeConversionEvent, normalizeEventName, validateClickId, validateUTMTemplate };
|
|
1436
|
+
export { type AdPlatform, type AddKeywordsInput, type AddNegativeKeywordsInput, type AgentShieldPolicy, AmpToolbox, type AmpToolboxConfig, type AnalyticsEvent, type AnalyticsIntegration, type AnalyticsIntegrationConfig, AnalyticsIntegrationManager, type AnalyticsPlatform, AnalyticsResource, AngstromResource, type AngstromVerificationResult, AudiencesResource, type CampaignBriefInput, CampaignsResource, type ConversionPayload, ConversionsResource, type CreateConversionInput, type CreateDisplayCampaignInput, type CreateLinkedInCampaignInput, type CreateMetaCampaignInput, type CreatePmaxCampaignInput, type CreateRedditCampaignInput, type CreateSearchCampaignInput, CreativeResource, type CreativeVariant, DEFAULT_ARTIFACT_BASE_URL, DEFAULT_BASE_URL, type DateRange, type DiagnoseTrackingInput, type EngineVisibilityScore, type GenerateImageInput, type GenerateVideoInput, type GeneratedCampaign, type GetDailySpendInput, type GetPerformanceInput, type GetVisibilityInput, type GrowthSkillId, type GrowthSkillPlaybook, type InspectShieldInput, KeywordsResource, LinkedInResource, type ListCampaignsInput, type ManageAudienceInput, MetaResource, type OptimizationRecommendation, type PauseCampaignInput, type Platform, type PlatformConnection, type PlatformStatus, RedditResource, ShieldResource, SkillsResource, type StageAudienceArtifactInput, type StageAudienceArtifactResult, type SyncAudienceInput, Synter, type SynterConfig, SynterError, SynterValidationError, type TrackingParams, type UTMParameters, type UTMTemplate, type UpdateCampaignBudgetInput, type UploadImageInput, type VerifyAngstromClaimInput, type VisibilityReportResult, VisibilityResource, buildConversionPayload, buildTrackingURL, buildUTMParameters, Synter as default, detectClickId, extractTrackingParams, extractUTMParameters, generateDefaultUTMTemplate, normalizeAdClickEvent, normalizeConversionEvent, normalizeEventName, validateClickId, validateUTMTemplate };
|
package/dist/index.js
CHANGED
|
@@ -23,18 +23,23 @@ __export(index_exports, {
|
|
|
23
23
|
AmpToolbox: () => AmpToolbox,
|
|
24
24
|
AnalyticsIntegrationManager: () => AnalyticsIntegrationManager,
|
|
25
25
|
AnalyticsResource: () => AnalyticsResource,
|
|
26
|
+
AngstromResource: () => AngstromResource,
|
|
26
27
|
AudiencesResource: () => AudiencesResource,
|
|
27
28
|
CampaignsResource: () => CampaignsResource,
|
|
28
29
|
ConversionsResource: () => ConversionsResource,
|
|
29
30
|
CreativeResource: () => CreativeResource,
|
|
31
|
+
DEFAULT_ARTIFACT_BASE_URL: () => DEFAULT_ARTIFACT_BASE_URL,
|
|
30
32
|
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
31
33
|
KeywordsResource: () => KeywordsResource,
|
|
32
34
|
LinkedInResource: () => LinkedInResource,
|
|
33
35
|
MetaResource: () => MetaResource,
|
|
34
36
|
RedditResource: () => RedditResource,
|
|
37
|
+
ShieldResource: () => ShieldResource,
|
|
38
|
+
SkillsResource: () => SkillsResource,
|
|
35
39
|
Synter: () => Synter,
|
|
36
40
|
SynterError: () => SynterError,
|
|
37
41
|
SynterValidationError: () => SynterValidationError,
|
|
42
|
+
VisibilityResource: () => VisibilityResource,
|
|
38
43
|
buildConversionPayload: () => buildConversionPayload,
|
|
39
44
|
buildTrackingURL: () => buildTrackingURL,
|
|
40
45
|
buildUTMParameters: () => buildUTMParameters,
|
|
@@ -202,7 +207,7 @@ var PAUSE_CAMPAIGN_ARG_MAPPING = [
|
|
|
202
207
|
];
|
|
203
208
|
var UPDATE_BUDGET_ARG_MAPPING = [
|
|
204
209
|
{ field: "campaign_id", flag: "--campaign-id", type: "string", required: true },
|
|
205
|
-
{ field: "daily_budget", flag: "--budget", type: "number", required: true }
|
|
210
|
+
{ field: "daily_budget", flag: "--daily-budget", type: "number", required: true }
|
|
206
211
|
];
|
|
207
212
|
var CampaignsResource = class {
|
|
208
213
|
constructor(client) {
|
|
@@ -275,6 +280,72 @@ var CampaignsResource = class {
|
|
|
275
280
|
const args = buildArgsFromMapping(UPDATE_BUDGET_ARG_MAPPING, input);
|
|
276
281
|
return this.client.runTool("update_campaign_budget", args, "google");
|
|
277
282
|
}
|
|
283
|
+
/**
|
|
284
|
+
* Update campaign budget with deterministic readback verification.
|
|
285
|
+
*
|
|
286
|
+
* Executes the budget update, waits for propagation, and reads back
|
|
287
|
+
* campaign status from the platform to verify the update succeeded on the wire.
|
|
288
|
+
*/
|
|
289
|
+
async updateBudgetAndVerify(input) {
|
|
290
|
+
const mutation = await this.updateBudget(input);
|
|
291
|
+
const maxWaitMs = input.maxWaitMs ?? 5e3;
|
|
292
|
+
const pollIntervalMs = input.pollIntervalMs ?? 1e3;
|
|
293
|
+
const startTime = Date.now();
|
|
294
|
+
let lastReadback;
|
|
295
|
+
while (Date.now() - startTime <= maxWaitMs) {
|
|
296
|
+
try {
|
|
297
|
+
const readback = await this.list({
|
|
298
|
+
platform: input.platform
|
|
299
|
+
});
|
|
300
|
+
lastReadback = readback;
|
|
301
|
+
const campaigns = readback.campaigns || readback.data || [];
|
|
302
|
+
const match = campaigns.find(
|
|
303
|
+
(c) => String(c.id || c.campaign_id) === String(input.campaign_id)
|
|
304
|
+
);
|
|
305
|
+
if (match) {
|
|
306
|
+
const budget = Number(match.daily_budget_usd || match.daily_budget || match.budget);
|
|
307
|
+
if (Math.abs(budget - input.daily_budget) < 0.01) {
|
|
308
|
+
return { mutation, verified: true, readback: match };
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} catch {
|
|
312
|
+
}
|
|
313
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
314
|
+
}
|
|
315
|
+
return { mutation, verified: false, readback: lastReadback };
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Pause a campaign with deterministic readback verification.
|
|
319
|
+
*
|
|
320
|
+
* Executes the pause command, waits for propagation, and reads back
|
|
321
|
+
* campaign status from the platform to verify status === 'PAUSED' on the wire.
|
|
322
|
+
*/
|
|
323
|
+
async pauseAndVerify(input) {
|
|
324
|
+
const mutation = await this.pause(input);
|
|
325
|
+
const maxWaitMs = input.maxWaitMs ?? 5e3;
|
|
326
|
+
const pollIntervalMs = input.pollIntervalMs ?? 1e3;
|
|
327
|
+
const startTime = Date.now();
|
|
328
|
+
let lastReadback;
|
|
329
|
+
while (Date.now() - startTime <= maxWaitMs) {
|
|
330
|
+
try {
|
|
331
|
+
const readback = await this.list({
|
|
332
|
+
platform: input.platform,
|
|
333
|
+
status: "PAUSED"
|
|
334
|
+
});
|
|
335
|
+
lastReadback = readback;
|
|
336
|
+
const campaigns = readback.campaigns || readback.data || [];
|
|
337
|
+
const match = campaigns.find(
|
|
338
|
+
(c) => String(c.id || c.campaign_id) === String(input.campaign_id)
|
|
339
|
+
);
|
|
340
|
+
if (match) {
|
|
341
|
+
return { mutation, verified: true, readback: match };
|
|
342
|
+
}
|
|
343
|
+
} catch {
|
|
344
|
+
}
|
|
345
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
346
|
+
}
|
|
347
|
+
return { mutation, verified: false, readback: lastReadback };
|
|
348
|
+
}
|
|
278
349
|
};
|
|
279
350
|
|
|
280
351
|
// src/resources/analytics.ts
|
|
@@ -368,6 +439,21 @@ var CREATE_CONVERSION_ARG_MAPPING = [
|
|
|
368
439
|
var DIAGNOSE_TRACKING_ARG_MAPPING = [
|
|
369
440
|
{ field: "url", flag: "--url", type: "string", required: true }
|
|
370
441
|
];
|
|
442
|
+
var GET_PIXEL_HEALTH_ARG_MAPPING = [
|
|
443
|
+
{ field: "site_key", flag: "--site-key", type: "string" }
|
|
444
|
+
];
|
|
445
|
+
var LIST_EVENT_DELIVERIES_ARG_MAPPING = [
|
|
446
|
+
{ field: "site_key", flag: "--site-key", type: "string" },
|
|
447
|
+
{ field: "status", flag: "--status", type: "string" },
|
|
448
|
+
{ field: "platform", flag: "--platform", type: "string" },
|
|
449
|
+
{ field: "limit", flag: "--limit", type: "number" }
|
|
450
|
+
];
|
|
451
|
+
var GET_CLICK_ATTRIBUTION_ARG_MAPPING = [
|
|
452
|
+
{ field: "site_key", flag: "--site-key", type: "string" },
|
|
453
|
+
{ field: "user_id", flag: "--user-id", type: "number" },
|
|
454
|
+
{ field: "email", flag: "--email", type: "string" },
|
|
455
|
+
{ field: "limit", flag: "--limit", type: "number" }
|
|
456
|
+
];
|
|
371
457
|
var ConversionsResource = class {
|
|
372
458
|
constructor(client) {
|
|
373
459
|
this.client = client;
|
|
@@ -393,7 +479,19 @@ var ConversionsResource = class {
|
|
|
393
479
|
*/
|
|
394
480
|
async diagnoseTracking(input) {
|
|
395
481
|
const args = buildArgsFromMapping(DIAGNOSE_TRACKING_ARG_MAPPING, input);
|
|
396
|
-
return this.client.runTool("
|
|
482
|
+
return this.client.runTool("diagnose_tracking", args);
|
|
483
|
+
}
|
|
484
|
+
async getPixelHealth(input = {}) {
|
|
485
|
+
const args = buildArgsFromMapping(GET_PIXEL_HEALTH_ARG_MAPPING, input);
|
|
486
|
+
return this.client.runTool("get_pixel_health", args);
|
|
487
|
+
}
|
|
488
|
+
async listEventDeliveries(input = {}) {
|
|
489
|
+
const args = buildArgsFromMapping(LIST_EVENT_DELIVERIES_ARG_MAPPING, input);
|
|
490
|
+
return this.client.runTool("list_event_deliveries", args);
|
|
491
|
+
}
|
|
492
|
+
async getClickAttribution(input = {}) {
|
|
493
|
+
const args = buildArgsFromMapping(GET_CLICK_ATTRIBUTION_ARG_MAPPING, input);
|
|
494
|
+
return this.client.runTool("get_click_attribution", args);
|
|
397
495
|
}
|
|
398
496
|
};
|
|
399
497
|
|
|
@@ -486,7 +584,6 @@ var RedditResource = class {
|
|
|
486
584
|
|
|
487
585
|
// src/resources/audiences.ts
|
|
488
586
|
var CONSENT_WARNING = "[@synterai/sdk-js] i_have_consent was not provided. Confirm lawful basis under GDPR/CCPA and the destination platform's terms for every identifier before staging or syncing PII, then pass `i_have_consent: true`. (Soft-launch notice \u2014 mirrors the backend's own behavior; this call is not blocked.)";
|
|
489
|
-
var ARTIFACT_ENDPOINT = "https://api.syntermedia.ai/artifacts/audience-sync-input";
|
|
490
587
|
var SYNC_AUDIENCE_SCRIPT_BY_PLATFORM = {
|
|
491
588
|
google: "google_ads_create_customer_match",
|
|
492
589
|
meta: "meta_ads_create_audience",
|
|
@@ -518,7 +615,7 @@ var AudiencesResource = class {
|
|
|
518
615
|
* identifiers inline when over ~500 entries.
|
|
519
616
|
*
|
|
520
617
|
* Bypasses the primary `tools/run` dispatcher: different host
|
|
521
|
-
* (`https://api.
|
|
618
|
+
* (`https://api.synterai.com`) and a different auth header
|
|
522
619
|
* (`X-Synter-Key`, not `Authorization: Bearer`) — see SPEC.md/catalog.json
|
|
523
620
|
* `transport.special`.
|
|
524
621
|
*/
|
|
@@ -533,7 +630,7 @@ var AudiencesResource = class {
|
|
|
533
630
|
if (input.script_name !== void 0) payload.script_name = input.script_name;
|
|
534
631
|
if (input.ttl_seconds !== void 0) payload.ttl_seconds = input.ttl_seconds;
|
|
535
632
|
if (input.i_have_consent !== void 0) payload.i_have_consent = input.i_have_consent;
|
|
536
|
-
return this.client.sendAbsolute(
|
|
633
|
+
return this.client.sendAbsolute(`${this.client.getArtifactBaseUrl()}/artifacts/audience-sync-input`, {
|
|
537
634
|
method: "POST",
|
|
538
635
|
headers: {
|
|
539
636
|
"X-Synter-Key": this.client.getApiKey(),
|
|
@@ -608,6 +705,91 @@ var AudiencesResource = class {
|
|
|
608
705
|
}
|
|
609
706
|
};
|
|
610
707
|
|
|
708
|
+
// src/resources/shield.ts
|
|
709
|
+
var ShieldResource = class {
|
|
710
|
+
constructor(client) {
|
|
711
|
+
this.client = client;
|
|
712
|
+
}
|
|
713
|
+
/**
|
|
714
|
+
* Inspect Agent Shield velocity limits, burst thresholds, circuit breakers,
|
|
715
|
+
* and kill-switch status before executing ad-spend mutations.
|
|
716
|
+
*/
|
|
717
|
+
async inspect(input = {}) {
|
|
718
|
+
const args = [];
|
|
719
|
+
if (input.platform) {
|
|
720
|
+
args.push("--platform", input.platform);
|
|
721
|
+
}
|
|
722
|
+
const result = await this.client.runTool("inspect_agent_shield", args, input.platform);
|
|
723
|
+
return result;
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
|
|
727
|
+
// src/resources/angstrom.ts
|
|
728
|
+
var AngstromResource = class {
|
|
729
|
+
constructor(client) {
|
|
730
|
+
this.client = client;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Verify attribution claims against Synter Ångström's deterministic confidence rubric.
|
|
734
|
+
*/
|
|
735
|
+
async verify(input = {}) {
|
|
736
|
+
const args = [];
|
|
737
|
+
if (input.platform) args.push("--platform", input.platform);
|
|
738
|
+
if (input.claimed_conversions !== void 0) args.push("--conversions", String(input.claimed_conversions));
|
|
739
|
+
if (input.claimed_revenue_usd !== void 0) args.push("--revenue", String(input.claimed_revenue_usd));
|
|
740
|
+
if (input.touchpoint_ids && input.touchpoint_ids.length > 0) {
|
|
741
|
+
args.push("--touchpoints", input.touchpoint_ids.join(","));
|
|
742
|
+
}
|
|
743
|
+
const result = await this.client.runTool("verify_angstrom_claim", args, input.platform);
|
|
744
|
+
return result;
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
// src/resources/skills.ts
|
|
749
|
+
var SkillsResource = class {
|
|
750
|
+
constructor(client) {
|
|
751
|
+
this.client = client;
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Load an autonomous growth runbook by ID.
|
|
755
|
+
*/
|
|
756
|
+
async get(skillId) {
|
|
757
|
+
const result = await this.client.runTool("get_skill", ["--skill-id", skillId]);
|
|
758
|
+
return result;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* List available autonomous growth runbook IDs.
|
|
762
|
+
*/
|
|
763
|
+
list() {
|
|
764
|
+
return [
|
|
765
|
+
"pmax-brand-cannibalization",
|
|
766
|
+
"search-hygiene-shield",
|
|
767
|
+
"marginal-cpa-budget-rebalancer",
|
|
768
|
+
"meta-asc-dark-pool-auditor",
|
|
769
|
+
"single-truth-attribution"
|
|
770
|
+
];
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// src/resources/visibility.ts
|
|
775
|
+
var VisibilityResource = class {
|
|
776
|
+
constructor(client) {
|
|
777
|
+
this.client = client;
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Read AI search brand visibility and AEO share of voice across ChatGPT, Claude, Perplexity, and Gemini.
|
|
781
|
+
*/
|
|
782
|
+
async get(input = {}) {
|
|
783
|
+
const args = [];
|
|
784
|
+
if (input.query) args.push("--query", input.query);
|
|
785
|
+
if (input.competitor_domains && input.competitor_domains.length > 0) {
|
|
786
|
+
args.push("--competitors", input.competitor_domains.join(","));
|
|
787
|
+
}
|
|
788
|
+
const result = await this.client.runTool("get_llm_visibility", args);
|
|
789
|
+
return result;
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
|
|
611
793
|
// src/toolbox/amp-tools.ts
|
|
612
794
|
var AmpToolbox = class {
|
|
613
795
|
constructor(client, config = {}) {
|
|
@@ -841,7 +1023,8 @@ var AmpToolbox = class {
|
|
|
841
1023
|
};
|
|
842
1024
|
|
|
843
1025
|
// src/client.ts
|
|
844
|
-
var DEFAULT_BASE_URL = "https://
|
|
1026
|
+
var DEFAULT_BASE_URL = "https://synterai.com";
|
|
1027
|
+
var DEFAULT_ARTIFACT_BASE_URL = "https://api.synterai.com";
|
|
845
1028
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
846
1029
|
var DEFAULT_MAX_RETRIES = 3;
|
|
847
1030
|
var RETRY_BASE_MS = 1e3;
|
|
@@ -859,7 +1042,9 @@ var Synter = class {
|
|
|
859
1042
|
throw new SynterValidationError("`apiKey` is required to construct a Synter client.", "apiKey");
|
|
860
1043
|
}
|
|
861
1044
|
this.apiKey = fullConfig.apiKey;
|
|
862
|
-
|
|
1045
|
+
const env = typeof process !== "undefined" ? process.env : void 0;
|
|
1046
|
+
this.baseUrl = fullConfig.baseUrl ?? (env?.SYNTER_API_URL || DEFAULT_BASE_URL);
|
|
1047
|
+
this.artifactBaseUrl = fullConfig.artifactBaseUrl ?? (env?.SYNTER_ARTIFACT_API_URL || DEFAULT_ARTIFACT_BASE_URL);
|
|
863
1048
|
this.timeout = fullConfig.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
864
1049
|
this.maxRetries = fullConfig.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
865
1050
|
this.fetchImpl = fullConfig.fetch ?? globalThis.fetch.bind(globalThis);
|
|
@@ -872,6 +1057,10 @@ var Synter = class {
|
|
|
872
1057
|
this.linkedin = new LinkedInResource(this);
|
|
873
1058
|
this.reddit = new RedditResource(this);
|
|
874
1059
|
this.audiences = new AudiencesResource(this);
|
|
1060
|
+
this.shield = new ShieldResource(this);
|
|
1061
|
+
this.angstrom = new AngstromResource(this);
|
|
1062
|
+
this.skills = new SkillsResource(this);
|
|
1063
|
+
this.visibility = new VisibilityResource(this);
|
|
875
1064
|
this.amp = new AmpToolbox(this, ampConfig);
|
|
876
1065
|
}
|
|
877
1066
|
// ---------------------------------------------------------------------
|
|
@@ -950,7 +1139,11 @@ var Synter = class {
|
|
|
950
1139
|
"Content-Type": "application/json"
|
|
951
1140
|
};
|
|
952
1141
|
}
|
|
953
|
-
/**
|
|
1142
|
+
/** Artifact host used by audience staging. */
|
|
1143
|
+
getArtifactBaseUrl() {
|
|
1144
|
+
return this.artifactBaseUrl;
|
|
1145
|
+
}
|
|
1146
|
+
/** The raw API key, for tools that need a non-Bearer header. */
|
|
954
1147
|
getApiKey() {
|
|
955
1148
|
return this.apiKey;
|
|
956
1149
|
}
|
|
@@ -1439,18 +1632,23 @@ function normalizeConversionEvent(params) {
|
|
|
1439
1632
|
AmpToolbox,
|
|
1440
1633
|
AnalyticsIntegrationManager,
|
|
1441
1634
|
AnalyticsResource,
|
|
1635
|
+
AngstromResource,
|
|
1442
1636
|
AudiencesResource,
|
|
1443
1637
|
CampaignsResource,
|
|
1444
1638
|
ConversionsResource,
|
|
1445
1639
|
CreativeResource,
|
|
1640
|
+
DEFAULT_ARTIFACT_BASE_URL,
|
|
1446
1641
|
DEFAULT_BASE_URL,
|
|
1447
1642
|
KeywordsResource,
|
|
1448
1643
|
LinkedInResource,
|
|
1449
1644
|
MetaResource,
|
|
1450
1645
|
RedditResource,
|
|
1646
|
+
ShieldResource,
|
|
1647
|
+
SkillsResource,
|
|
1451
1648
|
Synter,
|
|
1452
1649
|
SynterError,
|
|
1453
1650
|
SynterValidationError,
|
|
1651
|
+
VisibilityResource,
|
|
1454
1652
|
buildConversionPayload,
|
|
1455
1653
|
buildTrackingURL,
|
|
1456
1654
|
buildUTMParameters,
|
package/dist/index.mjs
CHANGED
|
@@ -149,7 +149,7 @@ var PAUSE_CAMPAIGN_ARG_MAPPING = [
|
|
|
149
149
|
];
|
|
150
150
|
var UPDATE_BUDGET_ARG_MAPPING = [
|
|
151
151
|
{ field: "campaign_id", flag: "--campaign-id", type: "string", required: true },
|
|
152
|
-
{ field: "daily_budget", flag: "--budget", type: "number", required: true }
|
|
152
|
+
{ field: "daily_budget", flag: "--daily-budget", type: "number", required: true }
|
|
153
153
|
];
|
|
154
154
|
var CampaignsResource = class {
|
|
155
155
|
constructor(client) {
|
|
@@ -222,6 +222,72 @@ var CampaignsResource = class {
|
|
|
222
222
|
const args = buildArgsFromMapping(UPDATE_BUDGET_ARG_MAPPING, input);
|
|
223
223
|
return this.client.runTool("update_campaign_budget", args, "google");
|
|
224
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Update campaign budget with deterministic readback verification.
|
|
227
|
+
*
|
|
228
|
+
* Executes the budget update, waits for propagation, and reads back
|
|
229
|
+
* campaign status from the platform to verify the update succeeded on the wire.
|
|
230
|
+
*/
|
|
231
|
+
async updateBudgetAndVerify(input) {
|
|
232
|
+
const mutation = await this.updateBudget(input);
|
|
233
|
+
const maxWaitMs = input.maxWaitMs ?? 5e3;
|
|
234
|
+
const pollIntervalMs = input.pollIntervalMs ?? 1e3;
|
|
235
|
+
const startTime = Date.now();
|
|
236
|
+
let lastReadback;
|
|
237
|
+
while (Date.now() - startTime <= maxWaitMs) {
|
|
238
|
+
try {
|
|
239
|
+
const readback = await this.list({
|
|
240
|
+
platform: input.platform
|
|
241
|
+
});
|
|
242
|
+
lastReadback = readback;
|
|
243
|
+
const campaigns = readback.campaigns || readback.data || [];
|
|
244
|
+
const match = campaigns.find(
|
|
245
|
+
(c) => String(c.id || c.campaign_id) === String(input.campaign_id)
|
|
246
|
+
);
|
|
247
|
+
if (match) {
|
|
248
|
+
const budget = Number(match.daily_budget_usd || match.daily_budget || match.budget);
|
|
249
|
+
if (Math.abs(budget - input.daily_budget) < 0.01) {
|
|
250
|
+
return { mutation, verified: true, readback: match };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
} catch {
|
|
254
|
+
}
|
|
255
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
256
|
+
}
|
|
257
|
+
return { mutation, verified: false, readback: lastReadback };
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Pause a campaign with deterministic readback verification.
|
|
261
|
+
*
|
|
262
|
+
* Executes the pause command, waits for propagation, and reads back
|
|
263
|
+
* campaign status from the platform to verify status === 'PAUSED' on the wire.
|
|
264
|
+
*/
|
|
265
|
+
async pauseAndVerify(input) {
|
|
266
|
+
const mutation = await this.pause(input);
|
|
267
|
+
const maxWaitMs = input.maxWaitMs ?? 5e3;
|
|
268
|
+
const pollIntervalMs = input.pollIntervalMs ?? 1e3;
|
|
269
|
+
const startTime = Date.now();
|
|
270
|
+
let lastReadback;
|
|
271
|
+
while (Date.now() - startTime <= maxWaitMs) {
|
|
272
|
+
try {
|
|
273
|
+
const readback = await this.list({
|
|
274
|
+
platform: input.platform,
|
|
275
|
+
status: "PAUSED"
|
|
276
|
+
});
|
|
277
|
+
lastReadback = readback;
|
|
278
|
+
const campaigns = readback.campaigns || readback.data || [];
|
|
279
|
+
const match = campaigns.find(
|
|
280
|
+
(c) => String(c.id || c.campaign_id) === String(input.campaign_id)
|
|
281
|
+
);
|
|
282
|
+
if (match) {
|
|
283
|
+
return { mutation, verified: true, readback: match };
|
|
284
|
+
}
|
|
285
|
+
} catch {
|
|
286
|
+
}
|
|
287
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
288
|
+
}
|
|
289
|
+
return { mutation, verified: false, readback: lastReadback };
|
|
290
|
+
}
|
|
225
291
|
};
|
|
226
292
|
|
|
227
293
|
// src/resources/analytics.ts
|
|
@@ -315,6 +381,21 @@ var CREATE_CONVERSION_ARG_MAPPING = [
|
|
|
315
381
|
var DIAGNOSE_TRACKING_ARG_MAPPING = [
|
|
316
382
|
{ field: "url", flag: "--url", type: "string", required: true }
|
|
317
383
|
];
|
|
384
|
+
var GET_PIXEL_HEALTH_ARG_MAPPING = [
|
|
385
|
+
{ field: "site_key", flag: "--site-key", type: "string" }
|
|
386
|
+
];
|
|
387
|
+
var LIST_EVENT_DELIVERIES_ARG_MAPPING = [
|
|
388
|
+
{ field: "site_key", flag: "--site-key", type: "string" },
|
|
389
|
+
{ field: "status", flag: "--status", type: "string" },
|
|
390
|
+
{ field: "platform", flag: "--platform", type: "string" },
|
|
391
|
+
{ field: "limit", flag: "--limit", type: "number" }
|
|
392
|
+
];
|
|
393
|
+
var GET_CLICK_ATTRIBUTION_ARG_MAPPING = [
|
|
394
|
+
{ field: "site_key", flag: "--site-key", type: "string" },
|
|
395
|
+
{ field: "user_id", flag: "--user-id", type: "number" },
|
|
396
|
+
{ field: "email", flag: "--email", type: "string" },
|
|
397
|
+
{ field: "limit", flag: "--limit", type: "number" }
|
|
398
|
+
];
|
|
318
399
|
var ConversionsResource = class {
|
|
319
400
|
constructor(client) {
|
|
320
401
|
this.client = client;
|
|
@@ -340,7 +421,19 @@ var ConversionsResource = class {
|
|
|
340
421
|
*/
|
|
341
422
|
async diagnoseTracking(input) {
|
|
342
423
|
const args = buildArgsFromMapping(DIAGNOSE_TRACKING_ARG_MAPPING, input);
|
|
343
|
-
return this.client.runTool("
|
|
424
|
+
return this.client.runTool("diagnose_tracking", args);
|
|
425
|
+
}
|
|
426
|
+
async getPixelHealth(input = {}) {
|
|
427
|
+
const args = buildArgsFromMapping(GET_PIXEL_HEALTH_ARG_MAPPING, input);
|
|
428
|
+
return this.client.runTool("get_pixel_health", args);
|
|
429
|
+
}
|
|
430
|
+
async listEventDeliveries(input = {}) {
|
|
431
|
+
const args = buildArgsFromMapping(LIST_EVENT_DELIVERIES_ARG_MAPPING, input);
|
|
432
|
+
return this.client.runTool("list_event_deliveries", args);
|
|
433
|
+
}
|
|
434
|
+
async getClickAttribution(input = {}) {
|
|
435
|
+
const args = buildArgsFromMapping(GET_CLICK_ATTRIBUTION_ARG_MAPPING, input);
|
|
436
|
+
return this.client.runTool("get_click_attribution", args);
|
|
344
437
|
}
|
|
345
438
|
};
|
|
346
439
|
|
|
@@ -433,7 +526,6 @@ var RedditResource = class {
|
|
|
433
526
|
|
|
434
527
|
// src/resources/audiences.ts
|
|
435
528
|
var CONSENT_WARNING = "[@synterai/sdk-js] i_have_consent was not provided. Confirm lawful basis under GDPR/CCPA and the destination platform's terms for every identifier before staging or syncing PII, then pass `i_have_consent: true`. (Soft-launch notice \u2014 mirrors the backend's own behavior; this call is not blocked.)";
|
|
436
|
-
var ARTIFACT_ENDPOINT = "https://api.syntermedia.ai/artifacts/audience-sync-input";
|
|
437
529
|
var SYNC_AUDIENCE_SCRIPT_BY_PLATFORM = {
|
|
438
530
|
google: "google_ads_create_customer_match",
|
|
439
531
|
meta: "meta_ads_create_audience",
|
|
@@ -465,7 +557,7 @@ var AudiencesResource = class {
|
|
|
465
557
|
* identifiers inline when over ~500 entries.
|
|
466
558
|
*
|
|
467
559
|
* Bypasses the primary `tools/run` dispatcher: different host
|
|
468
|
-
* (`https://api.
|
|
560
|
+
* (`https://api.synterai.com`) and a different auth header
|
|
469
561
|
* (`X-Synter-Key`, not `Authorization: Bearer`) — see SPEC.md/catalog.json
|
|
470
562
|
* `transport.special`.
|
|
471
563
|
*/
|
|
@@ -480,7 +572,7 @@ var AudiencesResource = class {
|
|
|
480
572
|
if (input.script_name !== void 0) payload.script_name = input.script_name;
|
|
481
573
|
if (input.ttl_seconds !== void 0) payload.ttl_seconds = input.ttl_seconds;
|
|
482
574
|
if (input.i_have_consent !== void 0) payload.i_have_consent = input.i_have_consent;
|
|
483
|
-
return this.client.sendAbsolute(
|
|
575
|
+
return this.client.sendAbsolute(`${this.client.getArtifactBaseUrl()}/artifacts/audience-sync-input`, {
|
|
484
576
|
method: "POST",
|
|
485
577
|
headers: {
|
|
486
578
|
"X-Synter-Key": this.client.getApiKey(),
|
|
@@ -555,6 +647,91 @@ var AudiencesResource = class {
|
|
|
555
647
|
}
|
|
556
648
|
};
|
|
557
649
|
|
|
650
|
+
// src/resources/shield.ts
|
|
651
|
+
var ShieldResource = class {
|
|
652
|
+
constructor(client) {
|
|
653
|
+
this.client = client;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Inspect Agent Shield velocity limits, burst thresholds, circuit breakers,
|
|
657
|
+
* and kill-switch status before executing ad-spend mutations.
|
|
658
|
+
*/
|
|
659
|
+
async inspect(input = {}) {
|
|
660
|
+
const args = [];
|
|
661
|
+
if (input.platform) {
|
|
662
|
+
args.push("--platform", input.platform);
|
|
663
|
+
}
|
|
664
|
+
const result = await this.client.runTool("inspect_agent_shield", args, input.platform);
|
|
665
|
+
return result;
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// src/resources/angstrom.ts
|
|
670
|
+
var AngstromResource = class {
|
|
671
|
+
constructor(client) {
|
|
672
|
+
this.client = client;
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Verify attribution claims against Synter Ångström's deterministic confidence rubric.
|
|
676
|
+
*/
|
|
677
|
+
async verify(input = {}) {
|
|
678
|
+
const args = [];
|
|
679
|
+
if (input.platform) args.push("--platform", input.platform);
|
|
680
|
+
if (input.claimed_conversions !== void 0) args.push("--conversions", String(input.claimed_conversions));
|
|
681
|
+
if (input.claimed_revenue_usd !== void 0) args.push("--revenue", String(input.claimed_revenue_usd));
|
|
682
|
+
if (input.touchpoint_ids && input.touchpoint_ids.length > 0) {
|
|
683
|
+
args.push("--touchpoints", input.touchpoint_ids.join(","));
|
|
684
|
+
}
|
|
685
|
+
const result = await this.client.runTool("verify_angstrom_claim", args, input.platform);
|
|
686
|
+
return result;
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
|
|
690
|
+
// src/resources/skills.ts
|
|
691
|
+
var SkillsResource = class {
|
|
692
|
+
constructor(client) {
|
|
693
|
+
this.client = client;
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Load an autonomous growth runbook by ID.
|
|
697
|
+
*/
|
|
698
|
+
async get(skillId) {
|
|
699
|
+
const result = await this.client.runTool("get_skill", ["--skill-id", skillId]);
|
|
700
|
+
return result;
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* List available autonomous growth runbook IDs.
|
|
704
|
+
*/
|
|
705
|
+
list() {
|
|
706
|
+
return [
|
|
707
|
+
"pmax-brand-cannibalization",
|
|
708
|
+
"search-hygiene-shield",
|
|
709
|
+
"marginal-cpa-budget-rebalancer",
|
|
710
|
+
"meta-asc-dark-pool-auditor",
|
|
711
|
+
"single-truth-attribution"
|
|
712
|
+
];
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
|
|
716
|
+
// src/resources/visibility.ts
|
|
717
|
+
var VisibilityResource = class {
|
|
718
|
+
constructor(client) {
|
|
719
|
+
this.client = client;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Read AI search brand visibility and AEO share of voice across ChatGPT, Claude, Perplexity, and Gemini.
|
|
723
|
+
*/
|
|
724
|
+
async get(input = {}) {
|
|
725
|
+
const args = [];
|
|
726
|
+
if (input.query) args.push("--query", input.query);
|
|
727
|
+
if (input.competitor_domains && input.competitor_domains.length > 0) {
|
|
728
|
+
args.push("--competitors", input.competitor_domains.join(","));
|
|
729
|
+
}
|
|
730
|
+
const result = await this.client.runTool("get_llm_visibility", args);
|
|
731
|
+
return result;
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
|
|
558
735
|
// src/toolbox/amp-tools.ts
|
|
559
736
|
var AmpToolbox = class {
|
|
560
737
|
constructor(client, config = {}) {
|
|
@@ -788,7 +965,8 @@ var AmpToolbox = class {
|
|
|
788
965
|
};
|
|
789
966
|
|
|
790
967
|
// src/client.ts
|
|
791
|
-
var DEFAULT_BASE_URL = "https://
|
|
968
|
+
var DEFAULT_BASE_URL = "https://synterai.com";
|
|
969
|
+
var DEFAULT_ARTIFACT_BASE_URL = "https://api.synterai.com";
|
|
792
970
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
793
971
|
var DEFAULT_MAX_RETRIES = 3;
|
|
794
972
|
var RETRY_BASE_MS = 1e3;
|
|
@@ -806,7 +984,9 @@ var Synter = class {
|
|
|
806
984
|
throw new SynterValidationError("`apiKey` is required to construct a Synter client.", "apiKey");
|
|
807
985
|
}
|
|
808
986
|
this.apiKey = fullConfig.apiKey;
|
|
809
|
-
|
|
987
|
+
const env = typeof process !== "undefined" ? process.env : void 0;
|
|
988
|
+
this.baseUrl = fullConfig.baseUrl ?? (env?.SYNTER_API_URL || DEFAULT_BASE_URL);
|
|
989
|
+
this.artifactBaseUrl = fullConfig.artifactBaseUrl ?? (env?.SYNTER_ARTIFACT_API_URL || DEFAULT_ARTIFACT_BASE_URL);
|
|
810
990
|
this.timeout = fullConfig.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
811
991
|
this.maxRetries = fullConfig.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
812
992
|
this.fetchImpl = fullConfig.fetch ?? globalThis.fetch.bind(globalThis);
|
|
@@ -819,6 +999,10 @@ var Synter = class {
|
|
|
819
999
|
this.linkedin = new LinkedInResource(this);
|
|
820
1000
|
this.reddit = new RedditResource(this);
|
|
821
1001
|
this.audiences = new AudiencesResource(this);
|
|
1002
|
+
this.shield = new ShieldResource(this);
|
|
1003
|
+
this.angstrom = new AngstromResource(this);
|
|
1004
|
+
this.skills = new SkillsResource(this);
|
|
1005
|
+
this.visibility = new VisibilityResource(this);
|
|
822
1006
|
this.amp = new AmpToolbox(this, ampConfig);
|
|
823
1007
|
}
|
|
824
1008
|
// ---------------------------------------------------------------------
|
|
@@ -897,7 +1081,11 @@ var Synter = class {
|
|
|
897
1081
|
"Content-Type": "application/json"
|
|
898
1082
|
};
|
|
899
1083
|
}
|
|
900
|
-
/**
|
|
1084
|
+
/** Artifact host used by audience staging. */
|
|
1085
|
+
getArtifactBaseUrl() {
|
|
1086
|
+
return this.artifactBaseUrl;
|
|
1087
|
+
}
|
|
1088
|
+
/** The raw API key, for tools that need a non-Bearer header. */
|
|
901
1089
|
getApiKey() {
|
|
902
1090
|
return this.apiKey;
|
|
903
1091
|
}
|
|
@@ -1385,18 +1573,23 @@ export {
|
|
|
1385
1573
|
AmpToolbox,
|
|
1386
1574
|
AnalyticsIntegrationManager,
|
|
1387
1575
|
AnalyticsResource,
|
|
1576
|
+
AngstromResource,
|
|
1388
1577
|
AudiencesResource,
|
|
1389
1578
|
CampaignsResource,
|
|
1390
1579
|
ConversionsResource,
|
|
1391
1580
|
CreativeResource,
|
|
1581
|
+
DEFAULT_ARTIFACT_BASE_URL,
|
|
1392
1582
|
DEFAULT_BASE_URL,
|
|
1393
1583
|
KeywordsResource,
|
|
1394
1584
|
LinkedInResource,
|
|
1395
1585
|
MetaResource,
|
|
1396
1586
|
RedditResource,
|
|
1587
|
+
ShieldResource,
|
|
1588
|
+
SkillsResource,
|
|
1397
1589
|
Synter,
|
|
1398
1590
|
SynterError,
|
|
1399
1591
|
SynterValidationError,
|
|
1592
|
+
VisibilityResource,
|
|
1400
1593
|
buildConversionPayload,
|
|
1401
1594
|
buildTrackingURL,
|
|
1402
1595
|
buildUTMParameters,
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synterai/sdk-js",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "TypeScript SDK for the Synter advertising API — manage campaigns across Google Ads, Meta, LinkedIn, Reddit, Microsoft, TikTok, and X",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Official Synter TypeScript SDK for the Synter advertising API — manage campaigns across Google Ads, Meta, LinkedIn, Reddit, Microsoft, TikTok, and X. @iflow-mcp/* copies are unofficial.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
9
|
-
"dist"
|
|
9
|
+
"dist",
|
|
10
|
+
"CHANGELOG.md"
|
|
10
11
|
],
|
|
11
12
|
"scripts": {
|
|
12
13
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
@@ -42,15 +43,15 @@
|
|
|
42
43
|
"analytics",
|
|
43
44
|
"ppc"
|
|
44
45
|
],
|
|
45
|
-
"author": "
|
|
46
|
+
"author": "Synter <hello@synterai.com>",
|
|
46
47
|
"license": "MIT",
|
|
47
48
|
"repository": {
|
|
48
49
|
"type": "git",
|
|
49
|
-
"url": "https://github.com/
|
|
50
|
-
"directory": "
|
|
50
|
+
"url": "git+https://github.com/Synter-Media-AI/synter-docs.git",
|
|
51
|
+
"directory": "sdk/typescript"
|
|
51
52
|
},
|
|
52
|
-
"homepage": "https://
|
|
53
|
-
"bugs": "https://github.com/
|
|
53
|
+
"homepage": "https://synterai.com",
|
|
54
|
+
"bugs": "https://github.com/Synter-Media-AI/synter-docs/issues",
|
|
54
55
|
"dependencies": {},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/node": "^20.10.0",
|