---
title: "Upsert a location"
method: POST
path: "/public/v1/locations"
tags: ["Location"]
---

# Upsert a location

`POST /public/v1/locations`

## Request

- Base URL: `https://app.distru.com`
- URL: `https://app.distru.com/public/v1/locations`
- Auth: HTTP bearer

Upsert a single [location](#model-location) belonging to your own company — one POST handles both create and update. Include an existing location `id` in the body to update that location, or omit `id` to create a new one. The create path returns 201 and the update path returns 200; either way the response body is the full location, including its geocoded `latitude`/`longitude`. Locations written here are the ones returned by [GET /public/v1/locations](#get-locations) and referenced across the API:
• a [purchase](#model-purchase) receives inventory into a location, and an [order](#model-order) ships from one
• every [package](#model-package) sits at a location, and can be moved from one location to another
• [inventory](#model-inventory) quantities are always tracked per location
• an [assembly](#model-assembly) claims its inputs and produces its outputs at locations
• [stock adjustments](#model-stockadjustment) add or remove inventory at a location

To manage the locations of your partner companies instead, use [POST /public/v1/companies/{id}/locations](#upsert-a-companys-location).

`latitude` and `longitude` cannot be sent — they are derived by geocoding the address, because Distru uses these coordinates to generate directions for transfer templates and to optimize delivery routes. Since those features require coordinates, an address that cannot be geocoded is rejected: nothing is saved and the request returns 400 (correct the address fields and retry). If the geocoding service itself is temporarily unavailable the request returns 503 — the address may be fine; retry later. Previously geocoded addresses resolve without contacting the geocoding service.

Any location that will hold cannabis inventory must be associated with one of your [licenses](#model-license) via `license_id` — compliance is tracked per license, so a location without one is only suitable for non-regulated items. Choose the license carefully: once a location is linked to a Metrc or BioTrack license, the link is permanent — it can never be changed or cleared. Only links to Distru-only licenses (`compliance_type` `NONE`) can be swapped or removed later.

This endpoint never writes to Metrc: it does not create Metrc rooms, and `metrc_id` is read-only — it stays null unless the location is synced through the Distru app. Linking the first location to a Metrc license that cannot assign locations to plant batches auto-assigns that location as the license's intake location.

Companies with a BioTrack integration cannot manage locations through the API at all — their requests return a 400, because BioTrack locations require room configuration and syncing this endpoint does not support.

Updates are sparse: only the fields you send are changed, any field you omit keeps its current value, and sending `null` for a nullable field clears it (a required field rejects `null` with a 400). Changing any address field re-geocodes the location and refreshes its coordinates.

Required permission: `companies_permissions_create` to create a location, `companies_permissions_edit` to update an existing one.

## Request body

- object
  - `id` string: ID of the location. Provide it to update that location — it must belong to your company and not be soft-deleted, otherwise the request returns 404. Omit it to create a new location.
  - `name` string: Display name of the location. Required on create; cannot be set to `null`. Characters with diacritics are replaced with their closest ASCII equivalent (e.g. `Española` becomes `Espanola`).
  - `street_address` string: Street address (e.g. `1234 Mission St`). Required on create; cannot be set to `null`. Part of the geocoded address.
  - `apt` string: Apartment, suite, or unit within the street address, or `null` to clear it. Optional.
  - `city` string: City of the address. Required on create; cannot be set to `null`.
  - `state` string: State or region of the address. Required on create; cannot be set to `null`. When `country` is `US`, must be a two-letter US state abbreviation (e.g. `CA`).
  - `zip` string: Postal code of the address. Required on create; cannot be set to `null`. When `country` is `US`, must be a valid ZIP code (`#####` or `#####-####`) whose prefix matches the state.
  - `country` string: Country of the address as an ISO 3166-1 alpha-2 code (e.g. `US`). Required on create; cannot be set to `null`. Official country names and common spellings are normalized to their code (e.g. `United States` becomes `US`).
  - `license_id` string: ID of one of your company's [licenses](#model-license) (as returned by [GET /public/v1/licenses](#get-licenses)), linking the location to that license, or `null` to unlink. Optional. A license that doesn't belong to your company is rejected with a 400. Once linked to a Metrc or BioTrack license the link is permanent and cannot be changed or cleared; only Distru-only licenses can be relinked.

## Response `200`

An updated location

- LocationResponse: A single location wrapped in a data envelope
  - `data` Location: A place where inventory is held. This is flexible: it can be a whole site such as a warehouse or store, or a more specific spot like a room or area within one. Has an address and optionally a license.
    - `address` string, required: The full address as a single formatted line, built from the street, apt, city, state, zip, and country fields
    - `apt` string: The apartment/suite/unit of this location, or null when none was entered
    - `city` string, required: The city of this location
    - `company_id` string: ID of the [company](#model-company) that owns this location
    - `country` string, required: The country of this location
    - `deleted_at` string: ISO 8601 datetime this location was deleted at, or null when it is not deleted
    - `id` string, required: ID for this location
    - `inserted_datetime` string, required: ISO 8601 datetime this location was created at
    - `latitude` number: The latitude of this location, or null when it has not been geocoded
    - `license` License: A cannabis license held by a company or tied to a location, identifying it to the state and its compliance system.
      - `active` boolean, required: Whether this license is currently active
      - `expiry_datetime` string, required: ISO 8601 datetime this license expires (e.g. "2026-08-20T00:00:00Z")
      - `id` string, required: ID for this license
      - `inserted_datetime` string, required: ISO 8601 datetime this license was created at
      - `issue_datetime` string: ISO 8601 datetime this license was issued, or null when not set
      - `license_number` string, required: License number
      - `license_type` string, required: The license type as configured in Distru. A state-specific free-form value, e.g. "Distributor" or "Type 11 Distributor-Transport"
    - `license_id` string: ID of the [license](#model-license) this location is associated with, or null when the location has no license
    - `longitude` number: The longitude of this location, or null when it has not been geocoded
    - `metrc_id` integer: The location's ID in Metrc. A Metrc identifier, not a Distru ID. Null when the location is not linked to Metrc.
    - `name` string, required: Human readable name for this location
    - `state` string, required: The state of this location
    - `street_address` string, required: The street address of this location
    - `updated_datetime` string, required: ISO 8601 datetime this location was last updated at
    - `zip` string, required: The postal code of this location

## Other responses

- `201`: A new location
- `400`: Invalid parameters
- `401`: Missing or invalid API token
- `403`: The API token lacks the required permission, or team restrictions hide the record
- `404`: Not Found
- `503`: The geocoding service is temporarily unavailable — retry later

## Changes

- **2026-09-04** `f8930b2c2924`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/distru/apis/distru-api/changes/public/v1/locations/post.md)

---

[API](https://skmtc.dev/distru/apis/distru-api.md) - [All operations](https://skmtc.dev/distru/apis/distru-api/llms.txt) - [OpenAPI document](https://skmtc.dev/distru/apis/distru-api/revisions/9d851a88e82f?raw)
