Cancel phone line
⚠️ Real side effect — this is NOT a simulation, including from the playground. Cancels the line and answers the line as it is afterwards. What happens depends on its status:
status before | Result | Response |
|---|---|---|
ACTIVE | Cancelled at period end, no refund. The line stays ACTIVE and fully usable — activation codes included — until currentPeriodEnd; it is not renewed and becomes CANCELED when the period ends. | 200, status: "ACTIVE", cancelAtPeriodEnd: true |
ACTIVE, already cancelled | Nothing changes — calling again is safe. | 200, same line |
PAYMENT_PENDING, SUSPENDED | Returned to the carrier immediately — IRREVERSIBLE. There is no paid period left. | 200, status: "RETURNED" |
RETURNED, CANCELED | Refused — the line is already finished. | 409 NOT_CANCELABLE |
A returned number stops being yours: nothing undoes a return, and there is no guarantee it can be bought back — it goes back to the carrier’s pool, where anyone may rent it next. The WhatsApp account activated on it stays tied to that number. The line’s code history — codes and call recordings — is deleted. Cancelling an unpaid line does this at once, with no grace period. Undoing a scheduled cancellation of an ACTIVE line is dashboard-only (Owner).
If a return of the same unpaid line is already under way (hourly billing run, or the dashboard’s Choose which lines to keep), the call answers 200 with the line as it stands — possibly still PAYMENT_PENDING or SUSPENDED — and that process completes the return. Events: phone_line.canceled when a line cancelled at period end becomes CANCELED; phone_line.returned with reason: "canceled_by_customer" right away for an unpaid line returned by this call.
Permissions: with an OAuth / MCP token, only the workspace Owner may cancel (phone_lines:cancel) — 403 PERMISSION_DENIED otherwise.
Every /v1/phone-lines endpoint takes a tenant-scoped key only: a line belongs to the workspace, not to a WhatsApp number, so a number-scoped key (or a per-number OAuth grant) gets 403 NUMBER_SCOPE_NOT_ALLOWED before any role is looked at. A 403 PERMISSION_DENIED / WORKSPACE_MEMBERSHIP_REQUIRED is sent with Cache-Control: no-store.
Requires a tenant-scoped key.
curl --request DELETE \
--url https://pilotstatus.com.br/v1/phone-lines/{id} \
--header 'x-api-key: <api-key>'import requests
url = "https://pilotstatus.com.br/v1/phone-lines/{id}"
headers = {"x-api-key": "<api-key>"}
response = requests.delete(url, headers=headers)
print(response.text)const options = {method: 'DELETE', headers: {'x-api-key': '<api-key>'}};
fetch('https://pilotstatus.com.br/v1/phone-lines/{id}', 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/phone-lines/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://pilotstatus.com.br/v1/phone-lines/{id}"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.delete("https://pilotstatus.com.br/v1/phone-lines/{id}")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://pilotstatus.com.br/v1/phone-lines/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"line": {
"id": "cmg5k2l1n0001pl8example9x",
"name": "Support SP",
"number": "551148637200",
"display": "(11) 4863-7200",
"ddd": "11",
"status": "ACTIVE",
"price": 33.9,
"currency": "BRL",
"purchasedAt": "2026-10-01T14:03:11.000Z",
"currentPeriodEnd": "2026-11-01T14:03:11.000Z",
"cancelAtPeriodEnd": true,
"paymentPendingSince": null,
"suspendedAt": null,
"returnedAt": null,
"canceledAt": null,
"activationCount": 1,
"amountDue": null
}
}ACTIVE line is cancelled at the end of its period, with no refund. An unpaid line (PAYMENT_PENDING, SUSPENDED) is returned to the carrier at once, with no guarantee it can be bought back, and its code history is deleted. See Cancel a line.Was this page helpful?
curl --request DELETE \
--url https://pilotstatus.com.br/v1/phone-lines/{id} \
--header 'x-api-key: <api-key>'import requests
url = "https://pilotstatus.com.br/v1/phone-lines/{id}"
headers = {"x-api-key": "<api-key>"}
response = requests.delete(url, headers=headers)
print(response.text)const options = {method: 'DELETE', headers: {'x-api-key': '<api-key>'}};
fetch('https://pilotstatus.com.br/v1/phone-lines/{id}', 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/phone-lines/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"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"
"net/http"
"io"
)
func main() {
url := "https://pilotstatus.com.br/v1/phone-lines/{id}"
req, _ := http.NewRequest("DELETE", url, nil)
req.Header.Add("x-api-key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.delete("https://pilotstatus.com.br/v1/phone-lines/{id}")
.header("x-api-key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://pilotstatus.com.br/v1/phone-lines/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Delete.new(url)
request["x-api-key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"line": {
"id": "cmg5k2l1n0001pl8example9x",
"name": "Support SP",
"number": "551148637200",
"display": "(11) 4863-7200",
"ddd": "11",
"status": "ACTIVE",
"price": 33.9,
"currency": "BRL",
"purchasedAt": "2026-10-01T14:03:11.000Z",
"currentPeriodEnd": "2026-11-01T14:03:11.000Z",
"cancelAtPeriodEnd": true,
"paymentPendingSince": null,
"suspendedAt": null,
"returnedAt": null,
"canceledAt": null,
"activationCount": 1,
"amountDue": null
}
}