Monthly Statement
curl --request GET \
--url https://app.tuco.ai/api/agency/statement \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.tuco.ai/api/agency/statement"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.tuco.ai/api/agency/statement', 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/agency/statement",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
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/agency/statement"
req, _ := http.NewRequest("GET", 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.get("https://app.tuco.ai/api/agency/statement")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/agency/statement")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyAgency
Monthly Statement
What to invoice your clients this month — setup fees and prorated line charges, per client, per line. For agencies Tuco invoices offline.
GET
/
api
/
agency
/
statement
Monthly Statement
curl --request GET \
--url https://app.tuco.ai/api/agency/statement \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.tuco.ai/api/agency/statement"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.tuco.ai/api/agency/statement', 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/agency/statement",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
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/agency/statement"
req, _ := http.NewRequest("GET", 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.get("https://app.tuco.ai/api/agency/statement")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/agency/statement")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_bodyFor agencies Tuco invoices offline. Tuco bills you for the whole group, so
your client workspaces have no card and no Stripe subscription — which leaves
you working out what to charge each client by hand. This does the arithmetic.It charges nothing. You still send your own invoice.
Endpoint
- Method:
GET - Path:
/api/agency/statement - Auth:
Authorization: Bearer tucoagency_xxxxxxxxxxxxx(agency key)
Query parameters
| Name | Required | Notes |
|---|---|---|
month | no | YYYY-MM. Defaults to the current UTC month. Anything else is a 400 |
format | no | csv for a spreadsheet download. Omit for JSON |
How a line is priced
| Setup | Charged once, in full, in the month the line was ordered. Never prorated — it paid for provisioning work, not for time |
| Monthly | Prorated: rate × billable days ÷ days in month |
| Billing starts | The day the line is ordered, not the day it goes live. The provisioning wait is billable |
| Cancelling | Billed through the end of the month it takes effect, so the final month is always a full month |
setupRateCents and monthlyRateCents it was priced at,
so a number is always traceable to a rate.
Example request
curl "https://app.tuco.ai/api/agency/statement?month=2026-10" \
-H "Authorization: Bearer tucoagency_xxxxxxxxxxxxx"
Success response (200)
{
"agencyId": "user_3H08IRicrVUYLDZRyOh4jKRVwrx",
"month": "2026-10",
"periodStart": "2026-10-01T00:00:00.000Z",
"periodEnd": "2026-10-31T23:59:59.999Z",
"currency": "usd",
"workspaces": [
{
"clerkOrgId": "org_3KKJKupHJ8Y9I2NXVAga0c6ZqgT",
"name": "Acme Roofing",
"plan": "growth",
"setupRateCents": 16800,
"monthlyRateCents": 14500,
"lines": [
{
"lineId": "68c1f0a7d2b4e91f3c7a55e2",
"identifier": "+14155550134",
"channelType": "phone",
"orderedAt": "2026-09-10T11:02:00.000Z",
"endsAt": null,
"status": "active",
"billableDays": 31,
"daysInMonth": 31,
"setupCents": 0,
"monthlyCents": 14500,
"totalCents": 14500,
"fullMonth": true
},
{
"lineId": "68c1f0a7d2b4e91f3c7a55e9",
"identifier": "+14155550198",
"channelType": "phone",
"orderedAt": "2026-10-20T09:14:00.000Z",
"endsAt": null,
"status": "provisioning",
"billableDays": 12,
"daysInMonth": 31,
"setupCents": 16800,
"monthlyCents": 5613,
"totalCents": 22413,
"fullMonth": false
}
],
"setupCents": 16800,
"monthlyCents": 20113,
"totalCents": 36913
}
],
"newLines": 1,
"activeLines": 2,
"setupCents": 16800,
"monthlyCents": 20113,
"totalCents": 36913
}
14500 × 12 ÷ 31 = 5613.
Fields
| Field | |
|---|---|
billableDays / daysInMonth | The proration, shown so a client can check it |
fullMonth | true when the line ran the whole month and monthlyCents is the undivided rate |
orderedAt | When billing started for this line |
endsAt | When it stops, or null while it is running |
newLines | Lines ordered this month — the ones carrying a setup fee |
activeLines | Lines still running at period end |
CSV
curl "https://app.tuco.ai/api/agency/statement?month=2026-10&format=csv" \
-H "Authorization: Bearer tucoagency_xxxxxxxxxxxxx" -o statement.csv
TOTAL row, with dollar amounts rather than cents —
ready to paste into whatever you invoice from.
Error responses
| Status | Code | When |
|---|---|---|
400 | INVALID_MONTH | month is not YYYY-MM |
401 | UNAUTHORIZED | Missing, unknown, revoked or expired key |
403 | AGENCY_KEY_REQUIRED | A workspace key (tuco_…) was used |
409 | NOT_INVOICED | Your clients are billed through Stripe — their real invoices and your MRR are on the Billing tab |
A Stripe-billed agency gets a
409 on purpose. It already has real Stripe
invoices; a second set of numbers computed a different way would be two
sources of truth that can disagree.