Products & Pricing
Manage the product catalogue over the LedgerBee public API (base URL
https://api.ledgerbee.com/api/v1). A
product price is what an invoice, quote, or order-confirmation line references
through its priceId to bill a real catalogue product. Authenticate with the
x-api-key header; the key carries the tenant, and every :id path segment is
a UUID.
The catalogue is three resources, all under one scope pair:
products-read— list and get products, prices, and product groups.products-write— create, update, and delete products, prices, and product groups, and run price lifecycle actions.
A product belongs to a product group, and a product has one or more prices. Create them in that order: group, then product, then price.
Product groups
A product group maps a product's sales to ledger accounts per VAT zone (domestic, EU, abroad, domestic-without-VAT) and is required on every product.
| Operation | Endpoint | Scope |
|---|---|---|
| List | GET /v1/product-groups | products-read |
| Get | GET /v1/product-groups/{id} | products-read |
| Create | POST /v1/product-groups | products-write |
| Update | PATCH /v1/product-groups/{id} | products-write |
| Delete | DELETE /v1/product-groups/{id} | products-write |
All four account fields are required: domesticAccountId, euAccountId,
abroadAccountId, and domesticWithoutVatAccountId. The domestic, EU, and
abroad accounts must each reference a ledger account carrying a VAT code valid
for sales; the domestic-without-VAT account has no VAT requirement. Ledger
accounts and VAT codes are available over the public API. See the
create operation.
Code
Products
A product is a catalogue item belonging to a product group. GET /v1/products/{id}
returns the product with its prices array, so the get response is where you read
the priceId for a billing-document line. The list (GET /v1/products) is a
lean index and omits the prices array; get a single product to read its prices.
| Operation | Endpoint | Scope |
|---|---|---|
| List (no prices) | GET /v1/products | products-read |
| Get (with prices) | GET /v1/products/{id} | products-read |
| Create | POST /v1/products | products-write |
| Update | PATCH /v1/products/{id} | products-write |
| Archive | POST /v1/products/{id}/archive | products-write |
| Delete | DELETE /v1/products/{id} | products-write |
Archive a product once it is in use: the product and every price on it go archived, nothing new can be sold against it, and the subscriptions and documents already referencing it keep resolving. Delete is for a product nothing references — one that is locked cannot be deleted. There is no unarchive.
productGroupId is required and must reference an existing group. productNumber
is unique per company. An optional initialPrice creates, activates, and
sets-default a first price in the same call. See the
create operation.
Code
Product prices
A price belongs to a product. Its id is the priceId used on invoice, quote,
and order-confirmation lines.
| Operation | Endpoint | Scope |
|---|---|---|
| Create | POST /v1/product-prices | products-write |
| Get | GET /v1/product-prices/{id} | products-read |
| Update | PATCH /v1/product-prices/{id} | products-write |
| Delete | DELETE /v1/product-prices/{id} | products-write |
| Activate | POST /v1/product-prices/{id}/activate | products-write |
| Disable | POST /v1/product-prices/{id}/disable | products-write |
| Archive | POST /v1/product-prices/{id}/archive | products-write |
| Set default | POST /v1/product-prices/{id}/set-default | products-write |
A price is created active and is usable on a document immediately; pass
status: "draft" to stage it instead and activate it later. The
default price of a product cannot be disabled, archived, or deleted. A price
already used on a subscription or invoice is locked and only a limited field set
can change. See the
create operation.
Code
Pricing models
billingPeriodType and pricingModel together describe how a price bills.
| Field | Value | Meaning |
|---|---|---|
billingPeriodType | one_time | A one-off charge. No billing interval. |
billingPeriodType | recurring | Bills each interval. Requires billingInterval and a Subscription license. |
billingPeriodType | usage | Metered. Requires meterId, a billing interval, and the Subscription license. |
pricingModel | flat_rate | One unitAmount. No tiers. |
pricingModel | package | Exactly one tier. |
pricingModel | volume / graduated | One or more tiers; the last tier must be open-ended (omit its toQuantity). |
A recurring or usage price requires the matching license. A request without
it is rejected with LICENSE.REQUIRED. Meters are available over the public API.
Errors
| Condition | Error code | Fix |
|---|---|---|
| Group number already used | PRODUCT_GROUP_NUMBER_EXISTS | Use a unique number. |
| Account missing / wrong type | PRODUCT_GROUP_INVALID_ACCOUNT_ID | Reference an existing sales account. |
| Sales account has no VAT code | PRODUCT_GROUP_ACCOUNT_MUST_HAVE_VAT_CODE | Pick a domestic/EU/abroad account with a VAT code. |
| Product number already used | PRODUCT_NUMBER_EXISTS | Use a unique productNumber. |
| Product group not found | PRODUCT_GROUP_NOT_FOUND | Create the group first, then reference its id. |
| Recurring/usage price without the license | LICENSE.REQUIRED | The tenant needs the Subscription license. |
| Disabling, deleting, or editing a restricted field on a price already referenced by an invoice, credit note, subscription, or plan | PRODUCT_PRICE_IS_LOCKED | A locked price only allows nickname, amount, currency, tiers, and archiving to change. Create a new price and set it as default instead. |