@spyglasshq/sdk 0.1.3 → 0.1.4
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 +40 -42
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/version.d.mts +1 -1
- package/dist/esm/version.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
- [Discover Creators](#3-discover-creators)
|
|
49
49
|
- [Creative Insights & Landing Pages](#4-creative-insights--landing-pages)
|
|
50
50
|
- [Post Comments](#5-post-comments)
|
|
51
|
-
- [Index a New
|
|
51
|
+
- [Index a New Account](#6-index-a-new-account)
|
|
52
52
|
- [Check Team Credit Usage](#7-check-team-credit-usage)
|
|
53
53
|
- [API Reference Overview](#api-reference-overview)
|
|
54
54
|
- [TypeScript Types](#typescript-types)
|
|
@@ -86,7 +86,7 @@ const client = new Spyglass({
|
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
// 1. Resolve a brand by name
|
|
89
|
-
const { brands } = await client.
|
|
89
|
+
const { brands } = await client.searchBrands({
|
|
90
90
|
names: ["Nike"],
|
|
91
91
|
limit: 1,
|
|
92
92
|
});
|
|
@@ -95,7 +95,7 @@ const brand = brands[0];
|
|
|
95
95
|
|
|
96
96
|
if (brand) {
|
|
97
97
|
// 2. Search the creatives that brand is running
|
|
98
|
-
const { media } = await client.
|
|
98
|
+
const { media } = await client.searchMedia({
|
|
99
99
|
brandId: brand.id,
|
|
100
100
|
query: "marathon running shoes comfort",
|
|
101
101
|
limit: 10,
|
|
@@ -124,13 +124,13 @@ Search advertisers by name (`names`), social handle (`igUsername`, `tiktokUserna
|
|
|
124
124
|
|
|
125
125
|
```ts
|
|
126
126
|
// Fuzzy name lookup
|
|
127
|
-
const byName = await client.
|
|
127
|
+
const byName = await client.searchBrands({
|
|
128
128
|
names: ["Athletic Greens", "AG1"],
|
|
129
129
|
limit: 5,
|
|
130
130
|
});
|
|
131
131
|
|
|
132
132
|
// Natural-language discovery
|
|
133
|
-
const byBrief = await client.
|
|
133
|
+
const byBrief = await client.searchBrands({
|
|
134
134
|
query: "DTC electrolyte and hydration powder brands",
|
|
135
135
|
limit: 10,
|
|
136
136
|
});
|
|
@@ -142,16 +142,16 @@ Pass `brandId` to inspect a specific brand or creator's creatives, or omit `bran
|
|
|
142
142
|
|
|
143
143
|
```ts
|
|
144
144
|
// Optional: look up valid product taxonomy paths first (free call)
|
|
145
|
-
const {
|
|
145
|
+
const { paths } = await client.searchTaxonomies({
|
|
146
146
|
query: "running shoes",
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
-
const { media, count } = await client.
|
|
149
|
+
const { media, count } = await client.searchMedia({
|
|
150
150
|
query: "UGC founder story explaining product benefits",
|
|
151
151
|
channel: ["META_AD", "TIKTOK"],
|
|
152
152
|
format: ["VIDEO"],
|
|
153
153
|
status: "ACTIVE",
|
|
154
|
-
taxonomy:
|
|
154
|
+
taxonomy: paths.slice(0, 2),
|
|
155
155
|
minDaysRun: 14,
|
|
156
156
|
limit: 20,
|
|
157
157
|
offset: 0,
|
|
@@ -168,23 +168,23 @@ Each item in `media` includes creative intelligence extracted by Spyglass:
|
|
|
168
168
|
Search creators by handle, name, or natural-language brief, and filter by demographic and profile attributes (`gender`, `ageRange`, `ethnicity`, `location`, `language`):
|
|
169
169
|
|
|
170
170
|
```ts
|
|
171
|
-
const { creators } = await client.
|
|
171
|
+
const { creators } = await client.searchCreators({
|
|
172
172
|
query: "skincare routine and dermatology tips",
|
|
173
173
|
gender: "female",
|
|
174
|
-
ageRange:
|
|
175
|
-
location:
|
|
176
|
-
language:
|
|
174
|
+
ageRange: "25-34",
|
|
175
|
+
location: "United States",
|
|
176
|
+
language: "English",
|
|
177
177
|
limit: 20,
|
|
178
178
|
});
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
### 4. Creative Insights & Landing Pages
|
|
182
182
|
|
|
183
|
-
Pull clustered creative themes (`HOOK`, `USP`, `PERSONA`, `MEDIA_MIX`) and ranked destination landing pages for any
|
|
183
|
+
Pull clustered creative themes (`HOOK`, `USP`, `PERSONA`, `MEDIA_MIX`) and ranked destination landing pages for any account:
|
|
184
184
|
|
|
185
185
|
```ts
|
|
186
186
|
// Ranked hooks + weekly volume breakdown over the last 90 days
|
|
187
|
-
const insights = await client.
|
|
187
|
+
const insights = await client.account.insights({
|
|
188
188
|
id: brand.id,
|
|
189
189
|
type: "HOOK",
|
|
190
190
|
maxDaysBack: 90,
|
|
@@ -192,7 +192,7 @@ const insights = await client.search.getBrandMediaInsights({
|
|
|
192
192
|
});
|
|
193
193
|
|
|
194
194
|
// Top landing pages where the brand sends ad traffic
|
|
195
|
-
const { landingPages } = await client.
|
|
195
|
+
const { landingPages } = await client.account.landingPages({
|
|
196
196
|
id: brand.id,
|
|
197
197
|
showInactive: "false",
|
|
198
198
|
limit: 20,
|
|
@@ -204,19 +204,19 @@ const { landingPages } = await client.search.getBrandLandingPages({
|
|
|
204
204
|
Fetch public comments from Instagram posts/reels (by shortcode or URL) and TikTok videos (by video ID or URL):
|
|
205
205
|
|
|
206
206
|
```ts
|
|
207
|
-
const { posts } = await client.
|
|
207
|
+
const { posts } = await client.getComments({
|
|
208
208
|
instagramIds: ["https://www.instagram.com/reel/C2xY9abcD1e/"],
|
|
209
209
|
tiktokIds: ["https://www.tiktok.com/@nike/video/7234567890123456789"],
|
|
210
210
|
limit: 1, // comment pages per post
|
|
211
211
|
});
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
### 6. Index a New
|
|
214
|
+
### 6. Index a New Account
|
|
215
215
|
|
|
216
|
-
If Spyglass doesn't have a brand yet, submit its website or social profile URL (`POST /account/index` is free) and poll until `status` is `"ready"`:
|
|
216
|
+
If Spyglass doesn't have a brand or creator yet, submit its website or social profile URL (`POST /account/index` is free) and poll until `status` is `"ready"`:
|
|
217
217
|
|
|
218
218
|
```ts
|
|
219
|
-
const indexed = await client.
|
|
219
|
+
const indexed = await client.account.index({
|
|
220
220
|
websiteUrl: "https://www.on.com",
|
|
221
221
|
});
|
|
222
222
|
|
|
@@ -224,12 +224,12 @@ const indexed = await client.indexing.indexBrand({
|
|
|
224
224
|
let status = indexed.status;
|
|
225
225
|
while (status === "indexing") {
|
|
226
226
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
227
|
-
const check = await client.
|
|
227
|
+
const check = await client.account.indexStatus({ id: indexed.brandId });
|
|
228
228
|
status = check.status;
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
if (status === "ready" || status === "already_exists") {
|
|
232
|
-
const account = await client.
|
|
232
|
+
const account = await client.account.get({ id: indexed.brandId });
|
|
233
233
|
console.log("Indexed account:", account.name);
|
|
234
234
|
}
|
|
235
235
|
```
|
|
@@ -239,7 +239,7 @@ if (status === "ready" || status === "already_exists") {
|
|
|
239
239
|
Check your team's remaining monthly credits and current billing window (free call):
|
|
240
240
|
|
|
241
241
|
```ts
|
|
242
|
-
const usage = await client.
|
|
242
|
+
const usage = await client.getCreditUsage();
|
|
243
243
|
console.log(`Remaining: ${usage.remainingCredits} / ${usage.planCredits}`);
|
|
244
244
|
```
|
|
245
245
|
|
|
@@ -249,17 +249,17 @@ console.log(`Remaining: ${usage.remainingCredits} / ${usage.planCredits}`);
|
|
|
249
249
|
|
|
250
250
|
| SDK Method | HTTP Endpoint | Cost | Rate Limit |
|
|
251
251
|
| --- | --- | --- | --- |
|
|
252
|
-
| `client.
|
|
253
|
-
| `client.
|
|
254
|
-
| `client.
|
|
255
|
-
| `client.
|
|
256
|
-
| `client.
|
|
257
|
-
| `client.
|
|
258
|
-
| `client.
|
|
259
|
-
| `client.
|
|
260
|
-
| `client.
|
|
261
|
-
| `client.
|
|
262
|
-
| `client.
|
|
252
|
+
| `client.searchBrands(req)` | `POST /brands` | $0.0020 / brand returned | 120 / min |
|
|
253
|
+
| `client.searchCreators(req)` | `POST /creators` | $0.0020 / creator returned | 120 / min |
|
|
254
|
+
| `client.searchMedia(req)` | `POST /media` | $0.0010 / creative returned | 120 / min |
|
|
255
|
+
| `client.searchTaxonomies({ query })` | `GET /taxonomies` | Free | 120 / min |
|
|
256
|
+
| `client.getComments(req)` | `POST /comments` | $0.0100 / live page fetched | 20 / min |
|
|
257
|
+
| `client.account.get({ id })` | `GET /account/{id}` | $0.0020 / account returned | 120 / min |
|
|
258
|
+
| `client.account.insights(req)` | `GET /account/{id}/insights` | $0.0010 / cluster returned | 120 / min |
|
|
259
|
+
| `client.account.landingPages(req)` | `GET /account/{id}/landing-pages` | $0.0050 / landing page returned | 120 / min |
|
|
260
|
+
| `client.account.index(req)` | `POST /account/index` | Free | 50 / min |
|
|
261
|
+
| `client.account.indexStatus({ id })` | `GET /account/{id}/index-status` | Free | 300 / min |
|
|
262
|
+
| `client.getCreditUsage()` | `GET /team/credit-usage` | Free | 120 / min |
|
|
263
263
|
|
|
264
264
|
Full method signatures and parameter types are available in [`reference.md`](https://github.com/spyglass-so/spyglass-typescript/blob/main/reference.md) and at [docs.spyglass.so](https://docs.spyglass.so).
|
|
265
265
|
|
|
@@ -272,13 +272,13 @@ All request and response types are exported under the `spyglass` namespace:
|
|
|
272
272
|
```ts
|
|
273
273
|
import { spyglass } from "@spyglasshq/sdk";
|
|
274
274
|
|
|
275
|
-
const request: spyglass.
|
|
275
|
+
const request: spyglass.SearchMediaRequest = {
|
|
276
276
|
query: "summer sale",
|
|
277
277
|
channel: ["META_AD"],
|
|
278
278
|
limit: 25,
|
|
279
279
|
};
|
|
280
280
|
|
|
281
|
-
type MediaItem = spyglass.
|
|
281
|
+
type MediaItem = spyglass.SearchMediaResponse.Media.Item;
|
|
282
282
|
```
|
|
283
283
|
|
|
284
284
|
## Error Handling
|
|
@@ -289,7 +289,7 @@ When the API returns a non-2xx status code (`400`, `401`, `402` out of credits,
|
|
|
289
289
|
import { SpyglassError } from "@spyglasshq/sdk";
|
|
290
290
|
|
|
291
291
|
try {
|
|
292
|
-
await client.
|
|
292
|
+
await client.searchBrands({ names: ["Nike"], limit: 5 });
|
|
293
293
|
} catch (err) {
|
|
294
294
|
if (err instanceof SpyglassError) {
|
|
295
295
|
console.error("Status:", err.statusCode);
|
|
@@ -310,7 +310,7 @@ The SDK defaults to a **60-second timeout** and **2 automatic retries** with exp
|
|
|
310
310
|
```ts
|
|
311
311
|
const controller = new AbortController();
|
|
312
312
|
|
|
313
|
-
const response = await client.
|
|
313
|
+
const response = await client.searchMedia(
|
|
314
314
|
{ query: "protein bar", limit: 10 },
|
|
315
315
|
{
|
|
316
316
|
timeoutInSeconds: 30,
|
|
@@ -326,8 +326,8 @@ const response = await client.search.getMedia(
|
|
|
326
326
|
Chain `.withRawResponse()` on any request promise to inspect HTTP status codes and headers alongside parsed data:
|
|
327
327
|
|
|
328
328
|
```ts
|
|
329
|
-
const { data, rawResponse } = await client
|
|
330
|
-
.
|
|
329
|
+
const { data, rawResponse } = await client
|
|
330
|
+
.searchBrands({ names: ["Nike"], limit: 1 })
|
|
331
331
|
.withRawResponse();
|
|
332
332
|
|
|
333
333
|
console.log(data.brands);
|
|
@@ -336,11 +336,9 @@ console.log(rawResponse.headers.get("retry-after"));
|
|
|
336
336
|
|
|
337
337
|
### Tree-Shakeable Subpackage Imports
|
|
338
338
|
|
|
339
|
-
Import
|
|
339
|
+
Import the `account` resource client directly for minimal bundle sizes:
|
|
340
340
|
|
|
341
341
|
```ts
|
|
342
|
-
import { SearchClient } from "@spyglasshq/sdk/search";
|
|
343
|
-
import { IndexingClient } from "@spyglasshq/sdk/indexing";
|
|
344
342
|
import { AccountClient } from "@spyglasshq/sdk/account";
|
|
345
343
|
```
|
|
346
344
|
|
package/dist/cjs/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.1.
|
|
1
|
+
export declare const SDK_VERSION = "0.1.4";
|
package/dist/cjs/version.js
CHANGED
package/dist/esm/version.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.1.
|
|
1
|
+
export declare const SDK_VERSION = "0.1.4";
|
package/dist/esm/version.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const SDK_VERSION = "0.1.
|
|
1
|
+
export const SDK_VERSION = "0.1.4";
|