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 }