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.
Discounts on products, customers and date windows use the same scopes; see Discounts.
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. The list
(GET /v1/products) and the get (GET /v1/products/{id}) both return each
product with its prices array, where you read the priceId for a
billing-document line. Each price carries a billingPeriodType, so the list
alone tells you which products have a one_time price that a single invoice
can bill. The list includes recurring and usage prices when your company
has the Subscriptions module. A product's entitlements are returned by the get.
| Operation | Endpoint | Scope |
|---|---|---|
| List | GET /v1/products | products-read |
| Get | 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
A product carries an optional metadata map of string keys to string values
(at most 50 entries, keys up to 128 characters, values up to 500 characters).
Send it on create or on update; on update the map replaces the stored
metadata wholesale, and {} clears it. Every read returns it, and
GET /v1/products?metadata[sku]=WH-100 filters the list on exact-match pairs
(AND across pairs, at most 10). Archiving keeps the metadata; deleting the
product deletes it. See Metadata.
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. |