Esto es una traducción. La versión alemana es la vinculante: si este texto difiere de ella, se aplica el alemán. Puedes cambiar de idioma al pie de la página.
Contenido
Visión general
v2 es la API de tellmelo para tus propios programas. Cada petición lleva una clave, cada respuesta es JSON y cada lista se pagina de la misma manera. Lo que ocurre detrás de una clave pasa por las mismas reglas que un clic en la aplicación: límites de ritmo, suspensiones, derechos retirados y los ajustes de esta instancia valen aquí igual.
Cada ruta empieza por /api/v2 en la dirección de esta instancia, la que aparece en los ejemplos de esta página.
Las peticiones y las respuestas son JSON en UTF-8. Los nombres de campo, los códigos y los valores están en inglés y seguirán así.
Una clave actúa como tu cuenta y nunca más allá: lo que no puedes ver en la aplicación, tampoco lo puede leer ninguna clave.
https://tellmelo.com/api/v2
Inicio rápido
Crea una clave en «Ajustes → App y datos → API» y cópiala. Solo se muestra una vez.
Consulta con ella la raíz. La respuesta dice qué versión está funcionando, qué puede hacer la clave y cuántas peticiones le quedan en este minuto.
A partir de ahí todas las rutas funcionan igual: la clave en la cabecera, JSON de vuelta y, en las listas, items y next.
Para seguir: /me para tu propio perfil, /posts para lo público, /feed para lo que te muestra la aplicación.
Tu clave
Hay exactamente una clave por cuenta, ligada a tu identificador de usuario. Empieza por tm_key_, para que un escáner la reconozca donde no pinta nada. Se muestra una sola vez, en el momento en que se crea; después aquí solo queda su huella, y nadie te la puede volver a leer, ni nosotros ni tú. Quien la pierde crea una nueva; la vieja deja de valer en ese momento.
La creas en «Ajustes → App y datos → API». Viaja en la cabecera de la petición, como Authorization: Bearer tm_key_… o como X-Tellmelo-Key. No en la barra de direcciones, porque lo que está ahí acaba en los registros de acceso, en el historial del navegador y en el referer de cada enlace.
No en la barra de direcciones. Lo que está ahí acaba en el registro de cada servidor intermedio, en el historial del navegador y en el referer de cada enlace. Una clave no pinta nada ahí.
La misma clave también carga imágenes. Cada url de una respuesta apunta a /api/media de esta instancia; envía allí también la clave en la cabecera y la imagen vuelve, en la medida en que tu cuenta pueda verla.
Una clave lleva dos derechos, y cada ruta de las tablas de abajo dice cuál de ellos necesita. Dos y no cinco: un derecho que no sabes explicarte en una frase es un derecho que marcas sin leer. Y la línea honesta pasa entre mirar y cambiar.
read: mirar. Las publicaciones públicas, los perfiles, las comunidades y las etiquetas, y tu propia cuenta tal como la ves: feed, notificaciones, conversaciones, mensajes.
write: cambiar. Todo lo que ocurre en tu nombre: publicar, responder, votar, enviar mensajes, seguir, unirse, bloquear, marcar notificaciones como leídas.
Lo que ninguna clave puede
Ninguna clave llega a los datos de tu cuenta: ni contraseña, ni dirección de correo, ni tipo de cuenta, ni lugar, ni rol, ni eliminación. Tampoco las sesiones, ni los dispositivos de aviso, ni las claves mismas: una que pudiera emitir claves ya no se podría apagar. Tampoco la administración, ni la dirección de una comunidad, porque disolver una comunidad o entregarla es una decisión sobre publicaciones ajenas. Lo que guarda la contraseña, ninguna clave lo puede: un secreto que está en un script en la máquina de otro no debe poder lo que puede el inicio de sesión. Apoderarse de una cuenta sigue costando el inicio de sesión.
Peticiones y respuestas
JSON en todas partes. Cada respuesta es application/json en UTF-8, errores incluidos. Solo las imágenes llegan como imágenes.
Lo que envías. Un POST lleva sus campos como objeto JSON en el cuerpo. Los parámetros de la dirección completan lo que el cuerpo no nombra; si ambos nombran el mismo campo, gana el cuerpo.
Las fechas son números enteros de milisegundos desde el 1 de enero de 1970, UTC, tal como las guarda la base de datos. No hay zona horaria que leer mal.
Los identificadores son cadenas. No los desmontes ni confíes en su forma; compáralos solo enteros.
Cada campo está siempre. Lo que no existe es null, nunca falta; un recuento es siempre un número y una lista siempre una lista, vacía si hace falta.
Los textos son texto plano, tal como se escribieron. Las #etiquetas, los @nombres y los enlaces quedan como están, igual que los emojis propios de la instancia, como :name:; sus imágenes están en /emojis.
Las imágenes son direcciones relativas a esta instancia, /api/media?id=…. Cárgalas con la misma clave en la cabecera; sin ella la respuesta es 401.
Páginas
Cada lista toma limit y cursor y responde con items y next. Sigues enviando de vuelta el next de la última respuesta como cursor; cuando next está vacío, se ha llegado al final. Una página llena puede ser aun así la última, y quien solo para ante una página vacía pregunta una vez de más. El cursor es opaco: un lugar en una lista, no un instante. No lo desarmes ni te fabriques uno; lo que lleva dentro puede cambiar sin que cambie ninguna ruta.
Una página tiene 20 entradas sin limit, 50 como mucho. Algunas listas no se paginan en absoluto: se indica en su ruta, y su next es siempre null.
Solo lo nuevo
Cada respuesta lleva un ETag. Un programa que pregunta una y otra vez debería devolver el último como If-None-Match: si desde entonces no ha cambiado nada, la respuesta es 304 y no lleva cuerpo. Esa es la diferencia entre una lista que cruza el cable cada minuto y una que lo cruza cuando hay algo dentro, para tu máquina tanto como para esta.
Dos excepciones, ambas a propósito: /feed no lleva ETag, porque su orden se mueve con el tiempo y cada respuesta es distinta; y una escritura nunca responde 304. Dos publicaciones iguales son dos publicaciones.
Límites
Una clave puede hacer 120 peticiones por minuto, 600 con la suscripción «Organización», salvo que la administración le haya puesto otro número. El límite vale por clave, no por cuenta ni por dirección. Por encima, la respuesta es 429 y no ha pasado nada: la petición se rechazó, no se ejecutó. Espera un minuto y vuelve a enviarla; un programa que choca a menudo debería ir más despacio en vez de preguntar otra vez al momento.
Además del límite de la clave, las escrituras cuentan para los mismos límites que en la aplicación: cuántas publicaciones, respuestas o relaciones en pocos minutos. También responden 429 con el código rate_limited.
Cabeceras
Los nombres son los que ya conoce cualquier biblioteca cliente. Ninguna es obligatoria salvo la clave.
Lo que envías
Cabecera
Significado
Authorization
Lleva la clave: Bearer tm_key_…. La forma habitual.
X-Tellmelo-Key
La clave, como alternativa a Authorization, para herramientas que usan esa cabecera para otra cosa.
Content-Type
application/json, para una petición con cuerpo.
If-None-Match
El ETag de la última respuesta. Si nada ha cambiado desde entonces, la respuesta es 304 sin cuerpo.
Lo que vuelve
Cabecera
Significado
ETag
La huella de esta respuesta, marcada como débil (W/). Devuélvela como If-None-Match.
X-RateLimit-Limit
Cuántas peticiones puede hacer esta clave por minuto.
X-RateLimit-Remaining
Cuántas quedan en el minuto actual.
X-RateLimit-Reset
Cuándo empieza el siguiente minuto, en segundos desde 1970, UTC.
X-Tellmelo-Scope
Lo que puede hacer esta clave: read o read write.
Retry-After
Con un 429: cuántos segundos esperar antes de volver a preguntar.
WWW-Authenticate
Con un 401 por falta de clave: Bearer, así se espera una clave.
Cache-Control
no-store: ningún proxy intermedio puede guardar una respuesta, porque depende de la clave que pregunta. Tu propio programa sí puede comprobarla con el ETag.
Cuando algo no funciona
Los errores llegan como JSON con dos campos: un código fijo en inglés en error que tu programa puede comparar, y una frase en message para la persona que está delante, con el código de estado que le corresponde. El código se mantiene; la frase puede cambiar, y puede cambiar en cualquier idioma: un programa que compara la frase se rompe un día que nadie ha anunciado.
{ "error": "rate_limited",
"message": "Too many requests. Try again in a minute.",
"limit": 120 }
Algunos errores traen un campo más: docs con un 401 por falta de clave, limit con un 429.
Estado
Código
Significado
400
bad_request
La petición no se puede leer, falta un campo obligatorio o un valor no está entre los permitidos. El message dice cuál.
401
key_missing
No hay clave en la cabecera.
401
key_invalid
La clave no es válida: mal copiada, sustituida por una nueva o su cuenta está suspendida. Cuál de estas, no se dice a propósito.
401
unauthorized
Rechazado como sin sesión, por un motivo distinto de la clave. Raro, y un motivo para mirar la cuenta que hay detrás de la clave.
403
scope_missing
A la clave le falta el derecho que necesita esta ruta: casi siempre write en una clave que solo puede leer.
403
account_data_locked
Esto afecta a los datos de tu cuenta, a los que no llega ninguna clave: contraseña, correo electrónico, eliminación y cosas así.
403
forbidden
Tu cuenta no puede hacer esto: el mismo rechazo que en la aplicación, por ejemplo un derecho retirado o un bloqueo.
404
unknown_path
Esta ruta no existe, o no con este método.
404
not_found
La ruta existe, pero no lo que nombra, o no puedes verlo. Ambas cosas no se distinguen.
409
conflict
Choca con algo que ya existe, por ejemplo un nombre ocupado.
413
too_large
Demasiado grande: un texto o una petición por encima de lo que acepta esta instancia.
422
unprocessable
Legible, pero no posible de esta forma.
429
rate_limited
Demasiadas peticiones. No se ha hecho nada; espera y envíala de nuevo.
500
internal_error
Algo ha fallado de nuestro lado, no del tuyo. Queda registrado completo en el servidor.
Versiones
La versión está en la ruta. Mientras ahí ponga v2, estas rutas y sus campos se quedan como están; lo que se añade viene al lado.
Las novedades suben el segundo número: 2.1 trajo /emojis y marcar una conversación como leída. 2.4 quitó el campo contentWarning, porque ya no hay avisos de contenido. 2.5 quitó el campo alt de las imágenes, porque ya no hay descripciones de imágenes. 2.6 añade el tipo de notificación team para el nuevo trabajo del equipo. Cada ruta dice desde qué versión existe, y la raíz dice qué versión está funcionando.
Rutas
Todas las rutas de un vistazo y luego cada una en detalle: qué recibe, una petición de ejemplo y qué devuelve.
Una publicación necesita texto o una encuesta. Su longitud, el número de respuestas de una encuesta y cuántas publicaciones en cuánto tiempo los fija esta instancia; por encima, la respuesta es 400 o 429, con un message que dice cuál.
Todavía no se pueden adjuntar imágenes a través de la API, solo en la aplicación.
Parámetros
Nombre
Tipo
Significado
texten el cuerpo
stringopcional
El texto mismo: de la publicación, de la respuesta o del mensaje.
communityen el cuerpo
stringopcional
El id de la comunidad a la que va la publicación. Sin él, fuera de toda comunidad.
quotesen el cuerpo
stringopcional
El id de la publicación que esta cita.
pollen el cuerpo
string[]opcional
Las opciones de respuesta de una encuesta, como una lista de textos. Cuántas se permiten lo fija la instancia.
Petición de ejemplo
curl -X POST \
-H "Authorization: Bearer tm_key_…" \
-H "Content-Type: application/json" \
-d '{"text":"The bees are back in the garden 🐝 #garden"}' \
"https://tellmelo.com/api/v2/posts"
La conversación bajo una publicación: leída como una lista que parentId convierte en árbol, escrita respondiendo a la publicación o a una respuesta.
GET/api/v2/posts/{id}/replies
Las respuestas a una publicación, tal como las ves tú: lo que escribió una cuenta bloqueada se queda fuera.
Derecho read
paginable
con ETag
desde v2.0
La lista es plana y en el orden de escritura; parentId la convierte en árbol. Una página contiene hilos enteros, así que una respuesta nunca llega sin aquella a la que responde. Lo que escribió una cuenta que bloqueaste, o que te bloqueó, queda fuera. Dos claves pueden ver listas distintas.
Parámetros
Nombre
Tipo
Significado
iden la ruta
stringobligatorio
El id de una publicación.
limiten la dirección
integeropcional
Cuántas entradas caben en una página: 20 por defecto, 50 como máximo.
cursoren la dirección
stringopcional
Por dónde sigue: el next de la respuesta anterior. Sin él, desde arriba.
En una publicación en modo lento, cada persona puede responder una vez cada 10 minutos; otra respuesta recibe 429 con la espera en el mensaje. El modo no se aplica al autor ni a las cuentas que sigue.
Parámetros
Nombre
Tipo
Significado
iden la ruta
stringobligatorio
El id de una publicación.
texten el cuerpo
stringobligatorio
El texto mismo: de la publicación, de la respuesta o del mensaje.
parentIden el cuerpo
stringopcional
El id de la respuesta a la que esta responde. Sin él, directo a la publicación.
Petición de ejemplo
curl -X POST \
-H "Authorization: Bearer tm_key_…" \
-H "Content-Type: application/json" \
-d '{"text":"Same here, the lavender is full of them."}' \
"https://tellmelo.com/api/v2/posts/5f0c2a9e-8d41-4b7a-9c3e-2e61d0f4a7b1/replies"
Una búsqueda por publicaciones, nombres, alias y etiquetas.
Derecho read
con ETag
desde v2.0
Busca solo en lo público: publicaciones fuera de comunidades, perfiles y etiquetas. limit cuenta por tipo: 20 puede traer hasta 20 publicaciones, 20 perfiles y 20 etiquetas.
Parámetros
Nombre
Tipo
Significado
qen la dirección
stringobligatorio
Las palabras que se buscan.
typeen la dirección
stringopcional
Qué clase de resultado. Sin él, todas las clases.allpostsprofilestags
limiten la dirección
integeropcional
Cuántas entradas caben en una página: 20 por defecto, 50 como máximo.
Los emojis propios de la instancia, con la dirección de sus imágenes.
Derecho read
con ETag
desde v2.1
En los textos, un emoji de esta instancia aparece como :name:. Sustitúyelo por la imagen de esta lista; un nombre que no esté en ella sigue siendo texto: se borró o nunca existió.
Tu propio feed, tal como lo compone la aplicación.
Derecho read
paginable
desde v2.0
Aquí no hay ETag: el orden se mueve con el tiempo, así que cada respuesta es distinta. Aun así, una lista empezada sigue igual hasta el final: next lleva el momento en que empezó.
Parámetros
Nombre
Tipo
Significado
taben la dirección
stringopcional
Qué feed: for-you, following, latest o bookmarks. latest por defecto.for-youfollowinglatestbookmarks
tagen la dirección
stringopcional
Solo publicaciones con esta etiqueta. Sin ella, ningún filtro.
limiten la dirección
integeropcional
Cuántas entradas caben en una página: 20 por defecto, 50 como máximo.
cursoren la dirección
stringopcional
Por dónde sigue: el next de la respuesta anterior. Sin él, desde arriba.
Lo que ha pasado en torno a tu cuenta, legible página a página, para que un programa pueda ponerse al día con lo que se perdió.
GET/api/v2/notifications
Tus propias notificaciones, las más nuevas primero, paginables, para que un programa recupere lo que se ha perdido.
Derecho read
paginable
con ETag
desde v2.0
Leer no marca nada como leído; lo hace POST /notifications/read. Varios eventos del mismo tipo sobre la misma publicación se agrupan en una fila, y more dice cuántos.
Parámetros
Nombre
Tipo
Significado
limiten la dirección
integeropcional
Cuántas entradas caben en una página: 20 por defecto, 50 como máximo.
cursoren la dirección
stringopcional
Por dónde sigue: el next de la respuesta anterior. Sin él, desde arriba.
Se aplican las mismas reglas que en la aplicación: a quien te bloqueó no se le puede escribir, y cuentan los ajustes de la otra persona. La respuesta dice entonces por qué.
Todavía no se pueden adjuntar imágenes a través de la API, solo en la aplicación.
Parámetros
Nombre
Tipo
Significado
withen la ruta
stringobligatorio
El id de la cuenta con la que hablas. Una conversación no tiene un id propio: es la otra cuenta, el mismo valor que el buzón llama with.
texten el cuerpo
stringobligatorio
El texto mismo: de la publicación, de la respuesta o del mensaje.
replyToen el cuerpo
stringopcional
El id de un mensaje anterior de esta conversación al que responde este. Desde 2.2.
Petición de ejemplo
curl -X POST \
-H "Authorization: Bearer tm_key_…" \
-H "Content-Type: application/json" \
-d '{"text":"See you on Saturday at the market!"}' \
"https://tellmelo.com/api/v2/conversations/a3e1f7c2-54b9-4d0e-8f16-7b2c9d4e1a05/messages"
Me gusta, guardar, compartir, seguir, unirse y bloquear: una sola ruta para todo, activada y retirada con active.
POST/api/v2/relations
Dar me gusta, guardar, compartir, seguir, unirse, bloquear, silenciar, según kind.
Derecho write
desde v2.0
target es una publicación para like, save y repost, una comunidad para join y una cuenta para follow, block y mute, siempre por su id. active: false retira la relación. Nadie puede seguir a través de un bloqueo, en ninguna dirección. Solo quien silencia ve el silencio.
Una notificación. Una fila puede agrupar varios eventos del mismo tipo.
Campo
Tipo
Significado
id
string
El identificador de la notificación.
kind
string
Qué ha pasado.
reply — Alguien te ha respondido.
like — A alguien le gusta tu publicación.
repost — Alguien ha compartido tu publicación.
follow — Alguien te sigue.
mention — Alguien te ha mencionado.
group_mention — Alguien ha mencionado un grupo que diriges; text es su nombre.
message — Alguien te ha escrito un mensaje.
scheduled — Una publicación tuya programada ya ha salido.
reminder — Ha llegado un recordatorio de una publicación guardada.
report — Qué ha sido de una denuncia que enviaste.
moderation — Una decisión sobre tu cuenta: una advertencia, una restricción, un recurso.
team — Nuevo trabajo para el equipo, solo para propietarios, admins y moderadores: denuncias, recursos, enlaces enviados, consultas, solicitudes de verificación y cancelaciones.
text
stringo null
Solo en denuncias y moderación: el texto que la acompaña. Si no, null: la frase de una notificación la construye tu programa.
El id del mensaje al que responde este (null si no responde a ninguno). Desde 2.2.
createdAt
integer
Cuándo se envió.
Ejemplo
{
"id": "7c6b5a49-3827-4165-9f0e-d1c2b3a49586",
"text": "See you on Saturday at the market!",
"from": "a3e1f7c2-54b9-4d0e-8f16-7b2c9d4e1a05",
"to": "d4c3b2a1-6e5f-4a7b-9c8d-1e2f3a4b5c6d",
"read": true,
"media": [],
"replyTo": null,
"createdAt": 1758624060000
}
Created
La respuesta de una escritura que creó algo.
Campo
Tipo
Significado
id
string
El identificador de lo que se creó.
scheduledFor
integero null
Cuándo aparece, si se programó la publicación (si no, null).
deleteAt
integero null
Cuándo se borra solo, si se configuró (si no, null).
La respuesta de una escritura que no tiene nada que devolver.
Campo
Tipo
Significado
ok
boolean
Siempre true.
Ejemplo
{
"ok": true
}
La descripción legible por una máquina
La misma tabla con la que está construida esta página se sirve en /api/v2/openapi.json: rutas, parámetros, derechos y las formas que vuelven. Un generador de clientes puede leerla, y no puede alejarse de la API, porque la página, el enrutador y la descripción salen de una sola lista.
https://tellmelo.com/api/v2/openapi.json
Qué ha sido de v1
v1 está eliminada. Las rutas antiguas bajo /api/v1/ responden 410 y dicen en el cuerpo adónde ir. Sin redirección, porque v2 responde con otra forma, y un programa que la siguiera recibiría un 200 que no sabe leer. En ese momento aún no había cuentas públicas y por tanto nadie con un programa encima; quitarla más tarde habría significado no quitarla nunca.
Lo que esperamos
Los mismos principios que en todo lo demás: sin acoso, sin spam, sin contenidos ajenos sin derecho a ellos. Un programa no disculpa nada: de lo que escribe tu clave respondes tú.