Menú de la documentación

Desarrolladores

Publicar en tu propia API

Contrato HTTP que debe implementar tu web para que Blogenia le envíe los artículos: rutas, cabeceras, cuerpo, respuesta, tiempos y reintentos, con un receptor de ejemplo.

Ver como Markdown

Si tu web tiene su propia API, Blogenia puede publicar en ella cada artículo: lo crea al publicarlo, lo actualiza cuando lo editas y lo retira si lo despublicas o lo borras. Tu web recibe el artículo en HTML y decide cómo mostrarlo.

Si tu web es WordPress no necesitas esto: elige WordPress en la misma pantalla.

Conectar tu API

  1. En el panel, abre Blog y la pestaña Publicación. Solo el propietario de la cuenta puede configurarla.
  2. Elige API propia e indica la dirección de tu web, la clave de acceso y, si cambian, las rutas.
  3. Guarda y comprueba la conexión.
CampoReglas
Dirección de la webhttps, sin usuario, parámetros ni fragmento, y puerto 443. Debe ser una dirección pública.
Clave de accesoSe envía como Authorization: Bearer <clave>. Se guarda cifrada y no se vuelve a mostrar.
Ruta de artículosPor defecto /articles. Debe empezar por / y llevar solo letras, números, _, - y /.
Ruta de comprobaciónPor defecto /health. Mismas reglas.

Lo que debe implementar tu API

OperaciónPeticiónCuándo
ComprobarGET {ruta de comprobación}Al comprobar la conexión.
CrearPOST {ruta de artículos}Se publica un artículo por primera vez.
ActualizarPUT {ruta de artículos}/{id}Se edita un artículo ya publicado.
DespublicarPUT {ruta de artículos}/{id} con status: "draft"El artículo deja de estar publicado.
BorrarDELETE {ruta de artículos}/{id}Se borra el artículo en Blogenia.
ConsultarGET {ruta de artículos}/{id}Solo al conciliar a mano una creación dudosa (ver más abajo).

{id} es el identificador que tu API devolvió al crear el artículo.

Cabeceras

CabeceraValor
AuthorizationBearer <clave de acceso>
Acceptapplication/json
Content-Typeapplication/json
Idempotency-KeyEn POST, PUT y DELETE: 64 caracteres hexadecimales. Los reintentos de la misma operación llevan la misma clave.

Cuerpo de POST y PUT

Campos

CampoTipoDescripción
sourceIdstringUUID estable del artículo en Blogenia. Úsalo para no crear duplicados.
titlestringTítulo.
slugstringSlug del artículo.
contentstringContenido en HTML. Los enlaces a otros artículos ya publicados en tu API apuntan a su url; los enlaces a artículos aún no publicados allí llegan sin href.
excerptstringExtracto. Cadena vacía si no tiene.
statusstringpublished, o draft al despublicar.

DELETE no lleva cuerpo.

Tu respuesta

Responde con un código 2xx y un objeto JSON. GET de comprobación solo necesita un objeto JSON cualquiera.

Campos de la respuesta a POST y PUT

CampoTipoDescripción
idstring | numberIdentificador del artículo en tu API: un entero positivo o un texto de hasta 200 caracteres con letras, números, _ y -. En PUT debe ser el mismo del que está en la ruta.
urlstringOpcional. URL pública del artículo en tu web. Solo se guarda si es https, del mismo origen que la dirección configurada y de menos de 2048 caracteres.
  • DELETE: cualquier 2xx vale (también sin cuerpo). 404 y 410 se tratan como «ya borrado».
  • No seguimos redirecciones: un 3xx cuenta como error. Configura la dirección definitiva.
Cuerpo
{
  "sourceId": "0b8e2f6c-6d63-4d0e-9c1a-5d8f3c1d7a11",
  "title": "¿Cuánto cuesta reformar una cocina?",
  "slug": "cuanto-cuesta-reformar-una-cocina",
  "content": "<h2>Precio medio</h2><p>…</p>",
  "excerpt": "Precios orientativos y qué incluye cada partida.",
  "status": "published"
}
Respuesta
{
  "id": "42",
  "url": "https://tuweb.example/blog/cuanto-cuesta-reformar-una-cocina"
}

Tiempos, tamaños y reintentos

ConceptoValor
Tiempo máximo por petición15 segundos.
Cuerpo de la peticiónHasta 2 MiB.
RespuestaHasta 256 KB.
Actualizar, despublicar y borrarUn error de red, un 5xx o un 429 se reintenta solo, hasta 3 intentos en total: tras 1 y 2 minutos. Otros 4xx no se reintentan.
CrearUn 429 se reintenta igual; otro 4xx es un fallo definitivo. Un error de red o un 5xx no se reintenta: Blogenia no sabe si tu API llegó a crear el artículo y pide al propietario que lo revise en el panel antes de repetir.

Un fallo no automático se puede reintentar a mano desde el artículo en el panel.

Creaciones dudosas

Si un POST termina en error de red o 5xx, el propietario revisa en tu web si el artículo se creó. Si existe, indica su id en el panel y Blogenia lo enlaza tras comprobar que GET {ruta de artículos}/{id} devuelve el mismo id y el mismo slug. Implementa ese GET y haz el POST idempotente por sourceId o Idempotency-Key para evitar duplicados.

Receptor de ejemplo

Un servidor Express mínimo que cumple el contrato. Guarda los artículos en memoria: úsalo como punto de partida.

Node.js con Express
import express from 'express';

const TOKEN = process.env.BLOGENIA_TOKEN; // la clave de acceso que pegas en Blogenia
const articles = new Map(); // id -> artículo
const bySource = new Map(); // sourceId -> id
let nextId = 1;

const app = express();
app.use(express.json({ limit: '3mb' }));

// Autenticación Bearer
app.use((req, res, next) => {
  if (req.get('authorization') !== 'Bearer ' + TOKEN) return res.sendStatus(401);
  next();
});

// Ruta de comprobación
app.get('/health', (_req, res) => res.json({ ok: true }));

// Crear (idempotente por sourceId)
app.post('/articles', (req, res) => {
  const { sourceId, title, slug, content, excerpt, status } = req.body;
  let id = bySource.get(sourceId);
  if (!id) {
    id = String(nextId++);
    bySource.set(sourceId, id);
  }
  articles.set(id, { id, sourceId, title, slug, content, excerpt, status });
  res.status(201).json({ id, url: 'https://tuweb.example/blog/' + slug });
});

// Consultar (lo usa Blogenia al conciliar)
app.get('/articles/:id', (req, res) => {
  const a = articles.get(req.params.id);
  if (!a) return res.sendStatus(404);
  res.json({ id: a.id, slug: a.slug, url: 'https://tuweb.example/blog/' + a.slug });
});

// Actualizar o despublicar (status: "draft")
app.put('/articles/:id', (req, res) => {
  if (!articles.has(req.params.id)) return res.sendStatus(404);
  const { sourceId, title, slug, content, excerpt, status } = req.body;
  const id = req.params.id;
  articles.set(id, { id, sourceId, title, slug, content, excerpt, status });
  res.json({ id, url: 'https://tuweb.example/blog/' + slug });
});

// Borrar
app.delete('/articles/:id', (req, res) => {
  articles.delete(req.params.id);
  res.sendStatus(204);
});

app.listen(3000);