Invoices
3 endpoints. Every path below is relative to the API base URL and already includes the /api/v1 prefix — see conventions for authentication, pagination, errors and idempotency.
| Endpoint | ||
|---|---|---|
| GET | /billing/invoices | List invoices newest first, optionally filtered by status, with totals and amount due |
| GET | /billing/invoices/{invoice} | Retrieve one invoice with its line items, usage appendix, bill-to block and tax breakdown |
| GET | /billing/invoices/{invoice}/download | Render the invoice as a printable HTML document the browser can save as a PDF |
Endpoints
List invoices newest first, optionally filtered by status, with totals and amount due
GET/billing/invoices
- Requires
billing.read. statusaccepts repeated values and is matched with whereIn
bash
curl -X GET "$CALLAGENT_API_URL/billing/invoices" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/invoices`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/invoices');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/billing/invoices",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped array |
Errors
| Status | When it happens |
|---|---|
403 | Neither the API key scope nor the session user's permission allows billing.read |
Example response, generated from the schema:
json
{
"data": [
{
"id": null,
"number": "+40712345678",
"status": "string",
"type": "string",
"currency": "string",
"period_start": "string",
"period_end": "string",
"issue_date": "string",
"due_date": "string",
"subtotal": "string",
"tax_total": "string",
"credit_total": "string",
"total": "string",
"amount_paid": "string",
"amount_due": "string",
"overdue": true,
"hosted_invoice_url": "https://example.com/hook"
}
],
"meta": {
"current_page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}Retrieve one invoice with its line items, usage appendix, bill-to block and tax breakdown
GET/billing/invoices/{invoice}
- Requires
billing.read.
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
invoice | string | yes |
bash
curl -X GET "$CALLAGENT_API_URL/billing/invoices/01JQ0000000000000000000000" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/invoices/01JQ0000000000000000000000`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/invoices/01JQ0000000000000000000000');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/billing/invoices/01JQ0000000000000000000000",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | data-wrapped object |
Errors
| Status | When it happens |
|---|---|
403 | Neither the API key scope nor the session user's permission allows billing.read |
404 | No invoice with that id in this organization |
Example response, generated from the schema:
json
{
"data": {
"id": null,
"number": "+40712345678",
"status": "string",
"type": "string",
"currency": "string",
"period_start": "string",
"period_end": "string",
"issue_date": "string",
"due_date": "string",
"subtotal": "string",
"tax_total": "string",
"credit_total": "string",
"total": "string",
"amount_paid": "string",
"amount_due": "string",
"overdue": true,
"hosted_invoice_url": "https://example.com/hook",
"lines": [
{}
],
"usage_appendix": {},
"bill_to": {},
"tax": {
"rate": "string",
"total": "string",
"type": "string",
"jurisdiction": "https://example.com/hook",
"reverse_charge": true,
"exempt": true,
"note": "string"
}
}
}Render the invoice as a printable HTML document the browser can save as a PDF
GET/billing/invoices/{invoice}/download
- Requires
billing.read. - This response is not
data-wrapped. - Returns text/html served inline, never a PDF and never JSON, despite the endpoint being named download
Path parameters
| Name | Type | Required | Notes |
|---|---|---|---|
invoice | string | yes |
bash
curl -X GET "$CALLAGENT_API_URL/billing/invoices/01JQ0000000000000000000000/download" \
-H "Authorization: Bearer $CALLAGENT_API_KEY" \
-H "Accept: application/json"js
const response = await fetch(`${process.env.CALLAGENT_API_URL}/billing/invoices/01JQ0000000000000000000000/download`, {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.CALLAGENT_API_KEY}`,
Accept: 'application/json',
},
});
if (!response.ok) {
const { error } = await response.json();
throw new Error(`${error.type}: ${error.message}`);
}
const { data } = await response.json();php
<?php
$handle = curl_init(getenv('CALLAGENT_API_URL') . '/billing/invoices/01JQ0000000000000000000000/download');
curl_setopt_array($handle, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('CALLAGENT_API_KEY'),
'Accept: application/json',
],
]);
$body = json_decode(curl_exec($handle), true);
$status = curl_getinfo($handle, CURLINFO_HTTP_CODE);
curl_close($handle);
if ($status >= 400) {
throw new RuntimeException("{$body['error']['type']}: {$body['error']['message']}");
}
$data = $body['data'];python
import os, requests
response = requests.get(
f"{os.environ['CALLAGENT_API_URL']}/billing/invoices/01JQ0000000000000000000000/download",
headers={"Authorization": f"Bearer {os.environ['CALLAGENT_API_KEY']}"},
timeout=30,
)
response.raise_for_status()
data = response.json()["data"]Responses
| Status | Body |
|---|---|
200 | Not JSON — text/html; charset=utf-8 |
Errors
| Status | When it happens |
|---|---|
403 | Neither the API key scope nor the session user's permission allows billing.read |
404 | No invoice with that id in this organization |