API reference
Billing API
LanaChat is paid from one prepaid balance in US dollars: licences (one per Telegram account, 30 days) and a commission on net sales are taken from it. You top it up with crypto deposits. Affiliate earnings can be withdrawn. Every billing endpoint needs an owner token: in the examples, $LANACHAT_TOKEN holds one.
Every endpoint on this page is marked Planned: it is the published contract the backend is built from, and it does not answer yet.
Endpoints #
| Method | Path | Description | Permission | Status |
|---|---|---|---|---|
| GET | /billing/balance | The balance, this month's net sales and commission tier | owner | Planned |
| GET | /billing/ledger | Every movement: deposits, licences, commission, refunds | owner | Planned |
| GET | /billing/ledger.csv | The same ledger as CSV (from=, to=) | owner | Planned |
| GET | /billing/deposit-addresses | One deposit address per chain (with a memo on Solana) | owner | Planned |
| GET | /billing/deposits | Deposits and their confirmations | owner | Planned |
| GET | /billing/licences | Licences in stock and assigned, with days left | owner | Planned |
| POST | /billing/licences/buy | Buy licences: single or a pack of 10, 25 or 50 | owner | Planned |
| POST | /billing/licences/assign | Give a licence from stock to an account | owner | Planned |
| POST | /billing/licences/unassign | Take it back to stock with its days left | owner | Planned |
| PATCH | /billing/licences/auto-renew | Turn auto-renew on or off for an account | owner | Planned |
| GET | /billing/withdrawals | Affiliate withdrawals and their status | owner | Planned |
| POST | /billing/withdrawals | Ask for a withdrawal of affiliate earnings (from $500) | owner | Planned |
| GET | /billing/invoices | Monthly statements (year=) | owner | Planned |
| GET | /billing/invoices/{id}.pdf | One statement as PDF | owner | Planned |
| PUT | /billing/details | Company name, address and VAT number on statements | owner | Planned |
Prices in one table #
| What | Price |
|---|---|
| One licence (one Telegram account, 30 days) | $19 |
| Pack of 10 licences | $170 |
| Pack of 25 licences | $375 |
| Pack of 50 licences | $650 |
| Commission up to $30k of net sales in the month | 12% of AI sales, 4% of manual sales |
| Commission from $30k to $100k | 10% and 3% |
| Commission above $100k | 8% and 2% |
The counter is the net sales of the whole workspace in the calendar month; it resets on the 1st. Telegram Stars count at $0.013 each in net sales.
The balance object #
{
"balance_cents": 48210,
"month": "2026-10",
"net_sales_cents": 1870400,
"tier": { "up_to_cents": 3000000, "ai_rate_bp": 1200, "manual_rate_bp": 300 },
"licences": { "in_stock": 4, "assigned": 11, "expiring_7d": 2 },
"low_balance": false
}| Field | Type | Description |
|---|---|---|
balance_cents | integer | Prepaid balance, in US cents |
month | string | The calendar month counted, YYYY-MM |
net_sales_cents | integer | Net sales of the workspace this month |
tier | object | The current tier: its ceiling up_to_cents, the AI rate and the manual rate in basis points |
licences | object | Licences in_stock, assigned, and assigned ones ending within 7 days (expiring_7d) |
low_balance | boolean | true when the balance does not cover the next 7 days of licences |
Rates are in basis points: 1200 is 12%.
The ledger entry object #
Each line of Billing › Activity in the Console.
{
"id": "led_90211",
"at": "2026-10-06T14:40:00Z",
"kind": "licences",
"label": "Licences · pack of 10",
"amount_cents": -17000,
"balance_after_cents": 31210
}| Field | Type | Description |
|---|---|---|
id | string | The line |
at | string | ISO 8601, UTC |
kind | string | deposit, licences, commission, refund, affiliate or other |
label | string | The text of the line, as in the Console |
amount_cents | integer | Positive when money comes in, negative when it goes out |
balance_after_cents | integer | The balance after this line |
A commission line belongs to one sale: the Console shows the fan, the tier, who sent the offer (AI or manual), how the net was counted ("12,500 ★ × $0.013") and the rate.
The deposit object #
{
"id": "dep_4",
"at": "2026-10-06T13:52:00Z",
"chain": "usdt-tron",
"sent_cents": 100000,
"fee_cents": 1000,
"credited_cents": 99000,
"status": "pending",
"confirmations": "12/19"
}| Field | Type | Description |
|---|---|---|
id | string | The deposit |
at | string | When it was seen, ISO 8601 |
chain | string | usdc-eth, usdc-sol, usdt-sol, usdt-tron or usdt-eth |
sent_cents, fee_cents, credited_cents | integer | What you sent, the fee, what lands on the balance |
status | string | pending then confirmed |
confirmations | string | Network confirmations counted, while pending |
USDC on Ethereum is credited 1:1 with no fee. Every other chain has a 1% fee: the deposit is converted to USDC (ERC20) when it arrives. The minimum is $25 per top-up.
The licence object #
{
"account_id": "acc_1001",
"creator_id": "cr_lea",
"days_left": 18,
"expires_at": "2026-10-24T09:00:00Z",
"auto_renew": true
}| Field | Type | Description |
|---|---|---|
account_id | string | The Telegram account the licence runs on |
creator_id | string | Her creator |
days_left | integer | Days before it ends, out of 30 |
expires_at | string | When it ends |
auto_renew | boolean | Renew from stock (or buy a single) when it ends |
Licences in stock are counted, not listed one by one: each keeps its own days left (30 for a new one).
The withdrawal object #
{ "id": "wd_118", "status": "pending_review", "amount_cents": 50000, "requested_at": "2026-10-06T15:00:00Z", "tx_hash": null }| Field | Type | Description |
|---|---|---|
id | string | The withdrawal |
status | string | pending_review, sent (with tx_hash) or rejected with a reason |
amount_cents | integer | Amount asked, at least 50000 ($500) |
requested_at | string | ISO 8601, UTC |
tx_hash | string or null | The transaction, once sent |
The invoice object #
{
"id": "LC-2026-09",
"month": "2026-09",
"licences_cents": 22800,
"commission_cents": 930000,
"total_cents": 952800,
"status": "paid",
"pdf_url": "https://api.lanachat.ai/v1/billing/invoices/LC-2026-09.pdf"
}| Field | Type | Description |
|---|---|---|
id | string | Statement number, LC-YYYY-MM |
month | string | The month it covers |
licences_cents, commission_cents, total_cents | integer | Licences, commission and total of the month |
status | string | Paid, in progress (the current month) or failed |
pdf_url | string | The PDF of the statement |
Balance and ledger #
Get the balance #
/billing/balancePlannedNeeds ownercurl https://api.lanachat.ai/v1/billing/balance \
-H "Authorization: Bearer $LANACHAT_TOKEN"const res = await fetch('https://api.lanachat.ai/v1/billing/balance', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/balance",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
print(r.json())The answer is the balance object.
List the ledger #
/billing/ledgerPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
from, to | string | No | Days YYYY-MM-DD, UTC, both included |
limit, cursor | number, string | No | Pagination |
curl "https://api.lanachat.ai/v1/billing/ledger?from=2026-10-01&to=2026-10-06" \
-H "Authorization: Bearer $LANACHAT_TOKEN"const res = await fetch('https://api.lanachat.ai/v1/billing/ledger?from=2026-10-01&to=2026-10-06', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/ledger?from=2026-10-01&to=2026-10-06",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
print(r.json()){
"data": [
{ "id": "led_90211", "at": "2026-10-06T14:40:00Z", "kind": "licences", "label": "Licences · pack of 10", "amount_cents": -17000, "balance_after_cents": 31210 },
{ "id": "led_90207", "at": "2026-10-06T13:20:00Z", "kind": "commission", "label": "Lea · Marco", "amount_cents": -468, "balance_after_cents": 48210 },
{ "id": "led_90150", "at": "2026-10-05T09:02:00Z", "kind": "deposit", "label": "Deposit · USDC on Ethereum", "amount_cents": 300000, "balance_after_cents": 48678 }
],
"next_cursor": "eyJpZCI6ImxlZF85MDE0OSJ9"
}Export the ledger as CSV #
/billing/ledger.csvPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
from, to | string | No | Days YYYY-MM-DD, UTC |
curl "https://api.lanachat.ai/v1/billing/ledger.csv?from=2026-09-01&to=2026-09-30" \
-H "Authorization: Bearer $LANACHAT_TOKEN" -o ledger-2026-09.csvimport { writeFile } from 'node:fs/promises';
const res = await fetch('https://api.lanachat.ai/v1/billing/ledger.csv?from=2026-09-01&to=2026-09-30', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile('ledger-2026-09.csv', Buffer.from(await res.arrayBuffer()));import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/ledger.csv?from=2026-09-01&to=2026-09-30",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
with open("ledger-2026-09.csv", "wb") as f:
f.write(r.content)The same lines as Export CSV in Billing › Activity, ready for your accountant.
Deposits #
Get the deposit addresses #
/billing/deposit-addressesPlannedNeeds ownercurl https://api.lanachat.ai/v1/billing/deposit-addresses \
-H "Authorization: Bearer $LANACHAT_TOKEN"const res = await fetch('https://api.lanachat.ai/v1/billing/deposit-addresses', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/deposit-addresses",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
print(r.json())The answer gives one address per chain (Ethereum, Solana, Tron) and, for Solana, the memo.
On Solana, a deposit sent without the memo cannot be matched to your workspace. Always send both the address and the memo.
You can send USDC on Ethereum (ERC20), USDC on Solana, USDT on Solana, USDT on Tron (TRC20) or USDT on Ethereum (ERC20). The network fee of your transfer is paid from your wallet.
List deposits #
/billing/depositsPlannedNeeds ownercurl https://api.lanachat.ai/v1/billing/deposits \
-H "Authorization: Bearer $LANACHAT_TOKEN"const res = await fetch('https://api.lanachat.ai/v1/billing/deposits', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/deposits",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
print(r.json()){
"data": [
{ "id": "dep_4", "at": "2026-10-06T13:52:00Z", "chain": "usdt-tron", "sent_cents": 100000, "fee_cents": 1000, "credited_cents": 99000, "status": "pending", "confirmations": "12/19" },
{ "id": "dep_3", "at": "2026-10-05T09:02:00Z", "chain": "usdc-eth", "sent_cents": 300000, "fee_cents": 0, "credited_cents": 300000, "status": "confirmed", "confirmations": null }
],
"next_cursor": null
}The balance is credited automatically when a deposit is confirmed; it is then also a deposit line of the ledger.
Licences #
List licences #
/billing/licencesPlannedNeeds ownercurl https://api.lanachat.ai/v1/billing/licences \
-H "Authorization: Bearer $LANACHAT_TOKEN"const res = await fetch('https://api.lanachat.ai/v1/billing/licences', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/licences",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
print(r.json())The answer gives the licences in stock and one licence object per assigned account, with its days left.
Buy licences #
/billing/licences/buyPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
pack | integer | Yes | 1 (single, $19), 10 ($170), 25 ($375) or 50 ($650) |
qty | integer | Yes | How many of that pack |
curl -X POST https://api.lanachat.ai/v1/billing/licences/buy \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"pack": 10, "qty": 1}'const res = await fetch('https://api.lanachat.ai/v1/billing/licences/buy', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({ pack: 10, qty: 1 }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import uuid
import requests
r = requests.post(
"https://api.lanachat.ai/v1/billing/licences/buy",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"pack": 10, "qty": 1},
timeout=30,
)
r.raise_for_status()
print(r.json()){ "licences_added": 10, "amount_cents": 17000, "balance_cents": 31210, "ledger_id": "led_90211" }The licences go to your stock at once. A balance too low answers 402 (insufficient_balance). Licences in stock never expire, and bought licences are not refundable.
Assign a licence #
/billing/licences/assignPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | string | Yes | The Telegram account that gets a licence |
curl -X POST https://api.lanachat.ai/v1/billing/licences/assign \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"account_id": "acc_1001"}'const res = await fetch('https://api.lanachat.ai/v1/billing/licences/assign', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({ account_id: 'acc_1001' }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import uuid
import requests
r = requests.post(
"https://api.lanachat.ai/v1/billing/licences/assign",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"account_id": "acc_1001"},
timeout=30,
)
r.raise_for_status()
print(r.json())The answer is the licence object of the account. The stock licence with the fewest days left is used first: its remaining days, or 30 days if it is new. Auto-renew is on by default.
Take a licence back #
/billing/licences/unassignPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | string | Yes | The account that gives its licence back |
curl -X POST https://api.lanachat.ai/v1/billing/licences/unassign \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"account_id": "acc_1001"}'const res = await fetch('https://api.lanachat.ai/v1/billing/licences/unassign', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({ account_id: 'acc_1001' }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import uuid
import requests
r = requests.post(
"https://api.lanachat.ai/v1/billing/licences/unassign",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"account_id": "acc_1001"},
timeout=30,
)
r.raise_for_status()
print(r.json())The licence goes back to your stock with its days left. The AI stops replying on that account right away. To move a licence to another account, take it back, then assign it: it keeps its days, for free.
Turn auto-renew on or off #
/billing/licences/auto-renewPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | string | Yes | The account |
auto_renew | boolean | Yes | true to renew it when its days run out |
curl -X PATCH https://api.lanachat.ai/v1/billing/licences/auto-renew \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"account_id": "acc_1001", "auto_renew": false}'const res = await fetch('https://api.lanachat.ai/v1/billing/licences/auto-renew', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ account_id: 'acc_1001', auto_renew: false }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.patch(
"https://api.lanachat.ai/v1/billing/licences/auto-renew",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
json={"account_id": "acc_1001", "auto_renew": False},
timeout=30,
)
r.raise_for_status()
print(r.json())When the days run out, auto-renew takes a licence from your stock first, or buys a single licence ($19) if the stock is empty. It cannot buy without balance: watch low_balance or the billing.low_balance webhook.
Affiliate withdrawals #
List withdrawals #
/billing/withdrawalsPlannedNeeds ownercurl https://api.lanachat.ai/v1/billing/withdrawals \
-H "Authorization: Bearer $LANACHAT_TOKEN"const res = await fetch('https://api.lanachat.ai/v1/billing/withdrawals', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/withdrawals",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
print(r.json())A list of withdrawal objects, newest first.
Ask for a withdrawal #
/billing/withdrawalsPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
amount_cents | integer | Yes | At least 50000 ($500), at most what is available to withdraw |
curl -X POST https://api.lanachat.ai/v1/billing/withdrawals \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"amount_cents": 50000}'const res = await fetch('https://api.lanachat.ai/v1/billing/withdrawals', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
'Idempotency-Key': crypto.randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify({ amount_cents: 50000 }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import uuid
import requests
r = requests.post(
"https://api.lanachat.ai/v1/billing/withdrawals",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"amount_cents": 50000},
timeout=30,
)
r.raise_for_status()
print(r.json()){ "id": "wd_118", "status": "pending_review", "amount_cents": 50000, "requested_at": "2026-10-06T15:00:00Z", "tx_hash": null }The earnings are sent in USDC to the wallet on file, 7 days after the month ends. Only affiliate earnings can be withdrawn, never the prepaid balance. A request under $500 is refused.
Statements #
List statements #
/billing/invoicesPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
year | integer | No | For example 2026 |
curl "https://api.lanachat.ai/v1/billing/invoices?year=2026" \
-H "Authorization: Bearer $LANACHAT_TOKEN"const res = await fetch('https://api.lanachat.ai/v1/billing/invoices?year=2026', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/invoices?year=2026",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
print(r.json())One invoice object per month.
Download a statement #
/billing/invoices/{id}.pdfPlannedNeeds ownercurl https://api.lanachat.ai/v1/billing/invoices/LC-2026-09.pdf \
-H "Authorization: Bearer $LANACHAT_TOKEN" -o LC-2026-09.pdfimport { writeFile } from 'node:fs/promises';
const res = await fetch('https://api.lanachat.ai/v1/billing/invoices/LC-2026-09.pdf', {
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
},
});
if (!res.ok) throw new Error((await res.json()).error.message);
await writeFile('LC-2026-09.pdf', Buffer.from(await res.arrayBuffer()));import os
import requests
r = requests.get(
"https://api.lanachat.ai/v1/billing/invoices/LC-2026-09.pdf",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
timeout=30,
)
r.raise_for_status()
with open("LC-2026-09.pdf", "wb") as f:
f.write(r.content)Check your statements. A billing error must be reported within 60 days of the statement that shows it; after that, the statement is final.
Set the billing details #
/billing/detailsPlannedNeeds owner| Parameter | Type | Required | Description |
|---|---|---|---|
company | string | No | Company name |
email | string | No | Billing e-mail |
address, city, postal, country | string | No | Postal address |
vat | string | No | VAT number |
curl -X PUT https://api.lanachat.ai/v1/billing/details \
-H "Authorization: Bearer $LANACHAT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"company": "Mia Agency Ltd", "email": "[email protected]", "address": "12 Market Street", "city": "Dublin", "postal": "D02 X285", "country": "IE", "vat": "IE1234567T"}'const res = await fetch('https://api.lanachat.ai/v1/billing/details', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.LANACHAT_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
company: 'Mia Agency Ltd',
email: '[email protected]',
address: '12 Market Street',
city: 'Dublin',
postal: 'D02 X285',
country: 'IE',
vat: 'IE1234567T',
}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());import os
import requests
r = requests.put(
"https://api.lanachat.ai/v1/billing/details",
headers={
"Authorization": f"Bearer {os.environ['LANACHAT_TOKEN']}",
},
json={
"company": "Mia Agency Ltd",
"email": "[email protected]",
"address": "12 Market Street",
"city": "Dublin",
"postal": "D02 X285",
"country": "IE",
"vat": "IE1234567T",
},
timeout=30,
)
r.raise_for_status()
print(r.json())The same fields as Billing › Billing details. Statements carry these details. PUT replaces them all: a field you leave out is emptied.
Errors #
Every endpoint answers errors in the same JSON body, {"error": {"code": "…", "message": "…"}}, with the common codes 400, 401, 402, 403, 404, 409, 429 and 500 listed in Errors. What the endpoints of this page say they answer:
| Endpoint | Status | When |
|---|---|---|
| Buy licences | 402 | A balance too low answers 402 (insufficient_balance). |