Deprecate Flow
Retires a Flow from circulation on Meta without deleting it, and without deleting the responses people already submitted. Not the same as DELETE /v1/flows/{id}: delete works only on a DRAFT and removes the row; deprecate acts on a Flow that reached Meta and only marks it.
supersededByFlowId closes the pair with clonedFromFlowId: the clone points backwards, the deprecation forwards. Since publishing is irreversible, that pointer is the only thing tying the versions of one form together over time.
supersededBy is echoed in the response always, null included — it is the only way to tell “the successor I sent was recorded” from “the field was dropped between my client and the row”. A truncated body is 400, not an empty one, because an empty body is a legitimate request here. Permission flows:manage.
Requires a number-scoped key. A tenant-scoped key must name the number with the x-whatsapp-number-id header, or it gets 403 TENANT_SCOPE_NOT_ALLOWED.
curl --request POST \
--url https://pilotstatus.com.br/v1/flows/{id}/deprecate \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"supersededByFlowId": "cmf2b3c4d5e6f7g8h9i0j1k2"
}
'import requests
url = "https://pilotstatus.com.br/v1/flows/{id}/deprecate"
payload = { "supersededByFlowId": "cmf2b3c4d5e6f7g8h9i0j1k2" }
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({supersededByFlowId: 'cmf2b3c4d5e6f7g8h9i0j1k2'})
};
fetch('https://pilotstatus.com.br/v1/flows/{id}/deprecate', 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://pilotstatus.com.br/v1/flows/{id}/deprecate",
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([
'supersededByFlowId' => 'cmf2b3c4d5e6f7g8h9i0j1k2'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$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://pilotstatus.com.br/v1/flows/{id}/deprecate"
payload := strings.NewReader("{\n \"supersededByFlowId\": \"cmf2b3c4d5e6f7g8h9i0j1k2\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
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://pilotstatus.com.br/v1/flows/{id}/deprecate")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"supersededByFlowId\": \"cmf2b3c4d5e6f7g8h9i0j1k2\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pilotstatus.com.br/v1/flows/{id}/deprecate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"supersededByFlowId\": \"cmf2b3c4d5e6f7g8h9i0j1k2\"\n}"
response = http.request(request)
puts response.read_body{
"flowId": "cmf1a2b3c4d5e6f7g8h9i0j1",
"deprecated": true,
"supersededBy": "cmf2b3c4d5e6f7g8h9i0j1k2"
}{
"error": "`supersededByFlowId`, quando enviado, tem de ser o id LOCAL (não vazio) do Flow sucessor — o mesmo `id` que `GET /api/v1/flows` devolve, e não o `metaFlowId`. Omita o campo para depreciar sem sucessor.",
"errorEN": "`supersededByFlowId`, when sent, must be the LOCAL (non-empty) id of the successor Flow — the same `id` `GET /api/v1/flows` returns, not the `metaFlowId`. Omit the field to deprecate with no successor.",
"code": "FLOW_DEPRECATE_INVALID_SUCCESSOR"
}{
"error": "Unauthorized"
}{
"error": "Tenant-scoped keys cannot call number endpoints",
"code": "TENANT_SCOPE_NOT_ALLOWED"
}{
"error": "Flow não encontrado para o número desta chave.",
"errorEN": "Flow not found for this key's number.",
"code": "FLOW_NOT_FOUND"
}{
"error": "Este Flow já foi publicado na Meta e não pode mais ser alterado. Clone-o para criar uma nova versão.",
"errorEN": "This Flow is already published on Meta and can no longer be changed. Clone it to create a new version.",
"code": "FLOW_NOT_DRAFT"
}{
"error": "Flows existem apenas em números Meta (API Oficial). O número desta chave não é Meta ou não tem uma WABA associada — use uma chave de um número Meta.",
"errorEN": "Flows only exist on Meta (Cloud API) numbers. This key's number is not a Meta number, or has no WABA behind it — use a key bound to a Meta number.",
"code": "FLOW_REQUIRES_META_NUMBER"
}{
"error": "Too many requests"
}{
"error": "Erro interno do servidor.",
"errorEN": "Internal server error.",
"code": "INTERNAL_ERROR"
}Authorizations
Your ps_ API key
Path Parameters
The local id of the Flow — the id field GET /v1/flows returns, never metaFlowId.
Body
The LOCAL id of the successor Flow — the same id GET /v1/flows returns, not the metaFlowId. Optional: deprecating with no successor is legitimate. But present-and-unusable is a different request from absent — an empty or whitespace-only string is refused with 400 FLOW_DEPRECATE_INVALID_SUCCESSOR rather than dropped, because a version chain that ends silently is invisible afterwards. The successor is verified to belong to your tenant; one that does not is 404.
1"cmf2b3c4d5e6f7g8h9i0j1k2"
Response
Flow deprecated
Was this page helpful?
curl --request POST \
--url https://pilotstatus.com.br/v1/flows/{id}/deprecate \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"supersededByFlowId": "cmf2b3c4d5e6f7g8h9i0j1k2"
}
'import requests
url = "https://pilotstatus.com.br/v1/flows/{id}/deprecate"
payload = { "supersededByFlowId": "cmf2b3c4d5e6f7g8h9i0j1k2" }
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({supersededByFlowId: 'cmf2b3c4d5e6f7g8h9i0j1k2'})
};
fetch('https://pilotstatus.com.br/v1/flows/{id}/deprecate', 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://pilotstatus.com.br/v1/flows/{id}/deprecate",
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([
'supersededByFlowId' => 'cmf2b3c4d5e6f7g8h9i0j1k2'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$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://pilotstatus.com.br/v1/flows/{id}/deprecate"
payload := strings.NewReader("{\n \"supersededByFlowId\": \"cmf2b3c4d5e6f7g8h9i0j1k2\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
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://pilotstatus.com.br/v1/flows/{id}/deprecate")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"supersededByFlowId\": \"cmf2b3c4d5e6f7g8h9i0j1k2\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pilotstatus.com.br/v1/flows/{id}/deprecate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"supersededByFlowId\": \"cmf2b3c4d5e6f7g8h9i0j1k2\"\n}"
response = http.request(request)
puts response.read_body{
"flowId": "cmf1a2b3c4d5e6f7g8h9i0j1",
"deprecated": true,
"supersededBy": "cmf2b3c4d5e6f7g8h9i0j1k2"
}{
"error": "`supersededByFlowId`, quando enviado, tem de ser o id LOCAL (não vazio) do Flow sucessor — o mesmo `id` que `GET /api/v1/flows` devolve, e não o `metaFlowId`. Omita o campo para depreciar sem sucessor.",
"errorEN": "`supersededByFlowId`, when sent, must be the LOCAL (non-empty) id of the successor Flow — the same `id` `GET /api/v1/flows` returns, not the `metaFlowId`. Omit the field to deprecate with no successor.",
"code": "FLOW_DEPRECATE_INVALID_SUCCESSOR"
}{
"error": "Unauthorized"
}{
"error": "Tenant-scoped keys cannot call number endpoints",
"code": "TENANT_SCOPE_NOT_ALLOWED"
}{
"error": "Flow não encontrado para o número desta chave.",
"errorEN": "Flow not found for this key's number.",
"code": "FLOW_NOT_FOUND"
}{
"error": "Este Flow já foi publicado na Meta e não pode mais ser alterado. Clone-o para criar uma nova versão.",
"errorEN": "This Flow is already published on Meta and can no longer be changed. Clone it to create a new version.",
"code": "FLOW_NOT_DRAFT"
}{
"error": "Flows existem apenas em números Meta (API Oficial). O número desta chave não é Meta ou não tem uma WABA associada — use uma chave de um número Meta.",
"errorEN": "Flows only exist on Meta (Cloud API) numbers. This key's number is not a Meta number, or has no WABA behind it — use a key bound to a Meta number.",
"code": "FLOW_REQUIRES_META_NUMBER"
}{
"error": "Too many requests"
}{
"error": "Erro interno do servidor.",
"errorEN": "Internal server error.",
"code": "INTERNAL_ERROR"
}