@graph8/sdk 0.295.2 → 0.303.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/docs/api/seo.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /* Generated by sdk/js/scripts/generate-agent-docs.ts from developer-contract/openapi.json. Regenerated on every build. */
2
2
 
3
3
  /**
4
- * Types for `g8.api.seo` (SEO): 11 operations.
4
+ * Types for `g8.api.seo` (SEO): 14 operations.
5
5
  *
6
6
  * For reading. In code, import from the package instead:
7
7
  * import type { ApiInput, ApiOutput, G8Contract } from "@graph8/sdk";
@@ -18,7 +18,10 @@ export interface SeoMembers {
18
18
  getSeoDomainBacklinks: "get_seo_domain_backlinks_seo_domains__domain__backlinks_get";
19
19
  getSeoDomainOverview: "get_seo_domain_overview_seo_domains__domain__overview_get";
20
20
  getSeoRankHistory: "get_seo_rank_history_seo_rank_tracking__keyword_id__history_get";
21
+ getSeoTrackedDomain: "get_seo_tracked_domain_seo_domains_tracked__domain__get";
21
22
  listSeoAudits: "list_seo_audits_seo_audits_get";
23
+ listSeoDomainPages: "list_seo_domain_pages_seo_domains_tracked__domain__pages_get";
24
+ listSeoTrackedDomains: "list_seo_tracked_domains_seo_domains_tracked_get";
22
25
  listSeoTrackedKeywords: "list_seo_tracked_keywords_seo_rank_tracking_get";
23
26
  removeSeoTrackedKeywords: "remove_seo_tracked_keywords_seo_rank_tracking_keywords_remove_post";
24
27
  researchSeoKeywords: "research_seo_keywords_seo_keywords_research_post";
@@ -115,6 +118,23 @@ export interface SeoOperations {
115
118
  };
116
119
  output: ApiResponse_SeoRankHistory_;
117
120
  };
121
+ /**
122
+ * GET /seo/domains/tracked/{domain}
123
+ * Get Seo Tracked Domain
124
+ * tier: read · scope: intent:read
125
+ */
126
+ get_seo_tracked_domain_seo_domains_tracked__domain__get: {
127
+ input: {
128
+ path: {
129
+ /** A saved domain from `GET /seo/domains/tracked`. */
130
+ domain: string;
131
+ };
132
+ headers?: {
133
+ "X-Target-Org-Id"?: string | null;
134
+ };
135
+ };
136
+ output: ApiResponse_SeoTrackedDomainDetail_;
137
+ };
118
138
  /**
119
139
  * GET /seo/audits
120
140
  * List Seo Audits
@@ -131,6 +151,47 @@ export interface SeoOperations {
131
151
  };
132
152
  output: ApiResponse_List_SeoAudit__;
133
153
  };
154
+ /**
155
+ * GET /seo/domains/tracked/{domain}/pages
156
+ * List Seo Domain Pages
157
+ * tier: read · scope: intent:read
158
+ */
159
+ list_seo_domain_pages_seo_domains_tracked__domain__pages_get: {
160
+ input: {
161
+ path: {
162
+ /** A saved domain from `GET /seo/domains/tracked`. */
163
+ domain: string;
164
+ };
165
+ query?: {
166
+ /** Rows to skip (the saved pages are capped at 1,000). */
167
+ offset?: number;
168
+ /** Rows to return. */
169
+ limit?: number;
170
+ /** Sort column: estimated_traffic, ranking_keywords_count, best_position, url, traffic_change_30d or audit_issues. */
171
+ sort?: string;
172
+ order?: "asc" | "desc";
173
+ /** Only pages whose URL contains this text. */
174
+ q?: string | null;
175
+ };
176
+ headers?: {
177
+ "X-Target-Org-Id"?: string | null;
178
+ };
179
+ };
180
+ output: ApiResponse_SeoDomainPages_;
181
+ };
182
+ /**
183
+ * GET /seo/domains/tracked
184
+ * List Seo Tracked Domains
185
+ * tier: read · scope: intent:read
186
+ */
187
+ list_seo_tracked_domains_seo_domains_tracked_get: {
188
+ input: {
189
+ headers?: {
190
+ "X-Target-Org-Id"?: string | null;
191
+ };
192
+ };
193
+ output: ApiResponse_SeoTrackedDomains_;
194
+ };
134
195
  /**
135
196
  * GET /seo/rank-tracking
136
197
  * List Seo Tracked Keywords
@@ -206,7 +267,7 @@ export interface SeoOperations {
206
267
  };
207
268
  }
208
269
 
209
- // 27 schemas referenced above (the same as G8Contract.<Name>).
270
+ // 37 schemas referenced above (the same as G8Contract.<Name>).
210
271
 
211
272
  export interface ApiResponse_List_SeoAudit__ {
212
273
  data: Array<SeoAudit>;
@@ -238,6 +299,11 @@ export interface ApiResponse_SeoDomainOverviewResponse_ {
238
299
  pagination?: PaginationMeta | null;
239
300
  }
240
301
 
302
+ export interface ApiResponse_SeoDomainPages_ {
303
+ data: SeoDomainPages;
304
+ pagination?: PaginationMeta | null;
305
+ }
306
+
241
307
  export interface ApiResponse_SeoRankHistory_ {
242
308
  data: SeoRankHistory;
243
309
  pagination?: PaginationMeta | null;
@@ -253,6 +319,16 @@ export interface ApiResponse_SeoResearchKeywordsResponse_ {
253
319
  pagination?: PaginationMeta | null;
254
320
  }
255
321
 
322
+ export interface ApiResponse_SeoTrackedDomainDetail_ {
323
+ data: SeoTrackedDomainDetail;
324
+ pagination?: PaginationMeta | null;
325
+ }
326
+
327
+ export interface ApiResponse_SeoTrackedDomains_ {
328
+ data: SeoTrackedDomains;
329
+ pagination?: PaginationMeta | null;
330
+ }
331
+
256
332
  export interface PaginationMeta {
257
333
  /** Whether there are more pages */
258
334
  has_next: boolean;
@@ -335,6 +411,16 @@ export interface SeoBacklinksOverview {
335
411
  total_backlinks?: number | null;
336
412
  }
337
413
 
414
+ /**
415
+ * Mirrors `DomainChangeDTO`: the current snapshot against the one nearest
416
+ * 30 days back. `traffic_pct` is null when the baseline traffic was zero.
417
+ */
418
+ export interface SeoDomainChange {
419
+ keywords_delta?: number | null;
420
+ since?: string | null;
421
+ traffic_pct?: number | null;
422
+ }
423
+
338
424
  /**
339
425
  * Mirrors `DomainOverviewResponse`. `data_freshness` labels how old the
340
426
  * provider's view of the domain is - research surfaces must say.
@@ -346,6 +432,29 @@ export interface SeoDomainOverviewResponse {
346
432
  top_pages: Array<Record<string, unknown>>;
347
433
  }
348
434
 
435
+ /** Mirrors `DomainPageDTO`. */
436
+ export interface SeoDomainPage {
437
+ audit_issues?: number | null;
438
+ best_position?: number | null;
439
+ estimated_traffic: number;
440
+ ranking_keywords_count: number;
441
+ top_keyword?: string | null;
442
+ traffic_change_30d?: number | null;
443
+ url: string;
444
+ }
445
+
446
+ /**
447
+ * Mirrors `DomainPagesResponse`. `refreshed_at` is null when the pages
448
+ * were never fetched; `total` counts every saved page, `rows` is one page.
449
+ */
450
+ export interface SeoDomainPages {
451
+ audit_completed_at?: string | null;
452
+ cap: number;
453
+ refreshed_at?: string | null;
454
+ rows: Array<SeoDomainPage>;
455
+ total: number;
456
+ }
457
+
349
458
  /** Mirrors `KeywordRow`. */
350
459
  export interface SeoKeywordRow {
351
460
  competition?: number;
@@ -437,6 +546,64 @@ export interface SeoTrackKeywordItem {
437
546
  search_volume?: number | null;
438
547
  }
439
548
 
549
+ /**
550
+ * Mirrors `TrackedDomainDTO`. `kind` is `own` for the organisation's own
551
+ * sites and `competitor` for the Radar competitors shown beside them.
552
+ */
553
+ export interface SeoTrackedDomain {
554
+ change_30d?: SeoDomainChange | null;
555
+ domain: string;
556
+ is_primary?: boolean;
557
+ kind: "own" | "competitor";
558
+ metrics?: SeoTrackedDomainMetrics | null;
559
+ name?: string | null;
560
+ snapshot_at?: string | null;
561
+ }
562
+
563
+ /**
564
+ * Mirrors `TrackedDomainDetailResponse`: one domain's saved snapshot,
565
+ * rendered without any paid call. Empty until the first refresh in the app.
566
+ */
567
+ export interface SeoTrackedDomainDetail {
568
+ backlinks?: SeoBacklinksOverview | null;
569
+ change_30d?: SeoDomainChange | null;
570
+ data_freshness?: string;
571
+ domain: string;
572
+ is_primary?: boolean;
573
+ kind: "own" | "competitor";
574
+ metrics?: SeoTrackedDomainMetrics | null;
575
+ name?: string | null;
576
+ overview?: Record<string, unknown> | null;
577
+ refreshed?: boolean;
578
+ snapshot_at?: string | null;
579
+ top_keywords?: Array<Record<string, unknown>>;
580
+ top_pages?: Array<Record<string, unknown>>;
581
+ }
582
+
583
+ /** Mirrors `TrackedDomainMetricsDTO`. */
584
+ export interface SeoTrackedDomainMetrics {
585
+ authority_score?: number | null;
586
+ estimated_traffic?: number | null;
587
+ organic_keywords?: number | null;
588
+ referring_domains?: number | null;
589
+ top3_positions?: number | null;
590
+ }
591
+
592
+ /**
593
+ * Mirrors `TrackedDomainsResponse`: the saved domains (own first, primary
594
+ * first, then competitors) plus the credit price of each paid refresh, so a
595
+ * caller can quote the cost before anyone asks for one.
596
+ */
597
+ export interface SeoTrackedDomains {
598
+ domains: Array<SeoTrackedDomain>;
599
+ max_own_domains: number;
600
+ page_keywords_credits: number;
601
+ page_keywords_limit: number;
602
+ pages_cap: number;
603
+ pages_max_credits: number;
604
+ refresh_credits: number;
605
+ }
606
+
440
607
  /** Mirrors `TrackedKeywordDTO`. */
441
608
  export interface SeoTrackedKeyword {
442
609
  cadence: string;
package/docs/api/seo.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # `g8.api.seo`: SEO
4
4
 
5
- 11 operations (5 read, 2 write, 4 billable).
5
+ 14 operations (8 read, 2 write, 4 billable).
6
6
 
7
7
  No hand-written client covers this area. Call it through `g8.api.seo.*` as shown below, or by operationId with `g8.api.call(operationId, input)`.
8
8
 
@@ -27,7 +27,10 @@ Exact TypeScript types for every operation on this page, and every schema they u
27
27
  | [`getSeoDomainBacklinks`](#op-getseodomainbacklinks) | `GET /api/v1/seo/domains/{domain}/backlinks` | billable | `intent:run` | Get Seo Domain Backlinks |
28
28
  | [`getSeoDomainOverview`](#op-getseodomainoverview) | `GET /api/v1/seo/domains/{domain}/overview` | billable | `intent:run` | Get Seo Domain Overview |
29
29
  | [`getSeoRankHistory`](#op-getseorankhistory) | `GET /api/v1/seo/rank-tracking/{keyword_id}/history` | read | `intent:read` | Get Seo Rank History |
30
+ | [`getSeoTrackedDomain`](#op-getseotrackeddomain) | `GET /api/v1/seo/domains/tracked/{domain}` | read | `intent:read` | Get Seo Tracked Domain |
30
31
  | [`listSeoAudits`](#op-listseoaudits) | `GET /api/v1/seo/audits` | read | `intent:read` | List Seo Audits |
32
+ | [`listSeoDomainPages`](#op-listseodomainpages) | `GET /api/v1/seo/domains/tracked/{domain}/pages` | read | `intent:read` | List Seo Domain Pages |
33
+ | [`listSeoTrackedDomains`](#op-listseotrackeddomains) | `GET /api/v1/seo/domains/tracked` | read | `intent:read` | List Seo Tracked Domains |
31
34
  | [`listSeoTrackedKeywords`](#op-listseotrackedkeywords) | `GET /api/v1/seo/rank-tracking` | read | `intent:read` | List Seo Tracked Keywords |
32
35
  | [`removeSeoTrackedKeywords`](#op-removeseotrackedkeywords) | `POST /api/v1/seo/rank-tracking/keywords/remove` | write | `intent:write` | Remove Seo Tracked Keywords |
33
36
  | [`researchSeoKeywords`](#op-researchseokeywords) | `POST /api/v1/seo/keywords/research` | billable | `intent:run` | Research Seo Keywords |
@@ -258,6 +261,59 @@ const result = await g8.api.seo.getSeoRankHistory({ path: { keyword_id: "0000000
258
261
 
259
262
  ---
260
263
 
264
+ <a id="op-getseotrackeddomain"></a>
265
+
266
+ ### `g8.api.seo.getSeoTrackedDomain(input)`
267
+
268
+ **Get Seo Tracked Domain**
269
+
270
+ - HTTP: `GET /api/v1/seo/domains/tracked/{domain}`
271
+ - operationId: `get_seo_tracked_domain_seo_domains_tracked__domain__get` (also callable as `g8.api.call("get_seo_tracked_domain_seo_domains_tracked__domain__get", input)`)
272
+ - Tier: `read`: reads data; safe to call and to retry
273
+ - API-key scope: `intent:read`
274
+
275
+ SPENDS NOTHING. One saved domain's snapshot: overview, top keywords, top pages, backlinks.
276
+
277
+ Rendered from what the app last stored; it never calls the provider. 404
278
+ for a domain this organisation does not track. `snapshot_at` says how
279
+ old the snapshot is; it is null until the domain is first refreshed.
280
+
281
+ **Input**
282
+
283
+ | Field | Type | Required | Description |
284
+ |---|---|---|---|
285
+ | `path.domain` | `string` | yes | A saved domain from `GET /seo/domains/tracked`. |
286
+
287
+ **Returns** `ApiResponse_SeoTrackedDomainDetail_`: the envelope `{ data: SeoTrackedDomainDetail, ... }`. `g8.api` returns the envelope as-is, so read `result.data`.
288
+
289
+ Other envelope fields: `pagination` (PaginationMeta).
290
+
291
+ `SeoTrackedDomainDetail` fields:
292
+
293
+ | Field | Type | Required | Description |
294
+ |---|---|---|---|
295
+ | `domain` | `string` | yes | |
296
+ | `kind` | `"own" \| "competitor"` | yes | |
297
+ | `backlinks` | `SeoBacklinksOverview \| null` | no | |
298
+ | `change_30d` | `SeoDomainChange \| null` | no | |
299
+ | `data_freshness` | `string` | no | default `"labs-30-90d"` |
300
+ | `is_primary` | `boolean` | no | default `false` |
301
+ | `metrics` | `SeoTrackedDomainMetrics \| null` | no | |
302
+ | `name` | `string \| null` | no | |
303
+ | `overview` | `Record<string, unknown> \| null` | no | |
304
+ | `refreshed` | `boolean` | no | default `false` |
305
+ | `snapshot_at` | `string (date-time) \| null` | no | |
306
+ | `top_keywords` | `Array<Record<string, unknown>>` | no | default `[]` |
307
+ | `top_pages` | `Array<Record<string, unknown>>` | no | default `[]` |
308
+
309
+ **Example**
310
+
311
+ ```ts
312
+ const result = await g8.api.seo.getSeoTrackedDomain({ path: { domain: "acme.com" } });
313
+ ```
314
+
315
+ ---
316
+
261
317
  <a id="op-listseoaudits"></a>
262
318
 
263
319
  ### `g8.api.seo.listSeoAudits(input?)`
@@ -306,6 +362,102 @@ const result = await g8.api.seo.listSeoAudits();
306
362
 
307
363
  ---
308
364
 
365
+ <a id="op-listseodomainpages"></a>
366
+
367
+ ### `g8.api.seo.listSeoDomainPages(input)`
368
+
369
+ **List Seo Domain Pages**
370
+
371
+ - HTTP: `GET /api/v1/seo/domains/tracked/{domain}/pages`
372
+ - operationId: `list_seo_domain_pages_seo_domains_tracked__domain__pages_get` (also callable as `g8.api.call("list_seo_domain_pages_seo_domains_tracked__domain__pages_get", input)`)
373
+ - Tier: `read`: reads data; safe to call and to retry
374
+ - API-key scope: `intent:read`
375
+
376
+ SPENDS NOTHING. The saved ranking pages of a tracked domain, paged and sorted.
377
+
378
+ Read only: it never calls the provider. `refreshed_at` is null when the
379
+ pages were never fetched (fetching them is a paid action in the app).
380
+ An unknown sort column is a 422 naming the allowed ones.
381
+
382
+ **Input**
383
+
384
+ | Field | Type | Required | Description |
385
+ |---|---|---|---|
386
+ | `path.domain` | `string` | yes | A saved domain from `GET /seo/domains/tracked`. |
387
+ | `query.offset` | `integer` | no | Rows to skip (the saved pages are capped at 1,000). default `0` |
388
+ | `query.limit` | `integer` | no | Rows to return. default `50` |
389
+ | `query.sort` | `string` | no | Sort column: estimated_traffic, ranking_keywords_count, best_position, url, traffic_change_30d or audit_issues. default `"estimated_traffic"` |
390
+ | `query.order` | `"asc" \| "desc"` | no | default `"desc"` |
391
+ | `query.q` | `string \| null` | no | Only pages whose URL contains this text. |
392
+
393
+ **Returns** `ApiResponse_SeoDomainPages_`: the envelope `{ data: SeoDomainPages, ... }`. `g8.api` returns the envelope as-is, so read `result.data`.
394
+
395
+ Other envelope fields: `pagination` (PaginationMeta).
396
+
397
+ `SeoDomainPages` fields:
398
+
399
+ | Field | Type | Required | Description |
400
+ |---|---|---|---|
401
+ | `cap` | `integer` | yes | |
402
+ | `rows` | `Array<SeoDomainPage>` | yes | |
403
+ | `total` | `integer` | yes | |
404
+ | `audit_completed_at` | `string (date-time) \| null` | no | |
405
+ | `refreshed_at` | `string (date-time) \| null` | no | |
406
+
407
+ **Example**
408
+
409
+ ```ts
410
+ const result = await g8.api.seo.listSeoDomainPages({ path: { domain: "acme.com" } });
411
+ ```
412
+
413
+ ---
414
+
415
+ <a id="op-listseotrackeddomains"></a>
416
+
417
+ ### `g8.api.seo.listSeoTrackedDomains(input?)`
418
+
419
+ **List Seo Tracked Domains**
420
+
421
+ - HTTP: `GET /api/v1/seo/domains/tracked`
422
+ - operationId: `list_seo_tracked_domains_seo_domains_tracked_get` (also callable as `g8.api.call("list_seo_tracked_domains_seo_domains_tracked_get", input)`)
423
+ - Tier: `read`: reads data; safe to call and to retry
424
+ - API-key scope: `intent:read`
425
+
426
+ SPENDS NOTHING. The SEO overview: every saved domain with its last snapshot.
427
+
428
+ Own domains first (the primary one first), then the Radar competitors
429
+ shown beside them, each with its saved metrics and 30-day change. Also
430
+ carries what each PAID refresh would cost (`refresh_credits`,
431
+ `pages_max_credits`, `page_keywords_credits`), so a caller can quote a
432
+ price without spending anything. An organisation whose SEO storage is
433
+ still provisioning gets an empty list, matching the app.
434
+
435
+ **Input**: none.
436
+
437
+ **Returns** `ApiResponse_SeoTrackedDomains_`: the envelope `{ data: SeoTrackedDomains, ... }`. `g8.api` returns the envelope as-is, so read `result.data`.
438
+
439
+ Other envelope fields: `pagination` (PaginationMeta).
440
+
441
+ `SeoTrackedDomains` fields:
442
+
443
+ | Field | Type | Required | Description |
444
+ |---|---|---|---|
445
+ | `domains` | `Array<SeoTrackedDomain>` | yes | |
446
+ | `max_own_domains` | `integer` | yes | |
447
+ | `page_keywords_credits` | `integer` | yes | |
448
+ | `page_keywords_limit` | `integer` | yes | |
449
+ | `pages_cap` | `integer` | yes | |
450
+ | `pages_max_credits` | `integer` | yes | |
451
+ | `refresh_credits` | `integer` | yes | |
452
+
453
+ **Example**
454
+
455
+ ```ts
456
+ const result = await g8.api.seo.listSeoTrackedDomains();
457
+ ```
458
+
459
+ ---
460
+
309
461
  <a id="op-listseotrackedkeywords"></a>
310
462
 
311
463
  ### `g8.api.seo.listSeoTrackedKeywords(input?)`
@@ -621,6 +773,34 @@ Mirrors `AuditStateDTO` - the plain-language, recovery-oriented view of where an
621
773
  | `recovery` | `string` | yes | Plain-language, safe next step (may be empty) |
622
774
  | `diagnostic` | `string \| null` | no | Secondary technical detail (raw provider text) |
623
775
 
776
+ <a id="type-seodomainchange"></a>
777
+
778
+ ### `SeoDomainChange`
779
+
780
+ Mirrors `DomainChangeDTO`: the current snapshot against the one nearest 30 days back. `traffic_pct` is null when the baseline traffic was zero.
781
+
782
+ | Field | Type | Required | Description |
783
+ |---|---|---|---|
784
+ | `keywords_delta` | `integer \| null` | no | |
785
+ | `since` | `string \| null` | no | |
786
+ | `traffic_pct` | `number \| null` | no | |
787
+
788
+ <a id="type-seodomainpage"></a>
789
+
790
+ ### `SeoDomainPage`
791
+
792
+ Mirrors `DomainPageDTO`.
793
+
794
+ | Field | Type | Required | Description |
795
+ |---|---|---|---|
796
+ | `estimated_traffic` | `number` | yes | |
797
+ | `ranking_keywords_count` | `integer` | yes | |
798
+ | `url` | `string` | yes | |
799
+ | `audit_issues` | `integer \| null` | no | |
800
+ | `best_position` | `integer \| null` | no | |
801
+ | `top_keyword` | `string \| null` | no | |
802
+ | `traffic_change_30d` | `number \| null` | no | |
803
+
624
804
  <a id="type-seokeywordrow"></a>
625
805
 
626
806
  ### `SeoKeywordRow`
@@ -658,3 +838,33 @@ Mirrors `TrackKeywordItem`.
658
838
  |---|---|---|---|
659
839
  | `keyword` | `string` | yes | min length 1, max length 500 |
660
840
  | `search_volume` | `integer \| null` | no | |
841
+
842
+ <a id="type-seotrackeddomain"></a>
843
+
844
+ ### `SeoTrackedDomain`
845
+
846
+ Mirrors `TrackedDomainDTO`. `kind` is `own` for the organisation's own sites and `competitor` for the Radar competitors shown beside them.
847
+
848
+ | Field | Type | Required | Description |
849
+ |---|---|---|---|
850
+ | `domain` | `string` | yes | |
851
+ | `kind` | `"own" \| "competitor"` | yes | |
852
+ | `change_30d` | `SeoDomainChange \| null` | no | |
853
+ | `is_primary` | `boolean` | no | default `false` |
854
+ | `metrics` | `SeoTrackedDomainMetrics \| null` | no | |
855
+ | `name` | `string \| null` | no | |
856
+ | `snapshot_at` | `string (date-time) \| null` | no | |
857
+
858
+ <a id="type-seotrackeddomainmetrics"></a>
859
+
860
+ ### `SeoTrackedDomainMetrics`
861
+
862
+ Mirrors `TrackedDomainMetricsDTO`.
863
+
864
+ | Field | Type | Required | Description |
865
+ |---|---|---|---|
866
+ | `authority_score` | `number \| null` | no | |
867
+ | `estimated_traffic` | `number \| null` | no | |
868
+ | `organic_keywords` | `integer \| null` | no | |
869
+ | `referring_domains` | `number \| null` | no | |
870
+ | `top3_positions` | `integer \| null` | no | |
@@ -1097,7 +1097,7 @@ export interface WorkOperations {
1097
1097
  };
1098
1098
  }
1099
1099
 
1100
- // 122 schemas referenced above (the same as G8Contract.<Name>).
1100
+ // 123 schemas referenced above (the same as G8Contract.<Name>).
1101
1101
 
1102
1102
  export interface ApiResponse_WorkActivityPage_ {
1103
1103
  data: WorkActivityPage;
@@ -1558,6 +1558,22 @@ export interface WorkChannelDeleteRequest {
1558
1558
  confirmationName: string;
1559
1559
  }
1560
1560
 
1561
+ /**
1562
+ * A channel's icon: a glyph on a color, an emoji, or an uploaded image.
1563
+ *
1564
+ * `glyph` and `color` are ids from the client's curated sets, never raw CSS
1565
+ * or SVG, so nothing a member stores can inject markup or styles into
1566
+ * another member's sidebar. An image is a Work attachment id, never a URL:
1567
+ * readability is re-checked on every read (`readable_attachment_ids`).
1568
+ */
1569
+ export interface WorkChannelIcon {
1570
+ attachmentId?: string | null;
1571
+ color?: string | null;
1572
+ emoji?: string | null;
1573
+ glyph?: string | null;
1574
+ type: "glyph" | "emoji" | "image";
1575
+ }
1576
+
1561
1577
  /** The channels this credential may read. */
1562
1578
  export interface WorkChannelList {
1563
1579
  /** Channels visible to the caller */
@@ -1591,6 +1607,7 @@ export interface WorkChannelSettingsRequest {
1591
1607
  confirmAgentAccess?: boolean;
1592
1608
  description?: string | null;
1593
1609
  displayName?: string | null;
1610
+ icon?: WorkChannelIcon | null;
1594
1611
  memberUserIds?: Array<string>;
1595
1612
  participantAgentIds?: Array<string>;
1596
1613
  visibility?: ("open" | "private") | null;
package/docs/api/work.md CHANGED
@@ -2791,6 +2791,7 @@ Body fields (`WorkChannelSettingsRequest`):
2791
2791
  | `body.confirmAgentAccess` | `boolean` | no | default `false` |
2792
2792
  | `body.description` | `string \| null` | no | max length 1000 |
2793
2793
  | `body.displayName` | `string \| null` | no | max length 255 |
2794
+ | `body.icon` | `WorkChannelIcon \| null` | no | |
2794
2795
  | `body.memberUserIds` | `Array<string>` | no | max items 100 |
2795
2796
  | `body.participantAgentIds` | `Array<string>` | no | max items 32 |
2796
2797
  | `body.visibility` | `"open" \| "private" \| null` | no | |
@@ -2983,6 +2984,20 @@ One Work channel as the room stores it.
2983
2984
  | `system` | `boolean \| null` | no | True for a built-in channel (`#work`, `#signals`) |
2984
2985
  | `visibility` | `string \| null` | no | `open` (self-serve joinable) or `private` (invite only) |
2985
2986
 
2987
+ <a id="type-workchannelicon"></a>
2988
+
2989
+ ### `WorkChannelIcon`
2990
+
2991
+ A channel's icon: a glyph on a color, an emoji, or an uploaded image. `glyph` and `color` are ids from the client's curated sets, never raw CSS or SVG, so nothing a member stores can inject markup or styles into another member's sidebar. An image is a Work attachment id, never a URL: readability is re-checked on every read (`readable_attachment_ids`).
2992
+
2993
+ | Field | Type | Required | Description |
2994
+ |---|---|---|---|
2995
+ | `type` | `"glyph" \| "emoji" \| "image"` | yes | |
2996
+ | `attachmentId` | `string \| null` | no | pattern `^[A-Za-z0-9-]{1,64}$` |
2997
+ | `color` | `string \| null` | no | pattern `^[a-z0-9-]{1,32}$` |
2998
+ | `emoji` | `string \| null` | no | min length 1, max length 16 |
2999
+ | `glyph` | `string \| null` | no | pattern `^[a-z0-9-]{1,40}$` |
3000
+
2986
3001
  <a id="type-workevent"></a>
2987
3002
 
2988
3003
  ### `WorkEvent`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graph8/sdk",
3
- "version": "0.295.2",
3
+ "version": "0.303.0",
4
4
  "description": "graph8 SDK - CRM, enrichment, sequences, campaigns, and tracking for B2B",
5
5
  "license": "MIT",
6
6
  "author": "graph8 <support@graph8.com> (https://graph8.com)",