@@ -86,6 +86,29 @@ const result = await spoo.links.bulk.setStatus(ids, "INACTIVE");
8686console .log (result .summary ); // { total, succeeded, failed }
8787```
8888
89+ ## Tags
90+
91+ Tags are labels you attach to links, at most 10 per link. Links point at
92+ tags by id, so renaming a tag shows up on every link at once.
93+
94+ ``` ts
95+ const launch = await spoo .tags .create ({ name: " launch" , color: " violet" , icon: " rocket" });
96+
97+ await spoo .links .create ({ long_url: " https://example.com/launch" , tag_ids: [launch .id ] });
98+ await spoo .links .update (id , { tag_ids: [launch .id ] }); // replaces the list; [] or null clears it
99+
100+ const tagged = await spoo .links .list ({
101+ filter: { tagNames: [" launch" , " q3" ], tagsMatch: " all" },
102+ });
103+
104+ await spoo .links .bulk .tags (ids , { add: [launch .id ], remove: [oldTag .id ] });
105+ ```
106+
107+ Every link carries its ` tags ` (id, name, color, icon). ` spoo.tags.list() `
108+ returns every tag with its link count, and ` spoo.tags.delete(id) ` removes the
109+ tag from every link that had it. Stats calls take ` tag ` (names) or ` tagId `
110+ (ids) to slice clicks to tagged links; see [ Analytics] ( #analytics ) .
111+
89112## Pagination
90113
91114Every list is a ` Page ` : use it directly, walk it by hand, or iterate items
@@ -105,6 +128,7 @@ const stats = await spoo.stats.get({
105128 startDate: new Date (" 2026-01-01" ),
106129 groupBy: [" time" , " country" ],
107130 device: [" mobile" ],
131+ tag: [" launch" ],
108132 timezone: " Asia/Kolkata" ,
109133});
110134
@@ -230,7 +254,7 @@ naming the endpoint so it gets a typed method.
230254
231255The SDK covers the third-party integration surface of the API: identity
232256read (` auth.me ` ), Sign in with Spoo, and the full data plane, meaning
233- shortening, link management, claims, bulk operations, analytics, file
257+ shortening, link management, tags, claims, bulk operations, analytics, file
234258exports, public link reads and the emoji alias catalogue.
235259
236260Deliberately out of scope: API key management, service health, the contact
@@ -248,7 +272,9 @@ exist for backward compatibility, not for new integrations.
248272| ` links.update ` , ` links.setStatus ` | ` PATCH /api/v1/urls/{id} ` , ` PATCH /api/v1/urls/{id}/status ` |
249273| ` links.delete ` , ` links.deleteByDomain ` | ` DELETE /api/v1/urls/{id} ` , ` DELETE /api/v1/urls?domain= ` |
250274| ` links.claim ` | ` POST /api/v1/urls/claim ` |
251- | ` links.bulk.delete ` , ` links.bulk.setStatus ` , ` links.bulk.setExpiry ` , ` links.bulk.setDomain ` | ` POST /api/v1/urls/bulk/* ` |
275+ | ` links.bulk.delete ` , ` links.bulk.setStatus ` , ` links.bulk.setExpiry ` , ` links.bulk.setDomain ` , ` links.bulk.tags ` | ` POST /api/v1/urls/bulk/* ` |
276+ | ` tags.list ` , ` tags.create ` | ` GET /api/v1/tags ` , ` POST /api/v1/tags ` |
277+ | ` tags.update ` , ` tags.delete ` | ` PATCH /api/v1/tags/{id} ` , ` DELETE /api/v1/tags/{id} ` |
252278| ` stats.get ` , ` stats.getForLink ` | ` GET /api/v1/stats ` , ` GET /api/v1/stats/links/{id} ` |
253279| ` stats.export ` , ` stats.exportForLink ` | ` GET /api/v1/export ` , ` GET /api/v1/export/links/{id} ` |
254280| ` public.stats ` , ` public.statsWithPassword ` | ` GET or POST /api/v1/public/stats/{code} ` |
0 commit comments