---
title: "Find or create an entity"
method: POST
path: "/v1/entities"
tags: ["Entities"]
---

# Find or create an entity

`POST /v1/entities`

## Request

- Base URL: `https://nanostudiopro.com/api`
- URL: `https://nanostudiopro.com/api/v1/entities`
- Auth: HTTP bearer

Find-or-create by `kind` and `name`, the app's own rule: the same name answers the same entity (`200`, `created: false`), a new one is `201`. No `kind` means character; a look names its character in `parent_id`. `refs` and `traits` are then saved exactly as `PATCH /v1/entities/{id}` saves them — refs REPLACE the set, also on an entity the name found. A body they refuse is a `400`, and an entity this call had just made is not left behind. Free.

## Request body

- object
  - `name` string, required
  - `parent_id` string: A look's character.
  - `kind` 'character' | 'prop' | 'location' | 'look' | 'skin'
  - `refs` object[]: REPLACES the reference set. Pictures you own; `role` one this kind takes (a character: face, front, three_quarter, side, back, detail; a place: wide, angle, detail; a prop: front, side, back, detail; a skin: front, back, detail), a single role at most once.
    - `kind` 'generation' | 'asset', required
    - `id` string, required
    - `role` string
    - `note` string
  - `traits` object: MERGED onto what is there: `bio` field by field (null clears one; a prop or a place has `description` and `notes`), `voice`, `font`, `specs` and `slot` each whole.

## Response `200`

Found by name

- object: A character, prop, place, skin or look the user reuses, with the canonical reference set that keeps it looking like itself from shot to shot. A look is one outfit or state of a character, with views of its own; its character is `parent_id`. A skin is the garments themselves, with no one in them: it belongs to nobody and is worn by anybody.
  - `id` string
  - `name` string
  - `slug` string
  - `kind` 'character' | 'prop' | 'location' | 'look' | 'skin'
  - `parent_id` string, nullable: A look's character; `null` for every other kind.
  - `photo_count` integer: Distinct scans this entity is tagged on — what the app calls photos. OPTIONAL because it is a list-only field: `GET /v1/entities/{id}` leaves the key out rather than returning a zero, since there `facets[].count` is the number that matters and recounting would cost the detail view a query it never asked for.
  - `refs` object[]: The entity's own views in hand-off order (at most 12): roled views first, in the kind's role order, then the rest as their owner arranged them. A look's are the look's own; its character's are one `parent_id` away.
    - `kind` 'generation' | 'asset'
    - `id` string
    - `role` 'face' | 'front' | 'three_quarter' | 'side' | 'back' | 'wide' | 'angle' | 'detail' | 'null', nullable: Which view this is. `null` for a view with no role.
    - `note` string, nullable: What a detail view shows, in a few words (at most 80 chars).
    - `url` string, uri, nullable: Signed URL to the picture, on the same ~6-hour signing window as every other image URL here. `null` when the picture has since been deleted — the ref keeps its id, so the hole is visible instead of silently closing.
  - `voice` object, nullable: The voice this entity speaks with, when one has been chosen; `null` otherwise.
    - `voice_id` string
    - `voice_name` string: Snapshotted beside the id: the catalogue can be relabelled, a recording cannot.
    - `settings` object
      - `stability` number
      - `similarity_boost` number
      - `style` number
      - `use_speaker_boost` boolean
  - `bio` object, nullable: Free and structured facts; every field optional. Characters use them all; props, places and looks use `description` and `notes`. `null` when none were written.
    - `description` string
    - `logline` string
    - `backstory` string
    - `personality` string
    - `speech` string
    - `role` string
    - `pronouns` string
    - `aliases` string[]
    - `born` string: `YYYY`, `YYYY-MM` or `YYYY-MM-DD`.
    - `nationality` string
    - `occupation` string
    - `height` string
    - `weight` string
    - `world` string: The world they belong to (technology, condition, materials, mood). Canon for anything suggested for them: a mount, an item, a place. A look uses its character's.
    - `notes` string
  - `specs` object, nullable: A prop's or a place's facts, for records and automations (never sent to an image model). `type` is what a prop is; each field's `key` is stable snake_case (`top_speed`, `crew`, `load`, `climate`…), its `value` free text with its unit. `null` when none were written.
    - `type` 'vehicle' | 'creature' | 'object'
    - `fields` object[]
      - `key` string
      - `label` string
      - `value` string
  - `created_at` string, date-time
  - `created` boolean

## Other responses

- `201`: Created
- `400`: name is required
- `401`: Missing or invalid token
- `409`: Another look already uses that name
- `429`: Rate limit exceeded

---

[API](https://skmtc.dev/nanostudiopro/apis/nano-studio-pro-api.md) · [All operations](https://skmtc.dev/nanostudiopro/apis/nano-studio-pro-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nanostudiopro/apis/nano-studio-pro-api/revisions/b454211e598e?raw)
