Receivables

    Invoices

    Every charge is its own invoice, posted to the ledger immediately and never emailed by HelloLedger.

    Create an invoice

    Scope: invoices:write. HelloLedger posts the invoice to the ledger right away (debit A/R, credit each line's income account) and marks it sent. No email goes to the customer; your app stays in charge of communication.

    PUT
    curl -X PUT "https://api.helloledger.ai/v1/companies/{company_id}/invoices/by-external-id/chg_2026_10_rent_1001" \
      -H "Authorization: Bearer $HL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "customer_external_id": "stu_1001",
      "date": "2026-10-01",
      "due_date": "2026-10-05",
      "memo": "October rent, unit 4B",
      "lines": [
        {
          "item_id": "66f1a2b3c4d5e6f708091a2b",
          "description": "October rent",
          "quantity": "1",
          "unit_price": "850.00",
          "amount": "850.00"
        }
      ]
    }'
    Response
    {
      "invoice_id": "66f3…",
      "external_id": "chg_2026_10_rent_1001",
      "version": 1,
      "invoice_number": "1042",
      "customer_id": "66f2…",
      "customer_external_id": "stu_1001",
      "date": "2026-10-01",
      "due_date": "2026-10-05",
      "status": "sent",
      "total_amount": "850.00",
      "amount_paid": "0.00",
      "balance_due": "850.00",
      "tax_amount": "0.00",
      "currency": "USD",
      "lines": [
        { "item_id": "66f1a2b3c4d5e6f708091a2b", "item_name": "Rent", "account_id": "66f1…", "description": "October rent", "quantity": "1.0", "unit_price": "850.00", "amount": "850.00", "taxable": false }
      ],
      "result": "created"
    }

    Fields

    FieldTypeNotes
    customer_external_idstring, requiredThe customer's external ID.
    customerobjectOptional customer fields. Creates the customer if it doesn't exist yet; ignored otherwise.
    dateYYYY-MM-DD, requiredInvoice date. Posting date for the ledger.
    due_dateYYYY-MM-DDOr use terms.
    termsdue_on_receipt | net_15 | net_30 | net_45 | net_60Sets due_date when due_date is omitted.
    invoice_numberstringOptional. HelloLedger assigns the next number when omitted.
    memostringOptional.
    tax_ratedecimal 0–100Sales tax percent applied to taxable lines.
    linesarray, 1–100See below.

    Lines

    Each line names exactly one of item_id (a product or service from GET /items, which brings its income account) or account_id (any account from GET /coa, for example a liability for deposits).

    amount is the line total and is required. quantity and unit_price are shown on the invoice. taxable defaults to the item's setting, or false for account lines. Send money as strings like "850.00" to avoid floating-point surprises.

    Account line, with the customer created inline · PUT
    curl -X PUT "https://api.helloledger.ai/v1/companies/{company_id}/invoices/by-external-id/chg_2026_10_late_1001" \
      -H "Authorization: Bearer $HL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "customer_external_id": "stu_1001",
      "customer": {
        "name": "Jamie Rivera",
        "email": "jamie@example.com"
      },
      "date": "2026-10-06",
      "terms": "due_on_receipt",
      "lines": [
        {
          "account_id": "66f1a2b3c4d5e6f708091b2c",
          "description": "Late fee",
          "amount": "25.00"
        }
      ]
    }'

    Changing an invoice

    • Re-sending the same body returns result unchanged.
    • A different body on an unpaid invoice replaces it: HelloLedger voids the posted version and posts a new one with the same invoice number. version goes up by one and result is replaced.
    • If any payment or credit is applied, the change is rejected with 409 invoice_has_payments. Void the payment first.

    Void an invoice

    Reverses the ledger posting. A voided external ID stays voided; send a corrected charge under a new external ID.

    POST
    curl -X POST "https://api.helloledger.ai/v1/companies/{company_id}/invoices/by-external-id/chg_2026_10_late_1001/void" \
      -H "Authorization: Bearer $HL_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "reason": "Late fee waived"
    }'

    Read an invoice

    Returns the current version with amount_paid and balance_due. (GET /invoices/{invoice_id} takes HelloLedger's ID instead and needs reports:read.)

    GET
    curl "https://api.helloledger.ai/v1/companies/{company_id}/invoices/by-external-id/chg_2026_10_rent_1001" \
      -H "Authorization: Bearer $HL_API_KEY"