curl --request POST \
--url https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"connection_type": "waba",
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255"
}
}
'import requests
url = "https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate"
payload = {
"connection_type": "waba",
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
connection_type: 'waba',
waba: {
access_token: 'EAAxxxxxxx...',
phone_number_id: '1016102021584086',
waba_id: '419378847918255'
}
})
};
fetch('https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'connection_type' => 'waba',
'waba' => [
'access_token' => 'EAAxxxxxxx...',
'phone_number_id' => '1016102021584086',
'waba_id' => '419378847918255'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate"
payload := strings.NewReader("{\n \"connection_type\": \"waba\",\n \"waba\": {\n \"access_token\": \"EAAxxxxxxx...\",\n \"phone_number_id\": \"1016102021584086\",\n \"waba_id\": \"419378847918255\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"connection_type\": \"waba\",\n \"waba\": {\n \"access_token\": \"EAAxxxxxxx...\",\n \"phone_number_id\": \"1016102021584086\",\n \"waba_id\": \"419378847918255\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"connection_type\": \"waba\",\n \"waba\": {\n \"access_token\": \"EAAxxxxxxx...\",\n \"phone_number_id\": \"1016102021584086\",\n \"waba_id\": \"419378847918255\"\n }\n}"
response = http.request(request)
puts response.read_body{
"created_at": "2024-10-03T21:56:22.620Z",
"id": "xy9rexnkwobmgg3tehgvs",
"metadata": {
"customer_id": "123456",
"customer_name": "Joãozinho",
"phone_number": "+5587989075555"
},
"name": "MyNewInstance2",
"owner": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"display_name": null
},
"settings": {
"call_rejection": "all",
"delay_per_word": true,
"delete_chat_after_sent": true,
"message_delay": {
"enabled": true,
"max": 10,
"min": 1
},
"presence_behavior": "only_composing",
"read_confirmation": "never"
},
"status": "disconnected",
"webhooks": [
{
"enabled": true,
"events": [
"message.received"
],
"id": "2nenz69l0xbf0m3uu9tfo",
"name": "Webhook Name",
"test_mode": false,
"url": "https://webhook.mydomain.com",
"test_url": null
}
],
"connection_type": "unofficial",
"qrcode": null,
"lookup_key": "ins_8j7wlxmpjlixx9mux5"
}{
"errors": [
{
"code": "unsupported_webhook_event",
"message": "The events \"group.created\" are not supported by \"waba\" instances."
}
]
}{
"errors": [
{
"code": "waba_invalid_token",
"message": "The provided WABA access token is invalid or has expired. Please verify your credentials."
}
]
}{
"errors": [
{
"code": "instance_not_found",
"message": "Instance not found."
}
]
}{
"errors": [
{
"code": "confirmation_required",
"message": "This action interrupts the service of an instance that is currently \"connected\". Resend the request with the confirmation token to proceed.",
"details": {
"action": "instance.migrate_connection",
"confirmation_token": "eyJ2IjoxLCJhY3QiOiJpbnN0YW5jZS5taWdyYXRlX2Nvbm5lY3Rpb24ifQ.q1w2e3r4t5y6",
"expires_at": "2026-08-08T18:35:00.000Z",
"resource": "ozj35qv418rpmlrb",
"from": "unofficial",
"to": "waba",
"status": "connected",
"reason": "malformed"
}
}
]
}Migrando o Tipo de Conexão
Migra a instância entre a conexão não oficial (QR Code) e a API oficial (WABA), preservando o ID, os webhooks e as configurações.
curl --request POST \
--url https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"connection_type": "waba",
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255"
}
}
'import requests
url = "https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate"
payload = {
"connection_type": "waba",
"waba": {
"access_token": "EAAxxxxxxx...",
"phone_number_id": "1016102021584086",
"waba_id": "419378847918255"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
connection_type: 'waba',
waba: {
access_token: 'EAAxxxxxxx...',
phone_number_id: '1016102021584086',
waba_id: '419378847918255'
}
})
};
fetch('https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'connection_type' => 'waba',
'waba' => [
'access_token' => 'EAAxxxxxxx...',
'phone_number_id' => '1016102021584086',
'waba_id' => '419378847918255'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate"
payload := strings.NewReader("{\n \"connection_type\": \"waba\",\n \"waba\": {\n \"access_token\": \"EAAxxxxxxx...\",\n \"phone_number_id\": \"1016102021584086\",\n \"waba_id\": \"419378847918255\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"connection_type\": \"waba\",\n \"waba\": {\n \"access_token\": \"EAAxxxxxxx...\",\n \"phone_number_id\": \"1016102021584086\",\n \"waba_id\": \"419378847918255\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zapsterapi.com/v1/wa/instances/{instance_id}/migrate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"connection_type\": \"waba\",\n \"waba\": {\n \"access_token\": \"EAAxxxxxxx...\",\n \"phone_number_id\": \"1016102021584086\",\n \"waba_id\": \"419378847918255\"\n }\n}"
response = http.request(request)
puts response.read_body{
"created_at": "2024-10-03T21:56:22.620Z",
"id": "xy9rexnkwobmgg3tehgvs",
"metadata": {
"customer_id": "123456",
"customer_name": "Joãozinho",
"phone_number": "+5587989075555"
},
"name": "MyNewInstance2",
"owner": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"display_name": null
},
"settings": {
"call_rejection": "all",
"delay_per_word": true,
"delete_chat_after_sent": true,
"message_delay": {
"enabled": true,
"max": 10,
"min": 1
},
"presence_behavior": "only_composing",
"read_confirmation": "never"
},
"status": "disconnected",
"webhooks": [
{
"enabled": true,
"events": [
"message.received"
],
"id": "2nenz69l0xbf0m3uu9tfo",
"name": "Webhook Name",
"test_mode": false,
"url": "https://webhook.mydomain.com",
"test_url": null
}
],
"connection_type": "unofficial",
"qrcode": null,
"lookup_key": "ins_8j7wlxmpjlixx9mux5"
}{
"errors": [
{
"code": "unsupported_webhook_event",
"message": "The events \"group.created\" are not supported by \"waba\" instances."
}
]
}{
"errors": [
{
"code": "waba_invalid_token",
"message": "The provided WABA access token is invalid or has expired. Please verify your credentials."
}
]
}{
"errors": [
{
"code": "instance_not_found",
"message": "Instance not found."
}
]
}{
"errors": [
{
"code": "confirmation_required",
"message": "This action interrupts the service of an instance that is currently \"connected\". Resend the request with the confirmation token to proceed.",
"details": {
"action": "instance.migrate_connection",
"confirmation_token": "eyJ2IjoxLCJhY3QiOiJpbnN0YW5jZS5taWdyYXRlX2Nvbm5lY3Rpb24ifQ.q1w2e3r4t5y6",
"expires_at": "2026-08-08T18:35:00.000Z",
"resource": "ozj35qv418rpmlrb",
"from": "unofficial",
"to": "waba",
"status": "connected",
"reason": "malformed"
}
}
]
}Não oficial para API oficial (WABA)
Envieconnection_type: "waba" junto com o objeto waba, contendo access_token, phone_number_id e waba_id.
waba.connected.
API oficial (WABA) para não oficial
Envieconnection_type: "unofficial", sem credenciais. A configuração WABA é removida com segurança na Meta e um novo ambiente de conexão é preparado. A instância fica disconnected, aguardando a leitura do QR Code (ou código de pareamento) para conectar o número.
Webhooks são revalidados
Os tipos de conexão suportam conjuntos diferentes de eventos de webhook, e a API oficial suporta um conjunto menor. Antes de migrar, os webhooks já cadastrados na instância são validados contra o tipo de destino: se algum estiver inscrito em um evento que o destino não emite, a migração é rejeitada com400 (unsupported_webhook_event), listando todos os eventos incompatíveis e os eventos válidos. Ajuste as inscrições e repita a chamada.
Confirmação para instâncias em uso
Migrar uma instância que não estádisconnected interrompe o serviço dela durante a troca, mesmo quando ela está apenas offline: só a instância já disconnected dispensa a confirmação. Nesse caso, a chamada exige o header X-Confirmation-Token.
Esse token não é um valor arbitrário: é assinado pela própria API e vinculado ao usuário autenticado, à ação (instance.migrate_connection), à instância e ao tipo de conexão de destino. Um token obtido para migrar para waba não confirma uma migração para unofficial, e vice-versa. Ele expira em cerca de 5 minutos.
Existem duas formas de obter o token, e ambas produzem o mesmo resultado:
- Chame o endpoint sem o header. A resposta é
409(confirmation_required), e o corpo traz emdetails.confirmation_tokenum token já pronto para a chamada que você acabou de tentar, junto comexpires_at,from,to,statuseresource. Basta repetir a chamada idêntica com esse valor no header. - Peça o token antes de tentar migrar, em
POST /confirmations, informandoaction: "instance.migrate_connection", oresource(ID da instância) eparams.tocom o tipo de conexão de destino.
409 e um token novo pronto para uso. O campo details.reason existe só para depuração: o fluxo do cliente é sempre “recebi 409, pego o token, tento de novo”, nunca uma decisão baseada no motivo.
Essa confirmação não é uma camada de segurança. Quem tem o token de acesso da conta sempre consegue emitir uma confirmação; ela existe para tornar deliberada uma migração disruptiva que aconteceria por engano, não para impedir chamadas mal-intencionadas.Autorizações
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Cabeçalhos
Token de confirmação, obrigatório quando a instância NÃO está
desconectada, inclusive quando está offline: a migração interrompe
o serviço dela durante a troca. É um token opaco assinado pela
própria API, vinculado ao usuário autenticado, à ação e ao tipo de
conexão de destino, com validade de cerca de 5 minutos. Obtenha-o em
details.confirmation_token, na resposta 409 desta mesma chamada
sem o header, ou antecipadamente em POST /confirmations. Sem o
header nessa situação, a API responde 409 (confirmation_required).
Parâmetros de caminho
ID da instância.
Corpo
Tipo de conexão de destino:
unofficial: o metadata WABA é limpo e um pod é provisionado para a conexão por QR Codewaba: o pod é derrubado e o número é conectado pela Cloud API da Meta (exige credenciais)
unofficial, waba "waba"
Credenciais manuais da Cloud API da Meta, aceitas apenas
quando connection_type é waba.
Show child attributes
Show child attributes
Resposta
Success
Estrutura de uma instância registrada na API.
Data e hora de criação da instância no formato ISO 8601.
"2024-10-03T21:56:22.620Z"
Identificador único da instância.
"xy9rexnkwobmgg3tehgvs"
Metadados adicionais armazenados como chave e valor.
Show child attributes
Show child attributes
{ "customer_id": "123456", "customer_name": "Joãozinho", "phone_number": "+5587989075555" }
Nome da instância.
"MyNewInstance2"
Informações sobre o proprietário da instância.
Show child attributes
Show child attributes
Objeto opcional de configurações da sua instância.
Show child attributes
Show child attributes
Status atual da instância
connected, disconnected, offline "disconnected"
Lista de webhooks configurados para esta instância.
Show child attributes
Show child attributes
Tipo de conexão da instância:
unofficial: conexão via QR code (padrão)waba: conexão via API oficial do WhatsApp (Cloud API da Meta)
unofficial, waba "unofficial"
QR Code da instância, caso disponível.
null
Identificador de pesquisa criado anteriormente.
"ins_8j7wlxmpjlixx9mux5"