Tags
Create localized topic labels for post discovery and editorial grouping.
Tags add flexible topic labels to posts. Use their shared IDs for assignments, and use localized variants for topic-page names, slugs, descriptions, and SEO fields.
Choose a surface
The API, Node SDK, and CLI manage the same tag concepts. Compare all Cli Blog tools.
| Action | HTTP API | Node SDK | CLI | Description |
|---|---|---|---|---|
| List | GET /v1/tags | blog.tags.list() or .paginate() | cli-blog tags list | Page through localized tags |
| Create | POST /v1/tags | blog.tags.create() | cli-blog tags create | Create a tag or localized variant |
| Retrieve | GET /v1/tags/{id} | blog.tags.get() | cli-blog tags get | Get a tag by shared ID or localized slug |
| Update | POST /v1/tags/{id} | blog.tags.update() | cli-blog tags update | Change localized tag fields |
| Delete | DELETE /v1/tags/{id} | blog.tags.delete() | cli-blog tags delete | Delete a localized tag |
Public and private keys can list and retrieve tags. Create, update, and delete actions require a private key with tag permission.
Use the REST API
Call the resource from any technology that can send HTTP requests. Use a public key for allowed delivery reads and a private key for content changes.
GET or POST https://api.cli-blog.com/v1/tagsChoose an API keyUse the CLI
Use the CLI for local work, continuous integration, and JSON automation. Configure a narrowly scoped key before running content-changing commands.
cli-blog tags list --locale en-US --jsonRead the CLI guideUse the Node SDK
Use the Node SDK in Node.js 20+ servers, scripts, continuous integration, and trusted agent environments. Its methods map to the same resource actions.
await blog.tags.list({ locale: "en-US" })Read the Node SDK guideUse the agent skill
Give the agent the Cli Blog skill and a result-focused instruction. The skill helps it choose the API, CLI, or SDK and keeps publishing behind an approval gate.
Find the Release notes tag in en-US. Create it if missing, then return its stable tag ID.Install the agent skillCreate a tag
Create a tag before assigning its shared ID through a post's tag_ids field:
curl "https://api.cli-blog.com/v1/tags" \
--header "x-api-key: $CLI_BLOG_PRIVATE_API_KEY" \
--header "content-type: application/json" \
--data '{
"name": "Release notes",
"slug": "release-notes",
"locale": "en-US",
"description": "Product, platform, and integration updates.",
"robots_index": true
}'The response returns the shared concept ID:
{
"id": "term_tag_3c09f1",
"object": "taxonomy_term",
"organization_id": "org_demo_acme",
"taxonomy_type": "tag",
"parent_taxonomy_term_id": null,
"locale": "en-US",
"name": "Release notes",
"slug": "release-notes",
"description": "Product, platform, and integration updates.",
"seo_title": null,
"seo_description": null,
"canonical_url": null,
"focus_keyphrase": null,
"seo_keywords": [],
"robots_index": true,
"robots_follow": true,
"open_graph_title": null,
"open_graph_description": null,
"open_graph_media_asset_id": null,
"twitter_title": null,
"twitter_description": null,
"twitter_media_asset_id": null,
"schema_type": "CollectionPage",
"metadata": {},
"created_at": "2026-07-11T17:15:00.000Z",
"updated_at": "2026-07-11T17:15:00.000Z"
}The SDK and CLI create the same resource:
import { CliBlog } from "@cli-blog/node";
const blog = new CliBlog({
apiKey: process.env.CLI_BLOG_PRIVATE_API_KEY!,
apiUrl: "https://api.cli-blog.com",
});
const tag = await blog.tags.create({
name: "Release notes",
locale: "en-US",
description: "Product, platform, and integration updates.",
});cli-blog tags create \
--name "Release notes" \
--locale en-US \
--description "Product, platform, and integration updates." \
--jsonList and retrieve tags
Cursor pagination is the preferred list mode. Set limit up to 100, then pass next_cursor as after. Use numbered pagination only when a tag manager requires exact totals. See Pagination.
Omit locale to use the organization's primary locale. Cli Blog does not fall back to another locale in V1. Add include=translations when the current view needs every localized variant.
const firstPage = await blog.tags.list({
locale: "en-US",
include: "translations",
limit: 50,
});
const tag = await blog.tags.get("release-notes", {
locale: "en-US",
include: "translations",
});cli-blog tags list --locale en-US --include translations --limit 50 --json
cli-blog tags get release-notes --locale en-US --jsonAdd a translation
Pass an existing shared tag ID as translation_of_id. Posts keep the same tag_ids assignment across translations.
await blog.tags.create({
name: "Notas de lanzamiento",
slug: "notas-de-lanzamiento",
locale: "es-MX",
translation_of_id: "term_tag_3c09f1",
description: "Actualizaciones del producto, la plataforma y las integraciones.",
});Update and delete a tag
Pass locale when an ID or slug has localized variants. Tags do not accept parent_taxonomy_term_id; use Categories for hierarchy.
await blog.tags.update(
"term_tag_3c09f1",
{ description: "Release notes for the product, API, SDK, and CLI." },
{ locale: "en-US" },
);
await blog.tags.delete("term_tag_3c09f1", { locale: "en-US" });cli-blog tags update term_tag_3c09f1 \
--locale en-US \
--description "Release notes for the product, API, SDK, and CLI." \
--json
cli-blog tags delete term_tag_3c09f1 --locale en-US --yesReview post assignments before deleting a tag.
Tag fields
| Field family | Fields and description |
|---|---|
| Identity | id, object, organization_id, and taxonomy_type identify the shared concept |
| Localization | locale, name, slug, description, and optional translations describe localized variants |
| Search and social | Search, canonical, robots, Open Graph, X/Twitter, keyword, and schema_type fields describe the topic archive |
| Integration data | metadata stores integration-defined JSON up to 32 KB when serialized |
| Timestamps | created_at and updated_at report ISO timestamps |
Common errors
| Status | Cause | Resolution |
|---|---|---|
400 | Unsupported locale, category-only parent field, or mixed pagination modes | Check the error param and remove unsupported fields |
401 | Missing or invalid API key | Send the organization key in x-api-key |
403 | Public key used for a write or private key lacks permission | Use a scoped private key |
404 | Shared ID or slug does not exist in the requested locale | Confirm the locale and identifier |
409 | Slug already exists in that locale | Choose a unique locale-scoped slug |
Complete API operations
The operation reference lists every path, locale control, include, request field, response field, and error schema. Use Try it to open the request runner.
List tags
List localized tags. Cursor pagination is the default; page and per_page opt into exact numbered pagination and cannot be combined with after or limit. Omitted locale uses the organization primary/default locale; v1 does not fall back across locales.
Authorization
ApiKeyAuth Organization API key. Each key selects exactly one organization; do not send an organization ID separately. Public keys use the cli_blog_pk_ prefix and are intended for published-content delivery reads. Private keys use the cli_blog_sk_ prefix, belong only in trusted environments, and are required for write, publish, delete, and editorial-state workflows when their scopes allow it.
In: header
Query Parameters
Opaque cursor returned by the previous tag list page.
Maximum tags to return. Defaults to 20. The maximum accepted value is 100.
One-based exact page number. Supplying page selects numbered pagination and cannot be combined with after or limit.
Items per numbered page. Requires page, defaults to 20, and cannot be combined with after or limit.
BCP 47 locale tag to list, for example en-US or es-MX. Categories and tags are shared concepts with localized variants; omitted locale uses organization defaults.
Optional related data to include. Use translations to see available localized variants.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/v1/tags"{ "object": "list", "has_more": true, "next_cursor": "string", "page": 0, "per_page": 0, "total_items": 0, "total_pages": 0, "data": [ { "id": "string", "object": "taxonomy_term", "organization_id": "string", "taxonomy_type": "string", "parent_taxonomy_term_id": "string", "locale": "string", "name": "string", "slug": "string", "description": "string", "seo_title": "string", "seo_description": "string", "canonical_url": "string", "focus_keyphrase": "string", "seo_keywords": [ "string" ], "robots_index": true, "robots_follow": true, "open_graph_title": "string", "open_graph_description": "string", "open_graph_media_asset_id": "string", "twitter_title": "string", "twitter_description": "string", "twitter_media_asset_id": "string", "schema_type": "string", "metadata": null, "created_at": "string", "updated_at": "string", "translations": [ { "id": "string", "locale": "string", "name": "string", "slug": "string" } ] } ]}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}Create a tag
Send a JSON body to create a localized tag. Its stable shared ID can be assigned to posts across locales. Omit locale to use the organization primary/default locale.
Authorization
ApiKeyAuth Organization API key. Each key selects exactly one organization; do not send an organization ID separately. Public keys use the cli_blog_pk_ prefix and are intended for published-content delivery reads. Private keys use the cli_blog_sk_ prefix, belong only in trusted environments, and are required for write, publish, delete, and editorial-state workflows when their scopes allow it.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/tags" \ -H "Content-Type: application/json" \ -d '{ "name": "string" }'{ "id": "string", "object": "taxonomy_term", "organization_id": "string", "taxonomy_type": "string", "parent_taxonomy_term_id": "string", "locale": "string", "name": "string", "slug": "string", "description": "string", "seo_title": "string", "seo_description": "string", "canonical_url": "string", "focus_keyphrase": "string", "seo_keywords": [ "string" ], "robots_index": true, "robots_follow": true, "open_graph_title": "string", "open_graph_description": "string", "open_graph_media_asset_id": "string", "twitter_title": "string", "twitter_description": "string", "twitter_media_asset_id": "string", "schema_type": "string", "metadata": null, "created_at": "string", "updated_at": "string", "translations": [ { "id": "string", "locale": "string", "name": "string", "slug": "string" } ]}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}Retrieve a tag
Retrieve a tag by its stable shared ID or locale-scoped slug. Omitted locale uses the organization primary/default locale; v1 does not automatically fall back to another locale.
Authorization
ApiKeyAuth Organization API key. Each key selects exactly one organization; do not send an organization ID separately. Public keys use the cli_blog_pk_ prefix and are intended for published-content delivery reads. Private keys use the cli_blog_sk_ prefix, belong only in trusted environments, and are required for write, publish, delete, and editorial-state workflows when their scopes allow it.
In: header
Path Parameters
Shared tag concept ID or locale-scoped slug.
Query Parameters
BCP 47 locale tag used for tag slug lookup.
Optional related data to include. Use translations to see available localized variants.
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/v1/tags/string"{ "id": "string", "object": "taxonomy_term", "organization_id": "string", "taxonomy_type": "string", "parent_taxonomy_term_id": "string", "locale": "string", "name": "string", "slug": "string", "description": "string", "seo_title": "string", "seo_description": "string", "canonical_url": "string", "focus_keyphrase": "string", "seo_keywords": [ "string" ], "robots_index": true, "robots_follow": true, "open_graph_title": "string", "open_graph_description": "string", "open_graph_media_asset_id": "string", "twitter_title": "string", "twitter_description": "string", "twitter_media_asset_id": "string", "schema_type": "string", "metadata": null, "created_at": "string", "updated_at": "string", "translations": [ { "id": "string", "locale": "string", "name": "string", "slug": "string" } ]}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}Update a tag
Send a JSON body to update a localized tag.
Authorization
ApiKeyAuth Organization API key. Each key selects exactly one organization; do not send an organization ID separately. Public keys use the cli_blog_pk_ prefix and are intended for published-content delivery reads. Private keys use the cli_blog_sk_ prefix, belong only in trusted environments, and are required for write, publish, delete, and editorial-state workflows when their scopes allow it.
In: header
Path Parameters
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/tags/string" \ -H "Content-Type: application/json" \ -d '{}'{ "id": "string", "object": "taxonomy_term", "organization_id": "string", "taxonomy_type": "string", "parent_taxonomy_term_id": "string", "locale": "string", "name": "string", "slug": "string", "description": "string", "seo_title": "string", "seo_description": "string", "canonical_url": "string", "focus_keyphrase": "string", "seo_keywords": [ "string" ], "robots_index": true, "robots_follow": true, "open_graph_title": "string", "open_graph_description": "string", "open_graph_media_asset_id": "string", "twitter_title": "string", "twitter_description": "string", "twitter_media_asset_id": "string", "schema_type": "string", "metadata": null, "created_at": "string", "updated_at": "string", "translations": [ { "id": "string", "locale": "string", "name": "string", "slug": "string" } ]}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}Delete a tag
Delete a localized tag.
Authorization
ApiKeyAuth Organization API key. Each key selects exactly one organization; do not send an organization ID separately. Public keys use the cli_blog_pk_ prefix and are intended for published-content delivery reads. Private keys use the cli_blog_sk_ prefix, belong only in trusted environments, and are required for write, publish, delete, and editorial-state workflows when their scopes allow it.
In: header
Path Parameters
Query Parameters
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X DELETE "https://example.com/v1/tags/string"{ "deleted": true, "id": "string"}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}{ "error": { "code": "invalid_request", "message": "string", "param": "string" }}