Cost

Add costs to products

Changed on

Add one or more costs to each of the given product-tracked products, and return the affected products with their updated cost totals.

product_ids is a non-empty list of product IDs. Every product must exist, be accessible to the authenticated company, and be product-tracked (a product tracked by batch or package is rejected). The cost lands on each product's active-status stock quantity. location_ids optionally scopes which locations' stock the cost applies to; omit it to apply across all locations.

Each entry in costs records one cost against the selected records; the amount added to a record's cost basis is cost_per_unit × quantity. Every entry in the list is applied to every selected record, so N records and M cost entries create N × M cost entries. Fields:

  • cost_type_id (required): the cost type to apply, as its ID from GET /public/v1/cost-types. Must exist and be accessible to the authenticated company.
  • quantity (required): how many units of the cost type to apply, as a decimal. Must be greater than 0.
  • cost_per_unit (optional): the per-unit amount, as a decimal. When omitted, the cost type's own cost per unit is used. Must be omitted for cost types with a locked cost per unit (those that don't allow inline editing); sending it for such a type is rejected. It is only required when an inline-editable cost type has no cost per unit of its own.
  • description (optional): free-form text stored on the cost.

When distribute_by_quantity is true, the total of each cost (cost_per_unit × quantity) is split across the selected records in proportion to each record's quantity, instead of applying the full cost to every record. Quantities are converted to a common unit before the split, so all selected records must share the same unit type category. Selecting a single record is a no-op (the whole cost lands on it). Defaults to false when omitted, applying the same cost in full to each selected record.

This is applied synchronously and atomically: a 200 means every cost has already been recorded and the response body reflects the updated records — there is nothing to poll. If any id, cost, or validation fails, the entire request is rejected and nothing is changed.

Adding costs is additive, not an upsert. Each call records new cost entries and raises the recorded cost basis (COGS) of the selected inventory's stock; sending the same body twice applies the cost twice. Cost entries created here cannot be edited or removed through this endpoint. The effect is confined to Distru cost accounting — it does not push to, pull from, or alter Metrc or BioTrack.

Common errors (HTTP 400 unless noted):

  • The *_ids list is empty.
  • One or more ids don't exist or aren't accessible to the authenticated company.
  • A record isn't tracked by the endpoint's method (e.g. a product that isn't product-tracked, or a batch whose product isn't batch-tracked).
  • A record has no quantity to add a cost to.
  • cost_type_id is missing or unknown, or quantity is missing or not greater than 0.
  • cost_per_unit is set for a cost type with a locked cost per unit, or missing when required.
  • distribute_by_quantity is used across records with mixed unit type categories.
  • Cost Accounting module is not enabled, or the user lacks costs_permissions_apply_to_inventory (HTTP 403).

Required permission: costs_permissions_apply_to_inventory.

post/public/v1/products/add-costs

Request

  • Base URL
    https://app.distru.com
  • Auth
    HTTP bearer

Request body

distribute_by_quantityboolean

When true, split each cost across the listed products in proportion to each product's active quantity (all products must share the same unit type category). Defaults to false when omitted, applying the full cost to every product

location_idsstring[]

Optional list of location IDs scoping which locations' stock the cost applies to. Omit to apply across all locations; an explicit empty list is rejected

product_idsstring[] required

Required. Non-empty list of product IDs; every one must exist, be accessible to the authenticated company, and be product-tracked. Each cost is applied to all listed products

Response

The affected products

next_pagestring

URL for the next page of results; null when there is no next page

Example response

{
  "data": [
    {
      "batches_with_active_quantity_by_location": [
        {
          "location": {
            "address": "1234 Warehouse Street, Oakland, CA",
            "company_id": "02c88a3f-d759-4973-88f9-60049d682524",
            "id": "02c88a3f-d759-4973-88f9-60049d682524",
            "license_id": "02c88a3f-d759-4973-88f9-60049d682524",
            "name": "Warehouse 1"
          }
        }
      ],
      "brand": {
        "id": "3f128a34-cc59-4b49-8883-23bf10e59c6c",
        "name": "Retailer 1"
      },
      "packages_with_active_quantity_by_location": [
        {
          "location": {
            "address": "1234 Warehouse Street, Oakland, CA",
            "company_id": "02c88a3f-d759-4973-88f9-60049d682524",
            "id": "02c88a3f-d759-4973-88f9-60049d682524",
            "license_id": "02c88a3f-d759-4973-88f9-60049d682524",
            "name": "Warehouse 1"
          }
        }
      ],
      "quantity_active_by_location": [
        {
          "location": {
            "address": "1234 Warehouse Street, Oakland, CA",
            "company_id": "02c88a3f-d759-4973-88f9-60049d682524",
            "id": "02c88a3f-d759-4973-88f9-60049d682524",
            "license_id": "02c88a3f-d759-4973-88f9-60049d682524",
            "name": "Warehouse 1"
          }
        }
      ],
      "vendor": {
        "id": "3f128a34-cc59-4b49-8883-23bf10e59c6c",
        "name": "Retailer 1"
      }
    }
  ]
}

Changes

    • info

      added the required property /// to the response with the status

    • info

      added the required property /// to the response with the status