curl --request PATCH \
--url https://{instance}/wapi/v1/cards/{cardId}/stage \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"stageId": 9
}'import requests
url = "https://{instance}/wapi/v1/cards/{cardId}/stage"
payload = { "stageId": 9 }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({stageId: 9})
};
fetch('https://{instance}/wapi/v1/cards/{cardId}/stage', 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://{instance}/wapi/v1/cards/{cardId}/stage",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'stageId' => 9
]),
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://{instance}/wapi/v1/cards/{cardId}/stage"
payload := strings.NewReader("{\n \"stageId\": 9\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://{instance}/wapi/v1/cards/{cardId}/stage")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"stageId\": 9\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{instance}/wapi/v1/cards/{cardId}/stage")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"stageId\": 9\n}"
response = http.request(request)
puts response.read_body{
"requestId": "req_b71c40",
"card": {
"id": 981,
"title": "API — Maria Souza",
"value": 1500,
"status": "open",
"probability": 70,
"pipeline": {
"id": 2,
"name": "Vendas"
},
"stage": {
"id": 9,
"name": "Proposta enviada"
},
"contact": {
"id": 601,
"name": "Maria Souza",
"number": "5534992341048",
"email": null,
"tags": [
{
"id": 3,
"name": "Cliente ativo"
}
]
},
"user": {
"id": 12,
"name": "Ana Paula"
},
"source": {
"id": 4,
"name": "Indicação"
},
"lostReason": null,
"originTicketId": null,
"expectedCloseDate": "2026-10-15",
"closedAt": null,
"stageEnteredAt": "2026-09-23T09:45:00.000Z",
"createdAt": "2026-09-20T13:00:00.000Z",
"updatedAt": "2026-09-23T09:45:00.000Z"
}
}{
"error": "ERR_STAGE_REQUIRED",
"code": "ERR_STAGE_REQUIRED"
}{
"error": "Token não fornecido",
"code": "ERR_TOKEN_MISSING"
}{
"error": "Token sem permissão para esta ação",
"code": "ERR_SCOPE_MISSING"
}{
"error": "ERR_NO_CARD_FOUND",
"code": "ERR_NO_CARD_FOUND"
}{
"error": "ERR_STAGE_NOT_IN_PIPELINE",
"code": "ERR_STAGE_NOT_IN_PIPELINE"
}{
"error": "Limite de requisições excedido",
"code": "ERR_RATE_LIMITED"
}Mover card de etapa
Movimenta o card exatamente como um drag-and-drop no kanban do painel: dispara as mesmas automações de etapa configuradas no pipeline e emite o mesmo evento em tempo real do board — quem estiver com o kanban aberto vê o card mover na hora, sem recarregar a página. stageId é obrigatório e precisa pertencer ao MESMO pipeline do card; card inexistente ou de outra conta devolve 404 ERR_NO_CARD_FOUND; stageId ausente devolve 400 ERR_STAGE_REQUIRED; stageId inexistente (ou de outra conta) devolve 404 ERR_STAGE_NOT_FOUND; stageId que existe mas é de outro pipeline devolve 422 ERR_STAGE_NOT_IN_PIPELINE. Mover pra uma etapa final marca o card como ganho ou perdido conforme a configuração da etapa, e isso se reflete no status/probability da resposta. Requer escopo cards:write.
curl --request PATCH \
--url https://{instance}/wapi/v1/cards/{cardId}/stage \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"stageId": 9
}'import requests
url = "https://{instance}/wapi/v1/cards/{cardId}/stage"
payload = { "stageId": 9 }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({stageId: 9})
};
fetch('https://{instance}/wapi/v1/cards/{cardId}/stage', 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://{instance}/wapi/v1/cards/{cardId}/stage",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'stageId' => 9
]),
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://{instance}/wapi/v1/cards/{cardId}/stage"
payload := strings.NewReader("{\n \"stageId\": 9\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://{instance}/wapi/v1/cards/{cardId}/stage")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"stageId\": 9\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://{instance}/wapi/v1/cards/{cardId}/stage")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"stageId\": 9\n}"
response = http.request(request)
puts response.read_body{
"requestId": "req_b71c40",
"card": {
"id": 981,
"title": "API — Maria Souza",
"value": 1500,
"status": "open",
"probability": 70,
"pipeline": {
"id": 2,
"name": "Vendas"
},
"stage": {
"id": 9,
"name": "Proposta enviada"
},
"contact": {
"id": 601,
"name": "Maria Souza",
"number": "5534992341048",
"email": null,
"tags": [
{
"id": 3,
"name": "Cliente ativo"
}
]
},
"user": {
"id": 12,
"name": "Ana Paula"
},
"source": {
"id": 4,
"name": "Indicação"
},
"lostReason": null,
"originTicketId": null,
"expectedCloseDate": "2026-10-15",
"closedAt": null,
"stageEnteredAt": "2026-09-23T09:45:00.000Z",
"createdAt": "2026-09-20T13:00:00.000Z",
"updatedAt": "2026-09-23T09:45:00.000Z"
}
}{
"error": "ERR_STAGE_REQUIRED",
"code": "ERR_STAGE_REQUIRED"
}{
"error": "Token não fornecido",
"code": "ERR_TOKEN_MISSING"
}{
"error": "Token sem permissão para esta ação",
"code": "ERR_SCOPE_MISSING"
}{
"error": "ERR_NO_CARD_FOUND",
"code": "ERR_NO_CARD_FOUND"
}{
"error": "ERR_STAGE_NOT_IN_PIPELINE",
"code": "ERR_STAGE_NOT_IN_PIPELINE"
}{
"error": "Limite de requisições excedido",
"code": "ERR_RATE_LIMITED"
}Autorizações
Token criado em API → Tokens no painel. Prefixo wtx_live_ (ou wtx_test_).
Parâmetros de caminho
Corpo
Precisa ser do MESMO pipeline do card.