@synterai/sdk-js 0.1.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/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # @synterai/sdk-js
2
+
3
+ TypeScript SDK for the [Synter](https://syntermedia.ai) advertising API — manage campaigns across Google Ads, Meta, LinkedIn, Microsoft Ads, Reddit, TikTok, and X from your own code, with full types and IDE autocomplete.
4
+
5
+ > **Not yet published to npm.** This package isn't on the npm registry — install it from source (see below) until Joel ships a public release.
6
+
7
+ ## What this actually talks to
8
+
9
+ Every method in this SDK calls the same live, production endpoint that powers Synter's MCP server (`@synterai/mcp-server`) and the `synter` CLI: `POST https://syntermedia.ai/api/v1/tools/run`. There is no separate "SDK backend" — if a method works here, it works because the exact same call already works for every MCP client (Claude, Cursor, Codex, ChatGPT) today.
10
+
11
+ See [`../sdk-shared/SPEC.md`](../sdk-shared/SPEC.md) and [`../sdk-shared/catalog.json`](../sdk-shared/catalog.json) for the full transport contract this SDK — and every sibling-language SDK — implements.
12
+
13
+ ## Install (from source)
14
+
15
+ ```bash
16
+ git clone https://github.com/jshorwitz/synter-media.git
17
+ cd synter-media/packages/sdk-js
18
+ npm install
19
+ npm run build
20
+ ```
21
+
22
+ Then depend on it locally (e.g. `npm install ../path/to/synter-media/packages/sdk-js` or a workspace reference) until it's published.
23
+
24
+ ## Authentication
25
+
26
+ Get an API key at [syntermedia.ai/developer](https://syntermedia.ai/developer). Keys look like `syn_` followed by 32 base64url characters.
27
+
28
+ ```ts
29
+ import { Synter } from '@synterai/sdk-js';
30
+
31
+ const synter = new Synter(process.env.SYNTER_API_KEY!);
32
+ // or, with options:
33
+ const synter = new Synter({
34
+ apiKey: process.env.SYNTER_API_KEY!,
35
+ timeout: 30_000, // ms, default 30s
36
+ maxRetries: 3, // default 3
37
+ });
38
+ ```
39
+
40
+ ## Quickstart
41
+
42
+ ```ts
43
+ import { Synter } from '@synterai/sdk-js';
44
+
45
+ const synter = new Synter(process.env.SYNTER_API_KEY!);
46
+
47
+ // List campaigns (defaults to Google if no platform is given)
48
+ const campaigns = await synter.campaigns.list({ status: 'ENABLED', limit: 10 });
49
+
50
+ // Create a Google Search campaign
51
+ await synter.campaigns.createSearch({
52
+ campaign_name: 'Q4 Launch',
53
+ daily_budget: 50,
54
+ keywords: ['running shoes'],
55
+ headlines: ['Fast. Light. Yours.', 'New Season, New PR', 'Free Shipping Today'],
56
+ descriptions: ['Premium running shoes built for speed.', 'Order today, ships free.'],
57
+ final_url: 'https://example.com/shoes',
58
+ });
59
+
60
+ // Pull performance metrics
61
+ const perf = await synter.analytics.getPerformance({ date_range: 'LAST_30_DAYS' });
62
+
63
+ // Generate an AI creative
64
+ const image = await synter.creative.generateImage({ prompt: 'a running shoe on a cloud, product photography' });
65
+
66
+ // Escape hatch: call any of the 140+ backend scripts by name
67
+ await synter.execute('google_ads_list_audiences', { status: 'ENABLED' }, 'google');
68
+ ```
69
+
70
+ ## API surface
71
+
72
+ Methods are grouped by category, matching the tool catalog:
73
+
74
+ | Namespace | Methods |
75
+ |---|---|
76
+ | `synter.campaigns` | `list`, `createSearch`, `createDisplay`, `createPmax`, `pause`, `updateBudget` |
77
+ | `synter.analytics` | `getPerformance`, `getDailySpend` |
78
+ | `synter.keywords` | `add`, `addNegative` |
79
+ | `synter.conversions` | `create`, `list`, `diagnoseTracking` |
80
+ | `synter.creative` | `generateImage`, `generateVideo` |
81
+ | `synter.meta` | `createCampaign` |
82
+ | `synter.linkedin` | `createCampaign` |
83
+ | `synter.reddit` | `createCampaign` |
84
+ | `synter.audiences` | `stageArtifact`, `sync`, `manage` |
85
+ | `synter` (top level) | `listAdAccounts`, `uploadImage`, `listLandingPages`, `execute` |
86
+
87
+ Every method takes a fully-typed input object (required fields are non-optional in TypeScript) and returns `Promise<Record<string, unknown>>` — the backend scripts return script-specific JSON that isn't worth over-narrowing today.
88
+
89
+ `synter.execute(scriptName, args, platform?)` is the universal escape hatch: it can call any of the 140+ backend scripts beyond the typed methods above, converting an idiomatic `{flagName: value}` map into the CLI-flag wire format internally.
90
+
91
+ ## Errors
92
+
93
+ ```ts
94
+ import { SynterError, SynterValidationError } from '@synterai/sdk-js';
95
+
96
+ try {
97
+ await synter.campaigns.createSearch({ /* missing required fields */ } as any);
98
+ } catch (err) {
99
+ if (err instanceof SynterValidationError) {
100
+ // Caught client-side, before any network call — e.g. a missing required field.
101
+ } else if (err instanceof SynterError) {
102
+ // The API rejected the call: err.status, err.message, err.code, err.details
103
+ }
104
+ }
105
+ ```
106
+
107
+ The client automatically retries up to 3 times (exponential backoff, 1s base / 10s cap) on `429` responses (honoring `Retry-After`) and on network/timeout errors. Other 4xx/5xx responses are not retried.
108
+
109
+ ## Known issues (intentionally preserved, not "fixed" here)
110
+
111
+ These mirror real, current production behavior of the backend scripts. The SDK calls the backend exactly as it works today rather than silently diverging — see `../sdk-shared/SPEC.md`'s "Known issues" section and `catalog.json`'s `knownIssues`:
112
+
113
+ 1. `campaigns.pause()` and `campaigns.updateBudget()` accept a `platform` field (their schemas advertise all 7 platforms), but the live dispatch always uses `platform=google` regardless of what's passed.
114
+ 2. `uploadImage()` accepts an optional `platform` (google/meta/linkedin), but live dispatch always hardcodes `platform=google`.
115
+ 3. `campaigns.createDisplay()` and `campaigns.createPmax()` use different flag names for the same concept — `--landscape-image`/`--square-image` vs. `--landscape-image-url`/`--square-image-url`.
116
+
117
+ These are flagged to Joel as product bugs to fix upstream (in `catalog.json` first, then every SDK), not something to patch ad hoc in one language.
118
+
119
+ ## Amp Toolbox
120
+
121
+ `synter.amp` is a separate, AI-powered toolbox for Amp integration (campaign generation, creative variants, budget optimization, etc.) — see [`AMP_TOOLBOX_README.md`](./AMP_TOOLBOX_README.md). It predates and is independent of the catalog-driven transport rewrite above.
122
+
123
+ ## Development
124
+
125
+ ```bash
126
+ npm run build # tsup, dual ESM/CJS + .d.ts
127
+ npm run typecheck # tsc --noEmit
128
+ npx vitest run # test suite (mocked fetch, no real network/API key required)
129
+ ```
130
+
131
+ ## License
132
+
133
+ MIT