ClassifiedBilling API
The ClassifiedBilling API lets you read and manage invoices, customers, and workspaces programmatically. It works as a standard REST API, as an MCP server for Claude AI, and is compatible with any AI platform or custom application that supports HTTP tool calling.
This documentation covers everything — from getting your first API key to calling every available tool, handling errors, and integrating with Claude's connector directory.
Quick Start
Get up and running in under 5 minutes.
- Create an accountSign up at app.classifiedbilling.com. Any plan works — all plans include API access.
- Generate an API keyGo to Settings → API Keys in the left sidebar. Click New Key, give it a name, and copy your key — it starts with cb_live_ and is shown only once.
- Make your first requestCall the MCP server with your key in the Authorization header.
- Handle the responseAll responses are JSON. Successful responses include a result field. Errors include an error field.
"syn-cmt">// Your first API call — list all workspaces
const response = await fetch('https:"syn-cmt">//app.classifiedbilling.com/api/mcp-server', {
method: 'POST',
headers: {
'Authorization': 'Bearer cb_live_YOUR_KEY_HERE',
'Content-Type': 'application/json',
},
body: JSON.stringify({
tool: 'list_workspaces',
input: {}
})
});
const data = await response.json();
console.log(data.result.workspaces);# Same request with curl
curl -X POST https:"syn-cmt">//app.classifiedbilling.com/api/mcp-server \
-H "Authorization: Bearer cb_live_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{"tool":"list_workspaces","input":{}}'Authentication
All API requests require a Bearer token in the Authorization header. ClassifiedBilling supports two types of tokens:
API Keys (recommended for custom apps)
API keys start with cb_live_ and are generated from your Settings page. They are long-lived and scoped to the user who created them.
Authorization: Bearer cb_live_xK9mTz2pQrLvWnYs8dFgHj3a4BcDeFOAuth Access Tokens (for Claude and third-party apps)
OAuth tokens are issued after a user completes the authorization flow. They expire after 90 days and are used by Claude and other AI platforms.
Authorization: Bearer a3f8c9d2e1b4f7a6c5d8e2f1a9b3c6d4e7f2a5b8c1d4e7f3a6b9c2d5e8f1Base URL
All API requests go to the same single endpoint. The tool field in the request body specifies which operation to perform.
https:"syn-cmt">//app.classifiedbilling.com/api/mcp-serverRequest format
All requests are POST with a JSON body containing two fields:
| Field | Type | Description |
|---|---|---|
| toolrequired | string | The name of the tool to call e.g. list_invoices |
| inputoptional | object | Parameters for the tool. Pass {} for tools with no inputs. |
Response format
All successful responses return a result object. All error responses return an error string.
"syn-cmt">// Success response
{
"result": {
"workspaces": [...],
"total": 3
}
}
"syn-cmt">// Error response
{
"error": "Workspace not found or access denied."
}Error Handling
ClassifiedBilling uses standard HTTP status codes. Always check both the status code and the error field in the response body.
result field.error message for details."syn-cmt">// Recommended error handling pattern
const res = await fetch('https:"syn-cmt">//app.classifiedbilling.com/api/mcp-server', {
method: 'POST',
headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ tool: 'list_invoices', input: { workspace_id: '...' } })
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`API error ${res.status}: ${error}`);
}
const { result } = await res.json();
"syn-cmt">// use result...Rate Limits
API requests are limited per user to prevent abuse. Current limits:
| Plan | Requests / minute | Requests / day |
|---|---|---|
| Starter | 30 | 1,000 |
| Standard | 60 | 5,000 |
| Advance | 120 | 20,000 |
When you exceed a rate limit you will receive a 429 Too Many Requests response. Wait before retrying.
MCP Overview
ClassifiedBilling implements the Model Context Protocol (MCP) — an open standard for connecting AI models to external tools and data. This means Claude (and any other MCP-compatible AI) can call your billing data directly in conversation.
Connecting Claude
To connect ClassifiedBilling to Claude AI:
- Generate an API keyGo to Settings → API Keys and create a new key. Name it something like "Claude AI".
- Open Claude's connector pageIn Claude.ai, go to Customize → Connectors and find ClassifiedBilling in the directory.
- Click Connect and paste your keyYou will be redirected to app.classifiedbilling.com/mcp-connect. Paste your cb_live_... key and click Approve.
- Start using itAsk Claude: "Show my overdue invoices" or "How much revenue did I collect this month?"
List Workspaces
Returns all workspaces owned by the authenticated user. Call this first — you need a workspace_id for most other tools.
Input
No input fields required. Pass an empty object.
{
"tool": "list_workspaces",
"input": {}
}Response
{
"result": {
"workspaces": [
{
"id": "clx1a2b3c4d5e6f7g8h9",
"title": "SaaS Clerk",
"description": "My main billing workspace",
"workspaceUrlSlug": "saas-clerk",
"businessDetails": {
"businessName": "SaaS Clerk Ltd",
"businessEmail": "hello@saasclerk.com"
}
}
]
}
}Workspace Summary
Returns customer count, invoice count, service item count, team member count, and a breakdown of invoices by payment status.
{
"tool": "get_workspace_summary",
"input": { "workspace_id": "clx1a2b3c4d5e6f7g8h9" }
}Response
{
"result": {
"id": "clx1a2b3c4d5e6f7g8h9",
"title": "SaaS Clerk",
"business": "SaaS Clerk Ltd",
"counts": {
"customers": 12,
"invoices": 38,
"serviceItems": 6,
"teamMembers": 2
},
"invoices_by_status": [
{ "status": "Paid", "count": 30 },
{ "status": "Due", "count": 8 }
]
}
}List Customers
Returns customers in a workspace. Optionally filter by name or email using the search parameter. Returns up to 50 results.
Input parameters
| Field | Type | Description |
|---|---|---|
| workspace_idrequired | string | ID of the workspace to list customers from |
| searchoptional | string | Filter by company name or email (case insensitive) |
{
"tool": "list_customers",
"input": {
"workspace_id": "clx1a2b3c4d5e6f7g8h9",
"search": "acme" "syn-cmt">// optional
}
}Response
{
"result": {
"customers": [
{
"id": "cust_abc123",
"companyName": "Acme Corp",
"companyEmail": "billing@acme.com",
"companyCurrency": "USD",
"companyCountry": "United States",
"companyContactFirstName": "John",
"companyContactLastName": "Smith",
"companyContactPersonEmail": "john@acme.com"
}
],
"total": 1
}
}Create Customer
Creates a new customer in a workspace. All address and contact fields are required.
Input parameters
| Field | Type | Description |
|---|---|---|
| workspace_idrequired | string | Target workspace ID |
| company_namerequired | string | Company or client name |
| company_emailrequired | string | Company email address |
| currencyrequired | string | Currency code e.g. USD, EUR, GBP |
| contact_first_namerequired | string | Contact person first name |
| contact_last_namerequired | string | Contact person last name |
| contact_emailrequired | string | Contact person email |
| addressrequired | string | Street address |
| cityrequired | string | City |
| staterequired | string | State or region |
| ziprequired | string | Zip or postal code |
| countryrequired | string | Country name |
{
"tool": "create_customer",
"input": {
"workspace_id": "clx1a2b3c4d5e6f7g8h9",
"company_name": "Acme Corp",
"company_email": "billing@acme.com",
"currency": "USD",
"contact_first_name": "John",
"contact_last_name": "Smith",
"contact_email": "john@acme.com",
"address": "123 Main Street",
"city": "New York",
"state": "NY",
"zip": "10001",
"country": "United States"
}
}List Invoices
Returns invoices for a workspace. Filter by payment status and control how many results to return.
Input parameters
| Field | Type | Description |
|---|---|---|
| workspace_idrequired | string | Workspace ID |
| statusoptional | string | Due, Paid, or all. Defaults to all. |
| limitoptional | number | Max results to return. Default 20, max 100. |
{
"tool": "list_invoices",
"input": {
"workspace_id": "clx1a2b3c4d5e6f7g8h9",
"status": "Due",
"limit": 10
}
}Response
{
"result": {
"invoices": [
{
"id": "inv_xyz789",
"number": "INV-0042",
"client": "Acme Corp",
"amount": 2500.00,
"currency": "USD",
"status": "Due",
"issued": "2025-02-01T00:00:00.000Z",
"due": "2025-03-01T00:00:00.000Z"
}
],
"total": 1
}
}Get Overdue Invoices
Returns all unpaid invoices where the due date has already passed. Results are ordered by oldest due date first — the most urgent first.
{
"tool": "get_overdue_invoices",
"input": { "workspace_id": "clx1a2b3c4d5e6f7g8h9" }
}Response includes
A list of overdue invoices plus a total_overdue_amount sum.
{
"result": {
"overdue_invoices": [
{
"id": "inv_xyz789",
"number": "INV-0042",
"client": "Acme Corp",
"due_date": "2025-03-01T00:00:00.000Z",
"amount": 2500.00,
"currency": "USD"
}
],
"total_overdue_amount": 7850.00,
"count": 3
}
}Mark Invoice as Paid
Updates an invoice's status to Paid and records the payment date and method.
Input parameters
| Field | Type | Description |
|---|---|---|
| workspace_idrequired | string | Workspace ID |
| invoice_idrequired | string | ID of the invoice to mark as paid |
| payment_methodoptional | string | How it was paid e.g. Bank Transfer, Stripe, Cash |
{
"tool": "mark_invoice_paid",
"input": {
"workspace_id": "clx1a2b3c4d5e6f7g8h9",
"invoice_id": "inv_xyz789",
"payment_method": "Bank Transfer"
}
}Revenue Summary
Returns total paid revenue, total outstanding, and invoice counts for a workspace. Useful for dashboard-style overviews.
{
"tool": "get_revenue_summary",
"input": { "workspace_id": "clx1a2b3c4d5e6f7g8h9" }
}Response
{
"result": {
"total_paid": 18500.00,
"total_outstanding": 7850.00,
"paid_invoices": 12,
"unpaid_invoices": 4,
"total_invoices": 16
}
}OAuth 2.0 Flow
For third-party platforms (like Claude) that need to act on behalf of a user, ClassifiedBilling implements the OAuth 2.0 Authorization Code flow with PKCE.
Flow overview
Your app → redirect user to /mcp-connect?redirect_uri=...&state=...&code_challenge=...
User → pastes their ClassifiedBilling API key and clicks Approve
CB server → redirects back to redirect_uri?code=...&state=...
Your app → POST /api/mcp-token with code + code_verifier
CB server → returns { access_token, token_type, expires_in }
Your app → use access_token as Bearer token on all future API callsAuthorization endpoint
GET https:"syn-cmt">//app.classifiedbilling.com/mcp-connect
?redirect_uri=https:"syn-cmt">//yourapp.com/callback
&state=RANDOM_STATE_STRING
&code_challenge=BASE64URL_SHA256_OF_VERIFIER
&client_id=your_app_name| Field | Type | Description |
|---|---|---|
| redirect_urirequired | string | Where to redirect after the user approves |
| staterequired | string | Random string you generate — returned unchanged to verify the response |
| code_challengerequired | string | Base64url encoded SHA-256 of your code_verifier |
| client_idoptional | string | Your app identifier |
Token endpoint
POST https:"syn-cmt">//app.classifiedbilling.com/api/mcp-token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=CODE_FROM_CALLBACK
&redirect_uri=https:"syn-cmt">//yourapp.com/callback
&code_verifier=YOUR_ORIGINAL_VERIFIERReturns:
{
"access_token": "a3f8c9d2e1b4...",
"token_type": "Bearer",
"expires_in": 7776000 "syn-cmt">// 90 days in seconds
}