Publicar
Una petición, todas las redes. Cada destino puede llevar su propio texto, medios y opciones.
Ahora
curl -X POST "https://api.usecrier.com/v1/posts" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Lanzamos la colección de otoño 🍂",
"targets": [
{
"accountId": "acc_ig"
},
{
"accountId": "acc_li"
}
]
}'const res = await fetch('https://api.usecrier.com/v1/posts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": "Lanzamos la colección de otoño 🍂",
"targets": [
{
"accountId": "acc_ig"
},
{
"accountId": "acc_li"
}
]
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://api.usecrier.com/v1/posts",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"content": "Lanzamos la colección de otoño 🍂",
"targets": [
{
"accountId": "acc_ig"
},
{
"accountId": "acc_li"
}
]
},
)
data = res.json()["data"]Programado
Añade scheduledFor en ISO 8601 con zona horaria.
curl -X POST "https://api.usecrier.com/v1/posts" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Abrimos el viernes a las 9",
"scheduledFor": "2026-10-30T09:00:00+01:00",
"targets": [
{
"accountId": "acc_ig"
}
]
}'const res = await fetch('https://api.usecrier.com/v1/posts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": "Abrimos el viernes a las 9",
"scheduledFor": "2026-10-30T09:00:00+01:00",
"targets": [
{
"accountId": "acc_ig"
}
]
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://api.usecrier.com/v1/posts",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"content": "Abrimos el viernes a las 9",
"scheduledFor": "2026-10-30T09:00:00+01:00",
"targets": [
{
"accountId": "acc_ig"
}
]
},
)
data = res.json()["data"]Puedes cancelarla antes de que salga con POST /v1/posts/{id}/cancel.
En la cola
Con queue: true toma el siguiente hueco libre de la cola del perfil. Todas las cuentas tienen que ser del mismo perfil.
curl -X POST "https://api.usecrier.com/v1/posts" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Consejo del día",
"queue": true,
"targets": [
{
"accountId": "acc_ig"
}
]
}'const res = await fetch('https://api.usecrier.com/v1/posts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": "Consejo del día",
"queue": true,
"targets": [
{
"accountId": "acc_ig"
}
]
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://api.usecrier.com/v1/posts",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"content": "Consejo del día",
"queue": True,
"targets": [
{
"accountId": "acc_ig"
}
]
},
)
data = res.json()["data"]Borrador
Con draft: true se guarda sin publicar ni programar.
Texto y medios por red
Cada destino puede sustituir el texto (content) y los medios (media) del post, y llevar las opciones de su red con la clave de la red (instagram, youtube, tiktok…). Mira Opciones por red.
curl -X POST "https://api.usecrier.com/v1/posts" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Así se hace nuestra chaqueta",
"media": [
{
"type": "video",
"url": "https://cdn.acme.com/chaqueta.mp4"
}
],
"targets": [
{
"accountId": "acc_ig",
"instagram": {
"format": "reel",
"firstComment": "#otoño #moda"
}
},
{
"accountId": "acc_yt",
"youtube": {
"title": "Así se hace nuestra chaqueta",
"visibility": "public"
}
},
{
"accountId": "acc_x",
"content": "Así se hace nuestra chaqueta 🧵",
"x": {
"thread": [
"1/ Empieza en el taller…"
]
}
}
]
}'const res = await fetch('https://api.usecrier.com/v1/posts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": "Así se hace nuestra chaqueta",
"media": [
{
"type": "video",
"url": "https://cdn.acme.com/chaqueta.mp4"
}
],
"targets": [
{
"accountId": "acc_ig",
"instagram": {
"format": "reel",
"firstComment": "#otoño #moda"
}
},
{
"accountId": "acc_yt",
"youtube": {
"title": "Así se hace nuestra chaqueta",
"visibility": "public"
}
},
{
"accountId": "acc_x",
"content": "Así se hace nuestra chaqueta 🧵",
"x": {
"thread": [
"1/ Empieza en el taller…"
]
}
}
]
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://api.usecrier.com/v1/posts",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"content": "Así se hace nuestra chaqueta",
"media": [
{
"type": "video",
"url": "https://cdn.acme.com/chaqueta.mp4"
}
],
"targets": [
{
"accountId": "acc_ig",
"instagram": {
"format": "reel",
"firstComment": "#otoño #moda"
}
},
{
"accountId": "acc_yt",
"youtube": {
"title": "Así se hace nuestra chaqueta",
"visibility": "public"
}
},
{
"accountId": "acc_x",
"content": "Así se hace nuestra chaqueta 🧵",
"x": {
"thread": [
"1/ Empieza en el taller…"
]
}
}
]
},
)
data = res.json()["data"]Estados
| Estado | Qué significa |
|---|---|
draft | Borrador, sin fecha. |
pending_approval | Esperando a que un propietario o admin la apruebe. No sale hasta entonces. |
scheduled | Programada o en la cola, esperando su hora. |
publishing | Se está enviando a las redes. |
published | Publicada en todas. Cada destino tiene su url. |
partial | Publicada en algunas y fallida en otras. Reintenta las fallidas con POST /v1/posts/{id}/retry. |
failed | No salió en ninguna. Cada destino explica el motivo en error. |
cancelled | Cancelada antes de salir, o retirada de todas las redes. |
Editar
Mientras no ha salido (borrador, programada, con error o cancelada) puedes cambiar cualquier cosa con PATCH /v1/posts/{id}. Lo que no envíes se mantiene; targets sustituye la lista entera.
curl -X PATCH "https://api.usecrier.com/v1/posts/pst_7q1w0e" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Abrimos el viernes a las 10",
"scheduledFor": "2026-10-30T10:00:00+01:00"
}'const res = await fetch('https://api.usecrier.com/v1/posts/pst_7q1w0e', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": "Abrimos el viernes a las 10",
"scheduledFor": "2026-10-30T10:00:00+01:00"
}),
});
const { data } = await res.json();import os, requests
res = requests.patch(
"https://api.usecrier.com/v1/posts/pst_7q1w0e",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"content": "Abrimos el viernes a las 10",
"scheduledFor": "2026-10-30T10:00:00+01:00"
},
)
data = res.json()["data"]Con draft: false un borrador se publica: ahora, en scheduledFor o en la cola.
Una vez publicada, solo se puede cambiar el texto, y solo en las redes que lo permiten: X (cuentas Premium, durante la primera hora), Facebook, LinkedIn, YouTube, Pinterest, Google Business, Telegram, Discord y Reddit.
curl -X POST "https://api.usecrier.com/v1/posts/pst_7q1w0e/edit" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Texto corregido"
}'const res = await fetch('https://api.usecrier.com/v1/posts/pst_7q1w0e/edit', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": "Texto corregido"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://api.usecrier.com/v1/posts/pst_7q1w0e/edit",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"content": "Texto corregido"
},
)
data = res.json()["data"]Aprobación
Con requiresApproval: true la publicación queda en pending_approval: no sale hasta que alguien la apruebe. Si el workspace exige aprobación (PATCH /v1/workspace con requireApproval: true, o desde Equipo en el panel), las de los miembros pasan siempre por aquí. Las de propietarios, admins y API keys no, salvo que lo pidan.
curl -X POST "https://api.usecrier.com/v1/posts" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Nueva colección",
"scheduledFor": "2026-11-06T09:00:00+01:00",
"requiresApproval": true,
"targets": [
{
"accountId": "acc_ig"
}
]
}'const res = await fetch('https://api.usecrier.com/v1/posts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": "Nueva colección",
"scheduledFor": "2026-11-06T09:00:00+01:00",
"requiresApproval": true,
"targets": [
{
"accountId": "acc_ig"
}
]
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://api.usecrier.com/v1/posts",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"content": "Nueva colección",
"scheduledFor": "2026-11-06T09:00:00+01:00",
"requiresApproval": True,
"targets": [
{
"accountId": "acc_ig"
}
]
},
)
data = res.json()["data"]Un propietario, un admin o una API key decide con POST /v1/posts/{id}/review. Al aprobarla se programa para su fecha, entra en la cola si la pidió o sale ya si su fecha pasó mientras esperaba. Al rechazarla vuelve a borrador con la nota, y tu webhook recibe post.rejected.
curl -X POST "https://api.usecrier.com/v1/posts/pst_7q1w0e/review" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"decision": "reject",
"note": "Cambia la foto de portada"
}'const res = await fetch('https://api.usecrier.com/v1/posts/pst_7q1w0e/review', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"decision": "reject",
"note": "Cambia la foto de portada"
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://api.usecrier.com/v1/posts/pst_7q1w0e/review",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"decision": "reject",
"note": "Cambia la foto de portada"
},
)
data = res.json()["data"]Editarla mientras espera no la publica: sigue pendiente. Quien la escribió puede retirarla con POST /v1/posts/{id}/cancel.
Reciclar
Una publicación que funciona puede volver a salir sola: cada N semanas o meses, como una publicación nueva. Para cuando llega a maxCopies o pasa until, y las variations se usan por turnos para que no salga siempre el mismo texto.
curl -X PUT "https://api.usecrier.com/v1/posts/pst_7q1w0e/recycling" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"every": 2,
"unit": "month",
"maxCopies": 6,
"variations": [
"Vuelve el clásico de otoño 🍂",
"Por si te lo perdiste: nuestro clásico de otoño"
]
}'const res = await fetch('https://api.usecrier.com/v1/posts/pst_7q1w0e/recycling', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"every": 2,
"unit": "month",
"maxCopies": 6,
"variations": [
"Vuelve el clásico de otoño 🍂",
"Por si te lo perdiste: nuestro clásico de otoño"
]
}),
});
const { data } = await res.json();import os, requests
res = requests.put(
"https://api.usecrier.com/v1/posts/pst_7q1w0e/recycling",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"every": 2,
"unit": "month",
"maxCopies": 6,
"variations": [
"Vuelve el clásico de otoño 🍂",
"Por si te lo perdiste: nuestro clásico de otoño"
]
},
)
data = res.json()["data"]- Cada copia es una publicación propia con
recycledFrom, y tu webhook recibepost.recycled. - YouTube y TikTok no permiten repetir contenido: esas cuentas se quedan fuera de las copias.
- Cada cuenta puede tener hasta 10 publicaciones reciclándose a la vez.
DELETE /v1/posts/{id}/recyclinglo para; las copias ya creadas se quedan.
Métricas
GET /v1/posts/{id}/metrics devuelve impresiones, alcance, reproducciones, me gusta, comentarios, compartidos, guardados y clics, en total y por cuenta. Llegan unos minutos después de publicar; hasta entonces devuelve null. Cada red da solo las suyas: las demás valen 0.
Grupos de cuentas
Guarda selecciones de cuentas (por ejemplo, "Todas las de Acme") con POST /v1/account-groups y úsalas al importar un CSV o desde el panel.
curl -X POST "https://api.usecrier.com/v1/account-groups" \
-H "Authorization: Bearer $CRIER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Todas las de Acme",
"accountIds": [
"acc_ig",
"acc_li",
"acc_x"
]
}'const res = await fetch('https://api.usecrier.com/v1/account-groups', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRIER_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Todas las de Acme",
"accountIds": [
"acc_ig",
"acc_li",
"acc_x"
]
}),
});
const { data } = await res.json();import os, requests
res = requests.post(
"https://api.usecrier.com/v1/account-groups",
headers={"Authorization": f"Bearer {os.environ['CRIER_API_KEY']}"},
json={
"name": "Todas las de Acme",
"accountIds": [
"acc_ig",
"acc_li",
"acc_x"
]
},
)
data = res.json()["data"]Retirar y borrar
POST /v1/posts/{id}/unpublishla retira de todas las redes, o solo deaccountId. Instagram y TikTok no lo permiten por API: hay que borrarla en la app.DELETE /v1/posts/{id}la borra de Crier. Si sigue publicada, retírala antes.