Cancel a Line
curl --request POST \
--url https://app.tuco.ai/api/lines/cancel \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.tuco.ai/api/lines/cancel"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.tuco.ai/api/lines/cancel', 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://app.tuco.ai/api/lines/cancel",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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://app.tuco.ai/api/lines/cancel"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.tuco.ai/api/lines/cancel")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/lines/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyLines & Leads
Cancel a Line
Request a line cancellation. The line keeps sending until the end of the period you have paid for, then stops. Nothing is deleted.
POST
/
api
/
lines
/
cancel
Cancel a Line
curl --request POST \
--url https://app.tuco.ai/api/lines/cancel \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.tuco.ai/api/lines/cancel"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.tuco.ai/api/lines/cancel', 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://app.tuco.ai/api/lines/cancel",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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://app.tuco.ai/api/lines/cancel"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.tuco.ai/api/lines/cancel")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/lines/cancel")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyThis is a cancellation request, shaped like cancelling a subscription — not
a delete. The line keeps working right up to the end of the period you have
already paid for. Nothing is removed, and the conversations on it stay readable
afterwards.
Endpoint
- Method:
POST - Path:
/api/lines/cancel - Auth:
Authorization: Bearer tuco_xxxxxxxxxxxxx(workspace key)
Body
| Field | Type | Required | Notes |
|---|---|---|---|
lineId | string | yes | The line to cancel. 24-character hex id, from GET /api/lines |
Example request
curl https://app.tuco.ai/api/lines/cancel \
-H "Authorization: Bearer tuco_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "lineId": "6ac583d23e36ad490e7a902b" }'
Success response (200)
{
"success": true,
"lineId": "6ac583d23e36ad490e7a902b",
"status": "cancellation_requested",
"newlyRequested": true,
"cancelEffectiveAt": "2026-10-31T23:59:59.999Z",
"cancelBasis": "calendar_month_end",
"setupFeeRefunded": false,
"message": "Cancellation requested. This line keeps sending until 2026-10-31T23:59:59.999Z, then stops. The setup fee is not refunded."
}
The line keeps sending
This is the part worth internalising: a cancelled line is still a working line untilcancelEffectiveAt. It sends, it receives, it appears in your
campaigns. You paid for the period; you keep it.
What changes immediately is only what the line is called.
GET /api/lines reports:
status | Meaning |
|---|---|
active | Normal |
cancellation_requested | Cancelled, still sending, stops at cancelEffectiveAt |
canceled | The date has passed. No longer sends |
cancelEffectiveAt, or null if it is not cancelling.
When it stops
cancelBasis | |
|---|---|
subscription_period_end | The end of your current Stripe billing period |
calendar_month_end | The last moment of the current UTC month — used when Tuco invoices your agency and there is no Stripe period to read |
The setup fee is not refunded. It paid for provisioning that has already
happened — a number acquired, a device configured.
setupFeeRefunded: false is
returned on every response rather than left unsaid.Calling it twice is safe
A second request returns the same date withnewlyRequested: false. The
date is set once and never recomputed, so a repeated call can never
accidentally move your cancellation into the following month.
{
"success": true,
"status": "cancellation_requested",
"newlyRequested": false,
"cancelEffectiveAt": "2026-10-31T23:59:59.999Z",
"message": "This line was already scheduled to stop at 2026-10-31T23:59:59.999Z."
}
Only an active line
A line that is still being provisioned has never sent anything, so there is no paid period to run out. Cancel that order instead — the error says so:{
"error": "Only an active line can be cancelled at period end. A line still being provisioned is cancelled through POST /api/line-requests/{id} with action \"cancel\".",
"code": "LINE_NOT_ACTIVE",
"status": "provisioning"
}
Error responses
| Status | Code | When |
|---|---|---|
400 | LINE_REQUIRED | lineId missing |
400 | LINE_NOT_ACTIVE | The line is not active — see above |
401 | UNAUTHORIZED | Missing, unknown, revoked or expired key |
403 | NO_SUBSCRIPTION | The workspace has no active plan |
403 | AGENCY_ONLY | An agency-owned workspace: only the agency can cancel its lines |
404 | LINE_NOT_FOUND | No such line in this workspace |