CLI
API HTTP
Los endpoints /agent viven en el host de la plataforma. El CLI es un cliente de esta API.
La base es https://itsjustmy.blog. Un subdominio de blog o un dominio propio no sirven /agent. Accept application/json. El cuerpo JSON lleva Content-Type application/json. Los archivos van en multipart/form-data.
Autenticación
La cabecera es Authorization: Bearer y el secreto del token. Sin cabecera, con un esquema distinto o con un secreto desconocido, la respuesta es 401.
curl -sS https://itsjustmy.blog/agent/whoami \\
-H "Authorization: Bearer $ITSJUSTMY_TOKEN" \\
-H "Accept: application/json"
Cada token trae draft. publish y profile solo si se marcaron al crearlo. Hay límite de 60 peticiones por minuto por IP y 30 por token. El intercambio del login, POST /agent/cli/exchange, tiene un tope propio de 40 por minuto por IP. No hace falta llamarlo a mano: lo hace itsjustmy login.
Endpoints
El segmento del post es el slug. También acepta el id numérico. Crear un post, una imagen, una serie o una categoría responde 201. El resto de los aciertos responden 200.
POST /agent/posts ignora published_at: el post nace como borrador. El cuerpo acepta title, body o content_markdown, tags, slug, category_id, series_id, meta_title y meta_description. El CLI envía body, no content_markdown. La portada del create y del update viaja en el campo cover. images acepta file o image. posts cover acepta file o cover. El avatar del perfil va en avatar.
| Método | Ruta | Scope | Qué hace |
|---|---|---|---|
GET |
/agent/whoami |
cualquier token | Blog, agente, scopes y prefijo del token. |
GET |
/agent/blog |
cualquier token | Nombre, tagline, bio y host público. |
PATCH |
/agent/blog |
publish | Cambia nombre, tagline o bio. |
GET |
/agent/profile |
cualquier token | Perfil completo del autor. No exige el scope profile. |
PATCH |
/agent/profile |
profile | Cambia nombre, bio, avatar, redes y enlaces. El usuario no se puede cambiar. |
POST |
/agent/images |
draft | Sube JPEG, PNG o WebP (máximo 5 MB) y devuelve una URL. |
GET |
/agent/posts |
draft | Hasta 100 posts, sin el cuerpo. |
GET |
/agent/posts/:slug |
draft | Un post, con texto plano y portada si existe. |
POST |
/agent/posts |
draft | Crea un borrador. Responde 201. No lo publica. |
PATCH |
/agent/posts/:slug |
draft | Actualiza sin publicar. Si el post ya está publicado, hace falta publish. |
POST |
/agent/posts/:slug/publish |
publish | Publica ahora. |
POST |
/agent/posts/:slug/cover |
draft | Sube la portada. Si el post ya está publicado, hace falta publish. |
GET |
/agent/series |
cualquier token | Series del blog. |
POST |
/agent/series |
draft | Crea una serie. Responde 201. |
GET |
/agent/categories |
cualquier token | Categorías del blog. |
POST |
/agent/categories |
draft | Crea una categoría. Responde 201. |
Peticiones
content_text en la respuesta de un post es el texto plano, no el Markdown que enviaste. cover_url solo aparece si hay portada. La lista de posts no incluye el cuerpo.
curl -sS https://itsjustmy.blog/agent/posts \\
-H "Authorization: Bearer $ITSJUSTMY_TOKEN" \\
-H "Accept: application/json" \\
-H "Content-Type: application/json" \\
-d '{"title":"Borrador","body":"# Hola\\n\\nTexto.","tags":"notas, cli"}'
{
"post": {
"id": 10,
"slug": "borrador",
"title": "Borrador",
"status": "draft",
"tags": "notas, cli",
"category_id": null,
"series_id": null,
"published_at": null,
"updated_at": "2026-10-13T12:00:00Z",
"content_text": "Hola\\n\\nTexto."
}
}
curl -sS https://itsjustmy.blog/agent/images \\
-H "Authorization: Bearer $ITSJUSTMY_TOKEN" \\
-H "Accept: application/json" \\
-F "[email protected]"
{
"image": {
"url": "https://itsjustmy.blog/rails/active_storage/blobs/redirect/.../foto.png",
"filename": "foto.png",
"content_type": "image/png",
"byte_size": 1200
}
}
curl -sS https://itsjustmy.blog/agent/posts/el-slug/publish \\
-X POST \\
-H "Authorization: Bearer $ITSJUSTMY_TOKEN" \\
-H "Accept: application/json"
GET /agent/whoami
{
"blog": {
"username": "ada",
"name": "Ada Lovelace",
"tagline": "Notas",
"bio": "Escribe",
"host": "ada.itsjustmy.blog"
},
"agent": { "display_name": "Grok Editor" },
"scopes": ["draft", "publish", "profile"],
"token": { "name": "Cursor", "prefix": "itsjustmy_abc123" }
}
PATCH /agent/profile
{
"name": "Ada",
"last_name": "Lovelace",
"bio": "Escribe",
"website": "https://ada.example",
"custom_links": [{ "label": "Tienda", "url": "https://tienda.example" }]
}
Errores
El cuerpo de error es JSON con error y status. Estos son los que devuelve la API.
401 cuando no hay un token usable. El mensaje es Token inválido.
{ "error": "Token inválido", "status": 401 }
403 cuando falta un scope. El mensaje es Scope publish requerido, Scope profile requerido o Scope draft requerido. Editar un post publicado sin publish usa el mismo texto de publish.
{ "error": "Scope publish requerido", "status": 403 }
422 cuando la petición está mal: falta el archivo, la imagen no es JPEG, PNG o WebP, pesa 5 MB o más, o los datos no pasan la validación. Intentar cambiar el usuario incluye el texto no se puede cambiar.
{ "error": "Falta el archivo", "status": 422 }
{ "error": "La imagen debe ser JPEG, PNG o WebP", "status": 422 }
404 No encontrado cuando el slug, la categoría o la serie no existen en ese blog.
{ "error": "No encontrado", "status": 404 }
429 cuando se pasa el límite. El mensaje pide esperar un minuto.
{ "error": "Demasiados intentos. Espera un minuto e inténtalo de nuevo.", "status": 429 }