Por qué caduca un token de Meta y qué pasa el día que caduca
Un token de acceso de Instagram conectado por Meta dura 60 días, no para siempre. PlanVortex lo renueva automáticamente un día antes de que caduque, así que en el uso normal nunca lo notas. El día en que sí lo notas es cuando esa renovación falla: la cuenta se marca como caída, deja de reintentarse sola y tu producto recibe un aviso para pedirle al usuario que vuelva a conectarla.
¿Cuánto dura un token de acceso de Meta?
60 días. Es el tiempo que documenta Meta para el token de larga duración que se obtiene al conectar una cuenta de Instagram, y es fijo: no se puede pedir uno que dure más ni hay un plan de pago que lo alargue.
// src/orm/social_apis/instagram/index.ts
const expiresDate = new Date();
expiresDate.setSeconds(expiresDate.getSeconds() + (60 * 60 * 24 * 60)); // 60 días
Ese expiresDate es lo único que decide si una cuenta necesita renovarse o no. No hay heurística ni margen de seguridad en ese cálculo: son 60 días exactos desde el instante en que Meta entregó el token, contados en segundos.
¿Por qué Meta no da tokens que duren para siempre?
Porque el token de larga duración de Meta no es una excepción de Instagram: es la misma política que aplica a cualquier token de usuario del ecosistema de Facebook Login. Un token con caducidad limita el daño de uno que se filtra —deja de servir solo, sin que nadie tenga que revocarlo a mano— y obliga a que la integración demuestre, cada 60 días, que el usuario sigue detrás del permiso. La contrapartida es que quien integra la API tiene que asumir la renovación como parte del ciclo de vida de la cuenta, no como un caso raro.
¿Cómo se renueva un token antes de que caduque?
Con un job que corre una vez por hora y renueva cualquier cuenta cuyo token vaya a caducar en menos de 24 horas. La cadencia horaria existe precisamente para que sobre margen frente a esa ventana de un día:
// src/domain/repositories/account/index.ts — "Refrescamos con 1 dia de diferencia (requerido por instagram)"
const now = new Date();
now.setDate(new Date().getDate() + 1);
const account_match = {
deleted: false,
error_code: 0,
"access_data.expires_in": { $lte: now },
};
// src/jobs/index.ts
"refresh-tokens": {
cron: "7 * * * *", // cada hora, minuto 7
run: refreshTokens,
},
La renovación en sí es una llamada a refresh_access_token de Meta con grant_type=ig_refresh_token, que devuelve un token nuevo con otros 60 días por delante. Mientras esa llamada tenga éxito, el ciclo se repite solo y la cuenta no se entera de que su token cambió.
¿Duran lo mismo los tokens en todas las redes?
No, y tratarlas como si duraran lo mismo es el error que deja cuentas muertas. Cada red fuerza su propio plazo:
| Red | Duración del access_token | Fuente |
|---|---|---|
| Instagram (Meta) | 60 días | instagram/index.ts |
| 60 días (5.184.000 s) | __tests__/social/contract/linkedin.test.ts |
|
| TikTok | 24 horas | __tests__/social/contract/youtube.test.ts |
| YouTube (Google) | 1 hora | youtube.types.d.ts |
YouTube es el caso extremo: con un token que dura una hora, el job horario no basta por sí solo, así que su SDK renueva además bajo demanda antes de cada llamada. Instagram y LinkedIn, con 60 días, viven cómodamente dentro de la pasada horaria con margen de sobra. La consecuencia práctica es que el código de renovación no puede ser genérico: cada SDK sabe cuánto dura su propio token y qué campo de la respuesta trae la nueva caducidad, porque ni siquiera se llaman igual entre redes.
¿Qué pasa el día que el token caduca de verdad?
Que la renovación automática falla, y a partir de ahí la cuenta deja de intentarse sola. Esto solo ocurre si algo impidió que el ciclo de 60 días se cerrase a tiempo —el usuario revocó el permiso desde Meta, la app perdió el caso de uso aprobado, o el job llevaba más de un día sin poder correr—, nunca por el simple paso de los 60 días con el sistema funcionando con normalidad.
Cuando la llamada de renovación falla, pasan tres cosas en el mismo golpe:
- La cuenta se marca con un código de error (
error_code: 707, "Error while sincronyzing"). - Ese código la saca de la siguiente pasada del job: la consulta que selecciona cuentas a renovar exige
error_code: 0, así que una cuenta caída no se reintenta cada hora contra un token que ya no sirve. - Se encola un cambio de tipo
change_state_accountque se notifica por webhook, firmado, a las apps cliente que tengan ese cliente dado de alta.
El job procesa todas las cuentas que tocaba renovar en esa pasada en paralelo, agrupadas por cliente. Eso importa porque un cliente con varias cuentas de Instagram puede tener alguna que falle y el resto que se renueve sin problema en la misma pasada: el fallo de una no bloquea ni retrasa a las demás, y el webhook que le llega a la app cliente lleva agrupados los cambios de ese cliente, no un mensaje suelto por cada cuenta.
// src/jobs/RefreshTokens.ts
} catch (e) {
await AccountModel.updateOne({ _id: account._id }, { $set: { error_code: CustomError.ERROR_CODE_707.key } });
addAccountChange(grouped, account, {
field: ALLOWED_WEBHOOKS_NOTIFICATIONS.change_state_account,
id_account: account._id.toString(),
id_organization: account.id_organization._id.toString(),
social_network: account.social_network,
});
}
¿Cómo se entera tu producto de que una cuenta se desconectó?
Por el webhook, no por que el usuario intente publicar y falle. Si tu app integra la API de PlanVortex, el webhook change_state_account te llega con id_account, id_organization y social_network, firmado igual que el resto de webhooks salientes de PlanVortex, en el momento en que el job detecta el fallo — no en el momento en que alguien intenta publicar y descubre que la cuenta ya no responde.
Eso importa porque la alternativa —enterarse por un error al publicar— llega tarde: el usuario programó contenido para dentro de tres días dando por hecho que la cuenta seguía conectada, y el fallo no aparece hasta que ese contenido intenta salir. Con el webhook, tu producto puede avisar al usuario el mismo día que la cuenta se cayó, con tiempo de sobra para reconectarla antes de que nada se quede sin publicar.
Qué significa esto si integras cuentas de Meta en tu producto
Tres cosas que conviene tener resueltas antes de dar por hecho que una cuenta conectada sigue conectada:
- Una cuenta desconectada no es un error, es un estado. Pasa en el uso normal —el usuario revoca el permiso desde la configuración de Meta, cambia de contraseña, la app pierde acceso— y tu producto tiene que poder mostrarlo sin tratarlo como una excepción.
- Escuchar el webhook, no solo el error de publicación. Es la diferencia entre avisar el día que la cuenta se cae y avisar el día que algo programado falla por su culpa.
- La reconexión es manual siempre. No hay forma de que PlanVortex ni de que Meta renueven un permiso que el usuario ha revocado; el flujo de conectar la cuenta es el mismo que la primera vez, código de autorización incluido.
- No todas las redes fallan igual, así que el mensaje al usuario tampoco puede ser genérico. Una cuenta de TikTok caída y una de Instagram caída no comparten ni la causa más probable ni la urgencia: con un token de 24 horas, un fallo de TikTok casi siempre es un problema puntual del job; con uno de 60 días, un fallo de Instagram casi siempre significa que el usuario revocó el permiso.
La renovación automática hace que la caducidad sea invisible casi todo el tiempo: mientras el ciclo de 60 días se cierre solo, ni el usuario ni tu producto tienen que hacer nada. El caso que sí importa es el otro — la cuenta que se cae de verdad — y es exactamente el que un producto bien integrado tiene que saber contar, no solo detectar.
¿Cuánto dura el token de acceso de una cuenta de Instagram conectada por Meta?
60 días desde que se conecta o se renueva. Es un tiempo fijo que fuerza Meta, no una elección de PlanVortex: el token de larga duración que devuelve la API de Graph caduca exactamente a los 60×24×60 segundos, y no hay forma de pedir uno que dure más.
¿Con cuánta antelación se renueva antes de caducar?
Con un día. El job de renovación corre cada hora y recoge cualquier cuenta cuyo token caduque en menos de 24 horas, así que en condiciones normales una cuenta nunca llega a los 60 días exactos sin haberse renovado ya.
¿Qué pasa si la renovación falla el día que el token caduca de verdad?
La cuenta se marca con un código de error y sale de la cola de renovación automática: sin eso, el job la reintentaría cada hora contra un token que ya no sirve. Tu producto recibe un webhook firmado avisando de que esa cuenta cambió de estado, y la app tiene que pedirle al usuario que vuelva a conectarla desde cero.
¿Todas las redes sociales caducan sus tokens igual que Meta?
No. LinkedIn también da 60 días, pero TikTok solo 24 horas y el access_token de Google (YouTube) dura una hora. Cada red fuerza su propio ritmo de renovación y PlanVortex lo respeta por separado en vez de tratarlos como si fueran iguales.