Come spostare gli utenti su un nuovo numero WhatsApp dopo un ban

Numero WhatsApp bannato: le chat non si spostano e il nuovo non può scrivere per primo. Playbook con codice webhook per spostare gli utenti e ripristinare la cronologia.

Una fila di nuvolette di chat attraversa uno stretto ponte da un telefono spento a uno verde acceso.

In breve

  • Quando WhatsApp banna un numero whasp ricevi un sostituto senza costi, con la stessa etichetta, lo stesso profilo e lo stesso periodo pagato, annunciato da un evento webhook number.replaced, ma nessuna chat si sposta.
  • Il nuovo numero non può scrivere a nessuno per primo (409 chat_not_open), quindi ogni utente deve scrivergli, e l'invito deve viaggiare su un canale che controlli tu, come email, push o un banner nell'app.
  • Manda a ogni utente un link costruito da new_number.wa_link con un messaggio precompilato che porta un codice monouso, e invita a lotti di circa 25 al giorno, perché un numero consente 40 nuove chat ogni 24 ore.
  • Indicizza la cronologia per il tuo id utente, non per il numero, così chi torna viene riconosciuto dal telefono o dal codice e la conversazione riprende da dove si era fermata.
  • Preparati prima del primo ban: un secondo canale raccolto alla registrazione, un link di reindirizzamento stabile, quel link nella riga «info» del profilo e un gestore di number.replaced già testato.

Quando WhatsApp banna un numero, le chat non si spostano: il sostituto parte vuoto e non può scrivere a nessuno per primo. Per spostare i tuoi utenti, avvisali su un canale che controlli tu, manda a ciascuno un link wa.me al nuovo numero con un messaggio precompilato e riconoscili quando scrivono, così ripristini la loro cronologia dal tuo archivio.

Cosa succede quando WhatsApp banna il numero del tuo agente?

Quando WhatsApp banna in via definitiva un numero whasp, whasp lo ritira e ti passa a un numero pronto senza costi. Il sostituto ha la stessa etichetta, lo stesso profilo (nome, info, foto) e lo stesso periodo pagato. Nient’altro si trasferisce. Nessuna chat si sposta, e il nuovo numero non ha nulla della vecchia cronologia.

Il tuo webhook riceve un evento number.replaced con il vecchio numero e l’oggetto del nuovo numero, compreso il suo wa_link. Ecco l’evento, abbreviato:

{
  "id": "evt_9dK3mQ2vLx",
  "type": "number.replaced",
  "created_at": "2026-10-18T19:00:00Z",
  "data": {
    "old_number": "+15555550100",
    "new_number": {
      "number": "+15555550102",
      "wa_link": "https://wa.me/15555550102",
      "label": "ava",
      "status": "active",
      "profile": { "name": "Ava", "about": "La tua amica AI", "synced": true },
      "paid_until": "2026-11-17T19:00:00Z"
    }
  }
}

Può arrivare anche un evento number.status_changed, quando lo stato di salute del vecchio numero passa a critical. L’ordine degli eventi non è garantito, quindi non farci affidamento. Il numero bannato non risponde più a nessuno. Per capire perché è successo, leggi perché WhatsApp banna i numeri. Per la prima ora dopo un ban, compresa la pagina di WhatsApp sui ban degli account, vedi cosa fare quando un numero viene bannato.

Il nuovo numero può scrivere per primo ai tuoi utenti?

Il nuovo numero non può scrivere a nessuno che non gli abbia scritto. Un invio a una persona così restituisce 409 chat_not_open. Vale per ogni numero whasp, sostituti compresi, ed è voluto: sono i messaggi a freddo a far bannare i numeri personali, e un numero nuovo che aprisse centinaia di chat il primo giorno si tirerebbe addosso il ban successivo.

Quindi lo spostamento deve partire dall’utente: deve toccare un link e scrivere. Questo rende l’invito la parte difficile, perché non può arrivare dalla chat WhatsApp bannata né dal nuovo numero. Deve viaggiare su un canale che controlli tu. Quando un utente scrive, gli invii senza from partono dal nuovo numero, perché l’API usa il numero a cui la persona ha scritto per ultimo.

Qual è il playbook per spostare gli utenti?

Il playbook ha sette passi, e il codice qui sotto copre i primi sei.

  1. Verifica l’evento e deduplica sul suo id (gli eventi possono arrivare due volte, e la specifica Standard Webhooks consiglia di usare webhook-id come chiave di idempotenza).
  2. Trova gli utenti coinvolti: quelli la cui chat stava su old_number. Salva il numero su ogni utente da message.received, dove message.number indica quale numero ha ricevuto il messaggio.
  3. Costruisci un link per ogni utente: new_number.wa_link più ?text= (il formato click-to-chat di WhatsApp) con un breve messaggio che porta un codice monouso.
  4. Manda il link sul tuo canale: un banner nell’app, una notifica push o un’email.
  5. Invita a lotti, partendo da chi è stato attivo più di recente.
  6. Riconosci la persona quando scrive, ripristina la sua cronologia e fai dire all’agente che il numero è cambiato.
  7. Ricorda una volta, poi smetti. Dopo una settimana manda un solo promemoria a chi non è tornato. Gli altri tornano quando avranno di nuovo voglia di usare l’agente.

Come gestisci l’evento e mandi gli inviti?

Verifica la firma sul corpo grezzo, deduplica sull’id dell’evento e avvia gli inviti. Questo gestore riusa il controllo Standard Webhooks della documentazione di whasp.

import { randomBytes } from "node:crypto";
import { Webhook } from "standardwebhooks";

type User = { id: string; phone: string; number: string; lastActive: number; invited?: boolean };

declare const users: Map<string, User>; // il tuo database
declare function notify(user: User, link: string): Promise<void>; // email, push o banner nell'app

const wh = new Webhook(process.env.WHASP_WEBHOOK_SECRET ?? ""); // whsec_...
const seen = new Set<string>(); // id degli eventi già gestiti
export const codes = new Map<string, string>(); // codice di invito -> id utente
let moveFrom: { number: string; link: string } | null = null;
const DAILY_INVITES = 25; // sotto l'80% delle 40 nuove chat al giorno, con margine per le nuove registrazioni

export async function POST(request: Request) {
  const body = await request.text(); // il corpo grezzo: verifica prima di fare il parsing
  let event: any;
  try {
    event = wh.verify(body, Object.fromEntries(request.headers));
  } catch {
    return new Response("Invalid signature", { status: 401 });
  }
  if (seen.has(event.id)) return new Response(null, { status: 204 });
  seen.add(event.id);

  if (event.type === "number.replaced") {
    const { old_number, new_number } = event.data;
    moveFrom = { number: old_number, link: new_number.wa_link };
    await inviteBatch(); // in produzione: rispondi prima 2xx, poi invia da una coda
  }
  return new Response(null, { status: 204 });
}

// Eseguila una volta quando arriva l'evento, poi una volta al giorno finché non resta nessuno.
export async function inviteBatch() {
  const target = moveFrom;
  if (!target) return;
  const batch = [...users.values()]
    .filter((u) => u.number === target.number && !u.invited)
    .sort((a, b) => b.lastActive - a.lastActive)
    .slice(0, DAILY_INVITES);
  for (const user of batch) {
    const code = randomBytes(4).toString("hex");
    codes.set(code, user.id);
    const text = encodeURIComponent(`Ciao, sono di nuovo io (codice ${code})`);
    await notify(user, `${target.link}?text=${text}`);
    user.invited = true;
  }
}

Il codice è casuale e monouso, non l’id utente, perché un messaggio precompilato è un testo visibile e modificabile e gli id non vanno messi nei link. Sostituisci le Map e il Set con tabelle del database.

La dimensione del lotto viene dai limiti. Un numero whasp consente 40 nuove chat ogni 24 ore e 100 chat attive in 30 giorni, e il suo stato passa a at_risk quando un limite supera l’80%, cioè 32 nuove chat. Circa 25 inviti al giorno lasciano spazio alle nuove registrazioni. Un numero con 100 utenti attivi richiede quattro giorni, e chi è stato attivo più di recente va per primo, perché sono quelli che se ne accorgeranno.

Cosa deve dire l’invito?

L’invito deve dire che l’agente ha un nuovo numero, mostrare dove porta il link e suonare come un messaggio tuo, non come un avviso. Evita la parola «bannato»: agli utenti importa che Ava si sia spostata, non perché.

Oggetto: Ava ha un nuovo numero

Il vecchio numero WhatsApp di Ava ha smesso di funzionare. Tocca qui sotto per riprendere da dove vi eravate fermati. Il nome e la foto sono gli stessi, e lei si ricorda tutto. [Apri la chat]

Toccando il pulsante si apre WhatsApp con «Ciao, sono di nuovo io (codice 3f9a1c2e)» già pronto da inviare. Manda il link solo tramite la tua app o il tuo dominio. Un messaggio da un numero sconosciuto che dice di essere Ava ha l’aria di un tentativo di phishing, e il nuovo numero comunque non può mandarlo. Dopo la prima settimana conta tre cose: invitati, tornati e silenziosi. I silenziosi ricevono un solo promemoria.

Come riconosci un utente che torna e ripristini la cronologia?

Abbina la persona prima per telefono e poi per codice, poi carica la conversazione in base al tuo id utente. Il numero di telefono in chat è lo stesso sul nuovo numero e sul vecchio, quindi un utente che torna si trova senza codice. Il codice serve a chi scrive da un telefono nuovo.

declare const users: Map<string, User>;
declare const codes: Map<string, string>;
declare function reply(userId: string, text: string, opts: { moved: boolean }): Promise<void>; // il tuo agente: carica la cronologia in base all'id utente

export async function onInbound(m: { chat: string; number: string; text: string | null }) {
  const code = m.text?.match(/\(codice ([0-9a-f]{8})\)/)?.[1];
  const byCode = code ? users.get(codes.get(code) ?? "") : undefined;
  const user = byCode ?? [...users.values()].find((u) => u.phone === m.chat);
  if (!user) return; // uno sconosciuto: indicagli la registrazione

  if (code) codes.delete(code);
  user.phone = m.chat;
  const moved = user.number !== m.number;
  user.number = m.number; // questa chat ora sta sul nuovo numero
  // moved: fai dire all'agente «Sono io. Il mio vecchio numero ha smesso di funzionare, e mi ricordo ancora tutto.»
  await reply(user.id, m.text ?? "", { moved });
}

Chiama onInbound dal tuo gestore di message.received. La regola di progetto che sta dietro: indicizza la cronologia per utente, mai per numero. Se la tua tabella della memoria usa il numero whasp come parte della chiave, un ban rende orfana ogni conversazione. La memoria della conversazione mostra uno schema che sopravvive a uno spostamento.

Dì alla persona cosa è successo. Un agente che accoglie un utente che torna con il suo script di onboarding sembra un estraneo. Basta una riga: è lo stesso agente, il vecchio numero ha smesso di funzionare e la conversazione continua.

E se un utente non ha altri canali?

Se WhatsApp è il tuo unico canale con un utente, non puoi raggiungerlo. La vecchia chat è muta e il nuovo numero non può scrivere per primo. Tre abitudini riducono quel divario.

Raccogli un secondo canale alla registrazione. Un’email o un login nell’app costa un campo. È l’unica strada affidabile per tornare.

Pubblica un unico link stabile. Metti sul tuo dominio un reindirizzamento che chiede a GET /v1/numbers/pick un numero in salute al momento del clic. Usa quel link dove deve durare, come la tua app, le bio e i QR code, invece di un link wa.me grezzo.

// GET https://chat.example.com/ava: l'unico link che stampi, pubblichi e metti nelle email.
export async function GET() {
  const res = await fetch(
    `https://api.whasp.ai/v1/numbers/pick?text=${encodeURIComponent("Ciao, sono io")}`,
    { headers: { Authorization: `Bearer ${process.env.WHASP_API_KEY}` } },
  );
  if (!res.ok) return new Response("Riprova tra un minuto.", { status: 503 }); // 409 no_capacity
  const { wa_link } = await res.json();
  return Response.redirect(wa_link, 302);
}

Metti quel link nel profilo. Un sostituto mantiene il profilo, e la riga «info» per ora ammette fino a 139 caratteri in ASCII semplice. Un URL breve lì viaggia con ogni futuro sostituto e sta dove gli utenti possono leggerlo. Link wa.me e QR code spiega dove metterlo.

Cosa preparare prima del primo ban?

Qualsiasi numero usato come lo userebbe una persona può essere bannato, quindi preparati finché è tutto tranquillo.

  • Testa il gestore con un payload number.replaced di esempio, compresi un duplicato e una firma errata.
  • Prevedi un evento perso. whasp ritenta una consegna fino a 12 volte con backoff, poi si arrende e scarta il corpo, quindi non può essere rimandato. GET /v1/webhook/deliveries elenca gli ultimi 7 giorni. GET /v1/numbers elenca i tuoi numeri: uno che non riconosci è il sostituto, e i campi status e replaced_by mostrano cosa è successo al vecchio.
  • Usa più di un numero quando puoi. Un ban sposta allora solo gli utenti di quel numero. Di quanti numeri ha bisogno il tuo agente ha i conti.
  • Indicizza la cronologia per utente e tieni un numero di telefono su ogni record utente.

Cosa fare adesso

Aggiungi il gestore di number.replaced questa settimana, poi metti il link stabile nella tua app e nella riga «info» del profilo. D’ora in poi raccogli un’email alla registrazione. L’API completa è nella documentazione.

Domande

Cosa succede alle mie chat quando WhatsApp banna un numero?

Su whasp non si sposta nulla. Il numero bannato viene ritirato e ricevi un sostituto con la stessa etichetta, lo stesso profilo e lo stesso periodo pagato. Il nuovo numero parte senza chat, e la cronologia sta nel tuo sistema, quindi la ripristini quando ogni utente scrive.

Il numero sostitutivo può scrivere per primo ai miei utenti esistenti?

No. Un invio a chi non ha mai scritto a quel numero restituisce 409 chat_not_open, e la regola vale anche per i numeri sostitutivi. Gli utenti devono scrivere per primi, di solito toccando un link wa.me che mandi loro per email, push o nella tua app.

Quanti utenti posso spostare al giorno sul nuovo numero?

Un numero whasp consente 40 nuove chat ogni 24 ore e 100 chat attive in 30 giorni, e passa a at_risk oltre l'80% di un limite. Circa 25 inviti al giorno restano sotto quella soglia e lasciano spazio alle nuove registrazioni.

Come comunico il nuovo numero agli utenti se ho solo la loro chat WhatsApp?

Non puoi raggiungerli dal nuovo numero, e la chat bannata è muta. Preparati prima: raccogli un'email o un login nell'app alla registrazione e pubblica sul tuo dominio un link stabile che reindirizzi sempre a un numero in salute.

Cosa faccio se il mio webhook ha perso l'evento number.replaced?

whasp ritenta una consegna fino a 12 volte con backoff, poi si arrende e scarta il corpo. Elenca i tuoi numeri con GET /v1/numbers: uno che non riconosci è il sostituto, e i campi status e replaced_by mostrano cosa è successo al vecchio.

Tutti gli articoli