Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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

TypeDescription
OrganizationTop-level company account. Can have children.
IndividualSingle-person account. No children.
SubsidiaryChild account under an Organization. Used for cost-centers and subsidiaries.

Consolidation Modes

ModeDescription
StandaloneBilled independently (default)
ConsolidateToParentCharges roll up to the parent invoice

Fields

FieldTypeDescription
idstring (UUIDv7)Unique customer ID
display_namestringHuman-readable name
legal_namestring?Legal entity name (for invoices)
emailstringBilling contact email
account_typeenumOrganization / Individual / Subsidiary
statusenumActive / Suspended / Closed
parent_idstring?Parent customer ID (for subsidiaries)
bill_to_idstring?Override: which account receives the invoice
consolidationenumStandalone / ConsolidateToParent
billing_currencystringISO 4217 (e.g., “USD”, “EUR”)
payment_terms_daysintegerNet payment terms (default: 30)
tax_idstring?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.