# Create a layer

Add a new floor or layer to a location, either by uploading a floorplan file or defining it via the Spatial API, to serve as the container for rooms and spaces.

### Option A — Create a layer via the Spatial API&#x20;

{% tabs %}
{% tab title="Node.js" %}

### Prerequisites

* Completed **Setup Your Development Environment** and **Send Your First API Request**
* Node.js v18+ and npm v9+
* A valid gospace API key in your `.env` file
* An existing **location\_id** (layers must be linked to a location)

#### 1) Create `create-layer.ts`

```ts
import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  const res = await gospace.spatial.createLayers({
    layers: [
      {
        location_id: "loc_123",   // required: your existing location
        name: "Level 1",          // required: layer name
        // external_id: "level-1", // optional
        // ...include any other fields your schema supports
      },
    ],
  });

  console.log(JSON.stringify(res.data, null, 2));
}

main().catch((err) => {
  console.error("Request failed:", err);
  process.exit(1);
});
```

Run:

```bash
npx tsx create-layer.ts
```

{% endtab %}
{% endtabs %}

### Option B — Create a layer by uploading a floorplan (System API)

Use a file (e.g., DXF or PDF) to seed a new layer for a location. This is an **async** process: you request a signed URL, upload the file, and the system processes it.

{% tabs %}
{% tab title="Node.js" %}

### Prerequisites

* Completed **Setup Your Development Environment** and **Send Your First API Request**
* Node.js v18+ and npm v9+
* A valid gospace API key in your `.env` file
* An existing **location\_id**
* A floorplan file in DXF or PDF format
* The correct **MIME type** for your file (`application/dxf` or `application/pdf`)
* Access to the file path locally to perform the signed URL upload

#### 1) Request a signed URL

```ts
// request-upload.ts
import "dotenv/config";
import GospaceAI from "@gospace-ai/api";

async function main() {
  const gospace = new GospaceAI(process.env.GOSPACE_API_KEY!);

  const upload = await gospace.system.uploadFile({
    file_type: "application/dxf",     // or "application/pdf"
    upload_process: "floorplan",      // use the floorplan ingestion process
    binding_id: "loc_123",            // bind the upload to your location_id
  });

  console.log(JSON.stringify(upload.data, null, 2));
  // -> { signed_url, upload_id, ... }
}

main().catch(console.error);
```

Run:

```bash
npx tsx request-upload.ts
```

#### 2) Upload the file to the signed URL

```ts
// put-upload.ts
import "dotenv/config";
import { readFile } from "node:fs/promises";

async function main() {
  const signedUrl = process.env.SIGNED_URL!;     // set from step 1 output
  const filePath  = "./floorplans/level1.dxf";   // your local file path

  const body = await readFile(filePath);
  const resp = await fetch(signedUrl, {
    method: "PUT",
    headers: {
      "Content-Type": "application/dxf",         // must match file_type used in step 1
    },
    body,
  });

  if (!resp.ok) {
    throw new Error(`Upload failed: ${resp.status} ${resp.statusText}`);
  }

  console.log("Upload successful.");
}

main().catch((err) => {
  console.error("Upload failed:", err);
  process.exit(1);
});
```

Run:

```bash
SIGNED_URL="<<paste from step 1>>" npx tsx put-upload.ts
```

{% endtab %}
{% endtabs %}

### DXF File requirements

To auto-create **walls, desks/seats, rooms, clusters, zones,** and visual **areas** from a DXF, your file must follow the layer and geometry rules below.

### 1) Supported Layers & Geometry

| Layer name        | Geometry                    | Required | Purpose                                                                                                                                    |
| ----------------- | --------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `wall_perimeter`  | **Closed Polyline**         | ✅        | Outer building shell and internal voids (atria). Must be a single closed ring; holes/voids may be separate closed rings on the same layer. |
| `spaces`          | **Closed Polyline**         | ✅        | Bookable capacity units (e.g., a desk or seat). Each polygon = one space.                                                                  |
| `rooms`           | **Closed Polyline**         | ⭕        | Encloses *spaces* that belong to the same room. If omitted, spaces can exist without rooms.                                                |
| `clusters`        | **Closed Polyline**         | ⭕        | Groups of related *spaces* (e.g., team pods).                                                                                              |
| `zones`           | **Closed Polyline**         | ⭕        | Larger logical groupings across an area/floor (e.g., Zone A).                                                                              |
| `areas`           | **Polyline / Text / Block** | ⭕        | Decorative/non-bookable features: kitchens, open areas, elevators, stairs, icons. These render in UI but do not create capacity.           |
| `wall_partitions` | **Polyline**                | ⭕        | Interior partitions used for routing/visualization. Not required for area derivation.                                                      |
| `circulation`     | **Polyline**                | ⭕        | Walkways/aisles; optional hinting for pathing/analytics. Not required for ingestion.                                                       |

**Geometry rules**

* **Closed Polyline** = `LWPOLYLINE` or `POLYLINE` with the **Closed** flag set. Splines/ellipses are **not** supported for closed shapes.
* Coordinates must be **planar** (2D). Z is ignored.
* Units should be **meters** (recommended) or **millimeters**. If using mm, set scale metadata or export units consistently (see Export Checklist).
* Avoid self-intersections and duplicate vertices.
* Don’t rely on colors/linetypes for semantics; the **layer name** drives behavior.
* Blocks for semantic geometry should be **exploded** to polylines before export (icons may remain blocks on `areas`).

### 2) Hierarchy & Containment Expectations

* `spaces` **inside** a `rooms` polygon are assigned to that room.
* `rooms`/`clusters` **inside** a `zones` polygon inherit that zone.
* `wall_perimeter` encloses the usable floor boundary. **Voids** (e.g., atria) can be drawn as separate closed rings on the same layer **inside** the perimeter; these will be treated as holes.
* Overlaps:
  * `spaces` must **not** overlap each other.
  * `rooms` may touch but shouldn’t overlap.
  * `clusters` and `zones` can overlap if you intend multi-membership; otherwise, avoid overlaps.

### 3) Naming Conventions (recommended)

While not required, these help downstream mapping and reporting:

* `spaces`: add **space labels** as `MTEXT/TEXT` on the **same layer** or as block attributes (e.g., `SPACE_ID`, `TYPE`).
  * Examples: `D-001`, `S-014` (desk/seat IDs), `TYPE=desk|seat|focus`
* `rooms`: `RM-###` (e.g., `RM-201`) and optional attributes `NAME`, `TYPE` (e.g., `meeting`, `office`).
* `zones`: `ZN-A`, `ZN-B` or human-readable names.
* `clusters`: `CL-Eng-A` etc.
* Attributes are picked up if present; if not, IDs are auto-generated.

> **Tip:** If attributes are stored as block attributes, be sure the geometric boundary (closed polyline) still lives on the correct layer so it’s discoverable.

### 4) How DXF Layers Map in GoSpace

| DXF layer         | GoSpace entity             | Notes                                                                 |
| ----------------- | -------------------------- | --------------------------------------------------------------------- |
| `wall_perimeter`  | Floor boundary + voids     | Used for clipping and “inside/outside” tests.                         |
| `workpoints`      | Bookable Space (seat/desk) | One polygon → one workpoint; capacity defaults to 1 unless specified. |
| `rooms`           | Room                       | Aggregates contained spaces; can be bookable or just a container.     |
| `clusters`        | Cluster                    | Logical grouping for analytics/allocations.                           |
| `zones`           | Zone                       | High-level grouping used for planning and visibility.                 |
| `areas`           | Decorative Area            | Non-bookable; visible in maps and legends.                            |
| `wall_partitions` | Partition lines            | Rendering and optional routing hints.                                 |
| `circulation`     | Circulation paths          | Optional; used for analytics/path hints when present.                 |

### 5) Export Checklist (AutoCAD/BricsCAD/etc.)

* [ ] All bookable outlines are **Closed** Polylines on the **correct layers**.
* [ ] Units set consistently (meters preferred). If file is in **mm**, note it and keep consistent across floors.
* [ ] **Explode** blocks for walls/rooms/spaces into polylines (icons/text on `areas` may stay blocks).
* [ ] **Purge** unused layers/blocks; remove duplicate/hidden geometry.
* [ ] Ensure no stray polylines are outside `wall_perimeter`.
* [ ] No overlapping `spaces`; tiny gaps are OK.
* [ ] Save as **DXF R2018** or newer.

### 6) Common Validation Errors

* “Found open polyline on `spaces`”: close the polyline (set Closed flag).
* “Overlapping spaces detected”: adjust geometries so they don’t overlap.
* “Self-intersecting polygon”: simplify/clean the shape.
* “Missing `wall_perimeter`”: add the floor boundary as a closed polygon.
* “Unsupported entity on semantic layer”: convert to closed polylines (for rooms/spaces/zones/clusters) or polylines (for partitions/circulation).

#### Example DXF
