---
title: "Generate a zoning-chat response for a location"
method: POST
path: "/v1/chat/zoning"
---

# Generate a zoning-chat response for a location

`POST /v1/chat/zoning`

## Request

- Base URL: `https://api.struck.build`
- URL: `https://api.struck.build/v1/chat/zoning`
- Auth: HTTP bearer

Answers a question about the zoning rules that apply at one address or plot, the way the Struck zoning chat does. Returns complete JSON by default. Set stream: true for NDJSON events. Charging, retries and deadlines match the technical chat: https://unravel.struck.build/developers#api-charging-and-retries.

## Headers

- `Idempotency-Key` string, uuid

## Request body

- ZoningChatRequest
  - `location` union, required: Exactly one of: a PDOK location id, an RD coordinate pair, or a WGS84 coordinate pair. A coordinate resolves to the address at that point, or the cadastral plot when there is no address. A coordinate outside the Netherlands is a 422.
    - object
      - `location_id` string, required: A PDOK Locatieserver id for an address or plot, for example "adr-0db4e3b0c5c1f8d1b1e3a0e9d63d2c62".
    - object
      - `rd_lat` number, required: RD New (EPSG:28992) x coordinate in metres.
      - `rd_long` number, required: RD New (EPSG:28992) y coordinate in metres.
    - object
      - `lat` number, required: WGS84 latitude in decimal degrees.
      - `long` number, required: WGS84 longitude in decimal degrees.
  - `messages` object[], required: The conversation so far, oldest first. Roles alternate starting with "user", and the final message is always "user".
    - `role` 'user' | 'assistant', required
    - `content` string, required
  - `stream` boolean: Return NDJSON only when true. Omitted or false returns complete JSON.

## Response `200`

Complete JSON when stream is omitted or false; a UTF-8 NDJSON stream when true. JSON contains the final answer, cited sources and the location facts, with a maximum serialized size of 4,000,000 bytes.

- ZoningChatResponse
  - `request_id` string, uuid, required
  - `content` string, required
  - `sources` object[], required: Only cited sources, in ascending source_number order.
    - `source_number` integer, required: The N in the answer's citation marker. The marker is [Source N], or [Source N - article] when the source is one article of a zoning plan, and a Dutch answer may write Bron for Source ([Bron N - article]), so match the number after the keyword rather than the whole bracket. Unique within one response; the numbers carry no meaning across responses.
    - `title` string, required: The name of the source document, for example "Besluit bouwwerken leefomgeving".
    - `url` string, uri: For a zoning plan, its page in the Omgevingsloket for this location; for any other document, its page in the Struck document library when the library lists it. Absent otherwise.
  - `location` object, required: The location the question was answered for.
    - `id` string, required: The PDOK Locatieserver id; send it as location.location_id to ask about it again.
    - `type` 'address' | 'plot', required
    - `display_name` string, required
    - `municipality` string, required: The municipality: the civil municipality for an address, the cadastral municipality for a plot.
    - `province` string, nullable, required
    - `postal_code` string, nullable, required: A Dutch postal code such as "3512JC", or null when the location has none.
    - `plot_ids` string[], required: The cadastral plots the answer covers.
  - `monument` object, required: Monument status from the national, provincial and municipal registers, as the answer used it.
    - `status` 'monument' | 'not_monument' | 'unknown', required
    - `monument_type` 'Rijksmonument' | 'Provinciaal monument' | 'Gemeentelijk monument' | 'Archeologisch monument', nullable, required: The register designation when status is "monument", as the registers name it. Null otherwise.
    - `sources` object[], required
      - `title` string, required
      - `url` string, uri: Absent when the register gives no public page.
  - `protected_townscape` object, required: Protected townscape (beschermd stads- of dorpsgezicht) status, as the answer used it.
    - `status` 'protected' | 'not_protected' | 'unknown', required
    - `protection_type` 'RIJKS_BESCHERMD_STADS_DORPSGEZICHT' | 'GEMEENTELIJK_BESCHERMD_STADS_DORPSGEZICHT', nullable, required: RIJKS_BESCHERMD_STADS_DORPSGEZICHT when the state designated it, GEMEENTELIJK_BESCHERMD_STADS_DORPSGEZICHT when the municipality did. Null unless status is "protected".
    - `sources` object[], required
      - `title` string, required
      - `url` string, uri: Absent when the register gives no public page.
  - `credits_charged` integer, required

## Other responses

- `400`: The request body is not valid JSON.
- `401`: The API key is missing, invalid, or revoked.
- `402`: The organization does not have enough credits.
- `403`: API access is not enabled for this organization.
- `409`: The Idempotency-Key was already used: `idempotency_conflict` when the body differs, `already_completed` when it matches an earlier admitted request, whose response cannot be replayed.
- `413`: The request body exceeds the maximum size.
- `422`: The request body is invalid, or its location cannot be answered for: no address or plot was found there, or no municipal zoning plan covers it. A location rejected after admission is refunded.
- `429`: The API key has exceeded its rate limit.
- `500`: An unexpected error occurred.
- `503`: The chat service is unavailable.
- `504`: The chat service timed out.

---

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