Genuka WA docs

WhatsApp error 190: access token expired — cause and fix

WhatsApp Cloud API error 190 (access token expired): which token expired, how to replace it for good, and why Genuka WA users never handle Meta tokens.

WhatsApp error 190 means the access token sent to Meta's Cloud API has expired or is no longer valid. The fix is a new token, and above all to stop using a temporary user token: a system user token does not die after a few hours. With Genuka WA, you never handle a Meta token at all.

What does error 190 mean?

Meta lists it among the Cloud API authorization errors:

"Your access token has expired." — suggested fix: "Get a new access token." — Meta, Cloud API error codes

The general Graph API documentation, which the Cloud API is built on, names the same code "Access token has expired" and documents subcodes (Meta, Graph API error handling):

Graph subcodeMeta's nameWhat it tells you
463ExpiredThe token expired, was revoked or is otherwise invalid
467Invalid Access TokenThe token expired, was revoked or is otherwise invalid
460Password ChangedThe person who generated the token changed their password
458App Not InstalledThe user has not logged into your app

Do not build logic on those subcodes: the WhatsApp error page says error_subcode is deprecated and no longer returned from Graph v16.0 onward. The 190 code and the details field are enough.

When does error 190 happen?

  • You are using the API Setup token. Meta's App Dashboard generates a fresh user token every time you open WhatsApp > API Setup. Meta meant it for first tests: user tokens "expire quickly", so you have to generate a new one every few hours (Meta, Access tokens). It is the usual reason a service works in the morning and fails in the afternoon.
  • The token was invalidated. Password changed, app removed by the user, token revoked: Meta answers 190 even before the expiry date.
  • You are a partner and one customer's token died. At the end of Embedded Signup, a Tech Provider receives a business integration system user token scoped to that customer. We have seen it stop working as soon as the customer edits the partner's access in their Business Manager: Meta then answers 190 "Authentication Error" on every send, for a number that is otherwise healthy.

How do I fix error 190?

If you call the Cloud API with your own token

Inspect the token. Paste it into Meta's access token debugger: it shows the expiry and the permissions. It needs whatsapp_business_management and whatsapp_business_messaging (Meta, WhatsApp support).

Replace a user token with a system user token. In Business settings, System Users: create a system user, give it control of your app, then Generate token, picking the app, an expiration preference and the business_management, whatsapp_business_management and whatsapp_business_messaging permissions (Meta, Access tokens).

Give it access to the accounts. A system user without access to the target WhatsApp account no longer gets 190 but 200: assign it the WhatsApp account and the Messaging account in Meta Business Suite, from each account's People tab (same page).

Store it as an opaque secret. Meta warns that token formats can change: no fixed column length, no decoding.

If you go through Genuka WA

There is nothing for you to regenerate. Genuka WA holds the Cloud API access: every call on your number goes out with Genuka's system user token, created with no expiry date, rather than with the token Embedded Signup returned when the number was connected. Genuka made that choice precisely to avoid the partner case described above.

A 190 in a Genuka WA response is therefore, in the vast majority of cases, an incident on Genuka's side. It comes back like this:

409 — POST /api/v1/messages
{
  "error": "send_config",
  "message": "Authentication Error",
  "meta": {
    "errorClass": "config",
    "retryable": false,
    "code": 190,
    "traceId": "AbC…"
  }
}

When creating a template, the same refusal comes back as 403 meta_rejected with the same meta object (API reference). Either way:

  1. Do not retry in a loop. retryable: false: the same call will fail the same way.
  2. Contact Genuka support with the response's x-request-id header and meta.traceId.
  3. Do not ask the customer to reconnect straight away. Check GET /api/v1/connections first. disconnected means Meta reported the account as no longer shared with Genuka, or deleted, or that you released the number yourself. A customer who removed access restores it through the connect link, without using a new slot; a released number needs a free slot again; a deleted account, or one disabled by Meta (error 368), is not restored that way, and the account_update event forwarded to your webhooks tells you which case applies. If it still reads connected, stay with Genuka support.

Do not confuse it with errors on your own API key, which never come from Meta: 401 missing_bearer_token (no header) and 401 invalid_token (unknown or revoked key), see Authentication.

const response = await fetch("https://wa.genuka.com/api/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.GENUKA_WA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    connectionId: "con_1",
    to: "+237690000001",
    template: { name: "order_confirmation", language: "en_US", variables: ["Awa", "ORD-1042"] },
  }),
});
const json = await response.json();

if (response.status === 401) {
  // Your Genuka key: missing, unknown or revoked. Nothing to do with Meta.
  throw new Error(`API key refused: ${json.error}`);
}
if (json.meta?.code === 190 || json.meta?.code === 0) {
  // Meta token refused: on Genuka's side. Stop and alert, do not retry.
  console.error("Meta token refused", {
    requestId: response.headers.get("x-request-id"),
    traceId: json.meta.traceId,
  });
}

How do I prevent error 190?

  • Never run production on the API Setup token. It exists to send a first test message, not to power a service that runs overnight.
  • One system user token per environment, with only the WhatsApp permissions you need, kept in your secrets manager.
  • Watch for revoked access. As a partner, the account_update webhook reports PARTNER_APP_UNINSTALLED when a customer deauthenticates or uninstalls your app, and PARTNER_REMOVED when an account is no longer shared with you (Meta, account_update webhook). Genuka WA forwards these events to your webhooks (account_update event), but of the two, only PARTNER_REMOVED turns the number disconnected: after a PARTNER_APP_UNINSTALLED, it stays connected.
  • Alert on the class, not on the text. In Genuka WA, meta.errorClass: "config" covers token, permission and registration problems: a human has to look, and no retry will fix it.
  • 0: Meta could not authenticate the app user; same remedy.
  • 200: the token is valid but lacks access to the account or permission.
  • 10: permission not granted or removed.
  • 3: capability or permission missing for this endpoint.

FAQ

How long does a WhatsApp Cloud API access token last?

It depends on the type. A user token, like the one on the API Setup page, expires within a few hours. A system user token is long-lived, and you choose its expiration preference when you generate it.

Should I retry a send that failed with 190?

Not until the token has changed. The same token produces the same error; retrying only delays the alert.

Does my customer need to reconnect after a 190 on Genuka WA?

Only if their number shows disconnected in GET /api/v1/connections because they removed Genuka's access: the account_update event forwarded to your webhooks confirms it. A deleted account, or one disabled by Meta, is not restored by reconnecting. If the number still reads connected, contact Genuka support with x-request-id and meta.traceId.

Should I regenerate my Genuka API key?

No. Your pk_live_… key authenticates your calls to Genuka WA, not to Meta. A refused key produces a Genuka 401, never a 190.

Sources

On this page