Skip to content
Internal preview — Billtyme does not issue or send invoices yet.See what's included
Billtyme
Esc
navigateopen⌘Jpreview
On this page

Companies, customers, and invoices

Create legal sender companies, remember company-scoped customers, and prepare idempotent draft invoices through Billtyme's agent-first API.

Every invoice belongs to a legal sender company. An invoice starts as a persisted draft with exact totals and frozen issuer and customer snapshots, but no legal invoice number.

1. Select or create the sender

List the companies available to the authenticated WorkOS account. Use external_reference when the calling system already has a stable sender identifier.

curl "$BILLTYME_API_URL/v1/companies?external_reference=legal_entity_de" \
  --header "Authorization: Bearer $BILLTYME_ACCESS_TOKEN"

Create the company when the filtered data array is empty:

curl "$BILLTYME_API_URL/v1/companies" \
  --request POST \
  --header "Authorization: Bearer $BILLTYME_ACCESS_TOKEN" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: company-legal-entity-de-v1" \
  --data '{
    "legal_name": "Example Consulting GmbH",
    "external_reference": "legal_entity_de",
    "identifiers": [
      { "country_code": "DE", "scheme": "vat", "value": "DE123456789" }
    ],
    "address": {
      "line_1": "Example Street 1",
      "postal_code": "10115",
      "city": "Berlin",
      "country_code": "DE"
    },
    "default_currency": "EUR",
    "default_language": "de",
    "default_payment_terms_days": 14
  }'

The returned company UUID is explicit in every customer and invoice path. The authenticated account remains implicit and cannot be selected by request input.

2. Find or create the customer

Customers are scoped to a sender company because recipient details can differ between legal entities. The same external reference may exist under two companies without mixing their records.

Filter the company’s customer collection. An absent customer produces an empty data array rather than a 404.

curl "$BILLTYME_API_URL/v1/companies/$COMPANY_ID/customers?external_reference=crm_acme" \
  --header "Authorization: Bearer $BILLTYME_ACCESS_TOKEN"

Create the customer once when the filtered collection is empty.

curl "$BILLTYME_API_URL/v1/companies/$COMPANY_ID/customers" \
  --request POST \
  --header "Authorization: Bearer $BILLTYME_ACCESS_TOKEN" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: customer-acme-2026-08" \
  --data '{
    "name": "Acme GmbH",
    "external_reference": "crm_acme",
    "email": "billing@example.com",
    "address": {
      "line_1": "Customer Avenue 2",
      "postal_code": "20095",
      "city": "Hamburg",
      "country_code": "DE"
    }
  }'

3. Create the draft invoice

Amounts use minor currency units. For EUR, 15000 means EUR 150.00. Tax rates use basis points, so 1900 means 19%.

PropType
quantitydecimal string

Positive quantity with up to three decimal places.

Typedecimal string
unit_amount_minorinteger

Unit price in minor currency units; 15000 means EUR 150.00.

Typeinteger
tax_rate_bpsinteger

Tax rate from 0 to 10000 basis points; 1900 means 19%.

Typeinteger
curl "$BILLTYME_API_URL/v1/companies/$COMPANY_ID/invoices" \
  --request POST \
  --header "Authorization: Bearer $BILLTYME_ACCESS_TOKEN" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: invoice-acme-2026-08" \
  --data '{
    "customer_id": "01989f61-2a4b-7c8d-8e9f-000000000003",
    "external_reference": "erp_invoice_123",
    "issue_date": "2026-08-12",
    "lines": [
      {
        "description": "Consulting",
        "quantity": "8",
        "unit_amount_minor": 15000,
        "tax_rate_bps": 1900
      }
    ]
  }'

If omitted, currency, language, and due_date come from the company defaults. The response has status: "draft" and number: null.

4. Retrieve the invoice

List invoices with cursor pagination and optional customer_id, external_reference, or status filters:

curl "$BILLTYME_API_URL/v1/companies/$COMPANY_ID/invoices?status=draft" \
  --header "Authorization: Bearer $BILLTYME_ACCESS_TOKEN"

Retrieve one full invoice, including lines and snapshots, with its UUID:

curl "$BILLTYME_API_URL/v1/companies/$COMPANY_ID/invoices/$INVOICE_ID" \
  --header "Authorization: Bearer $BILLTYME_ACCESS_TOKEN"

Idempotency

Use one stable key for one logical write. Keys are scoped to the authenticated account, so accidental reuse across two companies is rejected rather than replaying a result from the wrong company. Completed results are retained for replay for 24 hours; after that window, the key may represent a new write.

Billtyme performs the write and stores the result for the idempotency key.

Billtyme returns the earlier result with Idempotency-Replayed: true.

Billtyme rejects the request with 409 Conflict.

What comes next

Last updated on August 12, 2026

Was this page helpful?