PlanVortex
  • Product
  • Pricing
  • API
  • Login
  • Get started
ProductSee the whole productUse casesComparisonResourcesMulti-network schedulingAI assistantAnalyticsAccount connectionDeveloper API
PricingAPILoginGet started
Language
Home/Resources/Why a Meta access token expires, and what happens the day it does
Engineering

Why a Meta access token expires, and what happens the day it does

7 min read·Published on Aug 27, 2026
Also inEspañol
A Meta token with 60 days on its counter and the renewal cycle turning around it

An Instagram access token issued by Meta lasts 60 days, not forever. PlanVortex renews it automatically a day before it expires, so in normal use you never notice. The day you do notice is the day that renewal fails: the account is flagged as down, stops retrying on its own, and your product gets a notification to ask the user to reconnect it.

How long does a Meta access token last?

60 days. That is the window Meta documents for the long-lived token you get when connecting an Instagram account, and it is fixed: you cannot request a longer one and there is no paid plan that extends it.

// src/orm/social_apis/instagram/index.ts
const expiresDate = new Date();
expiresDate.setSeconds(expiresDate.getSeconds() + (60 * 60 * 24 * 60)); // 60 days

That expiresDate is the only thing deciding whether an account needs renewing. There is no heuristic and no safety margin in that calculation: it is exactly 60 days from the instant Meta handed the token over, counted in seconds.

Why doesn't Meta issue tokens that last forever?

Because Meta's long-lived token is not an Instagram exception: it is the same policy that applies to any user token in the Facebook Login ecosystem. A token with an expiry limits the damage of one that leaks — it stops working on its own, without anyone having to revoke it by hand — and it forces the integration to prove, every 60 days, that the user is still behind the permission. The trade-off is that whoever integrates the API has to take renewal on as part of the account lifecycle, not as a rare edge case.

How is a token renewed before it expires?

With a job that runs once an hour and renews any account whose token is going to expire in less than 24 hours. The hourly cadence exists precisely so there is room to spare against that one-day window:

// 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 * * * *", // every hour, on minute 7
    run: refreshTokens,
},

The renewal itself is a call to Meta's refresh_access_token with grant_type=ig_refresh_token, which returns a new token with another 60 days ahead of it. As long as that call succeeds, the cycle repeats on its own and the account never learns its token changed.

Do tokens last the same on every network?

No, and treating them as if they did is the mistake that leaves accounts dead. Each network forces its own deadline:

Network access_token lifetime Source
Instagram (Meta) 60 days instagram/index.ts
LinkedIn 60 days (5,184,000 s) __tests__/social/contract/linkedin.test.ts
TikTok 24 hours __tests__/social/contract/youtube.test.ts
YouTube (Google) 1 hour youtube.types.d.ts

YouTube is the extreme case: with a token that lasts an hour, the hourly job is not enough on its own, so its SDK also renews on demand before every call. Instagram and LinkedIn, at 60 days, live comfortably inside the hourly pass with room to spare. The practical consequence is that the renewal code cannot be generic: each SDK knows how long its own token lasts and which field of the response carries the new expiry, because they are not even named the same across networks.

What happens the day the token really expires?

The automatic renewal fails, and from that point the account stops trying on its own. This only happens if something prevented the 60-day cycle from closing in time — the user revoked the permission from Meta, the app lost its approved use case, or the job had been unable to run for more than a day — never from the mere passing of 60 days with the system working normally.

When the renewal call fails, three things happen in the same stroke:

  1. The account is flagged with an error code (error_code: 707, "Error while sincronyzing").
  2. That code takes it out of the job's next pass: the query selecting accounts to renew requires error_code: 0, so a downed account is not retried every hour against a token that no longer works.
  3. A change_state_account change is queued and notified by signed webhook to the client apps that have that client registered.

The job processes every account due for renewal in that pass in parallel, grouped by client. That matters because a client with several Instagram accounts can have one fail and the rest renew without trouble in the same pass: one failure neither blocks nor delays the others, and the webhook that reaches the client app carries that client's changes grouped together, not one message per account.

// 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,
    });
}

How does your product find out an account disconnected?

Through the webhook, not because the user tries to publish and fails. If your app integrates the PlanVortex API, the change_state_account webhook reaches you with id_account, id_organization and social_network, signed like every other outbound PlanVortex webhook, at the moment the job detects the failure — not at the moment somebody tries to publish and discovers the account no longer answers.

That matters because the alternative — finding out through a publishing error — arrives late: the user scheduled content for three days out assuming the account was still connected, and the failure does not surface until that content tries to go out. With the webhook, your product can warn the user the same day the account went down, with plenty of time to reconnect it before anything is left unpublished.

What this means if you integrate Meta accounts into your product

Three things worth having settled before assuming a connected account is still connected:

  • A disconnected account is not an error, it is a state. It happens in normal use — the user revokes the permission from Meta's settings, changes their password, the app loses access — and your product has to be able to show that without treating it as an exception.
  • Listen to the webhook, not just to the publishing error. It is the difference between warning on the day the account goes down and warning on the day something scheduled fails because of it. The code that receives it — signature verification over the raw body included, which is where everyone trips — is in the Node.js and Python guides.
  • Reconnection is always manual. There is no way for PlanVortex or for Meta to renew a permission the user has revoked; the flow to connect the account is the same one as the first time, authorization code included.
  • Networks do not fail the same way, so the message to the user cannot be generic either. A downed TikTok account and a downed Instagram account share neither the most likely cause nor the urgency: with a 24-hour token, a TikTok failure is almost always a one-off problem with the job; with a 60-day one, an Instagram failure almost always means the user revoked the permission.

Automatic renewal makes the expiry invisible almost all of the time: as long as the 60-day cycle closes on its own, neither the user nor your product has to do anything. The case that does matter is the other one — the account that really goes down — and it is exactly the one a well-integrated product has to know how to explain, not just detect.

Frequently asked questions
How long does the access token of an Instagram account connected through Meta last?

60 days from the moment it is connected or renewed. That window is fixed by Meta, not a choice PlanVortex makes: the long-lived token the Graph API returns expires after exactly 60×24×60×60 seconds, and there is no way to ask for one that lasts longer.

How far in advance is it renewed before it expires?

By a day. The renewal job runs every hour and picks up any account whose token expires in less than 24 hours, so under normal conditions an account never reaches the full 60 days without having been renewed already.

What happens if the renewal fails on the day the token really expires?

The account is flagged with an error code and drops out of the automatic renewal queue: without that, the job would retry it every hour against a token that no longer works. Your product receives a signed webhook telling it that account changed state, and your app has to ask the user to connect it again from scratch.

Do all social networks expire their tokens the way Meta does?

No. LinkedIn also gives you 60 days, but TikTok only 24 hours and Google's access_token (YouTube) lasts one hour. Each network forces its own renewal rhythm and PlanVortex honours each one separately instead of treating them as if they were the same.

FJ
Francisco José Fernández-Medina López

Software developer and entrepreneur. He builds PlanVortex, the API other software companies use to integrate publishing to Facebook, Instagram, X, LinkedIn, TikTok, YouTube and WhatsApp inside their own product. A parent and a video game enthusiast.

LinkedIn profile
All resources
PlanVortex
Developed by TaliaSoftWorks S.A.
Phone: 640 29 96 58
About PlanVortexLegalPrivacy
FacebookTwitterInstagram