Customers
The Customer resource represents a billing entity — an organization, individual, or subsidiary. The billing platform supports multi-entity hierarchies for enterprise customers with complex corporate structures.
Account Types
| Type | Description |
|---|---|
Organization | Top-level company account. Can have children. |
Individual | Single-person account. No children. |
Subsidiary | Child account under an Organization. Used for cost-centers and subsidiaries. |
Consolidation Modes
| Mode | Description |
|---|---|
Standalone | Billed independently (default) |
ConsolidateToParent | Charges roll up to the parent invoice |
Fields
| Field | Type | Description |
|---|---|---|
id | string (UUIDv7) | Unique customer ID |
display_name | string | Human-readable name |
legal_name | string? | Legal entity name (for invoices) |
email | string | Billing contact email |
account_type | enum | Organization / Individual / Subsidiary |
status | enum | Active / Suspended / Closed |
parent_id | string? | Parent customer ID (for subsidiaries) |
bill_to_id | string? | Override: which account receives the invoice |
consolidation | enum | Standalone / ConsolidateToParent |
billing_currency | string | ISO 4217 (e.g., “USD”, “EUR”) |
payment_terms_days | integer | Net payment terms (default: 30) |
tax_id | string? | VAT/EIN for B2B tax exemption |
Create a Customer
# [curl]
curl -X POST https://api.bill.sh/admin/v1/customers \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "Globex Corp",
"email": "billing@globex.com",
"currency": "USD",
"account_type": "Organization"
}'
# [Python]
import requests
resp = requests.post(
"https://api.bill.sh/admin/v1/customers",
headers={"Authorization": f"Bearer {ADMIN_TOKEN}"},
json={
"display_name": "Globex Corp",
"email": "billing@globex.com",
"currency": "USD",
"account_type": "Organization",
},
)
customer = resp.json()
print(f"Customer ID: {customer['id']}")
// [Node.js]
const resp = await fetch("https://api.bill.sh/admin/v1/customers", {
method: "POST",
headers: {
"Authorization": `Bearer ${ADMIN_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
display_name: "Globex Corp",
email: "billing@globex.com",
currency: "USD",
account_type: "Organization",
}),
});
const customer = await resp.json();
console.log("Customer ID:", customer.id);
// [Go]
body, _ := json.Marshal(map[string]string{
"display_name": "Globex Corp",
"email": "billing@globex.com",
"currency": "USD",
"account_type": "Organization",
})
req, _ := http.NewRequest("POST", "https://api.bill.sh/admin/v1/customers", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+adminToken)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var customer map[string]interface{}
json.NewDecoder(resp.Body).Decode(&customer)
fmt.Println("Customer ID:", customer["id"])
Create a Subsidiary
# [curl]
curl -X POST https://api.bill.sh/admin/v1/customers \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"display_name": "Globex — Europe",
"email": "billing-eu@globex.com",
"currency": "EUR",
"account_type": "Subsidiary",
"parent_id": "01944b1f-0000-7000-8000-000000000001"
}'
# [Python]
resp = requests.post(
"https://api.bill.sh/admin/v1/customers",
headers={"Authorization": f"Bearer {ADMIN_TOKEN}"},
json={
"display_name": "Globex — Europe",
"email": "billing-eu@globex.com",
"currency": "EUR",
"account_type": "Subsidiary",
"parent_id": "01944b1f-0000-7000-8000-000000000001",
},
)
subsidiary = resp.json()
print(f"Subsidiary ID: {subsidiary['id']}, parent: {subsidiary.get('parent_id')}")
// [Node.js]
const resp = await fetch("https://api.bill.sh/admin/v1/customers", {
method: "POST",
headers: {
"Authorization": `Bearer ${ADMIN_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
display_name: "Globex — Europe",
email: "billing-eu@globex.com",
currency: "EUR",
account_type: "Subsidiary",
parent_id: "01944b1f-0000-7000-8000-000000000001",
}),
});
const subsidiary = await resp.json();
console.log("Subsidiary:", subsidiary.id, "parent:", subsidiary.parent_id);
// [Go]
body, _ := json.Marshal(map[string]string{
"display_name": "Globex — Europe",
"email": "billing-eu@globex.com",
"currency": "EUR",
"account_type": "Subsidiary",
"parent_id": "01944b1f-0000-7000-8000-000000000001",
})
req, _ := http.NewRequest("POST", "https://api.bill.sh/admin/v1/customers", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+adminToken)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
Get Customer 360 View
The 360 view returns everything about a customer in one call — subscriptions, invoices, ledger balances, and recent audit history:
# [curl]
curl https://api.bill.sh/admin/v1/customers/01944b1f-0000-7000-8000-000000000001 \
-H "Authorization: Bearer $ADMIN_TOKEN"
# [Python]
resp = requests.get(
f"https://api.bill.sh/admin/v1/customers/{customer_id}",
headers={"Authorization": f"Bearer {ADMIN_TOKEN}"},
)
view = resp.json()
print(f"Subscriptions: {len(view.get('subscriptions', []))}")
print(f"Open invoices: {[i['invoice_number'] for i in view.get('invoices', []) if i['status'] == 'Open']}")
// [Node.js]
const resp = await fetch(
`https://api.bill.sh/admin/v1/customers/${customerId}`,
{ headers: { "Authorization": `Bearer ${ADMIN_TOKEN}` } }
);
const view = await resp.json();
console.log("Subscriptions:", view.subscriptions?.length ?? 0);
// [Go]
req, _ := http.NewRequest("GET",
"https://api.bill.sh/admin/v1/customers/"+customerID, nil)
req.Header.Set("Authorization", "Bearer "+adminToken)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var view map[string]interface{}
json.NewDecoder(resp.Body).Decode(&view)
Get Entity Hierarchy
# [curl]
curl https://api.bill.sh/admin/v1/customers/01944b1f-0000-7000-8000-000000000001/hierarchy \
-H "Authorization: Bearer $ADMIN_TOKEN"
# [Python]
resp = requests.get(
f"https://api.bill.sh/admin/v1/customers/{customer_id}/hierarchy",
headers={"Authorization": f"Bearer {ADMIN_TOKEN}"},
)
hierarchy = resp.json()
# Returns the full tree of parent/subsidiary accounts
// [Node.js]
const resp = await fetch(
`https://api.bill.sh/admin/v1/customers/${customerId}/hierarchy`,
{ headers: { "Authorization": `Bearer ${ADMIN_TOKEN}` } }
);
const hierarchy = await resp.json();
console.log(JSON.stringify(hierarchy, null, 2));
// [Go]
req, _ := http.NewRequest("GET",
"https://api.bill.sh/admin/v1/customers/"+customerID+"/hierarchy", nil)
req.Header.Set("Authorization", "Bearer "+adminToken)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
var hierarchy map[string]interface{}
json.NewDecoder(resp.Body).Decode(&hierarchy)
Returns the full tree of parent/subsidiary accounts rooted at the given customer.