openapi: 3.0.3 info: title: Distru Public API version: v1 x-apievangelist-generated: '2026-07-18' x-apievangelist-method: generated x-apievangelist-source: https://apidocs.distru.dev description: >- The Distru Public API provides read and write access to a cannabis ERP: products, inventory, orders, invoices, purchases, companies, contacts, batches, packages, assemblies, strains, test results, locations, menus and more. Authentication uses a Bearer API key generated in the Distru app (Settings > Integrations > Distru API); keys expire one year from issue. Responses are JSON and list endpoints are paginated with page[number] and page[size] query parameters, returning a next_page URL when more pages exist. This specification was generated by API Evangelist from the published Distru API reference at https://apidocs.distru.dev — operation paths and methods are faithful to the documented surface; request/response schemas are intentionally generic where the reference does not publish a downloadable OpenAPI definition. contact: name: Distru email: hello@distru.com url: https://www.distru.com/features/distru-api servers: - url: https://app.distru.com/public/v1 description: Production tags: - name: Products - name: Inventory - name: Orders - name: Invoices - name: Purchases - name: Companies - name: Contacts - name: Batches - name: Packages - name: Assemblies - name: Strains - name: TestResults - name: Locations - name: Menus - name: PaymentMethods - name: Returns - name: StockAdjustments - name: CustomFields - name: FileAttachments - name: Vehicles - name: ProductPosMappings components: securitySchemes: bearerAuth: type: http scheme: bearer description: >- API key issued in the Distru app under Settings > Integrations > Distru API, sent as `Authorization: Bearer `. Keys expire one year from issue date. parameters: pageNumber: name: page[number] in: query required: false schema: type: integer minimum: 1 description: 1-based page number. pageSize: name: page[size] in: query required: false schema: type: integer maximum: 500 description: Page size (max 500 for most collections). schemas: Page: type: object properties: data: type: array items: type: object next_page: type: string nullable: true description: URL of the next page of results, or null on the last page. Resource: type: object Problem: type: object properties: error: type: string message: type: string responses: OK: description: Success. content: application/json: schema: { $ref: '#/components/schemas/Resource' } Paged: description: A page of results. content: application/json: schema: { $ref: '#/components/schemas/Page' } Unauthorized: description: Missing or invalid API key. content: application/json: schema: { $ref: '#/components/schemas/Problem' } NotFound: description: Resource not found. content: application/json: schema: { $ref: '#/components/schemas/Problem' } Unprocessable: description: Validation error. content: application/json: schema: { $ref: '#/components/schemas/Problem' } security: - bearerAuth: [] paths: /products: get: tags: [Products] operationId: listProducts summary: List products parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': description: A page of products. content: application/json: schema: { $ref: '#/components/schemas/Page' } '401': { $ref: '#/components/responses/Unauthorized' } post: tags: [Products] operationId: upsertProduct summary: Create or update a product requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /products/{id}: get: tags: [Products] operationId: getProduct summary: Retrieve a product parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /inventory: get: tags: [Inventory] operationId: listInventory summary: List inventory parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } '401': { $ref: '#/components/responses/Unauthorized' } /orders: get: tags: [Orders] operationId: listOrders summary: List orders parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } post: tags: [Orders] operationId: upsertOrder summary: Create or update an order requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /orders/{id}: get: tags: [Orders] operationId: getOrder summary: Retrieve an order parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /invoices: get: tags: [Invoices] operationId: listInvoices summary: List invoices parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } post: tags: [Invoices] operationId: createInvoice summary: Create an invoice requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /invoices/{id}: get: tags: [Invoices] operationId: getInvoice summary: Retrieve an invoice parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /invoices/{id}/payments: post: tags: [Invoices] operationId: createInvoicePayment summary: Record a payment against an invoice parameters: - { name: id, in: path, required: true, schema: { type: string } } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /purchases: get: tags: [Purchases] operationId: listPurchases summary: List purchases parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } post: tags: [Purchases] operationId: upsertPurchase summary: Create or update a purchase requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /purchases/{id}: get: tags: [Purchases] operationId: getPurchase summary: Retrieve a purchase parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /purchases/{id}/payments: post: tags: [Purchases] operationId: createPurchasePayment summary: Record a payment against a purchase parameters: - { name: id, in: path, required: true, schema: { type: string } } requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /companies: get: tags: [Companies] operationId: listCompanies summary: List companies parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } post: tags: [Companies] operationId: upsertCompany summary: Create or update a company requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /companies/{id}: get: tags: [Companies] operationId: getCompany summary: Retrieve a company parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /contacts: get: tags: [Contacts] operationId: listContacts summary: List contacts parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } /contacts/{id}: get: tags: [Contacts] operationId: getContact summary: Retrieve a contact parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /batches: get: tags: [Batches] operationId: listBatches summary: List batches parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } post: tags: [Batches] operationId: createBatch summary: Create a batch requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /batches/{id}: get: tags: [Batches] operationId: getBatch summary: Retrieve a batch parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /packages: get: tags: [Packages] operationId: listPackages summary: List packages parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } /assemblies: get: tags: [Assemblies] operationId: listAssemblies summary: List assemblies parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } /assemblies/{id}: get: tags: [Assemblies] operationId: getAssembly summary: Retrieve an assembly parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /strains: get: tags: [Strains] operationId: listStrains summary: List strains parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } post: tags: [Strains] operationId: upsertStrain summary: Create or update a strain requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /strains/{id}: get: tags: [Strains] operationId: getStrain summary: Retrieve a strain parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /test-results: get: tags: [TestResults] operationId: listTestResults summary: List test results parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } post: tags: [TestResults] operationId: createTestResult summary: Create a test result requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /locations: get: tags: [Locations] operationId: listLocations summary: List locations parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } /locations/{id}: get: tags: [Locations] operationId: getLocation summary: Retrieve a location parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /menus: get: tags: [Menus] operationId: listMenus summary: List menus parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } /menus/{id}: get: tags: [Menus] operationId: getMenu summary: Retrieve a menu parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /payment-methods: get: tags: [PaymentMethods] operationId: listPaymentMethods summary: List payment methods parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } /payment-methods/{id}: get: tags: [PaymentMethods] operationId: getPaymentMethod summary: Retrieve a payment method parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /returns: get: tags: [Returns] operationId: listReturns summary: List returns parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } /returns/{id}: get: tags: [Returns] operationId: getReturn summary: Retrieve a return parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /adjustments: get: tags: [StockAdjustments] operationId: listAdjustments summary: List stock adjustments parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } /adjustments/{id}: get: tags: [StockAdjustments] operationId: getAdjustment summary: Retrieve a stock adjustment parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /stock_adjustments: post: tags: [StockAdjustments] operationId: createStockAdjustment summary: Create a stock adjustment requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /custom-fields: post: tags: [CustomFields] operationId: createCustomField summary: Create a custom field requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /custom-fields/{id}: get: tags: [CustomFields] operationId: getCustomField summary: Retrieve a custom field parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } /file-attachments: post: tags: [FileAttachments] operationId: createFileAttachment summary: Upload a file attachment requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /vehicles: post: tags: [Vehicles] operationId: createVehicle summary: Create a vehicle requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /product-pos-mappings: get: tags: [ProductPosMappings] operationId: listProductPosMappings summary: List product POS mappings parameters: - $ref: '#/components/parameters/pageNumber' - $ref: '#/components/parameters/pageSize' responses: '200': { $ref: '#/components/responses/Paged' } post: tags: [ProductPosMappings] operationId: createProductPosMapping summary: Create a product POS mapping requestBody: required: true content: application/json: schema: { $ref: '#/components/schemas/Resource' } responses: '200': { $ref: '#/components/responses/OK' } '422': { $ref: '#/components/responses/Unprocessable' } /product-pos-mappings/{id}: get: tags: [ProductPosMappings] operationId: getProductPosMapping summary: Retrieve a product POS mapping parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' } delete: tags: [ProductPosMappings] operationId: deleteProductPosMapping summary: Delete a product POS mapping parameters: - { name: id, in: path, required: true, schema: { type: string } } responses: '200': { $ref: '#/components/responses/OK' } '404': { $ref: '#/components/responses/NotFound' }