Configure your first meters and prices

Walk through creating core Solvimon resources via the Configuration API: the metering layer, the product catalogue, and the pricing plan. By the end, you’ll have a complete billing configuration ready to attach to customers.

All examples use the test environment (https://test.api.solvimon.com) with the X-API-KEY header for authentication. The example throughout—an HR platform charging per registered employee—shows how IDs flow from one resource to the next.

What you’ll build

The process happens in three stages. Each stage depends on IDs returned from the previous one, so follow the sequence as written.

Stage 1: Metering — Define what you measure. Create meter values, properties, and the meter itself, then link it all together with a meter value calculation.

Stage 2: Product Catalogue — Define what you sell. Build categories, products, and revenue items. Usage-based items link back to the meter value calculation from Stage 1.

Stage 3: Pricing — Define how you charge. Create a pricing plan, a version, and the pricing configurations that attach prices to revenue items. You can condition prices on meter properties.


1. Meters

A Meter sits on top of two building blocks: Meter Values (the numeric inputs) and Meter Properties (the dimensions). Both must exist before you create the Meter that uses them. Once the Meter exists, define a Meter Value Calculation that aggregates a Value (or counts a Property) into a billable number.

1.1 Create a Meter Value

A Meter Value is a numeric or monetary input—the thing you actually count or sum. Create one per quantity you want to measure.

$curl -X POST https://test.api.solvimon.com/v1/meter-values \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "reference": "employee_count",
> "name": "Employee Count",
> "type": "NUMBER",
> "description": "The number of employees registered by the platform",
> "status": "ACTIVE"
> }'

Response:

1{
2 "id": "metv_owDe9k0tsIY5LkBAel1P",
3 "reference": "employee_count",
4 "name": "Employee Count",
5 "type": "NUMBER",
6 "description": "The number of employees registered by the platform",
7 "status": "ACTIVE",
8 "created_at": "2025-05-06T10:30:00Z"
9}

Field notes:

  • reference — your own slug; must be unique and contain no whitespace. You’ll use it as a stable handle in your code.
  • typeNUMBER for counts/quantities, AMOUNT for monetary values.
  • status — set to ACTIVE if you want to start using it immediately; otherwise it lands in DRAFT.

Save the returned id (metv_owDe9k0tsIY5LkBAel1P). The Meter step references it.

📖 API reference

1.2 Create a Meter Property

A Meter Property is a dimension—country, plan tier, employee type—that gives context to each measurement and lets you slice or condition pricing on it.

$curl -X POST https://test.api.solvimon.com/v1/meter-properties \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "reference": "employee_country",
> "name": "Employee Country",
> "type": "ENUM",
> "description": "Country where the employee is based.",
> "status": "ACTIVE",
> "enum_values": ["CAN", "DNK", "FIN", "GBR", "IRL", "JPN", "NOR", "SWE", "USA"]
> }'

Field notes:

  • typeNUMBER, STRING, or ENUM. ENUM is what you’ll most often want for pricing conditions; supply the allowed values via enum_values.
  • Only ENUM properties can be added to an active meter later; plan accordingly.

Save the returned id (e.g. metp_owDe9k0tsIY5LkBAel1X).

📖 API reference

1.3 Create the Meter

The Meter ties Values and Properties together. It’s the resource your event ingestion will target.

$curl -X POST https://test.api.solvimon.com/v1/meters \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "reference": "meter_registered_employee",
> "name": "registered_employees",
> "description": "The amount of employees registered with a customer.",
> "meter_values": [
> {
> "id": "metv_owDe9k0tsIY5LkBAel1P",
> "reference": "Employee count",
> "required": true
> }
> ],
> "meter_properties": [
> {
> "id": "metp_owDe9k0tsIY5LkBAel1X",
> "reference": "Employee type",
> "required": true
> }
> ]
> }'

Field notes:

  • meter_values[].id and meter_properties[].id are the IDs returned by steps 1.1 and 1.2.
  • required: true means an ingest event missing this field will be rejected. Required is also what makes a property usable in pricing conditions.

Save the returned Meter id (e.g. metr_kwDeeN0tv5UDtxADed1o).

📖 API reference

1.4 Create the Meter Value Calculation

The Meter Value Calculation (MVC) turns raw events into a billable number. You pick an aggregation type and point it at a Meter Value (most common) or a Meter Property (for things like distinct-count by country).

$curl -X POST https://test.api.solvimon.com/v1/meter-value-calculations \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "reference": "mvc_employee_count_sum",
> "calculation_type": "SUM",
> "meter_id": "metr_kwDeeN0tv5UDtxADed1o",
> "name": "Employee count (sum)",
> "description": "Total registered employees per billing period",
> "persist": false,
> "meter_value_id": "metv_owDe9k0tsIY5LkBAel1P"
> }'

Field notes:

  • calculation_typeSUM (counts, tokens, GB), MAX (peak concurrent), MIN, AVERAGE, or UNIQUE (distinct values).
  • meter_value_id vs meter_property_id — supply one. Use a value when aggregating a number; use a property when counting distinct dimension values (e.g. UNIQUE on employee_country).
  • persist: false is the default and fine for most cases. Set true only when you need the calculated value carried into the next billing period.

Save the returned id (e.g. mvca_AwDeeF0tu31PTQAbeN1t). This links a usage Revenue Item to this calculation in step 2.3.

📖 API reference


2. Product Catalogue

The catalogue itself is conceptual—there’s no POST /catalogue call. What you create are Product Categories, Products inside them, and Revenue Items (called Product Items in the API) inside each Product.

2.1 Create a Product Category

A Product Category is the top grouping (e.g. “ExpenseIt products”). At minimum you need a name, a reference, and a tax category.

$curl -X POST https://test.api.solvimon.com/v1/product-categories \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "name": "ExpenseIt products",
> "reference": "expenseit_products",
> "description": "All products that are offered and developed by ExpenseIt",
> "tax_category": "STANDARD"
> }'

Field notes:

  • tax_categorySTANDARD, NO_TAX, or EXEMPT. This becomes the default for products in the category but each product can override.

Save the returned id (e.g. proc_iwDeeN0tvaMQ3nAies1C).

📖 API reference

2.2 Create a Product

A Product belongs to one Category and groups one or more Revenue Items.

$curl -X POST https://test.api.solvimon.com/v1/products \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "category_id": "proc_iwDeeN0tvaMQ3nAies1C",
> "name": "Receipt Scanning",
> "reference": "receipt_scanning",
> "description": "Giving customer employees the possibility to scan receipts.",
> "product_type": "DEFAULT",
> "tax_category": "STANDARD"
> }'

Field notes:

  • product_typeDEFAULT for a normal sellable product, ADDON for something attached to another product.
  • The product is created in DRAFT status by default. You can activate it later with POST /products/:id/activate once its Revenue Items are in place.

Save the returned id (e.g. prod_jwDeAN0tsJCV11BBeT1h).

📖 API reference

2.3 Create Revenue Items

Revenue Items (called product-items in the API) are the actual billable units inside a Product. The model_type field determines the flavor—and only USAGE_BASED requires a Meter Value Calculation link.

A usage-based Revenue Item linked to the MVC from step 1.4:

$curl -X POST https://test.api.solvimon.com/v1/product-items \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "product_id": "prod_jwDeAN0tsJCV11BBeT1h",
> "name": "Reimbursed amount",
> "reference": "reimbursed_amount",
> "description": "Reimbursed amount per scanned receipt",
> "model_type": "USAGE_BASED",
> "tax_category": "STANDARD",
> "usage_based": {
> "meter_value_calculation_id": "mvca_AwDeeF0tu31PTQAbeN1t"
> }
> }'

Field notes:

  • model_type accepts (among others) USAGE_BASED, RECURRING, SEATS, and ONE_OFF.
  • For USAGE_BASED, the Meter Value Calculation ID must be supplied inside the nested usage_based object. The legacy top-level meter_value_calculation_id field is deprecated; use the nested form going forward.
  • For RECURRING, SEATS, and ONE_OFF, you can omit the usage_based block entirely.

Repeat the call once per Revenue Item your Product needs. Save the returned IDs (e.g. proi_jwDeAN0tsJCV11BBeT1h). They’re referenced by the pricing plan step.

📖 API reference


3. Price plan

A Price Plan is the container for one or more versions; a Version holds one or more Pricings; each Pricing is the actual price attached to a Revenue Item. Create them in that order.

3.1 Create the Price Plan

The Price Plan itself is a thin shell—name, reference, currencies. The pricing details live on the version.

$curl -X POST https://test.api.solvimon.com/v1/pricing-plans \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "reference": "default_pricing",
> "name": "Default Pricing Plan",
> "description": "Standard pricing plan for self-serve customers",
> "amount_type": "EXCLUDING_TAX",
> "pricing_currencies": ["EUR", "USD"]
> }'

Field notes:

  • amount_typeEXCLUDING_TAX (default) or INCLUDING_TAX. This is plan-wide; once set, every pricing inside is interpreted accordingly.
  • pricing_currencies — the currencies allowed in this plan’s pricings. Add every currency you might charge in.

Save the returned id (e.g. ppla_RwDeAC0tsJAiH2BOeq1d).

📖 API reference

3.2 Create a Pricing Plan Version

Versions exist so you can iterate pricing without breaking existing subscriptions. The first version is typically created in DRAFT, then activated.

A minimal version, no pricings yet:

$curl -X POST https://test.api.solvimon.com/v1/pricing-plan-versions \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "pricing_plan_id": "ppla_RwDeAC0tsJAiH2BOeq1d",
> "version": 1,
> "status": "DRAFT"
> }'

If you’re cloning from an existing version (typical when introducing a price change), supply copied_from_pricing_plan_version_id to seed it with the previous version’s pricings:

$curl -X POST https://test.api.solvimon.com/v1/pricing-plan-versions \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "pricing_plan_id": "ppla_RwDeAC0tsJAiH2BOeq1d",
> "version": 2,
> "status": "DRAFT",
> "copied_from_pricing_plan_version_id": "ppve_gwDeep0tDRcSvkAfeN1Z"
> }'

Save the returned id (e.g. ppve_gwDeep0tDRcSvkAfeN1Z).

📖 API reference

3.3 Create Pricings

A Pricing attaches a price configuration to one or more Revenue Items inside a specific Price Plan Version.

$curl -X POST https://test.api.solvimon.com/v1/pricings \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "pricing_plan_version_id": "ppve_gwDeep0tDRcSvkAfeN1Z",
> "name": "Receipt scanning – per receipt",
> "product_ids": ["prod_jwDeAN0tsJCV11BBeT1h"],
> "items": [
> {
> "product_item_ids": ["proi_jwDeAN0tsJCV11BBeT1h"],
> "configs": [
> {
> "type": "FLAT",
> "order": 1,
> "bands": [
> {
> "amount": { "quantity": "0.50", "currency": "EUR" }
> }
> ]
> }
> ]
> }
> ]
> }'

Field notes:

  • product_ids — the Products covered by this pricing (the Pricing sits at the Product level; items then narrows to specific Revenue Items).
  • items[].product_item_ids — the Revenue Items the pricing applies to.
  • configs[].typeFLAT, TIERED, VOLUME, PACKAGE, etc. FLAT is the simplest: one band, one amount.
  • configs[].bands[].amount — the monetary value. Pass quantity as a string ("0.50", not the number 0.50) to avoid floating-point rounding.

For non-usage Revenue Items (Recurring, Seats, One Offs), the structure is the same—you swap the band shape (e.g. add a billing_period for recurring) and target a different product_item_ids.

📖 API reference

3.4 Usage-based pricing with conditions

A common pattern is charging different rates for the same Revenue Item depending on a Meter Property—for instance, the cost of a registered employee differs by country. You express this by attaching multiple configs to one item, each guarded by a conditions block that matches a Meter Property value.

The example below puts two configs on the same usage-based Revenue Item: $0.50 EUR per employee in Germany, $0.40 USD per employee in the US. The Meter Property employee_country (created in step 1.2) is what each config matches against.

$curl -X POST https://test.api.solvimon.com/v1/pricings \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "pricing_plan_version_id": "ppve_gwDeep0tDRcSvkAfeN1Z",
> "name": "Registered employees – by country",
> "product_ids": ["prod_jwDeAN0tsJCV11BBeT1h"],
> "items": [
> {
> "product_item_ids": ["proi_jwDeAN0tsJCV11BBeT1h"],
> "configs": [
> {
> "type": "FLAT",
> "order": 1,
> "conditions": {
> "name": "Germany",
> "meter_properties": [
> {
> "id": "metp_owDe9k0tsIY5LkBAel1X",
> "value": "DEU",
> "comparator": "EQUALS"
> }
> ]
> },
> "bands": [
> { "amount": { "quantity": "0.50", "currency": "EUR" } }
> ]
> },
> {
> "type": "FLAT",
> "order": 2,
> "conditions": {
> "name": "United States",
> "meter_properties": [
> {
> "id": "metp_owDe9k0tsIY5LkBAel1X",
> "value": "USA",
> "comparator": "EQUALS"
> }
> ]
> },
> "bands": [
> { "amount": { "quantity": "0.40", "currency": "USD" } }
> ]
> }
> ]
> }
> ]
> }'

Field notes:

  • conditions.meter_properties[].id — the Meter Property ID from step 1.2. The property must be on a Meter that’s wired into the MVC linked to this Revenue Item, and it must be required: true to be usable in conditions.
  • conditions.meter_properties[].value — for ENUM properties, one of the enum_values you defined. Use values (array) instead of value together with comparator: "IN" to match multiple at once.
  • comparatorEQUALS, NOT_EQUALS, IN, NOT_IN, plus numeric ones (GREATER_THAN, LESS_THAN_OR_EQUAL, etc.) for NUMBER-typed properties.
  • order — controls evaluation order when configs are checked. The first config whose conditions match is the one that applies, so put the most specific configs first.
  • Cover the catch-all case. If an event arrives with employee_country: "GBR", neither config above matches and the event won’t be priced. Either add a config with no conditions block as a fallback, or constrain ingestion to the supported enum values.

The same pattern works with more than one Meter Property at once—list them all under meter_properties and they’re combined with AND. For OR or nested logic, use the expression form (with operator: "AND" or "OR" and operands) instead of the flat meter_properties list.

📖 API reference


4. Activate and create subscriptions

At this point you have a complete pricing configuration. Now link it to customers.

Activate the pricing plan version

Before you can subscribe customers, activate the version you just created:

$curl -X POST https://test.api.solvimon.com/v1/pricing-plan-versions/ppve_gwDeep0tDRcSvkAfeN1Z/activate \
> -H "X-API-KEY: <apiKey>"

Once activated, the version and its pricings are locked. You cannot edit them—only create a new version if pricing needs to change.

📖 API reference

Create a customer

A customer is who you bill. Create one with their contact and billing info:

$curl -X POST https://test.api.solvimon.com/v1/customers \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "reference": "acme-001",
> "type": "ORGANIZATION",
> "email": "billing@acme.com",
> "status": "DRAFT",
> "timezone": "Europe/London",
> "organization": {
> "legal_name": "ACME Corp",
> "registered_address": {
> "line1": "123 Business St",
> "city": "London",
> "postal_code": "SW1A 1AA",
> "country": "GB"
> }
> }
> }'

The response returns a customer id (e.g. cust_kwDeAF0ts1CV11BBet2i). Save it.

📖 API reference

Activate the customer

Customers start in DRAFT. Activate them before creating subscriptions:

$curl -X POST https://test.api.solvimon.com/v1/customers/acme-001/activate \
> -H "X-API-KEY: <apiKey>"

Create a subscription

Before creating subscriptions, configure at least one billing entity under Settings → Billing entities in Desk. This is required for invoice generation.

A subscription links a customer to a pricing plan and defines billing terms (currency, period, start date):

$curl -X POST https://test.api.solvimon.com/v1/pricing-plan-subscriptions/init \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "pricing_plan_subscription": {
> "reference": "acme-001-sub",
> "customer_reference": "acme-001",
> "billing_entity_reference": "<your_billing_entity_reference>",
> "billing_currency": "EUR",
> "billing_time": "EXACT"
> },
> "pricing_plan_schedules": [
> {
> "pricing_plan_version_selector": {
> "pricing_plan_reference": "default_pricing"
> },
> "start_at": "2025-05-06T00:00:00Z"
> }
> ]
> }'

Field notes:

  • billing_time: "EXACT" — invoices are generated on the same day of the month as start_at.
  • billing_entity_reference — the entity issuing invoices. Get this from your Desk billing settings.
  • The subscription starts in DRAFT and activates automatically once the first billing period begins.

The response returns a subscription id you can reference later.

📖 API reference


5. Send usage events

Once the subscription is active, start sending usage events. Events are matched to the customer and meter, then aggregated into the invoice.

$curl -X POST https://test.api.solvimon.com/v1/ingest/meter-data \
> -H "X-API-KEY: <apiKey>" \
> -H "Content-Type: application/json" \
> -d '{
> "meter_reference": "meter_registered_employee",
> "customer_reference": "acme-001",
> "reference": "evt_20250506_001",
> "timestamp": "2025-05-06T14:30:00Z",
> "meter_values": [
> {
> "reference": "employee_count",
> "number": "5"
> }
> ],
> "meter_properties": [
> {
> "reference": "employee_country",
> "value": "GBR"
> }
> ]
> }'

Field notes:

  • reference — a unique ID for this event. If sent twice, the second is deduplicated.
  • timestamp — when the usage occurred. Defaults to now if omitted.
  • meter_values — the measured quantity. Pass as a string ("5", not the number 5).
  • meter_properties — the dimensions matching a meter property value. Required if the property is required: true.

A 200 response means the event was accepted. Events are matched to invoices based on their timestamp and the subscription’s billing period.

📖 API reference


6. View your first invoice

Solvimon generates a draft invoice for the current billing period. Retrieve it to see your metered charges:

$curl "https://test.api.solvimon.com/v1/invoices?customer_reference=acme-001" \
> -H "X-API-KEY: <apiKey>"

Response:

1{
2 "data": [
3 {
4 "id": "inv_kwDeAF0ts1CV11BBet2i",
5 "status": "DRAFT",
6 "customer_reference": "acme-001",
7 "billing_period_start": "2025-05-06T00:00:00Z",
8 "billing_period_end": "2025-06-06T00:00:00Z",
9 "total_amount": {
10 "quantity": "2.50",
11 "currency": "EUR"
12 },
13 "line_items": [
14 {
15 "product_item_reference": "reimbursed_amount",
16 "description": "Registered employees – by country",
17 "quantity": "5",
18 "unit_price": {
19 "quantity": "0.50",
20 "currency": "EUR"
21 },
22 "total": {
23 "quantity": "2.50",
24 "currency": "EUR"
25 }
26 }
27 ]
28 }
29 ]
30}

The invoice stays in DRAFT during the billing period. New usage events continue to be added to it. At the end of the period, it automatically transitions to FINAL.

📖 API reference


How it all fits together

You now have a complete billing pipeline:

  1. Metering (metr_...) — defines what you measure via meter values and properties
  2. Calculation (mvca_...) — aggregates events into billable quantities
  3. Catalog (prod_...proi_...) — defines what you sell
  4. Pricing (ppla_...ppve_... → pricing configs) — defines how much you charge
  5. Subscription — links a customer to a pricing plan
  6. Events — raw usage data
  7. Invoice — automatically generated from the subscription and events

For a visual reference of how these resources connect, see the Concepts page.


Common gotchas

Order of activation. Resources are created in DRAFT by default. Activate Meter Values and Properties before the Meter, the Meter before the MVC, and the Product before its items. Activating a Pricing Plan Version locks its Pricings–make all edits in DRAFT.

References must be unique and slug-shaped. ^\S+$ is enforced–no whitespace. Pick a naming convention (e.g. domain_object_purpose) and stick with it; references are how you’ll find resources without juggling IDs.

required: true on Meter Values/Properties. Required fields make the property usable in pricing conditions and cause ingestion to fail if the field is missing. If you want flexibility, start permissive; you can tighten later.

amount.quantity is always a string. This applies to every monetary field across the API. Pass "0.50" not 0.50.

The Catalogue isn’t a resource. There’s no endpoint for it–it’s just the conceptual envelope around Categories.