> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chataigne.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Locations

> List, retrieve, and update restaurant locations — including the address object and partial address merge semantics.

A **location** represents a single restaurant venue: its currency, country, timezone, language, and physical address. Locations belong to an [organization](/location-organization-management/organizations) and carry their own [settings](/location-organization-management/location-settings) (opening hours, delivery, acceptance, AI instructions) and [special closings](/location-organization-management/special-closings).

On the public API you can **list**, **retrieve**, and **update** locations. Locations are created through the [Admin API](/admin/overview) or the organization endpoint — see [Creating locations](#creating-locations).

## The location object

<ResponseField name="id" type="string">
  Unique identifier, prefixed with `loc_`.
</ResponseField>

<ResponseField name="object" type="string">
  Always `location`.
</ResponseField>

<ResponseField name="organization_id" type="string | null">
  The [organization](/location-organization-management/organizations) this location belongs to (`org_…`), or `null` if it is standalone.
</ResponseField>

<ResponseField name="name" type="string">
  Display name of the location.
</ResponseField>

<ResponseField name="currency" type="string">
  ISO 4217 currency code. One of `CHF`, `EUR`, `GBP`, `BRL`, `USD`, `MXN`.
</ResponseField>

<ResponseField name="country" type="string">
  ISO 3166-1 alpha-2 country code. One of `FR`, `CH`, `GB`, `BR`, `LU`, `MX`, `US`.
</ResponseField>

<ResponseField name="timezone" type="string">
  IANA timezone identifier, e.g. `Europe/Zurich`.
</ResponseField>

<ResponseField name="default_language" type="string">
  Default language used for customer-facing messaging at this location.
</ResponseField>

<ResponseField name="address" type="object | null">
  Physical address of the location, or `null` if not set.

  <Expandable title="address properties">
    <ResponseField name="line1" type="string">
      Street address, first line.
    </ResponseField>

    <ResponseField name="line2" type="string">
      Street address, second line (apartment, suite, floor).
    </ResponseField>

    <ResponseField name="postal_code" type="string">
      Postal or ZIP code.
    </ResponseField>

    <ResponseField name="city" type="string">
      City.
    </ResponseField>

    <ResponseField name="country" type="string">
      ISO 3166-1 alpha-2 country code.
    </ResponseField>

    <ResponseField name="latitude" type="number">
      Geographic latitude in decimal degrees.
    </ResponseField>

    <ResponseField name="longitude" type="number">
      Geographic longitude in decimal degrees.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="created_at" type="string">
  Creation timestamp, ISO 8601 in UTC.
</ResponseField>

<ResponseField name="updated_at" type="string">
  Last update timestamp, ISO 8601 in UTC.
</ResponseField>

```json The location object theme={null}
{
  "id": "loc_8sKq2bXt9mZ1",
  "object": "location",
  "organization_id": "org_3aN7vP0kLeQ4",
  "name": "Châtaigne Genève — Plainpalais",
  "currency": "CHF",
  "country": "CH",
  "timezone": "Europe/Zurich",
  "default_language": "fr",
  "address": {
    "line1": "12 Rue de Carouge",
    "line2": "Rez-de-chaussée",
    "postal_code": "1205",
    "city": "Genève",
    "country": "CH",
    "latitude": 46.1959,
    "longitude": 6.1402
  },
  "created_at": "2025-01-14T09:32:11Z",
  "updated_at": "2025-03-02T17:48:55Z"
}
```

## List locations

Returns a [paginated list](/concepts/pagination) of locations accessible to your API key, ordered by `created_at`.

```
GET /v1/locations
```

<ParamField query="limit" type="integer" default="10">
  Number of objects to return, between `1` and `100`.
</ParamField>

<ParamField query="starting_after" type="string">
  Cursor for forward pagination — a location `id`. Mutually exclusive with `ending_before`.
</ParamField>

<ParamField query="ending_before" type="string">
  Cursor for backward pagination — a location `id`. Mutually exclusive with `starting_after`.
</ParamField>

<ParamField query="created_after" type="string">
  Return locations created at or after this ISO 8601 timestamp.
</ParamField>

<ParamField query="created_before" type="string">
  Return locations created at or before this ISO 8601 timestamp.
</ParamField>

<ParamField query="updated_after" type="string">
  Return locations updated at or after this ISO 8601 timestamp.
</ParamField>

<ParamField query="updated_before" type="string">
  Return locations updated at or before this ISO 8601 timestamp.
</ParamField>

<CodeGroup>
  ```bash curl theme={null}
  curl https://server.chataigne.ai/v1/locations?limit=2 \
    -H "x-api-key: ch_org_live_8f3kP2nQ..."
  ```

  ```js Node theme={null}
  const res = await fetch("https://server.chataigne.ai/v1/locations?limit=2", {
    headers: { "x-api-key": "ch_org_live_8f3kP2nQ..." },
  });
  const locations = await res.json();
  ```
</CodeGroup>

```json Response theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "loc_8sKq2bXt9mZ1",
      "object": "location",
      "organization_id": "org_3aN7vP0kLeQ4",
      "name": "Châtaigne Genève — Plainpalais",
      "currency": "CHF",
      "country": "CH",
      "timezone": "Europe/Zurich",
      "default_language": "fr",
      "address": {
        "line1": "12 Rue de Carouge",
        "line2": "Rez-de-chaussée",
        "postal_code": "1205",
        "city": "Genève",
        "country": "CH",
        "latitude": 46.1959,
        "longitude": 6.1402
      },
      "created_at": "2025-01-14T09:32:11Z",
      "updated_at": "2025-03-02T17:48:55Z"
    },
    {
      "id": "loc_5dWm0fYr4tH7",
      "object": "location",
      "organization_id": "org_3aN7vP0kLeQ4",
      "name": "Châtaigne Lausanne — Flon",
      "currency": "CHF",
      "country": "CH",
      "timezone": "Europe/Zurich",
      "default_language": "fr",
      "address": null,
      "created_at": "2025-02-20T11:05:43Z",
      "updated_at": "2025-02-20T11:05:43Z"
    }
  ],
  "has_more": true,
  "url": "/v1/locations"
}
```

<Note>
  To list only the locations within a specific organization, use `GET /v1/organizations/{organization_id}/locations`. See [Organizations](/location-organization-management/organizations).
</Note>

## Retrieve a location

Retrieves a single location by its `id`.

```
GET /v1/locations/{location_id}
```

<ParamField path="location_id" type="string" required>
  The identifier of the location, e.g. `loc_8sKq2bXt9mZ1`.
</ParamField>

<CodeGroup>
  ```bash curl theme={null}
  curl https://server.chataigne.ai/v1/locations/loc_8sKq2bXt9mZ1 \
    -H "x-api-key: ch_org_live_8f3kP2nQ..."
  ```

  ```js Node theme={null}
  const res = await fetch(
    "https://server.chataigne.ai/v1/locations/loc_8sKq2bXt9mZ1",
    { headers: { "x-api-key": "ch_org_live_8f3kP2nQ..." } },
  );
  const location = await res.json();
  ```
</CodeGroup>

```json Response theme={null}
{
  "id": "loc_8sKq2bXt9mZ1",
  "object": "location",
  "organization_id": "org_3aN7vP0kLeQ4",
  "name": "Châtaigne Genève — Plainpalais",
  "currency": "CHF",
  "country": "CH",
  "timezone": "Europe/Zurich",
  "default_language": "fr",
  "address": {
    "line1": "12 Rue de Carouge",
    "line2": "Rez-de-chaussée",
    "postal_code": "1205",
    "city": "Genève",
    "country": "CH",
    "latitude": 46.1959,
    "longitude": 6.1402
  },
  "created_at": "2025-01-14T09:32:11Z",
  "updated_at": "2025-03-02T17:48:55Z"
}
```

A `loc_…` that does not exist or is not accessible to your key returns a `404 not_found_error`. See [Errors](/concepts/errors).

## Update a location

Updates the specified location. Only the fields you pass are changed; omitted fields are left untouched.

```
PATCH /v1/locations/{location_id}
```

<ParamField path="location_id" type="string" required>
  The identifier of the location to update.
</ParamField>

<ParamField body="name" type="string">
  Display name of the location.
</ParamField>

<ParamField body="currency" type="string">
  ISO 4217 currency code. One of `CHF`, `EUR`, `GBP`, `BRL`, `USD`, `MXN`.
</ParamField>

<ParamField body="country" type="string">
  ISO 3166-1 alpha-2 country code. One of `FR`, `CH`, `GB`, `BR`, `LU`, `MX`, `US`.
</ParamField>

<ParamField body="timezone" type="string">
  IANA timezone identifier, e.g. `Europe/Zurich`.
</ParamField>

<ParamField body="default_language" type="string">
  Default language for customer-facing messaging.
</ParamField>

<ParamField body="address" type="object">
  Address fields to merge. See [Partial address merge](#partial-address-merge) below.

  <Expandable title="address properties">
    <ParamField body="line1" type="string" />

    <ParamField body="line2" type="string" />

    <ParamField body="postal_code" type="string" />

    <ParamField body="city" type="string" />

    <ParamField body="country" type="string" />

    <ParamField body="latitude" type="number" />

    <ParamField body="longitude" type="number" />
  </Expandable>
</ParamField>

### Partial address merge

When you include an `address` object in a `PATCH`, the keys you provide are **merged** into the existing address — fields you omit keep their current values. This lets you correct a single line without re-sending the full address.

<Note>
  Merge applies only when the location already has an address. The address as a whole remains optional on existing locations, but **`address` (with `latitude` and `longitude`) is required at creation time** — see [Creating locations](#creating-locations).
</Note>

<CodeGroup>
  ```bash curl theme={null}
  curl -X PATCH https://server.chataigne.ai/v1/locations/loc_8sKq2bXt9mZ1 \
    -H "x-api-key: ch_org_live_8f3kP2nQ..." \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Châtaigne Genève — Plainpalais (Carouge)",
      "address": {
        "line2": "1er étage",
        "postal_code": "1227"
      }
    }'
  ```

  ```js Node theme={null}
  const res = await fetch(
    "https://server.chataigne.ai/v1/locations/loc_8sKq2bXt9mZ1",
    {
      method: "PATCH",
      headers: {
        "x-api-key": "ch_org_live_8f3kP2nQ...",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        name: "Châtaigne Genève — Plainpalais (Carouge)",
        address: { line2: "1er étage", postal_code: "1227" },
      }),
    },
  );
  const location = await res.json();
  ```
</CodeGroup>

```json Response theme={null}
{
  "id": "loc_8sKq2bXt9mZ1",
  "object": "location",
  "organization_id": "org_3aN7vP0kLeQ4",
  "name": "Châtaigne Genève — Plainpalais (Carouge)",
  "currency": "CHF",
  "country": "CH",
  "timezone": "Europe/Zurich",
  "default_language": "fr",
  "address": {
    "line1": "12 Rue de Carouge",
    "line2": "1er étage",
    "postal_code": "1227",
    "city": "Genève",
    "country": "CH",
    "latitude": 46.1959,
    "longitude": 6.1402
  },
  "created_at": "2025-01-14T09:32:11Z",
  "updated_at": "2025-03-02T18:14:09Z"
}
```

Note in the response that only `name`, `address.line2`, and `address.postal_code` changed — `line1`, `city`, `country`, and the coordinates were preserved from the merge.

<Warning>
  Editing `address` does **not** automatically re-geocode the location. If you move the venue or correct the street, update `latitude` and `longitude` in the same request so delivery zones and distance calculations stay accurate.
</Warning>

## Creating locations

Locations cannot be created on the public read/update routes above. Create them through one of:

<CardGroup cols={2}>
  <Card title="Within an organization" icon="building" href="/location-organization-management/organizations">
    `POST /v1/organizations/{organization_id}/locations` — creates a location under an existing organization.
  </Card>

  <Card title="Admin API" icon="shield-halved" href="/admin/overview">
    `POST /admin/v1/locations` or `POST /admin/v1/organizations/{organization_id}/locations` — for provisioning across organizations.
  </Card>
</CardGroup>

<Warning>
  On creation, **`address` is required and must include `latitude` and `longitude`.** Coordinates power delivery radius checks, distance-based fees, and customer ETA — a location without them cannot accept geo-aware orders.
</Warning>

Resource-creating `POST`s require an [`Idempotency-Key`](/concepts/idempotency) header so retries are safe.

```bash Create a location under an organization theme={null}
curl -X POST https://server.chataigne.ai/v1/organizations/org_3aN7vP0kLeQ4/locations \
  -H "x-api-key: ch_org_live_8f3kP2nQ..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f1c2a9e-7b4d-4e2a-9c3f-0a1b2c3d4e5f" \
  -d '{
    "name": "Châtaigne Genève — Eaux-Vives",
    "currency": "CHF",
    "country": "CH",
    "timezone": "Europe/Zurich",
    "default_language": "fr",
    "address": {
      "line1": "8 Rue Versonnex",
      "postal_code": "1207",
      "city": "Genève",
      "country": "CH",
      "latitude": 46.2044,
      "longitude": 6.1577
    }
  }'
```

## Authentication & errors

All endpoints on this page live on the public `/v1` surface and authenticate with an **organization/location API key** (prefix `ch_org_`) sent in the `x-api-key` header.

<Note>
  Admin keys (`ch_admin_`) are rejected with `403` on `/v1`, and a missing key returns `401`. Dashboard sessions cannot be used on the API. See [Authentication](/concepts/authentication).
</Note>

| Status | Type                    | When                                                                    |
| ------ | ----------------------- | ----------------------------------------------------------------------- |
| `401`  | `authentication_error`  | Missing or invalid API key.                                             |
| `403`  | `authorization_error`   | Wrong key type for this surface, or no access to the location.          |
| `404`  | `not_found_error`       | The `loc_…` does not exist or is not visible to your key.               |
| `400`  | `invalid_request_error` | Invalid field value (e.g. unsupported `currency`, malformed `address`). |

Every response includes an [`X-Request-Id`](/concepts/request-ids); error bodies mirror it as `error.request_id`. See [Errors](/concepts/errors) for the full error shape.

## Related

<CardGroup cols={3}>
  <Card title="Organizations" icon="sitemap" href="/location-organization-management/organizations">
    Group locations and expand them inline.
  </Card>

  <Card title="Location settings" icon="sliders" href="/location-organization-management/location-settings">
    Opening hours, delivery, acceptance, AI instructions.
  </Card>

  <Card title="Special closings" icon="calendar-xmark" href="/location-organization-management/special-closings">
    Schedule one-off closures for a location.
  </Card>
</CardGroup>
