{"openapi":"3.1.0","info":{"title":"Kami World API","version":"1.0.0","description":"REST API for world building, entity CRUD, agent control, and real-time observation. API-first, agent-first, semantic-capable."},"servers":[{"url":"https://api.world.kami.bot","description":"Kami World"}],"tags":[{"name":"meta","description":"Server health and metadata"},{"name":"worlds","description":"Multi-world instance management"},{"name":"world","description":"World configuration and state"},{"name":"entities","description":"Entity CRUD"},{"name":"components","description":"Component-level updates (world builder)"},{"name":"actions","description":"Entity actions (move, speak, emote, trigger)"},{"name":"events","description":"Durable event log — the single source of truth for signals (chat, reactions, thresholds, custom)"},{"name":"agents","description":"Agent conversation history"},{"name":"blueprints","description":"Reusable entity group templates"},{"name":"sessions","description":"Per-session identity (JWT) and attribution"}],"components":{"schemas":{"MetaStats":{"type":"object","properties":{"pid":{"type":"number"},"nodeVersion":{"type":"string"},"uptimeMs":{"type":"number","description":"Milliseconds since the server started."},"memory":{"type":"object","properties":{"rss":{"type":"number"},"heapTotal":{"type":"number"},"heapUsed":{"type":"number"},"external":{"type":"number"}},"required":["rss","heapTotal","heapUsed","external"],"description":"process.memoryUsage() snapshot, bytes."},"activeSessions":{"type":["number","null"],"description":"Sessions with revokedAt IS NULL and expiresAt > now. Null when persistence is off."},"rateLimits":{"type":"object","properties":{"sessionMintHits":{"type":"number","description":"Count of POST /world/sessions requests rejected with 429 since boot."},"eventAppendHits":{"type":"number","description":"Count of POST /world/events requests rejected with 429 since boot."}},"required":["sessionMintHits","eventAppendHits"],"description":"Per-IP rate limiter hit counters. Persistent spikes = abuse or a broken agent."},"worlds":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"running":{"type":"boolean"},"entityCount":{"type":"number"},"eventPersistFailures":{"type":"number"},"isRecastWasmPoisoned":{"type":"boolean"},"viewAuthRejects":{"type":"number"},"actionRejects":{"type":"number"}},"required":["id","running","entityCount","eventPersistFailures","isRecastWasmPoisoned","viewAuthRejects","actionRejects"]}}},"required":["pid","nodeVersion","uptimeMs","memory","activeSessions","rateLimits","worlds"]},"WorldSummary":{"type":"object","properties":{"id":{"type":"string"},"entityCount":{"type":"number"},"running":{"type":"boolean"},"title":{"type":"string","description":"WorldDef.name, or a title made from the id."},"description":{"type":["string","null"],"description":"One sentence about the place (WorldDef.description), or null."},"poster":{"type":["string","null"],"description":"WorldDef.screenshotUrl: a path on the app or a URL, or null."},"madeFrom":{"$ref":"#/components/schemas/MadeFrom"},"household":{"type":"array","items":{"$ref":"#/components/schemas/HouseholdMember"},"description":"UI-8a: who lives here or hosts it (accepted home and host ties), named, oldest first, at most 3; empty unless the world is listed (its ties are public then)."},"visibility":{"type":"string","enum":["public","unlisted","private","lab"],"description":"The stricter of the stored link visibility and WorldDef.listing. Only public is listed to anonymous callers."},"humans":{"type":"number","description":"Visitors connected now."},"agents":{"type":"number","description":"Agents and characters connected now."},"agentsHere":{"type":"array","items":{"$ref":"#/components/schemas/ListedAgent"},"description":"The named agents, speaking ones first; at most 6."}},"required":["id","entityCount","running","title","description","poster","madeFrom","household","visibility","humans","agents","agentsHere"]},"MadeFrom":{"type":["object","null"],"properties":{"template":{"type":"string","description":"A GET /places/templates id."},"line":{"type":"string","description":"The template's line, « A home to live in »."}},"required":["template","line"],"description":"UI-8a: the template a place was made from and its line (« A home to live in »), or null for a world written by hand. The door says it when the place has no description of its own."},"HouseholdMember":{"type":"object","properties":{"name":{"type":"string"},"tie":{"type":"string","enum":["home","host"]}},"required":["name","tie"]},"ListedAgent":{"type":"object","properties":{"name":{"type":["string","null"],"description":"The agent's shown name (never an identifier)."},"isAgent":{"type":"boolean"},"speaking":{"type":"boolean"},"activity":{"type":["string","null"],"description":"The activity in progress (e.g. sit), or null when nothing is known."},"look":{"type":["string","null"],"description":"The creature the world gave this agent (its Avatar.skinId), or null for any other look."},"paletteSlot":{"type":["number","null"],"description":"That creature's colour slot in the DA-3 palette, or null."}},"required":["name","isAgent","speaking","activity","look","paletteSlot"]},"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"Refusal":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","description":"The rule that refused (auth/ties.ts RefusalCode)."}},"required":["error"]},"ProvisionalRefusal":{"type":"object","properties":{"error":{"type":"string","description":"The reason, as a sentence (the world-server convention)."},"code":{"type":"string","description":"AUTH-0 §4.4 error code: provisional_limit, vouch_required, account_required, claim_invalid, claim_expired, claimed_already, place_limit, provisional_unlisted."},"reason":{"type":"string"},"next":{"$ref":"#/components/schemas/NextStep"},"retry_after_s":{"type":"number"}},"required":["error","code","reason","next"]},"NextStep":{"type":"object","properties":{"do":{"type":"string"},"docs":{"type":"string"}},"required":["do","docs"]},"Tie":{"type":"object","properties":{"worldId":{"type":"string"},"entityStableId":{"type":"string"},"beingKind":{"type":"string","enum":["human","agent"]},"kind":{"type":"string","enum":["home","host","regular","guest"],"description":"home = Lives here, host = Hosts, regular = Regular, guest = Guest (D21). Visiting is no tie."},"displayName":{"type":["string","null"]},"guardianStableId":{"type":["string","null"],"description":"An agent's human, who says yes to its durable ties (D22)."},"status":{"type":"string","enum":["proposed","accepted"]},"proposedBy":{"type":["string","null"]},"proposedAt":{"type":"number"},"acceptedBy":{"type":["string","null"]},"acceptedAt":{"type":["number","null"]},"proposedByName":{"type":["string","null"],"description":"UI-11: the name of who proposed it (an account's name), when known."},"placeName":{"type":"string","description":"UI-11: the place's shown name."}},"required":["worldId","entityStableId","beingKind","kind","displayName","guardianStableId","status","proposedBy","proposedAt","acceptedBy","acceptedAt","proposedByName","placeName"]},"ScreenShareDescriptor":{"type":"object","properties":{"worldId":{"type":"string"},"screenStableId":{"type":"string"},"generationId":{"type":"string"},"room":{"type":"string"},"token":{"type":"string"},"url":{"type":"string"},"identity":{"type":"string"},"source":{"type":"string","enum":["screen","webcam"]},"audio":{"type":"boolean"}},"required":["worldId","screenStableId","generationId","room","token","url","identity","source","audio"]},"ScreenShareSessionBody":{"type":"object","properties":{"connectionId":{"type":"string","minLength":1}},"required":["connectionId"],"additionalProperties":false},"ScreenShareBinding":{"type":"object","properties":{"generationId":{"type":"string"},"participantSid":{"type":"string"},"trackSid":{"type":"string"},"source":{"type":"string","enum":["screen","webcam"]},"audioTrackSid":{"type":"string"}},"required":["generationId","participantSid","trackSid","source"]},"ScreenShareBindBody":{"type":"object","properties":{"connectionId":{"type":"string","minLength":1},"generationId":{"type":"string","minLength":1},"trackSid":{"type":"string","minLength":1},"audioTrackSid":{"type":"string","minLength":1}},"required":["connectionId","generationId","trackSid"],"additionalProperties":false},"Report":{"type":"object","properties":{"id":{"type":"number"},"targetKind":{"type":"string","enum":["thing","person","place"]},"stableId":{"type":["string","null"]},"reason":{"type":"string","enum":["rights","sexual_violent","hate_harassment","other"]},"note":{"type":["string","null"]},"createdAt":{"type":"number"},"status":{"type":"string","enum":["open","removed","dismissed"]},"decidedAt":{"type":["number","null"]}},"required":["id","targetKind","stableId","reason","note","createdAt","status","decidedAt"]},"CreateReportBody":{"type":"object","properties":{"targetKind":{"type":"string","enum":["thing","person","place"]},"stableId":{"type":["string","null"],"description":"Entity stable id for thing/person; null for a place report (the target world itself)."},"reason":{"type":"string","enum":["rights","sexual_violent","hate_harassment","other"]},"note":{"type":["string","null"],"maxLength":1000,"description":"Optional free-text detail, capped at 1000 chars."}},"required":["targetKind","stableId","reason"]},"BatchCreateRecordedResponse":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"created":{"type":"number"},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"stableId":{"type":"string"},"label":{"type":"string"}},"required":["id","stableId","label"]}},"live":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["instance_stopped","live_world_moved","world_full","apply_failed"]},"message":{"type":"string"}},"required":["ok","created","entities","live","reason","message"]},"BatchCreateBody":{"type":"object","properties":{"entities":{"type":"array","items":{"$ref":"#/components/schemas/CreateEntityBody"},"description":"Entities to create"}},"required":["entities"]},"CreateEntityBody":{"type":"object","properties":{"label":{"type":"string","description":"Unique entity label (also used as stableId)","example":"my-tree"},"parentId":{"type":"string","description":"Parent entity stableId (position/rotation/scale become local to parent)"},"position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}],"description":"World-space position (or local if parentId set)","example":[5,0,3]},"rotation":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"}],"description":"Rotation quaternion [x, y, z, w]","example":[0,0,0,1]},"scale":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}],"description":"Scale","example":[1,1,1]},"components":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}},"description":"Component data keyed by name"},"tags":{"type":"array","items":{"type":"string"},"description":"Entity tags (e.g. IsNPC)","example":[]},"controllable":{"type":"boolean","description":"Whether entity can be controlled (issues auth token)"},"from":{"type":"object","properties":{"ref":{"type":"string","minLength":1,"maxLength":300,"description":"A tile of `GET /world/add/search`: `kit/<kind>`, `yours/<asset id>` or `<source id>:<item id>`."}},"required":["ref"],"description":"AS-3: place a thing of the Add panel. The SERVER resolves it (its file, name and record facts; a source item's tier rule and scale clamp, sources/item.ts) and sets its Mesh, Primitive, Naming and Parts; the client gives only where."}}},"BatchUpdateBody":{"type":"object","properties":{"updates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number","description":"Entity ID"},"components":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}},"description":"Component data to merge"},"baseVersion":{"type":"number","description":"Optimistic-concurrency base for THIS entity (the version you last read). A mismatch fails the WHOLE batch with 409 (all-or-nothing). Omit to force-write."}},"required":["id","components"]},"description":"Entity updates"}},"required":["updates"]},"BatchDeleteBody":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"number"},"description":"Entity IDs to delete"}},"required":["ids"]},"CreateEntityResponse":{"type":"object","properties":{"id":{"type":"number"},"stableId":{"type":"string"},"label":{"type":"string"},"token":{"type":"string"},"ok":{"type":"boolean"},"version":{"type":"number","description":"New entity overlay version (baseVersion for the next edit)."}},"required":["id","stableId","label","ok"]},"CreateEntityRecordedResponse":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"live":{"type":"boolean","enum":[false]},"stableId":{"type":"string"},"label":{"type":"string"},"version":{"type":"number"},"id":{"type":["number","null"]},"reason":{"type":"string","enum":["instance_stopped","live_world_moved","world_full","apply_failed"]},"message":{"type":"string"}},"required":["ok","live","stableId","label","version","id","reason","message"]},"EditOk":{"type":"object","properties":{"ok":{"type":"boolean"},"version":{"type":"number","description":"New entity overlay version (pass as baseVersion on the next edit for optimistic concurrency)."}},"required":["ok"]},"EditRecorded":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"live":{"type":"boolean","enum":[false]},"version":{"type":"number","description":"New entity overlay version (baseVersion for the next edit)."},"reason":{"type":"string","enum":["instance_stopped","live_world_moved","world_full","apply_failed"]},"message":{"type":"string"}},"required":["ok","live","version","reason","message"]},"PatchComponentsBody":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}}},"ComponentData":{"type":"object","additionalProperties":{}},"RenameEntityBody":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60,"description":"The thing's new human name (Naming.name) - never its server identity.","example":"Red lighthouse"}},"required":["name"]},"ExecuteActionBody":{"type":"object","properties":{"action":{"type":"string","description":"Action name","example":"speak"},"params":{"type":"object","additionalProperties":{},"description":"Action parameters"}},"required":["action"]},"DeleteRecorded":{"allOf":[{"$ref":"#/components/schemas/EditRecorded"},{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]}},"required":["deleted"]}]},"WorldEvent":{"type":"object","properties":{"id":{"type":"number"},"type":{"type":"string"},"entityId":{"type":["number","null"]},"entityLabel":{"type":["string","null"]},"entityStableId":{"type":["string","null"]},"position":{"type":["array","null"],"prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"range":{"type":["number","null"]},"data":{"type":["object","null"],"additionalProperties":{}},"createdAt":{"type":"number"}},"required":["id","type","entityId","entityLabel","entityStableId","position","range","data","createdAt"]},"AppendEventBody":{"type":"object","properties":{"type":{"type":"string","minLength":1,"maxLength":128,"description":"Event type. Use dotted/colon namespaces.","example":"chat.text"},"entityId":{"type":"number","description":"Source ECS entity id."},"entityStableId":{"type":"string","description":"Source stableId (preferred — survives restart)."},"position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}],"description":"Source position when emitted."},"range":{"type":"number","exclusiveMinimum":0,"description":"Broadcast radius in metres."},"data":{"type":"object","additionalProperties":{},"description":"Type-keyed payload. For known types, unknown keys are stripped. Capped at 32 KB serialised."}},"required":["type"]},"ComponentInfo":{"type":"object","properties":{"name":{"type":"string"},"isTag":{"type":"boolean"},"visibility":{"type":"string","enum":["public","owner","server"]},"fields":{"type":"object","additionalProperties":{"type":"object","properties":{"type":{"type":"string"},"default":{}},"required":["type"]}}},"required":["name","isTag","visibility"]},"Vec3":{"type":["array","null"],"prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"Perception":{"type":["object","null"],"properties":{"self":{"$ref":"#/components/schemas/PerceptionSelf"},"entities":{"type":"array","items":{"$ref":"#/components/schemas/NearbyEntity"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/PerceptionEvent"}},"attending":{"type":"number"},"summary":{"type":"string"}},"required":["self","entities","events","summary"]},"PerceptionSelf":{"type":"object","properties":{"position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"bodyDirection":{"type":"number"},"animation":{"type":"string"},"isMoving":{"type":"boolean"},"activity":{"type":"string"},"label":{"type":"string"},"region":{"type":"string"},"liquid":{"type":"object","properties":{"entityId":{"type":"number"},"kind":{"type":"string","enum":["water"]},"surfaceY":{"type":"number"},"depth":{"type":"number"},"flow":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"}]},"distanceToEdge":{"type":"number"}},"required":["entityId","kind","surfaceY","depth","flow","distanceToEdge"]}},"required":["position","bodyDirection","animation","isMoving"]},"NearbyEntity":{"type":"object","properties":{"id":{"type":"number"},"label":{"type":"string"},"position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"distance":{"type":"number"},"direction":{"type":"string","enum":["ahead","ahead-right","right","behind-right","behind","behind-left","left","ahead-left"]},"components":{"type":"object","additionalProperties":{}},"salience":{"type":"number"},"bodyDirection":{"type":"number"},"gazeTarget":{"type":"number"}},"required":["id","position","distance","components","salience","bodyDirection"]},"PerceptionEvent":{"type":"object","properties":{"type":{"type":"string"},"entityId":{"type":["number","null"]},"entityLabel":{"type":["string","null"]},"position":{"type":["array","null"],"prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"data":{"type":["object","null"],"additionalProperties":{}},"createdAt":{"type":"number"}},"required":["type","entityId","entityLabel","position","data","createdAt"]},"PerceptionKeyframe":{"type":"object","properties":{"mode":{"type":"string","enum":["keyframe"]},"cursor":{"type":"string","description":"Pass back as ?cursor= next poll to receive deltas"},"tick":{"type":"number"},"perception":{"$ref":"#/components/schemas/Perception"}},"required":["mode","cursor","tick","perception"]},"PerceptionDeltaFrame":{"type":"object","properties":{"mode":{"type":"string","enum":["delta"]},"cursor":{"type":"string"},"tick":{"type":"number"},"delta":{"$ref":"#/components/schemas/PerceptionDelta"},"narrative":{"type":"string","description":"Synthesis of what changed since the last poll"}},"required":["mode","cursor","tick","delta","narrative"]},"PerceptionDelta":{"type":"object","properties":{"self":{"$ref":"#/components/schemas/PerceptionSelf"},"entered":{"type":"array","items":{"$ref":"#/components/schemas/NearbyEntity"}},"updated":{"type":"array","items":{"$ref":"#/components/schemas/NearbyEntity"}},"left":{"type":"array","items":{"type":"number"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/PerceptionEvent"}},"attending":{"type":["number","null"]},"summary":{"type":"string"}},"required":["entered","updated","left","events"]},"AddTile":{"type":"object","properties":{"ref":{"type":"string","description":"What `POST /world/entities` takes as `from.ref`: `kit/<kind>`, `yours/<asset id>` or `<source id>:<item id>`."},"title":{"type":"string"},"thumbUrl":{"type":["string","null"],"description":"Its picture, rendered like every other tile; null for a file nobody rendered (an upload)."},"group":{"type":"string","enum":["yours","kit","library"],"description":"Where it was found, for the order only: a tile never shows its source (law 1.2)."},"sizeMeters":{"type":"array","items":{"type":"number"}},"fileId":{"type":"string","description":"The AS-0 asset id of the file it places (one tile per file)."},"availability":{"type":"string","enum":["public","private"],"description":"D58: on a `yours` tile only, the availability of the caller's own file (`private` wears the Private mark). Absent on a kit or library tile."}},"required":["ref","title","thumbUrl","group","fileId"]},"SourceError":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]},"RegisteredSource":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"title":{"type":"string"},"hosts":{"type":"array","items":{"type":"string"}},"manifestUrl":{"type":"string"},"registeredAt":{"type":"number"}},"required":["id","kind","title","hosts","manifestUrl","registeredAt"]},"SourceCandidate":{"type":"object","properties":{"ref":{"type":"string","description":"`<source id>:<item id>`: pass it to the `make` act as `item` to place exactly this."},"title":{"type":"string"},"thumbUrl":{"type":"string"},"scaleThumbUrl":{"type":"string"},"sizeMeters":{"type":"array","items":{"type":"number"}},"tris":{"type":"number"},"description":{"type":"string"},"author":{"type":"string"},"license":{"type":"string"},"source":{"type":"string"}},"required":["ref","title","thumbUrl","source"]},"ActOk":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"outcome":{"type":"string","enum":["done","proposed"]},"kind":{"type":"string","enum":["placed","moved","removed","renamed","retouched","restored","kept","discarded","expired"]},"thing":{"$ref":"#/components/schemas/ActThing"},"proposalId":{"type":"string"},"askerName":{"type":"string"},"where":{"$ref":"#/components/schemas/ActWhere"}},"required":["ok","outcome","kind","thing","askerName"]},"ActThing":{"type":["object","null"],"properties":{"id":{"type":"number","description":"Live entity id"},"stableId":{"type":"string"},"name":{"type":"string"}},"required":["id","stableId","name"]},"ActWhere":{"type":"object","properties":{"relation":{"type":"string","enum":["on","beside","in_front"],"description":"on its top; next to it; in front of the asker (its shape is unknown)."},"thing":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"}},"required":["id","name"],"description":"The thing the line pointed at."},"reason":{"type":"string","enum":["too_small","no_room","not_flat","asked_beside","unknown_shape"]},"message":{"type":"string","description":"Where it went, in plain words, for the agent to say."}},"required":["relation","thing","message"],"description":"make, when the line pointed at a thing and at no \"here\": placed on its top, or next to it and why."},"ActNotLive":{"allOf":[{"$ref":"#/components/schemas/ActOk"},{"type":"object","properties":{"live":{"type":"boolean","enum":[false]},"stableId":{"type":"string"},"reason":{"type":"string","enum":["live_world_moved","instance_stopped","world_full","apply_failed"]},"message":{"type":"string"}},"required":["live","stableId","reason","message"]}]},"ActRequest":{"type":"object","properties":{"agentStableId":{"type":"string","minLength":1,"description":"The acting agent's durable identity (attested by the operator)."},"agentName":{"type":"string"},"utteranceId":{"type":"string","minLength":1,"description":"The io.* event id of the line this act answers (`chat.text|<entity>|<ms>`); the asker is read from it. Exactly one of utteranceId and privateAsk."},"privateAsk":{"type":"object","properties":{"accountId":{"type":"string","minLength":1},"at":{"type":"integer","minimum":0},"text":{"type":"string","maxLength":2000}},"required":["accountId","at"],"description":"BT-4: a request whispered to the agent through the private corridor, attested by the operator (the account, when, its words). The asker is that account's body in this place; the act line names nobody."},"act":{"type":"string","enum":["make","retouch","move","remove","rename","undo","keep","discard"]},"what":{"type":"string","maxLength":200,"description":"make: what to place, in the words said."},"item":{"type":"string","maxLength":200,"description":"make: a candidate of GET /world/sources/search (`<source id>:<item id>`): place exactly that item (IX-2)."},"target":{"type":"string","description":"move / remove / rename / retouch / keep / discard: the live entity id of the thing."},"part":{"type":"string"},"change":{"type":"string","maxLength":200},"name":{"type":"string","maxLength":200},"proposalId":{"type":"string"},"preview":{"type":"boolean","description":"Only say what the rights gate would answer this line's asker for a change (no act, no journal): `{ preview: { standing, askerName, removalNeedsYes, outcome | code + reason } }`."}},"required":["agentStableId","act"]},"ProposalView":{"type":"object","properties":{"id":{"type":"string"},"act":{"type":"string"},"thing":{"type":["object","null"],"properties":{"id":{"type":"number"},"name":{"type":"string"}},"required":["id","name"]},"byName":{"type":"string"},"forName":{"type":"string"},"createdAt":{"type":"number"},"expiresAt":{"type":"number"}},"required":["id","act","thing","byName","forName","createdAt","expiresAt"]},"AssetView":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["object","look","place","image","video","sound","player"]},"title":{"type":"string"},"origin":{"$ref":"#/components/schemas/AssetOrigin"},"author":{"type":["object","null"],"properties":{"name":{"type":"string"},"url":{"type":"string"}},"required":["name"]},"license":{"type":["object","null"],"properties":{"spdx":{"type":"string"},"url":{"type":"string"},"credit":{"type":"string"}}},"availability":{"type":"string","enum":["public","private"]},"removed":{"type":["object","null"],"properties":{"reason":{"type":"string"},"at":{"type":"number"}},"required":["reason","at"]},"yours":{"type":"boolean","description":"The caller owns it (and may change who uses it)."}},"required":["id","kind","title","origin","author","license","availability","removed","yours"]},"AssetOrigin":{"type":"object","properties":{"type":{"type":"string","enum":["source","upload","link","generated","token","player"]}},"required":["type"],"additionalProperties":{},"description":"Where the file comes from (assets.md §2): a source and its item, an upload, a pasted link, a generation, a token, an embedded player."},"AssetCopy":{"type":"object","properties":{"field":{"type":"string"},"addedBy":{"$ref":"#/components/schemas/CreditedBeing"},"addedByAgent":{"$ref":"#/components/schemas/CreditedBeing"},"addedAt":{"type":"number"}},"required":["field","addedBy","addedByAgent","addedAt"]},"CreditedBeing":{"type":["object","null"],"properties":{"name":{"type":["string","null"]},"isAgent":{"type":"boolean"}},"required":["name","isAgent"]},"ProvisionalClaimView":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"poster":{"type":["string","null"]},"state":{"type":"string","enum":["open","claimed"],"description":"open: it can be kept now; claimed: someone kept it."},"opened_by":{"type":["string","null"],"description":"The name the opening agent declared, as declared (never verified)."},"opened_at":{"type":"string"},"expires_at":{"type":["string","null"]},"visibility":{"type":"string"}},"required":["id","title","poster","state","opened_by","opened_at","expires_at","visibility"]},"PlaceTemplate":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"line":{"type":"string"},"kind":{"type":"string","enum":["home","stage","square","nature","plot"]},"poster":{"type":["string","null"]},"more":{"type":"boolean","description":"Shown behind « More places »."},"residentsQuestion":{"type":"string","description":"The words of the residents question for this kind (« Who hosts? »)."},"residentTie":{"type":"string","enum":["home","host","regular"],"description":"The tie a resident picked at creation gets."}},"required":["id","title","line","kind","poster","more","residentsQuestion","residentTie"]},"PlaceRefusal":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","description":"The rule that refused (places/rules.ts PlaceRefusalCode, or the standing code)."},"reason":{"type":"string"},"next":{"type":"object","properties":{"do":{"type":"string"},"docs":{"type":"string"}},"required":["docs"]}},"required":["error"]},"CreatePlaceBody":{"type":"object","properties":{"template":{"type":"string","description":"A template id from GET /places/templates (default: cottage)."},"name":{"type":"string","description":"The place's name."},"address":{"type":"string","description":"The address (slug) the person typed; made from the name when absent."},"audience":{"type":"string","enum":["private","unlisted","public"],"description":"Who may come: private (only people you invite), unlisted (anyone with the link, the default) or public (listed)."},"defaultLinkRole":{"type":"string","enum":["none","viewer","participant","editor"],"description":"What the link gives (default: participant; none for a private place)."},"agentsCanDropBy":{"type":"boolean","description":"D25: may an agent with no tie come in by itself (default: true in an open place)."},"coOwnerInvite":{"type":"boolean","description":"« Add a co-owner »: mint a one-use Owner invite."}},"required":["name"]},"MyPlace":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"poster":{"type":["string","null"]},"visibility":{"type":"string","enum":["public","unlisted","private","lab"]},"ownedByYou":{"type":"boolean"},"owners":{"type":"number","description":"How many Owners the place has."},"yourTie":{"type":["string","null"],"enum":["home","host","regular","guest",null],"description":"What you are to the place, when it is not only yours to own."},"residents":{"type":"array","items":{"$ref":"#/components/schemas/PlaceBeing"},"description":"Who lives here or hosts it (accepted ties), named."},"humans":{"type":"number"},"agents":{"type":"number"},"createdAt":{"type":["number","null"]}},"required":["id","title","poster","visibility","ownedByYou","owners","yourTie","residents","humans","agents","createdAt"]},"PlaceBeing":{"type":"object","properties":{"name":{"type":"string"},"isAgent":{"type":"boolean"},"tie":{"type":"string","enum":["home","host","regular","guest"]}},"required":["name","isAgent","tie"]},"PlacePeople":{"type":"object","properties":{"you":{"type":"object","properties":{"role":{"type":["string","null"],"enum":["owner","admin","editor","participant","viewer",null]},"isOwner":{"type":"boolean"},"canManage":{"type":"boolean"},"ownerIdentity":{"type":["string","null"]},"hasAccount":{"type":"boolean"}},"required":["role","isOwner","canManage","ownerIdentity","hasAccount"]},"place":{"type":["object","null"],"properties":{"name":{"type":"string"},"audience":{"type":"string","enum":["private","unlisted","public"]},"defaultLinkRole":{"type":"string"},"agentsCanDropBy":{"type":"boolean"},"screenShareOpen":{"type":"boolean","description":"AS-5: everyone present may share a screen (false: editors only, the default)."}},"required":["name","audience","defaultLinkRole","agentsCanDropBy","screenShareOpen"],"description":"The settings, for an Owner of a place made by someone (null for a first-party world or anyone else)."},"here":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"],"description":"The identity, given to the place side (Owner, Admin) and for your own rows only."},"name":{"type":["string","null"],"description":"The name, never an identifier; null when none is known."},"isAgent":{"type":"boolean"},"isYou":{"type":"boolean"},"tie":{"type":["string","null"],"enum":["home","host","regular","guest",null]},"invitedBy":{"type":["string","null"]},"invitedByYou":{"type":"boolean"},"invitable":{"type":"boolean","description":"An agent here with no tie: the place side may invite it to live here (P0-8, its human decides)."}},"required":["id","name","isAgent","isYou","tie","invitedBy","invitedByYou","invitable"]}},"ties":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"],"description":"The identity, given to the place side (Owner, Admin) and for your own rows only."},"name":{"type":["string","null"],"description":"The name, never an identifier; null when none is known."},"isAgent":{"type":"boolean"},"isYou":{"type":"boolean"},"kind":{"type":"string","enum":["home","host","regular","guest"]},"status":{"type":"string","enum":["proposed","accepted"]},"here":{"type":"boolean"},"at":{"type":["string","null"]},"invitedBy":{"type":["string","null"]},"invitedByYou":{"type":"boolean"},"role":{"type":["string","null"],"enum":["owner","admin","editor","participant","viewer",null]}},"required":["id","name","isAgent","isYou","kind","status","here","at","invitedBy","invitedByYou","role"]}},"owners":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"],"description":"The identity, given to the place side (Owner, Admin) and for your own rows only."},"name":{"type":["string","null"],"description":"The name, never an identifier; null when none is known."},"isAgent":{"type":"boolean"},"isYou":{"type":"boolean"}},"required":["id","name","isAgent","isYou"]}},"members":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"],"description":"The identity, given to the place side (Owner, Admin) and for your own rows only."},"name":{"type":["string","null"],"description":"The name, never an identifier; null when none is known."},"isAgent":{"type":"boolean"},"isYou":{"type":"boolean"},"role":{"type":"string","enum":["owner","admin","editor","participant","viewer"]}},"required":["id","name","isAgent","isYou","role"]}}},"required":["you","place","here","ties","owners","members"]},"PeopleRefusal":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]},"Ok":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"]},"BlueprintEntity":{"type":"object","properties":{"label":{"type":"string","description":"Entity label within the blueprint"},"parentId":{"type":"string","description":"Parent entity label (within the blueprint)"},"position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"rotation":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"}]},"scale":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"components":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}}},"tags":{"type":"array","items":{"type":"string"}}},"required":["label"]},"SkippedPlacement":{"type":"object","properties":{"index":{"type":"number","description":"Index of the skipped placement in the request array"},"reason":{"type":"string","enum":["duplicate-label","capacity-exceeded","asset-refused"],"description":"Why this placement was skipped (asset-refused: a file this place may not hold, D58, AS-0)"}},"required":["index","reason"]},"PlaceBlueprintRecordedResponse":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"placed":{"type":"number"},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"stableId":{"type":"string"},"label":{"type":"string"}},"required":["id","stableId","label"]}},"skipped":{"type":"array","items":{"$ref":"#/components/schemas/SkippedPlacement"}},"live":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["instance_stopped","live_world_moved","world_full","apply_failed"]},"message":{"type":"string"}},"required":["ok","placed","entities","skipped","live","reason","message"]},"BlueprintPlacement":{"type":"object","properties":{"position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}],"description":"World-space position for this placement"},"rotation":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"}],"description":"Rotation composed with each entity's own rotation (quaternion multiply)"},"scale":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}],"description":"Scale multiplied component-wise with each entity's own scale"},"prefix":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,64}$","description":"Label prefix — alphanumeric, _, -, max 64 chars (default: blueprint name + index)"},"overrides":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}}},"description":"Per-entity component overrides. Key = entity label within blueprint."}}},"WorldPresence":{"type":"object","properties":{"agents":{"type":"number"},"humans":{"type":"number"},"here":{"type":"array","items":{"$ref":"#/components/schemas/PresentBody"},"description":"At most 24 entries; the counts say the rest."},"ties":{"type":"array","items":{"$ref":"#/components/schemas/DoorTie"},"description":"Lot PL-1: who lives here (home), hosts (host) or comes often (regular), here or away, Lives here first. Empty for a caller with no relation to a place that is not listed public; a Guest tie is never shown."}},"required":["agents","humans","here","ties"]},"PresentBody":{"type":"object","properties":{"name":{"type":["string","null"],"description":"The shown name (Identity.username), or null when the body is still named by an identifier. Never a session id."},"isAgent":{"type":"boolean","description":"An agent or a scripted character (controllerType bot); false for a visitor."},"speaking":{"type":"boolean"},"activity":{"type":["string","null"],"description":"The activity in progress (e.g. sit), or null."},"look":{"type":["string","null"],"description":"The creature the world gave this agent (its Avatar.skinId, mochi:agent...), or null for any other look and for a person."},"paletteSlot":{"type":["number","null"],"description":"That creature's colour slot in the DA-3 palette (effectivePaletteSlot), or null."}},"required":["name","isAgent","speaking","activity","look","paletteSlot"]},"DoorTie":{"type":"object","properties":{"name":{"type":["string","null"],"description":"The shown name, or null when none is known. Never an identifier."},"kind":{"type":"string","enum":["home","host","regular","guest"]},"isAgent":{"type":"boolean"},"here":{"type":"boolean","description":"In the world now; false = away, still tied."},"at":{"type":["string","null"],"description":"Lot PL-2 (one body at a time): when away, the name of the place its body is in now, only when that place is listed public; null when here, nowhere, or in a place the door may not name."}},"required":["name","kind","isAgent","here","at"]},"WorldStats":{"type":"object","properties":{"entityCount":{"type":"number"},"componentDistribution":{"type":"object","additionalProperties":{"type":"number"}},"bounds":{"type":["object","null"],"properties":{"min":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"max":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]}},"required":["min","max"],"description":"null if world has no entities"},"overlayCount":{"type":"number"},"eventPersistFailures":{"type":"number","description":"Count of `chat:emit → events.append` failures since boot. A non-zero value means durable chat/events are being dropped silently — check server logs."},"isRecastWasmPoisoned":{"type":"boolean","description":"True if the Recast navmesh WASM layer faulted at any point since boot. SpatialView silently degrades to WaypointGraph — restart the process to recover."},"viewAuthRejects":{"type":"number","description":"403 count from /world/view/perception + /world/view/social/* auth gates. Probe pressure indicator, not inherently an error."},"actionRejects":{"type":"number","description":"Count of `POST /world/entities/:id/action` calls rejected at the contract level (verb not declared, out of range, exclusive busy, preconditions unmet). High → stale client state or hallucinating agent."}},"required":["entityCount","componentDistribution","bounds","overlayCount","eventPersistFailures","isRecastWasmPoisoned","viewAuthRejects","actionRejects"]},"WorldExport":{"type":"object","properties":{"id":{"type":"string"},"entityCount":{"type":"number"},"entities":{"type":"array","items":{"type":"object","properties":{"stableId":{"type":"string"},"label":{"type":"string"},"position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"rotation":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"},{"type":"number"}]},"scale":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]},"components":{"type":"object","additionalProperties":{}}},"required":["stableId","position","rotation","scale","components"]}}},"required":["id","entityCount","entities"]},"WorldDiff":{"type":"object","properties":{"created":{"type":"array","items":{"type":"object","properties":{"stableId":{"type":"string"},"data":{}},"required":["stableId"]}},"updated":{"type":"array","items":{"type":"object","properties":{"stableId":{"type":"string"},"data":{}},"required":["stableId"]}},"deleted":{"type":"array","items":{"type":"string"}}},"required":["created","updated","deleted"]},"UndoResult":{"type":"object","properties":{"ok":{"type":"boolean"},"undone":{"type":"number","description":"world_edits.id of the original edit that was undone."},"version":{"type":"number","description":"The entity overlay version after the undo edit."},"canUndo":{"type":"number","description":"Remaining undo depth for this author."},"canRedo":{"type":"number","description":"Available redo depth for this author."}},"required":["ok","undone","version","canUndo","canRedo"]},"UndoRecorded":{"allOf":[{"$ref":"#/components/schemas/UndoResult"},{"type":"object","properties":{"live":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["instance_stopped","live_world_moved","world_full","apply_failed"]},"message":{"type":"string"}},"required":["live","reason","message"]}]},"RedoResult":{"type":"object","properties":{"ok":{"type":"boolean"},"redone":{"type":"number","description":"world_edits.id of the original edit that was re-applied."},"version":{"type":"number","description":"The entity overlay version after the redo edit."},"canUndo":{"type":"number"},"canRedo":{"type":"number"}},"required":["ok","redone","version","canUndo","canRedo"]},"RedoRecorded":{"allOf":[{"$ref":"#/components/schemas/RedoResult"},{"type":"object","properties":{"live":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["instance_stopped","live_world_moved","world_full","apply_failed"]},"message":{"type":"string"}},"required":["live","reason","message"]}]},"SessionBundle":{"type":"object","properties":{"token":{"type":"string","description":"Signed JWT — send as `Authorization: Bearer <token>` on subsequent requests."},"session":{"$ref":"#/components/schemas/Session"},"isAnonymous":{"type":"boolean","description":"True when the caller did not supply `stableId` and a fresh `anon-…` id was minted."}},"required":["token","session","isAnonymous"]},"Session":{"type":"object","properties":{"id":{"type":"string"},"entityStableId":{"type":"string"},"platform":{"type":"string"},"device":{"type":["string","null"]},"ip":{"type":["string","null"]},"createdAt":{"type":"number"},"lastActiveAt":{"type":"number"},"expiresAt":{"type":"number"},"revokedAt":{"type":["number","null"]},"revokedReason":{"type":["string","null"]}},"required":["id","entityStableId","platform","device","ip","createdAt","lastActiveAt","expiresAt","revokedAt","revokedReason"]},"CreateSessionBody":{"type":"object","properties":{"stableId":{"type":"string","minLength":1,"maxLength":128,"description":"Claim a specific stableId. Omit to mint an anonymous one."},"platform":{"type":"string","minLength":1,"maxLength":32,"description":"Origin (\"web\", \"widget\", \"cli\", \"agent\", \"operator\").","example":"web"},"device":{"type":"string","maxLength":256,"description":"Parsed user-agent or client hint."}}},"RefreshSessionBody":{"type":"object","properties":{"token":{"type":"string","description":"The old JWT to rotate. Can be expired."}},"required":["token"]},"Standing":{"type":"object","properties":{"state":{"type":"string","enum":["good","warned","frozen","closed"]},"frozenUntil":{"type":["number","null"]},"closedAt":{"type":["number","null"]},"closedBy":{"type":["string","null"],"enum":["strikes","floor","email",null]},"counters":{"type":"object","properties":{"copyright":{"type":"string","enum":["none","warning","strike-1","strike-2","closed"]},"community":{"type":"string","enum":["none","warning","strike-1","strike-2","closed"]}},"required":["copyright","community"]},"scale":{"type":"object","properties":{"lifetimeMs":{"type":"number"},"strike1FreezeMs":{"type":"number"},"strike2FreezeMs":{"type":"number"}},"required":["lifetimeMs","strike1FreezeMs","strike2FreezeMs"]},"history":{"type":"array","items":{"$ref":"#/components/schemas/StandingMark"}},"account":{"type":["string","null"],"description":"The account this standing is about (`kami:<id>` once signed in), null for an anonymous session: it may visit and talk, not add."},"add":{"type":"object","properties":{"ok":{"type":"boolean"},"code":{"type":"string","enum":["add_frozen","account_closed","account_required"]},"reason":{"type":"string"},"until":{"type":"number"}},"required":["ok"],"description":"May this account add now? The same verdict every add path gives (the upload route relays it)."},"now":{"type":"number"}},"required":["state","frozenUntil","closedAt","closedBy","counters","scale","history","account","add","now"]},"StandingMark":{"type":"object","properties":{"id":{"type":"number"},"counter":{"type":"string","enum":["copyright","community"]},"kind":{"type":"string","enum":["warning","strike","floor"]},"n":{"type":["number","null"],"description":"The strike number (1, 2, 3), null for a warning or the floor."},"thing":{"type":["string","null"]},"worldId":{"type":["string","null"]},"reason":{"type":"string"},"byAgent":{"type":"boolean","description":"An agent added it for this account (§3: what your agents add counts for you)."},"at":{"type":"number"},"expiresAt":{"type":["number","null"]},"expired":{"type":"boolean"},"erased":{"type":"boolean"},"erasedReason":{"type":["string","null"]},"freezesUntil":{"type":["number","null"]},"appeal":{"type":["object","null"],"properties":{"id":{"type":"number"},"status":{"type":"string"}},"required":["id","status"]},"counterNotice":{"type":["object","null"],"properties":{"id":{"type":"number"},"status":{"type":"string"},"restoreAfter":{"type":"number"}},"required":["id","status","restoreAfter"]},"canAppeal":{"type":"boolean"},"canCounterNotice":{"type":"boolean"}},"required":["id","counter","kind","n","thing","worldId","reason","byAgent","at","expiresAt","expired","erased","erasedReason","freezesUntil","appeal","counterNotice","canAppeal","canCounterNotice"]},"StandingError":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]},"CounterNoticeBody":{"type":"object","properties":{"fullName":{"type":"string","minLength":1,"maxLength":200},"address":{"type":"string","minLength":1,"maxLength":2000},"statement":{"type":"string","minLength":1,"maxLength":2000,"description":"Why you have the right to use it."},"goodFaith":{"type":"boolean","enum":[true],"description":"Under penalty of perjury, the takedown was a mistake or a misidentification."},"consent":{"type":"boolean","enum":[true],"description":"Consent to the jurisdiction of the courts for your address, and to accept service from the claimant."},"signature":{"type":"string","minLength":1,"maxLength":200}},"required":["fullName","address","statement","goodFaith","consent","signature"]},"CopyrightClaimBody":{"type":"object","properties":{"worldId":{"type":"string","minLength":1,"description":"The place (the slug from its link)."},"stableId":{"type":"string","minLength":1,"description":"The thing claimed (from GET /claims/things)."},"placeUrl":{"type":"string","minLength":1,"maxLength":200},"work":{"type":"string","minLength":1,"maxLength":2000,"description":"What is yours."},"originalUrl":{"type":"string","maxLength":200},"name":{"type":"string","minLength":1,"maxLength":200},"company":{"type":"string","maxLength":200},"email":{"type":"string","format":"email"},"address":{"type":"string","minLength":1,"maxLength":2000},"goodFaith":{"type":"boolean","enum":[true],"description":"I believe in good faith that this use is not allowed by the owner, their agent or the law."},"accuracy":{"type":"boolean","enum":[true],"description":"Under penalty of perjury, this notice is accurate and I own the rights or may act for the owner."},"signature":{"type":"string","minLength":1,"maxLength":200,"description":"The full name, typed."}},"required":["worldId","stableId","placeUrl","work","name","email","address","goodFaith","accuracy","signature"]},"CopyrightClaimView":{"type":"object","properties":{"id":{"type":"number"},"status":{"type":"string"},"worldId":{"type":"string"},"stableId":{"type":"string"},"thing":{"type":"string"},"work":{"type":"string"},"originalUrl":{"type":["string","null"]},"claimant":{"type":"string"},"company":{"type":["string","null"]},"email":{"type":"string"},"filedAt":{"type":"number"}},"required":["id","status","worldId","stableId","thing","work","originalUrl","claimant","company","email","filedAt"]},"LookJob":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string","enum":["submitting","unknown","making","ready","failed"]},"detail":{"type":"string"},"expressions":{"type":"boolean"},"reason":{"type":"string"},"look":{"$ref":"#/components/schemas/MadeLookRef"}},"required":["id","state"]},"MadeLookRef":{"type":"object","properties":{"source":{"type":"string"},"id":{"type":"string"},"modelUrl":{"type":"string"},"modelType":{"type":"string"},"bytes":{"type":"integer"}},"required":["source","id","modelUrl","modelType"],"description":"The made look, as `look.set` takes it."},"LookJobError":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]}},"parameters":{}},"paths":{"/health":{"get":{"tags":["meta"],"summary":"Health check (liveness — for Fly/k8s probes)","description":"Deliberately minimal so health probes stay cheap. Operators wanting process/session/memory detail should hit `/meta/stats`.","responses":{"200":{"description":"Server is running","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"tick":{"type":"number"},"worlds":{"type":"array","items":{"type":"string"}},"navmeshPoisoned":{"type":"boolean"},"recastSwallowedTraps":{"type":"number"},"recastModuleGeneration":{"type":"number"},"navmeshFault":{"type":["object","null"],"properties":{"at":{"type":"number"},"world":{"type":"string"},"message":{"type":"string"},"verts":{"type":"number"},"tris":{"type":"number"},"heapBytes":{"type":["number","null"]},"config":{"type":"object","additionalProperties":{"type":"number"}},"moduleGeneration":{"type":"number"},"swallowedTraps":{"type":"number"},"swallowedBySite":{"type":"object","additionalProperties":{"type":"number"}}},"required":["at","world","message","verts","tris","heapBytes","config","moduleGeneration","swallowedTraps","swallowedBySite"]}},"required":["status","tick","worlds","navmeshPoisoned","recastSwallowedTraps","recastModuleGeneration","navmeshFault"]}}}}}}},"/meta/stats":{"get":{"tags":["meta"],"summary":"Server-level operator stats — uptime, memory, sessions, per-world tallies","description":"Everything an operator wants to page on: how long the process has been up, how much memory it uses, how many active sessions exist across all worlds, and per-world entity counts + event-persist failure counters.","responses":{"200":{"description":"Operator stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetaStats"}}}}}}},"/worlds":{"get":{"tags":["worlds"],"summary":"The world catalogue: every listed world, who is in it and what its agents are doing","description":"The single catalogue the hub, the door and the sitemap read (lot UI-3). Title, sentence and poster come from each world's definition; the counts from the live census (the same as GET /world/presence). Anonymous callers get public worlds only: a private place, an unlisted world (joinable by its link) and a lab world are never listed. The operator token (and dev-open mode) sees every world, each with its visibility.","responses":{"200":{"description":"The worlds, in the order the server runs them","content":{"application/json":{"schema":{"type":"object","properties":{"worlds":{"type":"array","items":{"$ref":"#/components/schemas/WorldSummary"}}},"required":["worlds"]}}}}}},"post":{"tags":["worlds"],"summary":"Create a world instance at runtime","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Unique world ID","example":"my-world"},"worldDef":{"type":"object","additionalProperties":{},"description":"WorldDef configuration"},"visibility":{"type":"string","enum":["private","unlisted","public"],"description":"Link visibility (default: public)."},"defaultLinkRole":{"type":"string","enum":["none","viewer","participant","editor"],"description":"Role granted to anyone opening via link (default: participant). Pass 'editor' for an open-to-edit world, 'none' to lock it."},"openedBy":{"type":"string","maxLength":200,"description":"AUTH-3: the name you go by, shown as declared on the claim page of a provisional place."}},"required":["id","worldDef"]}}}},"responses":{"201":{"description":"World created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"entityCount":{"type":"number"},"provisional":{"type":"boolean","description":"AUTH-3: true when opened without an account: empty, unlisted, deleted at expires_at unless a person keeps it."},"expires_at":{"type":"string","description":"AUTH-3: when an unkept provisional place is deleted (ISO 8601)."},"claim_url":{"type":"string","description":"AUTH-3: give this link to your person: signed in with kami.bot, they keep the place (it becomes theirs)."},"visibility":{"type":"string"},"next":{"type":"object","properties":{"do":{"type":"string"},"docs":{"type":"string"}},"required":["do","docs"]}},"required":["id","entityCount"]}}}},"400":{"description":"Missing id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"A session (or operator token) is required to create a world","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"AS-0 (D58): a file of its things this place may not hold; AUTH-3: vouch_required, a place opened without an account comes empty","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"409":{"description":"World already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"AUTH-3: provisional_limit (one live provisional place per session, three per IP per day)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalRefusal"}}}},"501":{"description":"Dynamic creation not supported","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/worlds/{id}":{"delete":{"tags":["worlds"],"summary":"Destroy a world instance","parameters":[{"schema":{"type":"string","description":"World ID to destroy"},"required":true,"description":"World ID to destroy","name":"id","in":"path"}],"responses":{"200":{"description":"World destroyed","content":{"application/json":{"schema":{"type":"object","properties":{"destroyed":{"type":"boolean"}},"required":["destroyed"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Admin role required (operator token for first-party worlds)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Dynamic destruction not supported","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/invites":{"post":{"tags":["members"],"summary":"Mint a share-link invite for a role (Admin+ only; an Owner link by an Owner only)","description":"Lot UI-11: `role: owner` mints « Add a co-owner », by an Owner only (an Admin cannot change who owns a place): one use, a week; redeeming it needs a kami.bot account, and the Owner row is the ACCOUNT (D20).","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["owner","admin","editor","participant","viewer"],"description":"Role granted on redeem."},"expiresAt":{"type":"number","description":"Optional expiry (unix-ms)."},"maxUses":{"type":"integer","exclusiveMinimum":0,"description":"Optional redemption cap."}},"required":["role"]}}}},"responses":{"201":{"description":"Invite created","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"code":{"type":"string"},"worldId":{"type":"string"},"role":{"type":"string"}},"required":["ok","code","worldId","role"]}}}},"403":{"description":"Admin role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Invites not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["members"],"summary":"List a world's outstanding invite links (Admin+ only)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Invites","content":{"application/json":{"schema":{"type":"object","properties":{"invites":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"role":{"type":"string"},"grantedBy":{"type":["string","null"]},"createdAt":{"type":"number"},"expiresAt":{"type":["number","null"]},"maxUses":{"type":["number","null"]},"usedCount":{"type":"number"}},"required":["code","role","grantedBy","createdAt","expiresAt","maxUses","usedCount"]}}},"required":["invites"]}}}},"403":{"description":"Admin role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Invites not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/invites/{code}/redeem":{"post":{"tags":["members"],"summary":"Redeem an invite - attaches its role to your session identity","parameters":[{"schema":{"type":"string","description":"Invite code"},"required":true,"description":"Invite code","name":"code","in":"path"}],"responses":{"200":{"description":"Redeemed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"worldId":{"type":"string"},"role":{"type":"string"}},"required":["ok","worldId","role"]}}}},"401":{"description":"A session is required to redeem","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"An Owner link needs a kami.bot account (UI-11)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"Invite not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"Invite expired or exhausted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Invites not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/members":{"get":{"tags":["members"],"summary":"List explicit members of a world (Admin+ only)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"object","properties":{"members":{"type":"array","items":{"type":"object","properties":{"entityStableId":{"type":"string"},"role":{"type":"string"},"resident":{"type":"boolean"},"grantedBy":{"type":["string","null"]},"grantedAt":{"type":"number"}},"required":["entityStableId","role","resident","grantedBy","grantedAt"]}}},"required":["members"]}}}},"403":{"description":"Admin role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Roles not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/residencies":{"get":{"tags":["members"],"summary":"Worlds where an identity lives or hosts (an accepted home or host tie, PL-1) - alias of GET /world/ties/of/{entityStableId} (operator token only)","parameters":[{"schema":{"type":"string","description":"The canonical identity (a human eid or an agentId) to look up residencies for"},"required":true,"description":"The canonical identity (a human eid or an agentId) to look up residencies for","name":"entityStableId","in":"query"}],"responses":{"200":{"description":"Resident worlds","content":{"application/json":{"schema":{"type":"object","properties":{"worlds":{"type":"array","items":{"type":"string"}}},"required":["worlds"]}}}},"403":{"description":"Operator token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Roles not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/subscriptions":{"post":{"tags":["subscriptions"],"summary":"Register an outbound event-delivery subscription (operator token only)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Subscription id; generated if omitted. Re-POSTing the same id REPLACES it (routing reset, cursor reset)."},"scope":{"type":"string","description":"worldId to match, or \"*\" for every world. Default \"*\".","example":"show-room"},"eventTypes":{"type":"array","items":{"type":"string"},"description":"Type globs, e.g. [\"presence.enter\",\"chat.*\"]. Empty/omitted = all types."},"entityStableId":{"type":"string","description":"Only deliver events from/about this entity."},"sinkUrl":{"type":"string","format":"uri","description":"HTTP endpoint deliveries POST to (signed x-world-signature).","example":"https://api.kami.bot/webhook/world-event"},"sinkSecret":{"type":"string","minLength":8,"description":"HMAC-SHA256 signing secret (write-only; never returned)."},"onlyWhenAbsent":{"type":"boolean","description":"Suppress delivery while the consumer is CONNECTED (the live WS push already served it)."},"consumerId":{"type":"string","description":"Opaque consumer identity for absent-detection + logs (e.g. an agentId)."}},"required":["sinkUrl","sinkSecret"]}}}},"responses":{"201":{"description":"Registered","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"scope":{"type":"string"},"eventTypes":{"type":"array","items":{"type":"string"}}},"required":["id","scope","eventTypes"]}}}},"403":{"description":"Operator token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Subscriptions not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["subscriptions"],"summary":"List outbound subscriptions (operator token only; secrets never returned)","responses":{"200":{"description":"Subscriptions","content":{"application/json":{"schema":{"type":"object","properties":{"subscriptions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"scope":{"type":"string"},"eventTypes":{"type":"array","items":{"type":"string"}},"entityStableId":{"type":["string","null"]},"sinkUrl":{"type":"string"},"onlyWhenAbsent":{"type":"boolean"},"consumerId":{"type":["string","null"]},"lastDeliveredSeq":{"type":"number"},"active":{"type":"boolean"},"createdAt":{"type":"number"}},"required":["id","scope","eventTypes","entityStableId","sinkUrl","onlyWhenAbsent","consumerId","lastDeliveredSeq","active","createdAt"]}}},"required":["subscriptions"]}}}},"403":{"description":"Operator token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Subscriptions not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/subscriptions/{id}":{"delete":{"tags":["subscriptions"],"summary":"Remove an outbound subscription (operator token only)","parameters":[{"schema":{"type":"string","description":"Subscription id to remove"},"required":true,"description":"Subscription id to remove","name":"id","in":"path"}],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"removed":{"type":"boolean"}},"required":["ok","removed"]}}}},"403":{"description":"Operator token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Subscriptions not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/members/{entityStableId}":{"delete":{"tags":["members"],"summary":"Revoke a member (Admin+ only; an Owner only by themself, never the last one)","parameters":[{"schema":{"type":"string","description":"Member identity to remove"},"required":true,"description":"Member identity to remove","name":"entityStableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"removed":{"type":"boolean"}},"required":["ok","removed"]}}}},"403":{"description":"Admin role required, or an Owner rule refused (with its reason)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"501":{"description":"Roles not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["members"],"summary":"Set a member's role - promote / demote, and/or the resident flag (Admin+ only)","parameters":[{"schema":{"type":"string","description":"Member identity to set"},"required":true,"description":"Member identity to set","name":"entityStableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["admin","editor","participant","viewer"]},"resident":{"type":"boolean","description":"Legacy alias of a Lives here tie (PL-1): true proposes one (born accepted from the operator token), false ends a Lives here or Hosts tie. Agents with an accepted one get embodied + their director bound. Prefer POST /world/ties."}},"required":["role"]}}}},"responses":{"200":{"description":"Set","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"role":{"type":"string"},"resident":{"type":"boolean"}},"required":["ok","role","resident"]}}}},"403":{"description":"Admin role required, or an Owner or tie rule refused (with its reason)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"501":{"description":"Roles not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/ties":{"get":{"tags":["ties"],"summary":"The owners and ties of a place (its people, or the operator)","description":"Readable by the operator and by anyone with a relation to the place (an Owner, a member, a tied or proposed being). A proposal is listed only to the place side (Owner, Admin) and to the being side. Anyone else is refused: the door (GET /world/presence) is the public face of a place's ties, and only on a listed public place.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Owners and ties","content":{"application/json":{"schema":{"type":"object","properties":{"owners":{"type":"array","items":{"type":"string"}},"ties":{"type":"array","items":{"$ref":"#/components/schemas/Tie"}}},"required":["owners","ties"]}}}},"403":{"description":"No relation to this place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"501":{"description":"Ties not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["ties"],"summary":"Propose a tie for a being (Owner or Admin, or the operator)","description":"A tie is knotted by two (places.md §2): the place proposes, the being says yes. When the proposer is also the being (a human, or an agent for a visit), the tie is born accepted. A new proposal replaces the being's previous tie to this place and asks for its yes again. A tie grants no right.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"entityStableId":{"type":"string"},"beingKind":{"type":"string","enum":["human","agent"]},"kind":{"type":"string","enum":["home","host","regular","guest"],"description":"home = Lives here, host = Hosts, regular = Regular, guest = Guest (D21). Visiting is no tie."},"displayName":{"type":"string","description":"The name the being goes by, shown at the door while it is away."},"guardianStableId":{"type":"string","description":"An agent's human (operator only: the platform attests it)."},"acceptedBy":{"type":"string","description":"Operator only: record the yes now, naming who gave it."}},"required":["entityStableId","beingKind","kind"]}}}},"responses":{"201":{"description":"Proposed (or accepted in one gesture)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"tie":{"$ref":"#/components/schemas/Tie"}},"required":["ok","tie"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Refused, with its reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"501":{"description":"Ties not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/ties/of/{entityStableId}":{"get":{"tags":["ties"],"summary":"A being's ties across places (the being itself, or the operator)","description":"The cross-world reverse lookup (Your places; the daemon's resident discovery reads the accepted home and host ties here). Never readable by anyone else: a being's ties to a private place are its own business.","parameters":[{"schema":{"type":"string","description":"The being (a human eid or an agent canonical id)"},"required":true,"description":"The being (a human eid or an agent canonical id)","name":"entityStableId","in":"path"}],"responses":{"200":{"description":"Ties","content":{"application/json":{"schema":{"type":"object","properties":{"ties":{"type":"array","items":{"$ref":"#/components/schemas/Tie"}}},"required":["ties"]}}}},"403":{"description":"Neither the being nor the operator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"501":{"description":"Ties not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/ties/{entityStableId}/accept":{"post":{"tags":["ties"],"summary":"Say yes to a proposed tie (the being; an agent's human for a durable tie, D22)","parameters":[{"schema":{"type":"string","description":"The being (a human eid or an agent canonical id)"},"required":true,"description":"The being (a human eid or an agent canonical id)","name":"entityStableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"acceptedBy":{"type":"string","description":"Operator only: who said yes."},"guardianStableId":{"type":"string","description":"Operator only (UI-11): the agent's human, attested as it says yes (the daemon, for an invitation the human accepted)."}}}}}},"responses":{"200":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"tie":{"$ref":"#/components/schemas/Tie"}},"required":["ok","tie"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Refused, with its reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"No such tie","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Ties not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/ties/{entityStableId}":{"delete":{"tags":["ties"],"summary":"End a tie (the being always; the place, except an Owner's tie)","parameters":[{"schema":{"type":"string","description":"The being (a human eid or an agent canonical id)"},"required":true,"description":"The being (a human eid or an agent canonical id)","name":"entityStableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Ended","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"removed":{"type":"boolean"}},"required":["ok","removed"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Refused, with its reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"No such tie","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Ties not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/owners":{"post":{"tags":["ties"],"summary":"Add a co-owner (an Owner, or the operator)","description":"A place may have several Owners, humans or agents (D20). An Admin cannot change who owns the place.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"entityStableId":{"type":"string"}},"required":["entityStableId"]}}}},"responses":{"201":{"description":"Added","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"owners":{"type":"array","items":{"type":"string"}}},"required":["ok","owners"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Refused, with its reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"No such place (a world with no authorization row is the operator's)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Owners not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/owners/{entityStableId}":{"delete":{"tags":["ties"],"summary":"Step down as an Owner (only the Owner themself, never the last one)","parameters":[{"schema":{"type":"string","description":"The being (a human eid or an agent canonical id)"},"required":true,"description":"The being (a human eid or an agent canonical id)","name":"entityStableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"owners":{"type":"array","items":{"type":"string"}}},"required":["ok","owners"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Refused, with its reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"No such place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Owners not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/visits/current":{"get":{"tags":["sessions"],"summary":"Observe the caller's exact connection and linked account","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"worldId","in":"query"},{"schema":{"type":"string","minLength":1},"required":true,"name":"identity","in":"query"}],"responses":{"200":{"description":"Non-atomic visit observation, not a lease","content":{"application/json":{"schema":{"type":"object","properties":{"worldId":{"type":"string"},"identity":{"type":"string"},"worldSessionId":{"type":"string"},"connectionId":{"type":"string"},"accountId":{"type":"string"},"observedAt":{"type":"number"}},"required":["worldId","identity","worldSessionId","connectionId","accountId","observedAt"]}}}},"400":{"description":"World and identity query parameters are required"},"401":{"description":"Active session required"},"403":{"description":"Linked account and actual visit required"},"404":{"description":"World not found"},"409":{"description":"Ambiguous or changed visit"},"503":{"description":"Account observation unavailable"}}}},"/world/media/authorization":{"get":{"tags":["media"],"summary":"Authorize media for the caller's current world connection","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","minLength":1},"required":true,"name":"identity","in":"query"}],"responses":{"200":{"description":"Current media rights","content":{"application/json":{"schema":{"type":"object","properties":{"room":{"type":"string"},"identity":{"type":"string"},"canShare":{"type":"boolean"},"expiresAt":{"type":"number"}},"required":["room","identity","canShare","expiresAt"]}}}},"401":{"description":"Session required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not present under this identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Identity used by another visit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/media/screens/{stableId}/session":{"post":{"tags":["media"],"summary":"Read the current share descriptor of a Screen","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"stableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenShareSessionBody"}}}},"responses":{"200":{"description":"Descriptor of the current generation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenShareDescriptor"}}}},"400":{"description":"Invalid body"},"401":{"description":"Active session required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Actual visit or right required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World or Screen not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not a stream Screen, no current generation, Screen occupied, or the visit changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Screen sharing is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The SFU could not sign, read or close","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/media/screens/{stableId}/start":{"post":{"tags":["media"],"summary":"Start sharing on a Screen and read its descriptor","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"stableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenShareSessionBody"}}}},"responses":{"200":{"description":"Descriptor of the current generation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenShareDescriptor"}}}},"400":{"description":"Invalid body"},"401":{"description":"Active session required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Actual visit or right required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World or Screen not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not a stream Screen, no current generation, Screen occupied, or the visit changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Screen sharing is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The SFU could not sign, read or close","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["media"],"summary":"Stop the share of a Screen; answers once the SFU closure is joined","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"stableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenShareSessionBody"}}}},"responses":{"204":{"description":"Stopped: the generation is retired and its SFU room closed"},"400":{"description":"Invalid body"},"401":{"description":"Active session required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Actual visit or right required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World or Screen not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not a stream Screen, no current generation, Screen occupied, or the visit changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Screen sharing is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The SFU could not sign, read or close","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/media/screens/{stableId}/bind":{"post":{"tags":["media"],"summary":"Bind the caller's own SFU track of the declared source (and its optional sound track) to the current generation of a stream Screen","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"stableId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenShareBindBody"}}}},"responses":{"200":{"description":"The binding the Screen now projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScreenShareBinding"}}}},"400":{"description":"Invalid body"},"401":{"description":"Active session required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Actual visit or right required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World or Screen not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not a stream Screen, no current generation, Screen occupied, or the visit changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Screen sharing is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The SFU could not sign, read or close","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/embody/{id}/attribution":{"get":{"tags":["world"],"summary":"Private attribution for a present visitor and a current body occupation","parameters":[{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","minLength":1},"required":true,"name":"identity","in":"query"}],"responses":{"200":{"description":"Names allowed for this visit and audience","content":{"application/json":{"schema":{"type":"object","properties":{"agentName":{"type":["string","null"]},"broughtBy":{"type":["string","null"]}},"required":["agentName","broughtBy"]}}}},"401":{"description":"Active session required"},"403":{"description":"Actual visit required"},"404":{"description":"No current occupation"},"409":{"description":"Identity collision"}}}},"/world/role/me":{"get":{"tags":["members"],"summary":"The caller's resolved role + capabilities for a world (replaces the client's optimistic guess)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Resolved role","content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":["string","null"],"description":"viewer|participant|editor|admin|owner, or null (no access / no session)."},"canEdit":{"type":"boolean"},"canManage":{"type":"boolean"},"isOwner":{"type":"boolean","description":"The caller is the world's createdBy owner."},"isSeedWorld":{"type":"boolean","description":"A first-party / seed world (no UGC row): legacy-open, no real owner to manage."}},"required":["role","canEdit","canManage","isOwner","isSeedWorld"]}}}}}}},"/world/invites/{code}":{"delete":{"tags":["members"],"summary":"Revoke an invite link so it can no longer be redeemed (Admin+ only)","parameters":[{"schema":{"type":"string","description":"Invite code to revoke"},"required":true,"description":"Invite code to revoke","name":"code","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revoked":{"type":"boolean"}},"required":["ok","revoked"]}}}},"403":{"description":"Admin role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Invites not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/reports":{"post":{"tags":["moderation"],"summary":"File a report against a thing, a person, or a place","description":"Requires a session (reporter identity). A second report by the same reporter against the same still-open target returns the EXISTING report rather than creating a duplicate (idempotency key: reporter + targetKind + stableId).","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportBody"}}}},"responses":{"201":{"description":"Filed","content":{"application/json":{"schema":{"type":"object","properties":{"report":{"$ref":"#/components/schemas/Report"},"alreadyOpen":{"type":"boolean"}},"required":["report","alreadyOpen"]}}}},"400":{"description":"A thing/person report needs a stableId that exists in this world","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"A session is required to file a report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (report-filing limit)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Reports not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["moderation"],"summary":"The open report queue for a world (Admin+ only - the operator triage view)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Open reports, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"$ref":"#/components/schemas/Report"}}},"required":["reports"]}}}},"403":{"description":"Admin role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Reports not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/reports/mine":{"get":{"tags":["moderation"],"summary":"The caller's own reports in this world and their outcomes","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Reports","content":{"application/json":{"schema":{"type":"object","properties":{"reports":{"type":"array","items":{"$ref":"#/components/schemas/Report"}}},"required":["reports"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Reports not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/reports/{id}/decide":{"post":{"tags":["moderation"],"summary":"Decide an open report: remove or dismiss (Admin+ only)","description":"A person decides, never an agent: no heuristic calls this route. remove on a \"thing\" report grey-boxes the entity (reversible). OC-2: a removal decided by the PLATFORM (the operator token) posts a warning or a strike on whoever added the thing, an agent's addition counting for its human; a place's own Admin deciding in their place costs nothing (§6). Deciding an already-decided report is a no-op (idempotent), returned as `alreadyDecided: true`.","parameters":[{"schema":{"type":"string","description":"Report id"},"required":true,"description":"Report id","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["remove","dismiss"]},"moderator":{"type":"string","minLength":1,"maxLength":200,"description":"OC-2: the PERSON deciding (a platform moderator), recorded on the mark so an appeal goes to someone else."}},"required":["decision"]}}}},"responses":{"200":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string"},"alreadyDecided":{"type":"boolean"},"strike":{"type":"object","properties":{"posted":{"type":"boolean"},"account":{"type":["string","null"]},"counter":{"type":["string","null"]},"kind":{"type":["string","null"]},"state":{"type":["string","null"]},"why":{"type":"string","description":"Why no mark was posted: a place's own decision, or nobody to strike."}},"required":["posted","account","counter","kind","state"],"description":"OC-2: a platform removal posts a warning or a strike on whoever added the thing (§5)."},"copies":{"type":"object","properties":{"removed":{"type":"array","items":{"type":"object","properties":{"worldId":{"type":"string"},"stableId":{"type":"string"}},"required":["worldId","stableId"]}},"skipped":{"type":"array","items":{"type":"object","properties":{"worldId":{"type":"string"},"stableId":{"type":"string"},"reason":{"type":"string"}},"required":["worldId","stableId"]}}},"required":["removed","skipped"],"description":"AS-0: a removal takes the FILE down, every copy in every running place (removal by fingerprint)."}},"required":["ok","status","alreadyDecided"]}}}},"403":{"description":"Admin role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Report, world, or target entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Target entity cannot be removed (e.g. carries a live RigidBody)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Reports not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/entities/{id}/remove":{"post":{"tags":["moderation"],"summary":"Owner-at-home removal: grey-box a thing in your own place, no report or strike needed","description":"Place-owner only (resolved role must be exactly Owner), or the operator token. Reversible by an operator via the restore route.","parameters":[{"schema":{"type":"string","description":"Entity ID","example":"5"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Removed (or already removed - idempotent)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"alreadyRemoved":{"type":"boolean"}},"required":["ok","alreadyRemoved"]}}}},"403":{"description":"Place owner required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Cannot remove (e.g. carries a live RigidBody)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Removal not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/entities/{id}/restore":{"post":{"tags":["moderation"],"summary":"Restore a removed thing (Admin+ only)","description":"Replays the archived inverse patch from the removal edit, undoing both the grey-box and the content-field nulling.","parameters":[{"schema":{"type":"string","description":"Entity ID","example":"5"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Restored (or already restored - idempotent)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"alreadyRestored":{"type":"boolean"},"copiesRestored":{"type":"number","description":"AS-0: the other copies the same report had greyed out, back too."}},"required":["ok","alreadyRestored"]}}}},"403":{"description":"Admin role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Cannot restore","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Restore not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/config":{"get":{"tags":["world"],"summary":"Get world rendering config (spawn position, environment, stage)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"World config","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/look-sources":{"get":{"tags":["world"],"summary":"List the registered look sources (id, label, allowed hosts)","responses":{"200":{"description":"Look sources","content":{"application/json":{"schema":{"type":"object","properties":{"sources":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"hosts":{"type":"array","items":{"type":"string"}}},"required":["id","label","hosts"]}}},"required":["sources"]}}}}}}},"/world/analytics":{"get":{"tags":["world"],"summary":"Presence analytics: unique visitors, dwell spans, occupied world-hours (Admin+ only)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":["number","null"],"description":"Only presence since this unix-ms timestamp.","example":1730000000000},"required":false,"description":"Only presence since this unix-ms timestamp.","name":"since","in":"query"}],"responses":{"200":{"description":"Presence analytics","content":{"application/json":{"schema":{"type":"object","properties":{"visitors":{"type":"object","properties":{"unique":{"type":"number"},"humans":{"type":"number"},"agents":{"type":"number"},"visits":{"type":"number"}},"required":["unique","humans","agents","visits"]},"sessions":{"type":"array","items":{"type":"object","properties":{"actorId":{"type":"string"},"session":{"type":"string"},"kind":{"type":"string"},"enteredAt":{"type":"number"},"leftAt":{"type":["number","null"]},"dwellMs":{"type":["number","null"]}},"required":["actorId","session","kind","enteredAt","leftAt","dwellMs"]}},"hours":{"type":"object","properties":{"humanMs":{"type":"number"},"agentMs":{"type":"number"},"totalMs":{"type":"number"},"openSpans":{"type":"number"},"since":{"type":"number"},"until":{"type":"number"}},"required":["humanMs","agentMs","totalMs","openSpans","since","until"]}},"required":["visitors","sessions","hours"]}}}},"403":{"description":"Admin role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Analytics not supported (persistence off)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/state":{"get":{"tags":["world"],"summary":"Get full serialized world state","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Admin token for private components"},"required":false,"description":"Admin token for private components","name":"admin","in":"query"}],"responses":{"200":{"description":"Serialized world state","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/entities":{"get":{"tags":["entities"],"summary":"List entities with optional filters","description":"Filters are composable: ?component=Mesh,LightSource&near=0,0,0&range=20&label=prop*","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Filter by component(s), comma-separated. Entity must have ALL listed.","example":"Mesh,RigidBody"},"required":false,"description":"Filter by component(s), comma-separated. Entity must have ALL listed.","name":"component","in":"query"},{"schema":{"type":"string","description":"Filter by label (supports trailing * wildcard)","example":"tree*"},"required":false,"description":"Filter by label (supports trailing * wildcard)","name":"label","in":"query"},{"schema":{"type":"string","description":"Spatial filter center: x,y,z","example":"0,0,0"},"required":false,"description":"Spatial filter center: x,y,z","name":"near","in":"query"},{"schema":{"type":"string","description":"Spatial filter radius (meters, requires near)","example":"10"},"required":false,"description":"Spatial filter radius (meters, requires near)","name":"range","in":"query"},{"schema":{"type":"string","description":"Bounding box filter: minX,minY,minZ,maxX,maxY,maxZ","example":"0,0,0,10,5,10"},"required":false,"description":"Bounding box filter: minX,minY,minZ,maxX,maxY,maxZ","name":"bbox","in":"query"}],"responses":{"200":{"description":"Entity list","content":{"application/json":{"schema":{"type":"object","properties":{"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"label":{"type":"string"},"position":{"type":"array","prefixItems":[{"type":"number"},{"type":"number"},{"type":"number"}]}},"required":["id","position"]}}},"required":["entities"]}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["entities"],"summary":"Create an entity in the world","description":"Creates a new entity with optional components. Persists as DB overlay.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEntityBody"}}}},"responses":{"201":{"description":"Entity created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEntityResponse"}}}},"202":{"description":"D58 W2 (agent key) and W2f (a session or the operator token, not a controllable body), ordered owner on: the addition is recorded (durable) but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why (`live_world_moved`, `instance_stopped`, `world_full`, `apply_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEntityRecordedResponse"}}}},"400":{"description":"components.Avatar.modelUrl is not on the allowed host list, or components.Screen.url fails AS-1 media admission, or `from.ref` is not a tile (`bad_ref`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Unauthorized: a session is required to create an entity; or (agent key, ordered owner on) the key expired before the write (`agent_key_expired`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Forbidden: a controllable body requires embody rights (owner or the operator token); a non-controllable entity requires Editor+ (owner, member, or the operator token); a file this place may not hold (`private_asset_public_place`, ...); a standing refusal; (ordered owner on) the person lost editing rights before the write (`edit_right_refused`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found, or `from.ref` names nothing any more (`unknown_item`, `not_yours`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Entity with this label already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`from.ref` is a tier B item, copied only on a pick, and that copy is not built (`copy_on_pick_unbuilt`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (OC-0 mutation limit)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"World is full; or (ordered owner on) the place changed or could not be checked while placing, nothing written, try again (`build_unchecked`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/entities/batch":{"post":{"tags":["entities"],"summary":"Create multiple entities in one request","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCreateBody"}}}},"responses":{"201":{"description":"Entities created","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"created":{"type":"number"},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"stableId":{"type":"string"},"label":{"type":"string"}},"required":["id","stableId","label"]}}},"required":["ok","created","entities"]}}}},"202":{"description":"D58 W2f, ordered owner on: the batch is recorded (durable) but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `entities` lists what reached the live place. `reason` says why (`live_world_moved`, `instance_stopped`, `world_full`, `apply_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchCreateRecordedResponse"}}}},"403":{"description":"Editor role required (builder token, or a session with Editor+ access); a file this place may not hold, `« reason (index i) »` with its code; a standing refusal; (ordered owner on) the right lost before the write (`edit_right_refused`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"(ordered owner on) a label that a deleted thing still holds, nothing written (`Batch create conflict at index i`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"(ordered owner on) the place changed or could not be checked while the batch was being made, nothing written, try again (`build_unchecked`); the place filled up (`World is full`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["entities"],"summary":"Update multiple entities in one request (atomic, all-or-nothing)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchUpdateBody"}}}},"responses":{"200":{"description":"Entities updated","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"updated":{"type":"number"}},"required":["ok","updated"]}}}},"202":{"description":"D58 W2d, a person or the operator token with the ordered owner on: the whole batch is recorded (durable) but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"updated":{"type":"number"},"live":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["instance_stopped","live_world_moved","world_full","apply_failed"]},"message":{"type":"string"}},"required":["ok","updated","live","reason","message"]}}}},"403":{"description":"Editor role required (builder token, or a session with Editor+ access to this world), a standing refusal, or a file this place may not hold. With the ordered owner on, also the person lost editing rights before the write (`edit_right_refused`); nothing written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Version conflict on a baseVersion-guarded update; the whole batch is rejected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"With the ordered owner on: the place changed or could not be checked while editing, nothing written, try again (`build_unchecked`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["entities"],"summary":"Delete multiple entities in one request (atomic, all-or-nothing)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchDeleteBody"}}}},"responses":{"200":{"description":"Entities deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"deleted":{"type":"number"}},"required":["ok","deleted"]}}}},"202":{"description":"D58 W2d, a person or the operator token with the ordered owner on: the whole batch is recorded (durable) but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"deleted":{"type":"number"},"live":{"type":"boolean","enum":[false]},"reason":{"type":"string","enum":["instance_stopped","live_world_moved","world_full","apply_failed"]},"message":{"type":"string"}},"required":["ok","deleted","live","reason","message"]}}}},"403":{"description":"Editor role required (builder token, or a session with Editor+ access to this world), a standing refusal, or a file this place may not hold. With the ordered owner on, also the person lost editing rights before the write (`edit_right_refused`); nothing written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A delete conflicted (tombstone); the whole batch is rejected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"With the ordered owner on: the place changed or could not be checked while editing, nothing written, try again (`build_unchecked`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/entities/{id}":{"get":{"tags":["entities"],"summary":"Get entity detail with all visible components","parameters":[{"schema":{"type":"string","description":"Entity ID","example":"5"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Admin token for private components"},"required":false,"description":"Admin token for private components","name":"admin","in":"query"}],"responses":{"200":{"description":"Entity detail","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"label":{"type":"string"},"components":{"type":"object","additionalProperties":{}},"version":{"type":"number","description":"Current overlay version (0 if unedited). Pass as baseVersion on the next edit for optimistic concurrency."}},"required":["id","components","version"]}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity or world not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["entities"],"summary":"Destroy an entity","description":"Records an ordered delete edit and tombstone. With expectedStableId present, requires one explicit worldId, expectedStableId and canonical baseVersion, a canonical numeric ID (including 0), and the exact body-owner Bearer. No operator, agent-key, body-admission or default-world fallback. Strict deletion atomically checks the durable version and token. A 503 with committed:true or null is incomplete and must never be treated as successful cleanup or retried automatically. Without the selector, the ordinary delete needs the place's editing right (builder token, or a session with Editor+ access, the door of DELETE /world/entities/batch), except a body's own owner token removing that body.","parameters":[{"schema":{"type":"string","description":"Entity ID","example":"5"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","example":"3"},"required":false,"description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","name":"baseVersion","in":"query"},{"schema":{"type":"string","description":"Select strict deletion, even when empty. Must match exactly one live numeric body and its creation receipt."},"required":false,"description":"Select strict deletion, even when empty. Must match exactly one live numeric body and its creation receipt.","name":"expectedStableId","in":"query"}],"responses":{"200":{"description":"Entity destroyed","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"ok":{"type":"boolean"},"version":{"type":"number"}},"required":["deleted","ok"]}}}},"202":{"description":"D58 W2e (the operator token) and W2h (a session with the editing right), ordered owner on: the delete is recorded (durable) but the live place moved meanwhile, so the thing is still shown; it is gone when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteRecorded"}}}},"400":{"description":"Invalid or ambiguous strict deletion fields","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Editor role required (builder token, or a session with Editor+ access to this world), or a body owned by another token; (ordered owner on, D58 W2h) the session lost editing rights before the write (`edit_right_refused`), nothing written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Version conflict (stale baseVersion)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (OC-0 mutation limit)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Strict deletion unavailable or incomplete; committed is true after a known commit, null for an unknown outcome. With the ordered owner on (the operator token, or a session since D58 W2h), the place changed or could not be checked while deleting, nothing written, try again (`build_unchecked`)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"committed":{"anyOf":[{"type":"boolean","enum":[true]},{"type":"null"}]}},"required":["error"]}}}}}}},"/world/entities/{id}/nearby":{"get":{"tags":["entities"],"deprecated":true,"summary":"[DEPRECATED] Flat perception — use GET /world/view/perception/{id}","description":"DEPRECATED legacy flat perception (no salience/summary/affordances, untyped). Use the canonical enriched surface instead: pull `GET /world/view/perception/{id}` (+ `?cursor=` for polling deltas), or the WS push `/world/stream`. Responses carry a `Deprecation` header + a `Link` to the successor.","parameters":[{"schema":{"type":"string","description":"Entity ID","example":"5"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Perception radius (meters)","example":"15"},"required":false,"description":"Perception radius (meters)","name":"range","in":"query"}],"responses":{"200":{"description":"Perception data","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Entity has no Transform","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/entities/{id}/components":{"patch":{"tags":["components"],"summary":"Partial update entity components","description":"Merges component data into existing entity. Unmentioned components are untouched. Recorded as an ordered edit + persisted as a versioned DB overlay.","parameters":[{"schema":{"type":"string","description":"Entity ID","example":"5"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","example":"3"},"required":false,"description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","name":"baseVersion","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchComponentsBody"}}}},"responses":{"200":{"description":"Components updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditOk"}}}},"202":{"description":"D58 W2c, a person or the operator token with the ordered owner on: the edit is recorded (durable) but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditRecorded"}}}},"400":{"description":"Avatar.modelUrl is not on the allowed host list, or the effective Screen.url/Screen.type fails AS-1 media admission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Editor role required (builder token, or a session with Editor+ access to this world). With the ordered owner on: the person lost editing rights before the write (`edit_right_refused`), a standing refusal (its scale code), or a file this place may not hold (`private_asset_public_place`, ...); nothing written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Version conflict (stale baseVersion), or the Screen changed before the edit (screen_edit_refused)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (OC-0 mutation limit)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Screen edit completion is unavailable (`screen_edit_incomplete`; committed is true (written) or null (unknown)); or, with the ordered owner on, the place changed or could not be checked while editing, nothing written, try again (`build_unchecked`)","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"error":{"type":"string","enum":["screen_edit_incomplete"]},"committed":{"type":["boolean","null"],"enum":[true]}},"required":["error","committed"]},{"$ref":"#/components/schemas/Error"}]}}}}}}},"/world/entities/{id}/components/{name}":{"put":{"tags":["components"],"summary":"Set a single component by name","description":"Merges the component data into the entity (creating the component if absent), recorded as an ordered edit + versioned DB overlay. Send `{ \"ComponentName\": null }` via DELETE to remove a component.","parameters":[{"schema":{"type":"string","description":"Entity ID"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"Component name","example":"LightSource"},"required":true,"description":"Component name","name":"name","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","example":"3"},"required":false,"description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","name":"baseVersion","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComponentData"}}}},"responses":{"200":{"description":"Component set","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditOk"}}}},"202":{"description":"D58 W2c, a person or the operator token with the ordered owner on: the edit is recorded (durable) but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditRecorded"}}}},"400":{"description":"Unknown component name, or (for `Avatar`) modelUrl is not on the allowed host list, or (for `Screen`) the effective url/type fails AS-1 media admission","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Editor role required (builder token, or a session with Editor+ access to this world). With the ordered owner on: the person lost editing rights before the write (`edit_right_refused`), a standing refusal (its scale code), or a file this place may not hold (`private_asset_public_place`, ...); nothing written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Version conflict (stale baseVersion), or the Screen changed before the edit (screen_edit_refused)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (OC-0 mutation limit)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Screen edit completion is unavailable (`screen_edit_incomplete`; committed is true (written) or null (unknown)); or, with the ordered owner on, the place changed or could not be checked while editing, nothing written, try again (`build_unchecked`)","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"error":{"type":"string","enum":["screen_edit_incomplete"]},"committed":{"type":["boolean","null"],"enum":[true]}},"required":["error","committed"]},{"$ref":"#/components/schemas/Error"}]}}}}}},"delete":{"tags":["components"],"summary":"Remove a component from an entity","description":"Records an ordered edit with a null marker in the overlay (component removal survives restart + is undoable).","parameters":[{"schema":{"type":"string","description":"Entity ID"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"Component name","example":"Interactive"},"required":true,"description":"Component name","name":"name","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","example":"3"},"required":false,"description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","name":"baseVersion","in":"query"}],"responses":{"200":{"description":"Component removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditOk"}}}},"202":{"description":"D58 W2c, a person or the operator token with the ordered owner on: the edit is recorded (durable) but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditRecorded"}}}},"400":{"description":"Unknown component name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Editor role required (builder token, or a session with Editor+ access to this world). With the ordered owner on: the person lost editing rights before the write (`edit_right_refused`), a standing refusal (its scale code), or a file this place may not hold (`private_asset_public_place`, ...); nothing written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity or component not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Version conflict (stale baseVersion), or the Screen changed before the edit (screen_edit_refused)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (OC-0 mutation limit)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Screen edit completion is unavailable (`screen_edit_incomplete`; committed is true (written) or null (unknown)); or, with the ordered owner on, the place changed or could not be checked while editing, nothing written, try again (`build_unchecked`)","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"error":{"type":"string","enum":["screen_edit_incomplete"]},"committed":{"type":["boolean","null"],"enum":[true]}},"required":["error","committed"]},{"$ref":"#/components/schemas/Error"}]}}}}}}},"/world/entities/{id}/name":{"put":{"tags":["entities"],"summary":"Rename a thing (BT-0)","description":"Sets a thing's human, editable, non-unique name. Never touches its kind, its server identity (stableId/label), its links, or its journal. Adds a Naming component (name set, kind left empty) if the entity did not have one yet.","parameters":[{"schema":{"type":"string","description":"Entity ID","example":"5"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","example":"3"},"required":false,"description":"Optimistic-concurrency base: the version you last read. A mismatch returns 409. Omit to force-write.","name":"baseVersion","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameEntityBody"}}}},"responses":{"200":{"description":"Renamed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditOk"}}}},"202":{"description":"D58 W2e, a person or the operator token with the ordered owner on: the rename is recorded (durable) but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditRecorded"}}}},"400":{"description":"Empty or oversized name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Editor role required (builder token, or a session with Editor+ access to this world). With the ordered owner on: the person lost editing rights before the write (`edit_right_refused`), a standing refusal (its scale code), or a file this place may not hold (`private_asset_public_place`, ...); nothing written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Version conflict (stale baseVersion)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"With the ordered owner on: the place changed or could not be checked while renaming, nothing written, try again (`build_unchecked`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/entities/{id}/action":{"post":{"tags":["actions"],"summary":"Execute an action on an entity","description":"Actions: move, speak, emote, trigger, etc. Requires entity owner token for owned entities.","parameters":[{"schema":{"type":"string","description":"Entity ID","example":"5"},"required":true,"description":"Entity ID","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteActionBody"}}}},"responses":{"200":{"description":"Action executed","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/waypoints":{"get":{"tags":["world"],"summary":"Get world waypoints (named positions)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Waypoints map","content":{"application/json":{"schema":{"type":"object","properties":{"waypoints":{"type":"object","additionalProperties":{}}},"required":["waypoints"]}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/events":{"get":{"tags":["events"],"summary":"Recent in-memory events","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Timestamp filter (ms)"},"required":false,"description":"Timestamp filter (ms)","name":"since","in":"query"},{"schema":{"type":"string","description":"Filter by entity ID"},"required":false,"description":"Filter by entity ID","name":"entityId","in":"query"}],"responses":{"200":{"description":"Event list","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{}}},"required":["events"]}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["events"],"summary":"Append an event to the durable log","description":"Direct event emission. Requires the builder token — **do not share with agents** (see PLATFORM.md §7.4 for the trust model).\n\nPayload handling:\n- Known types (`chat.text`, `chat.audio`, `chat.image`, `chat.emote`) are Zod-validated against a closed schema; unknown keys are stripped.\n- Unknown types pass through as a generic record.\n- Total serialised payload is capped at 32 KB (`MAX_EVENT_DATA_BYTES`); oversized requests return 400.\n- A `data.origin = \"api.post\"` key is stamped on every row for provenance; any caller-supplied `origin` is silently overwritten.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppendEventBody"}}}},"responses":{"201":{"description":"Event appended","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorldEvent"}}}},"400":{"description":"Invalid payload (type or payload rejected)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Builder token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Durable append failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/events/log":{"get":{"tags":["events"],"summary":"Query the durable event log","description":"Returns persisted events newest-first. Filters compose. Chat history for example: `?type=chat.*&near=0,0,0&radius=15&since=<ms>`.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Exact type or glob (`chat.*`, `action:*`). Prefix match up to the `.` / `:`.","example":"chat.*"},"required":false,"description":"Exact type or glob (`chat.*`, `action:*`). Prefix match up to the `.` / `:`.","name":"type","in":"query"},{"schema":{"type":"string","description":"Filter by numeric ECS entity id."},"required":false,"description":"Filter by numeric ECS entity id.","name":"entityId","in":"query"},{"schema":{"type":"string","description":"Alias of entityId."},"required":false,"description":"Alias of entityId.","name":"entity","in":"query"},{"schema":{"type":"string","description":"Filter by source entity stableId.","example":"alice"},"required":false,"description":"Filter by source entity stableId.","name":"sender","in":"query"},{"schema":{"type":"string","description":"Spatial filter centre, \"x,y,z\". Events without a stored position are excluded when set.","example":"0,0,0"},"required":false,"description":"Spatial filter centre, \"x,y,z\". Events without a stored position are excluded when set.","name":"near","in":"query"},{"schema":{"type":"string","description":"Spatial filter radius in metres (default 15 when `near` is set).","example":"20"},"required":false,"description":"Spatial filter radius in metres (default 15 when `near` is set).","name":"radius","in":"query"},{"schema":{"type":"string","description":"Unix ms; return events strictly newer than this."},"required":false,"description":"Unix ms; return events strictly newer than this.","name":"since","in":"query"},{"schema":{"type":"string","description":"Max rows (default 100, hard cap 1000).","example":"100"},"required":false,"description":"Max rows (default 100, hard cap 1000).","name":"limit","in":"query"}],"responses":{"200":{"description":"Persisted events","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/WorldEvent"}}},"required":["events"]}}}},"400":{"description":"Malformed filter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/components":{"get":{"tags":["world"],"summary":"List all available component definitions","description":"Returns component names, field schemas with defaults, visibility, and tag status. Essential for agents and builders to know what is possible.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Component catalog","content":{"application/json":{"schema":{"type":"object","properties":{"components":{"type":"array","items":{"$ref":"#/components/schemas/ComponentInfo"}}},"required":["components"]}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/reactions":{"get":{"tags":["world"],"summary":"List available reaction conditions, effects, and examples","description":"Describes the declarative reaction grammar. Conditions are AND-combined. Effects execute when conditions pass.","responses":{"200":{"description":"Reaction catalog","content":{"application/json":{"schema":{"type":"object","properties":{"conditions":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","additionalProperties":{"type":"string"}}},"required":["type","description","params"]}},"effects":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"description":{"type":"string"},"params":{"type":"object","additionalProperties":{"type":"string"}}},"required":["type","description","params"]}},"examples":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"reaction":{"type":"object","properties":{"when":{"type":"array","items":{}},"then":{"type":"array","items":{}}},"required":["when","then"]}},"required":["name","description","reaction"]}}},"required":["conditions","effects","examples"]}}}}}}},"/world/presence-grants":{"post":{"tags":["presence"],"summary":"Mint a host admission; the code is returned once","parameters":[{"schema":{"type":"string"},"required":false,"name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"expiresAt":{"type":["integer","null"],"exclusiveMinimum":0},"maxUses":{"type":["integer","null"],"exclusiveMinimum":0},"allowAnonymous":{"type":"boolean","default":false}}}}}},"responses":{"201":{"description":"Admission created","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"grant":{"type":"object","properties":{"id":{"type":"string"},"worldId":{"type":"string"},"grantedBy":{"type":"string"},"createdAt":{"type":"number"},"expiresAt":{"type":["number","null"]},"maxUses":{"type":["number","null"]},"usedCount":{"type":"number"},"allowAnonymous":{"type":"boolean"},"revokedAt":{"type":["number","null"]}},"required":["id","worldId","grantedBy","createdAt","expiresAt","maxUses","usedCount","allowAnonymous","revokedAt"]}},"required":["code","grant"]}}}},"400":{"description":"Invalid limits","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"A real Owner or Admin is required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Place unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"501":{"description":"Persistence unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"get":{"tags":["presence"],"summary":"List this place's admissions without bearer secrets","parameters":[{"schema":{"type":"string"},"required":false,"name":"worldId","in":"query"}],"responses":{"200":{"description":"Admissions","content":{"application/json":{"schema":{"type":"object","properties":{"grants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"worldId":{"type":"string"},"grantedBy":{"type":"string"},"createdAt":{"type":"number"},"expiresAt":{"type":["number","null"]},"maxUses":{"type":["number","null"]},"usedCount":{"type":"number"},"allowAnonymous":{"type":"boolean"},"revokedAt":{"type":["number","null"]}},"required":["id","worldId","grantedBy","createdAt","expiresAt","maxUses","usedCount","allowAnonymous","revokedAt"]}}},"required":["grants"]}}}},"400":{"description":"Invalid limits","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"A real Owner or Admin is required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Place unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"501":{"description":"Persistence unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/world/presence-grants/{id}":{"delete":{"tags":["presence"],"summary":"Revoke an admission in this place","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string"},"required":false,"name":"worldId","in":"query"}],"responses":{"200":{"description":"Revoked, or already absent","content":{"application/json":{"schema":{"type":"object","properties":{"revoked":{"type":"boolean"}},"required":["revoked"]}}}},"400":{"description":"Invalid limits","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"A real Owner or Admin is required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Place unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"501":{"description":"Persistence unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/world/embody":{"post":{"tags":["presence"],"summary":"Enter under a host permission","parameters":[{"schema":{"type":"string"},"required":false,"name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","minLength":1,"maxLength":256},"mode":{"type":"string","enum":["provision-new","claim-slot"],"default":"provision-new"},"bodyId":{"type":"integer","minimum":0},"label":{"type":"string","minLength":1,"maxLength":80,"default":"Guest agent"}},"required":["code"]}}}},"responses":{"200":{"description":"One body, one credential","content":{"application/json":{"schema":{"type":"object","properties":{"worldId":{"type":"string"},"entityId":{"type":"number"},"controlToken":{"type":"string"},"directorId":{"type":"string"},"grantId":{"type":"string"},"activityTimeoutMs":{"type":"number"}},"required":["worldId","entityId","controlToken","directorId","grantId","activityTimeoutMs"]}}}},"400":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"410":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"501":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/world/embody/{id}":{"post":{"tags":["presence"],"summary":"Rebind the same vouch after key rotation","parameters":[{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"id","in":"path"},{"schema":{"type":"string"},"required":false,"name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"agentKey":{"type":"string","maxLength":256}},"required":["agentKey"]}}}},"responses":{"200":{"description":"Completed","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"410":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"501":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"delete":{"tags":["presence"],"summary":"Release your body","parameters":[{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"id","in":"path"},{"schema":{"type":"string"},"required":false,"name":"worldId","in":"query"}],"responses":{"200":{"description":"Completed","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"410":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"501":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/world/embody/{id}/evict":{"post":{"tags":["presence"],"summary":"Host eviction","parameters":[{"schema":{"type":["integer","null"],"minimum":0},"required":false,"name":"id","in":"path"},{"schema":{"type":"string"},"required":false,"name":"worldId","in":"query"}],"responses":{"200":{"description":"Completed","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"409":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"410":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"501":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"503":{"description":"Admission refused; no anonymous or operator fallback","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/world/view/spatial/walkable":{"get":{"tags":["view"],"summary":"Is a position walkable?","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Vec3 as \"x,y,z\"","example":"0,0,0"},"required":true,"description":"Vec3 as \"x,y,z\"","name":"pos","in":"query"}],"responses":{"200":{"description":"Walkability result","content":{"application/json":{"schema":{"type":"object","properties":{"walkable":{"type":"boolean"}},"required":["walkable"]}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/spatial/nearest-walkable":{"get":{"tags":["view"],"summary":"Nearest walkable point within maxDist","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Vec3 as \"x,y,z\""},"required":true,"description":"Vec3 as \"x,y,z\"","name":"pos","in":"query"},{"schema":{"type":"string","description":"Search radius (default 10)"},"required":false,"description":"Search radius (default 10)","name":"maxDist","in":"query"}],"responses":{"200":{"description":"Nearest walkable point, or null","content":{"application/json":{"schema":{"type":"object","properties":{"point":{"$ref":"#/components/schemas/Vec3"}},"required":["point"]}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/spatial/path":{"get":{"tags":["view"],"summary":"Compute a path between two points","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Start Vec3 as \"x,y,z\""},"required":true,"description":"Start Vec3 as \"x,y,z\"","name":"from","in":"query"},{"schema":{"type":"string","description":"Goal Vec3 as \"x,y,z\""},"required":true,"description":"Goal Vec3 as \"x,y,z\"","name":"to","in":"query"}],"responses":{"200":{"description":"Path result (null if unreachable)","content":{"application/json":{"schema":{"type":"object","properties":{"path":{}}}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/spatial/describe":{"get":{"tags":["view"],"summary":"Natural-language description of a position","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string"},"required":true,"name":"pos","in":"query"}],"responses":{"200":{"description":"Description + regions","content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string"},"regions":{"type":"array","items":{"type":"string"}}},"required":["description","regions"]}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/spatial/waypoint":{"get":{"tags":["view"],"summary":"Resolve a named waypoint to a position","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string"},"required":true,"name":"name","in":"query"}],"responses":{"200":{"description":"Position or null","content":{"application/json":{"schema":{"type":"object","properties":{"position":{"$ref":"#/components/schemas/Vec3"}},"required":["position"]}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/affordances/vocabulary":{"get":{"tags":["view"],"summary":"All affordance verbs declared in this world","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Verb list","content":{"application/json":{"schema":{"type":"object","properties":{"verbs":{"type":"array","items":{"type":"string"}}},"required":["verbs"]}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/affordances/of/{entityId}":{"get":{"tags":["view"],"summary":"Affordances + current EntityState snapshot for an entity","description":"Returns both the declared affordance grammar (verbs, durations, ranges, describe hints) and the entity's current discrete state map in one call — the common case for headless agents planning their next action.","parameters":[{"schema":{"type":"string"},"required":true,"name":"entityId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Affordance + state snapshot","content":{"application/json":{"schema":{"type":"object","properties":{"affordances":{"type":"array","items":{}},"state":{"type":"object","additionalProperties":{}}},"required":["affordances","state"]}}}},"400":{"description":"Bad entity id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/state/{entityId}":{"get":{"tags":["view"],"summary":"Current EntityState for an entity (state-only snapshot)","description":"Returns `{ state: Record<string, unknown> }` for the entity. Auth: public, matching the rest of the affordance/spatial view layer (perception + social are the gated ones).","parameters":[{"schema":{"type":"string"},"required":true,"name":"entityId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"EntityState snapshot","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"object","additionalProperties":{}}},"required":["state"]}}}},"400":{"description":"Bad entity id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World or entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/affordances/near":{"get":{"tags":["view"],"summary":"Find affordance offers for a verb near a position","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string"},"required":true,"name":"verb","in":"query"},{"schema":{"type":"string"},"required":true,"name":"pos","in":"query"},{"schema":{"type":"string","description":"Search radius (default 10)"},"required":false,"description":"Search radius (default 10)","name":"radius","in":"query"}],"responses":{"200":{"description":"Offers sorted by distance","content":{"application/json":{"schema":{"type":"object","properties":{"offers":{"type":"array","items":{}}},"required":["offers"]}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/affordances/can-perform":{"get":{"tags":["view"],"summary":"Validate whether actor can perform verb on target right now","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string"},"required":true,"name":"actor","in":"query"},{"schema":{"type":"string"},"required":true,"name":"target","in":"query"},{"schema":{"type":"string"},"required":true,"name":"verb","in":"query"}],"responses":{"200":{"description":"Validation result","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"reason":{"type":"string"}},"required":["ok"]}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/perception/{entityId}":{"get":{"tags":["view"],"summary":"First-person perception snapshot (or cursor delta) for an entity","description":"Auth policy: NPCs (Presence.controllerType === \"bot\") are publicly readable. Player entities require a session token whose entityStableId maps to the requested entityId in this world, OR a builder token. Prevents anonymous probing of another player's perception radius as a wallhack vector.\n\nPolling deltas: pass `cursor` to switch from a full snapshot to incremental frames. First call with `cursor` (any value, e.g. empty) → a keyframe + a fresh `cursor`; pass that cursor back each poll → a `delta` (net change since YOUR last read) + an LLM-friendly `narrative`. Same shapes as the WS push. Omit `cursor` for the plain full snapshot (no server state created).","parameters":[{"schema":{"type":"string"},"required":true,"name":"entityId","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Override perception radius"},"required":false,"description":"Override perception radius","name":"radius","in":"query"},{"schema":{"type":"string","description":"Opt into delta polling; pass back the returned cursor each poll"},"required":false,"description":"Opt into delta polling; pass back the returned cursor each poll","name":"cursor","in":"query"}],"responses":{"200":{"description":"Perception payload (full snapshot, keyframe, or delta)","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"perception":{"$ref":"#/components/schemas/Perception"}},"required":["perception"]},{"$ref":"#/components/schemas/PerceptionKeyframe"},{"$ref":"#/components/schemas/PerceptionDeltaFrame"}]}}}},"400":{"description":"Bad entity id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not authorised to read this entity perception, or a private world and the caller is not a member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/social/near":{"get":{"tags":["view"],"summary":"Entity summaries near a position","description":"Auth: requires ANY authenticated principal (a session token from POST /world/sessions, or the builder token). Anonymous callers get 403. Social projections leak player positions, chat, and relationships — the token requirement gives us an audit trail without raising friction (anon session mint is free).","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string"},"required":true,"name":"pos","in":"query"},{"schema":{"type":"string","description":"Search radius (default 10)"},"required":false,"description":"Search radius (default 10)","name":"radius","in":"query"}],"responses":{"200":{"description":"Entity summaries","content":{"application/json":{"schema":{"type":"object","properties":{"entities":{"type":"array","items":{}}},"required":["entities"]}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Auth required (session or builder), or a private world and the caller is not a member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/social/relationship":{"get":{"tags":["view"],"summary":"Relationship between two entities (or null)","description":"Auth: requires ANY authenticated principal (a session token from POST /world/sessions, or the builder token). Anonymous callers get 403. Social projections leak player positions, chat, and relationships — the token requirement gives us an audit trail without raising friction (anon session mint is free).","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string"},"required":true,"name":"a","in":"query"},{"schema":{"type":"string"},"required":true,"name":"b","in":"query"}],"responses":{"200":{"description":"Relationship or null","content":{"application/json":{"schema":{"type":"object","properties":{"relationship":{}}}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Auth required (session or builder), or a private world and the caller is not a member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/social/groups":{"get":{"tags":["view"],"summary":"Detected social clusters near a position","description":"Auth: requires ANY authenticated principal (a session token from POST /world/sessions, or the builder token). Anonymous callers get 403. Social projections leak player positions, chat, and relationships — the token requirement gives us an audit trail without raising friction (anon session mint is free).","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string"},"required":true,"name":"pos","in":"query"},{"schema":{"type":"string","description":"Search radius (default 15)"},"required":false,"description":"Search radius (default 15)","name":"radius","in":"query"}],"responses":{"200":{"description":"Group list","content":{"application/json":{"schema":{"type":"object","properties":{"groups":{"type":"array","items":{}}},"required":["groups"]}}}},"400":{"description":"Bad input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Auth required (session or builder), or a private world and the caller is not a member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/view/events/stream":{"get":{"tags":["view"],"summary":"Server-Sent Events: live world event stream","description":"Emits a `subscribed` control event with the accepted filter, then `world-event` frames for every matching event. `ping` frames every 25s keep intermediaries from closing the connection.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Event type or comma-separated list (e.g. \"chat.text,entity.interacted\")"},"required":false,"description":"Event type or comma-separated list (e.g. \"chat.text,entity.interacted\")","name":"type","in":"query"},{"schema":{"type":"string","description":"Numeric entity id to scope the stream"},"required":false,"description":"Numeric entity id to scope the stream","name":"entity","in":"query"},{"schema":{"type":"string","description":"Stable id to scope the stream"},"required":false,"description":"Stable id to scope the stream","name":"stableId","in":"query"},{"schema":{"type":"string","description":"Spatial centre as \"x,y,z\" (requires radius)"},"required":false,"description":"Spatial centre as \"x,y,z\" (requires radius)","name":"near","in":"query"},{"schema":{"type":"string","description":"Spatial radius in metres (requires near)"},"required":false,"description":"Spatial radius in metres (requires near)","name":"radius","in":"query"}],"responses":{"200":{"description":"SSE stream","content":{"text/event-stream":{"schema":{"type":"string"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/accounts/{account}/erase":{"post":{"tags":["accounts"],"summary":"Erase everything Kami World keeps about a kami.bot account (operator only: the daemon, on « Delete my account »)","description":"Places the account alone owns are destroyed; its looks, their files and the provider's copies of its photos, its memberships, ties, sessions and journal rows go; what it made in places that stay keeps its thing and loses its id; moderation and legal records are kept, with the reason in `kept`. Idempotent: a second call answers zeros. A 503 changed nothing in the database: call again later.","parameters":[{"schema":{"type":"string","example":"kami:3f2a"},"required":true,"name":"account","in":"path"}],"responses":{"200":{"description":"Erased","content":{"application/json":{"schema":{"type":"object","properties":{"erased":{"type":"boolean","enum":[true]},"placesDestroyed":{"type":"number"},"placesKept":{"type":"number"},"files":{"type":"number"},"providerCopies":{"type":"number"},"sessionsRevoked":{"type":"number"},"thingsAnonymized":{"type":"number"},"rows":{"type":"object","additionalProperties":{"type":"number"}},"kept":{"type":"array","items":{"type":"object","properties":{"table":{"type":"string"},"reason":{"type":"string"}},"required":["table","reason"]}}},"required":["erased","placesDestroyed","placesKept","files","providerCopies","sessionsRevoked","thingsAnonymized","rows","kept"]}}}},"400":{"description":"Not a kami.bot account id","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]}}}},"501":{"description":"No persistence on this server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]}}}},"503":{"description":"A provider or the file store failed; nothing was erased, try again","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"}},"required":["error"]}}}}}}},"/world/add/search":{"get":{"tags":["sources"],"summary":"The Add panel's one search: the kit, « Yours » and the free library, merged (AS-3)","description":"For whoever may build in the place (Editor and up, or the operator). An empty `q` answers the kit and « Yours » and asks no library. `library` says whether the free library answered: `ok`, `offline` (a source failed or timed out), `none` (no library on this server).","parameters":[{"schema":{"type":"string","maxLength":200},"required":false,"name":"q","in":"query"},{"schema":{"type":"string"},"required":false,"name":"worldId","in":"query"}],"responses":{"200":{"description":"Tiles, in the order rule of sources/addSearch.ts","content":{"application/json":{"schema":{"type":"object","properties":{"tiles":{"type":"array","items":{"$ref":"#/components/schemas/AddTile"}},"library":{"type":"string","enum":["ok","offline","none"]}},"required":["tiles","library"]}}}},"403":{"description":"Not allowed to build here","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceError"}}}}}}},"/world/sources":{"get":{"tags":["sources"],"summary":"The registered sources of things (IX-2, operator only)","responses":{"200":{"description":"Registered sources","content":{"application/json":{"schema":{"type":"object","properties":{"sources":{"type":"array","items":{"$ref":"#/components/schemas/RegisteredSource"}}},"required":["sources"]}}}},"403":{"description":"Not the operator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceError"}}}}}},"post":{"tags":["sources"],"summary":"Register a source by its manifest URL (IX-2, operator only)","description":"Reads the manifest (sources.md §3) with the given bearer token, checks it, and registers it under its own id. The token stays in this process, never in a response.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"manifestUrl":{"type":"string","format":"uri"},"token":{"type":"string","minLength":1}},"required":["manifestUrl"]}}}},"responses":{"200":{"description":"Registered","content":{"application/json":{"schema":{"type":"object","properties":{"source":{"$ref":"#/components/schemas/RegisteredSource"}},"required":["source"]}}}},"403":{"description":"Not the operator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceError"}}}},"422":{"description":"The manifest could not be read or is not one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceError"}}}}}}},"/world/sources/search":{"get":{"tags":["sources"],"summary":"Five candidates across the registered sources (IX-2 find_asset, operator only)","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"required":true,"name":"q","in":"query"},{"schema":{"type":"string","enum":["object","look","place","agent"]},"required":false,"name":"kind","in":"query"},{"schema":{"type":"integer","exclusiveMinimum":0},"required":false,"name":"maxTris","in":"query"}],"responses":{"200":{"description":"Candidates, best first","content":{"application/json":{"schema":{"type":"object","properties":{"candidates":{"type":"array","items":{"$ref":"#/components/schemas/SourceCandidate"}},"sources":{"type":"number"}},"required":["candidates","sources"]}}}},"403":{"description":"Not the operator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SourceError"}}}}}}},"/world/acts":{"post":{"tags":["acts"],"summary":"An agent's gesture: make, retouch, move, remove, rename, undo, keep, discard (BT-3)","description":"Answers one line said to the agent, read back from this world's log (the asker is whoever said it). The rights gate reads roles and ties (PL-1): someone who may build gets it done; a guest gets what the agent's own right allows (done, a suggestion, or a refusal); a passer-by is refused. Operator token only. Every act writes a `world.act` journal event.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActRequest"}}}},"responses":{"200":{"description":"Done, or proposed (or, with `preview`, what the gate would answer)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ActOk"},{"type":"object","properties":{"preview":{"type":"object","properties":{"standing":{"type":"string"},"askerName":{"type":"string"},"removalNeedsYes":{"type":"boolean"},"outcome":{"type":"string"},"code":{"type":"string"},"reason":{"type":"string"}},"required":["standing","askerName","removalNeedsYes"]}},"required":["preview"]}]}}}},"202":{"description":"Recorded, but the live place did not take it (only with the ordered owner, D58 W2b): it appears when the place next starts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActNotLive"}}}},"403":{"description":"Refused, with its reason (or not the operator)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Nothing written, ask again: the place is full (`world_full`), or changed while the make was written (`build_unchecked`), with the ordered owner only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}}}}},"/world/proposals":{"get":{"tags":["acts"],"summary":"The suggestions waiting in a place (Keep or Undo)","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Pending suggestions, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"proposals":{"type":"array","items":{"$ref":"#/components/schemas/ProposalView"}}},"required":["proposals"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/proposals/{id}/keep":{"post":{"tags":["acts"],"summary":"Keep a suggestion (someone who can build here)","parameters":[{"schema":{"type":"string","description":"Suggestion id (`Proposed.id`)"},"required":true,"description":"Suggestion id (`Proposed.id`)","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Decided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActOk"}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Refused, with its reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"No such suggestion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}}}}},"/world/proposals/{id}/undo":{"post":{"tags":["acts"],"summary":"Undo a suggestion (someone who can build here, or who asked for it)","parameters":[{"schema":{"type":"string","description":"Suggestion id (`Proposed.id`)"},"required":true,"description":"Suggestion id (`Proposed.id`)","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Decided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActOk"}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Refused, with its reason","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"No such suggestion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}}}}},"/world/things/{id}/about":{"get":{"tags":["assets"],"summary":"« About this » on a thing: where its files come from, who made them, their licence, who added them (AS-0)","description":"For everyone who may be in the place (D37). A private place answers its own people only. Names, never identifiers. A thing with no file answers an empty list.","parameters":[{"schema":{"type":"string","description":"Live entity id"},"required":true,"description":"Live entity id","name":"id","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"The record of each file the thing carries","content":{"application/json":{"schema":{"type":"object","properties":{"thing":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"}},"required":["id","name"]},"files":{"type":"array","items":{"type":"object","properties":{"asset":{"$ref":"#/components/schemas/AssetView"},"copy":{"$ref":"#/components/schemas/AssetCopy"}},"required":["asset","copy"]}}},"required":["thing","files"]}}}},"403":{"description":"A private place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World or thing not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Records off (no persistence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/credits":{"get":{"tags":["assets"],"summary":"The Credits of a place: every file in it, who made it, its licence, who added it (AS-0)","description":"Kept by the machine, not by the owner's goodwill (assets.md §2). A person's additions and an agent's are credited alike (D64). A removed file is not credited.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"The credits","content":{"application/json":{"schema":{"type":"object","properties":{"place":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"]},"entries":{"type":"array","items":{"type":"object","properties":{"asset":{"$ref":"#/components/schemas/AssetView"},"copies":{"type":"number"},"addedBy":{"type":"array","items":{"$ref":"#/components/schemas/CreditedBeing"}}},"required":["asset","copies","addedBy"]}}},"required":["place","entries"]}}}},"403":{"description":"A private place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Records off (no persistence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/audience":{"put":{"tags":["assets"],"summary":"Change who may come to a place (private / unlisted / public) and what its link gives, by its Owner (D58, UI-9)","description":"A place that holds a private asset cannot become public: refused with `holds_private_asset` and the asset named. The change is written in one transaction that re-reads the files the place holds (D58 lot S2).","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"audience":{"type":"string","enum":["private","unlisted","public"],"description":"Who may come: private, unlisted (anyone with the link) or public (listed)."},"defaultLinkRole":{"type":"string","enum":["none","viewer","participant","editor"],"description":"Lot UI-9: what the link gives a visitor with no row (none locks it, editor opens building)."}}}}}},"responses":{"200":{"description":"Changed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"audience":{"type":"string"},"visibility":{"type":"string"},"defaultLinkRole":{"type":"string"}},"required":["ok","audience","visibility","defaultLinkRole"]}}}},"403":{"description":"Not the Owner; AUTH-3: provisional_unlisted, an unclaimed provisional place stays unlisted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Refused by D58","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"501":{"description":"Records off (no persistence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"D58 lot S2: `audience_unchecked`, the policy or the files the place holds could not be read in one transaction (a concurrent change, a live world that moved); nothing written, try again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}}}}},"/assets/{id}/availability":{"put":{"tags":["assets"],"summary":"Make an asset public or private (its owner, D58)","description":"Private: it goes only into invite-only or link-only places, by its owner or a borrower. Refused while a public place holds it (`asset_in_public_place`).","parameters":[{"schema":{"type":"string","description":"Asset id (`ast_...`)"},"required":true,"description":"Asset id (`ast_...`)","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"availability":{"type":"string","enum":["public","private"]}},"required":["availability"]}}}},"responses":{"200":{"description":"Changed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"availability":{"type":"string"}},"required":["ok","availability"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not the owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"Asset not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Refused by D58","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"501":{"description":"Records off (no persistence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"A holding place could not be checked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/assets/{id}/loans":{"post":{"tags":["assets"],"summary":"Lend a private asset to someone, who may then place it (its owner, D58)","parameters":[{"schema":{"type":"string","description":"Asset id (`ast_...`)"},"required":true,"description":"Asset id (`ast_...`)","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"borrowerStableId":{"type":"string","minLength":1}},"required":["borrowerStableId"]}}}},"responses":{"201":{"description":"Lent","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not the owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"Asset not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Records off (no persistence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/assets/{id}/loans/{borrowerStableId}":{"delete":{"tags":["assets"],"summary":"Take a loan back (its owner). Copies already placed stay; new ones are refused.","parameters":[{"schema":{"type":"string","description":"Asset id (`ast_...`)"},"required":true,"description":"Asset id (`ast_...`)","name":"id","in":"path"},{"schema":{"type":"string"},"required":true,"name":"borrowerStableId","in":"path"}],"responses":{"200":{"description":"Taken back","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"removed":{"type":"boolean"}},"required":["ok","removed"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Not the owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"Asset not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Records off (no persistence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/assets/{id}/copies":{"get":{"tags":["assets"],"summary":"Every copy of a file, in every place (operator): what a removal by fingerprint reaches","parameters":[{"schema":{"type":"string","description":"Asset id (`ast_...`)"},"required":true,"description":"Asset id (`ast_...`)","name":"id","in":"path"}],"responses":{"200":{"description":"The record and its copies","content":{"application/json":{"schema":{"type":"object","properties":{"asset":{"$ref":"#/components/schemas/AssetView"},"copies":{"type":"array","items":{"type":"object","properties":{"worldId":{"type":"string"},"stableId":{"type":"string"},"field":{"type":"string"},"removed":{"type":"boolean"}},"required":["worldId","stableId","field","removed"]}}},"required":["asset","copies"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Asset not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Records off (no persistence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/worlds/{id}/claim":{"get":{"tags":["worlds"],"summary":"What a provisional place is, for its claim page (AUTH-3)","parameters":[{"schema":{"type":"string","description":"The provisional place"},"required":true,"description":"The provisional place","name":"id","in":"path"},{"schema":{"type":"string","description":"The secret of the claim_url"},"required":false,"description":"The secret of the claim_url","name":"token","in":"query"}],"responses":{"200":{"description":"The place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalClaimView"}}}},"404":{"description":"No provisional place behind this link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalRefusal"}}}},"410":{"description":"It was not kept in time and is gone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalRefusal"}}}}}},"post":{"tags":["worlds"],"summary":"Keep a provisional place: the caller's kami.bot account becomes its Owner (AUTH-3)","description":"Requires an account session or a vouched agent key with world:create, plus the claim secret. Atomic: one claim wins. The account becomes Owner, the expiry is removed and the place stays unlisted until its person lists it.","parameters":[{"schema":{"type":"string","description":"The provisional place"},"required":true,"description":"The provisional place","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"]}}}},"responses":{"200":{"description":"Kept","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"kept":{"type":"boolean","enum":[true]},"visibility":{"type":"string"}},"required":["id","title","kept","visibility"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalRefusal"}}}},"403":{"description":"No account, the account may not add now, or its place limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalRefusal"}}}},"404":{"description":"No provisional place behind this link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalRefusal"}}}},"409":{"description":"Someone already kept it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalRefusal"}}}},"410":{"description":"It was not kept in time and is gone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvisionalRefusal"}}}},"501":{"description":"Places need persistence","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/worlds/provisional/sweep":{"post":{"tags":["worlds"],"summary":"Run the sweep of unclaimed provisional places now (operator, AUTH-3)","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"asOf":{"type":"number","description":"Sweep as if it were this time (ms). The operator may already delete any place."}}}}}},"responses":{"200":{"description":"Swept","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"array","items":{"type":"string"}},"skipped":{"type":"array","items":{"type":"string"}}},"required":["deleted","skipped"]}}}},"403":{"description":"Operator token required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"501":{"description":"No sweeper (no persistence)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/places/templates":{"get":{"tags":["places"],"summary":"The starting places a new place is made from (UI-9)","responses":{"200":{"description":"The templates, in the picker's order, and the per-account limit","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"$ref":"#/components/schemas/PlaceTemplate"}},"limit":{"type":"number"}},"required":["templates","limit"]}}}}}}},"/places":{"post":{"tags":["places"],"summary":"Make a place from a template, from the app (UI-9, D12: an account is required)","description":"Requires an account session or a vouched agent key with world:create. An agent creates for its voucher account; listing a place requires a person. The account becomes the place's Owner. Residents are not made here: the daemon brings each agent, checking it is the caller's and writing its tie (D22).","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePlaceBody"}}}},"responses":{"201":{"description":"Made","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"template":{"type":"string"},"visibility":{"type":"string"},"coOwnerInvite":{"type":["string","null"],"description":"The one-use Owner invite code, when asked."},"made":{"type":"number","description":"Places this account has made, this one included."},"limit":{"type":"number"}},"required":["id","title","template","visibility","coOwnerInvite","made","limit"]}}}},"400":{"description":"A bad name, address or template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceRefusal"}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceRefusal"}}}},"403":{"description":"No account (D12), the limit reached, or the account may not add now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceRefusal"}}}},"409":{"description":"The address is taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceRefusal"}}}},"501":{"description":"Places need persistence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceRefusal"}}}},"503":{"description":"The agent issuer is unavailable or not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceRefusal"}}}}}}},"/places/mine":{"get":{"tags":["places"],"summary":"« Your places »: the places your account made, owns or has a tie to (UI-9)","responses":{"200":{"description":"Your places, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"places":{"type":"array","items":{"$ref":"#/components/schemas/MyPlace"}},"made":{"type":"number"},"limit":{"type":"number"},"account":{"type":"boolean","description":"False for a session with no account: it has no places to list."}},"required":["places","made","limit","account"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceRefusal"}}}},"501":{"description":"Places need persistence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceRefusal"}}}}}}},"/world/people":{"get":{"tags":["places"],"summary":"The people of a place: here now, its ties, its owners and, for the place side, its members (UI-11)","description":"Names, never identifiers, except to the place side and for your own rows. A pending invitation is listed to the place side and to the being side only; who lives here, even away, follows the door's rule (a stranger reads it on a listed public place only); a private place answers 403 to someone with no role there.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"The people of the place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlacePeople"}}}},"403":{"description":"A private place, and you have no role there","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeopleRefusal"}}}},"404":{"description":"No such place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeopleRefusal"}}}}}}},"/world/place":{"put":{"tags":["places"],"summary":"Rename a place, say whether agents can drop by (UI-11, D25) or whether everyone present may share a screen (AS-5), by its Owner","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"The place's new name."},"agentsCanDropBy":{"type":"boolean","description":"D25: may an agent with no tie come in by itself (never in a private place)."},"screenShareOpen":{"type":"boolean","description":"AS-5: may everyone present share a screen on a share Screen (false: editors only). Never an edit right."}}}}}},"responses":{"200":{"description":"Changed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"name":{"type":"string"},"agentsCanDropBy":{"type":"boolean"},"screenShareOpen":{"type":"boolean"}},"required":["ok","name","agentsCanDropBy","screenShareOpen"]}}}},"400":{"description":"A bad name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeopleRefusal"}}}},"403":{"description":"Not an Owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeopleRefusal"}}}},"404":{"description":"No such place (a first-party world is the operator's)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeopleRefusal"}}}},"501":{"description":"Places need persistence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PeopleRefusal"}}}}}}},"/world/blueprints":{"post":{"tags":["blueprints"],"summary":"Save a reusable entity group template","description":"Blueprint entities can reference each other via parentId. Upserts if name exists.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","pattern":"^[a-zA-Z0-9_-]{1,128}$","description":"Unique blueprint name (alphanumeric, _, -)","example":"low-poly-tree"},"description":{"type":"string","description":"Human-readable description"},"entities":{"type":"array","items":{"$ref":"#/components/schemas/BlueprintEntity"}}},"required":["name","entities"]}}}},"responses":{"201":{"description":"Blueprint saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"400":{"description":"Invalid blueprint (bad name, cycle, duplicate label, unknown parentId, too large)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Builder token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["blueprints"],"summary":"List all blueprints for this world","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Blueprint list","content":{"application/json":{"schema":{"type":"object","properties":{"blueprints":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"entityCount":{"type":"number"}},"required":["name","description","entityCount"]}}},"required":["blueprints"]}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/blueprints/{name}":{"get":{"tags":["blueprints"],"summary":"Get a blueprint by name","parameters":[{"schema":{"type":"string"},"required":true,"name":"name","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Blueprint detail","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"entities":{"type":"array","items":{"$ref":"#/components/schemas/BlueprintEntity"}}},"required":["name","description","entities"]}}}},"404":{"description":"Blueprint not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["blueprints"],"summary":"Delete a blueprint","parameters":[{"schema":{"type":"string"},"required":true,"name":"name","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Blueprint deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"403":{"description":"Builder token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Blueprint not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/blueprints/{name}/place":{"post":{"tags":["blueprints"],"summary":"Place one or more instances of a blueprint in the world","description":"Each placement creates all entities from the blueprint template with optional position/scale/overrides.","parameters":[{"schema":{"type":"string"},"required":true,"name":"name","in":"path"},{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"placements":{"type":"array","items":{"$ref":"#/components/schemas/BlueprintPlacement"},"description":"Array of placements"}},"required":["placements"]}}}},"responses":{"201":{"description":"Entities placed","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"placed":{"type":"number"},"entities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"stableId":{"type":"string"},"label":{"type":"string"}},"required":["id","stableId","label"]}},"skipped":{"type":"array","items":{"$ref":"#/components/schemas/SkippedPlacement"},"description":"Placements that could not be applied and why"}},"required":["ok","placed","entities","skipped"]}}}},"202":{"description":"D58 W2g, ordered owner on: the placements are recorded (durable) but the live place moved meanwhile, so they are not shown yet; they appear when the place next starts. `entities` lists what reached the live place. `reason` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlaceBlueprintRecordedResponse"}}}},"403":{"description":"Builder token required; (ordered owner on) a file this place may not hold once the route had checked it, `« reason (placement i) »` with its code, nothing written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Blueprint or world not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"(ordered owner on) a placement the owner refused, nothing written (`Blueprint place conflict at placement i`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"(ordered owner on) the place changed or could not be checked while placing, nothing written, try again (`build_unchecked`); the place filled up (`World is full`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/events/stream":{"get":{"tags":["events"],"summary":"Server-Sent Events — real-time stream of world events","description":"Live tail of every row appended to the durable event log, plus a few engine-level niceties (`entity.created`, `entity.destroyed`, `action`).\n\nFilters (`type` glob, `sender`, `near`+`radius`, `since`) apply **only to the durable `event` frames** — the engine-level niceties are always forwarded so subscribers don't miss lifecycle transitions. Matching is done in-memory before each `event` frame is written.\n\nUse with EventSource or `curl -N`. Connection-time filter errors return 400 instead of opening the stream.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"},{"schema":{"type":"string","description":"Exact type or glob (`chat.*`, `action:*`).","example":"chat.*"},"required":false,"description":"Exact type or glob (`chat.*`, `action:*`).","name":"type","in":"query"},{"schema":{"type":"string","description":"Source stableId."},"required":false,"description":"Source stableId.","name":"sender","in":"query"},{"schema":{"type":"string","description":"Spatial filter centre \"x,y,z\". Events without a position are excluded when set.","example":"0,0,0"},"required":false,"description":"Spatial filter centre \"x,y,z\". Events without a position are excluded when set.","name":"near","in":"query"},{"schema":{"type":"string","description":"Spatial filter radius in metres (default 15).","example":"20"},"required":false,"description":"Spatial filter radius in metres (default 15).","name":"radius","in":"query"},{"schema":{"type":"string","description":"Unix ms; only forward events strictly newer than this."},"required":false,"description":"Unix ms; only forward events strictly newer than this.","name":"since","in":"query"}],"responses":{"200":{"description":"SSE stream (text/event-stream)"},"400":{"description":"Malformed subscription filter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/presence":{"get":{"tags":["world"],"summary":"Who is in a world right now - counts and display names, before joining (the world door)","description":"Read-only and rate-limited per IP. Agents and visitors whose controller is connected, agents first. Never returns a session id, a label or a position. A private world answers only its members (403 otherwise); public and unlisted worlds answer whoever has the link.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Presence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorldPresence"}}}},"403":{"description":"A private world, and the caller is not a member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/stats":{"get":{"tags":["world"],"summary":"World statistics — entity count, component distribution, bounds","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"World statistics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorldStats"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/reset":{"post":{"tags":["world"],"summary":"Reset world to template — drop all overlays","description":"Deletes all DB overlays for this world. Takes effect on next server restart.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Overlays dropped","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"dropped":{"type":"number"}},"required":["ok","dropped"]}}}},"403":{"description":"Builder token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/export":{"get":{"tags":["world"],"summary":"Export current world state as WorldDef JSON","description":"Returns every entity with all public components. Can be saved as .json and loaded as a new world.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Exported world","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorldExport"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/diff":{"get":{"tags":["world"],"summary":"Show overlay diff vs template","description":"Returns all entity overrides: created, updated, and deleted entities.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Overlay diff","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorldDiff"}}}},"403":{"description":"A private world, and the caller is not a member (the audience gate of GET /world/presence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/undo":{"post":{"tags":["world"],"summary":"Undo your most recent composition edit","description":"Replays the captured inverse of the calling session's most recent edit as a NEW durable edit (append-only - the world stays consistent + multiplayer-safe). The undo stack is per-session. Requires a Bearer session with the editing right of the place, read at the gesture; without it, a session may still undo an act an agent did FOR it (POST /world/acts), under the acts' rights (an account and a relation to the place), never a gesture of its own hand.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Edit undone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndoResult"}}}},"202":{"description":"D58 W2h, ordered owner on (an editor or the operator token): recorded (durable), but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UndoRecorded"}}}},"401":{"description":"Session required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Editor role required, read at the gesture (builder token, or a session with Editor+ access to this world): an editor demoted since cannot undo a gesture of their hand; without it, only an act an agent did for this session, by a guest of the place. With the ordered owner on (D58 W2h), a right lost before the write (`edit_right_refused`), a standing refusal, or a file this place may not hold; nothing written, the entry stays next","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Nothing to undo / world not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The edit can no longer be cleanly undone (the entity changed)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"D58 W2h, ordered owner on: the place changed while the edit was being made, or cannot be checked now; nothing written, the entry stays next on the stack, try again (`build_unchecked`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/redo":{"post":{"tags":["world"],"summary":"Redo the edit you last undid","description":"Re-applies the forward of the calling session's most recently undone edit as a NEW durable edit. The redo stack is cleared by any fresh edit. Requires a Bearer session with the editing right of the place, read at the gesture; without it, a session may still redo an act an agent did for it while that agent still builds freely for it.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"responses":{"200":{"description":"Edit redone","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedoResult"}}}},"202":{"description":"D58 W2h, ordered owner on (an editor or the operator token): recorded (durable), but the live place moved meanwhile, so it is not shown yet; it appears when the place next starts. `reason` says why.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedoRecorded"}}}},"401":{"description":"Session required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Editor role required, read at the gesture (builder token, or a session with Editor+ access to this world; without it, only an act an agent did for this session, while that agent still builds freely for it), or AS-0 (D58): the file it would put back is one this place may not hold. With the ordered owner on (D58 W2h), also a right lost before the write (`edit_right_refused`); nothing written, the entry stays next","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refusal"}}}},"404":{"description":"Nothing to redo / world not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The edit can no longer be cleanly redone (the entity changed)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"D58 W2h, ordered owner on: the place changed while the edit was being made, or cannot be checked now; nothing written, the entry stays next on the stack, try again (`build_unchecked`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/sessions":{"post":{"tags":["sessions"],"summary":"Create a session (anonymous, or claim a stableId with builder auth)","description":"Issues a JWT bound to a `{worldId, entityStableId}` pair. The token must be presented as `Authorization: Bearer <token>` on every authenticated request so the server can attribute the caller.\n\n- If `stableId` is omitted → a fresh `anon-…` id is minted (anonymous session, `isAnonymous: true`). **Open to any caller.**\n- If `stableId` is provided → **requires the builder token.** This is the operator path for impersonation / bootstrapping; untrusted callers cannot claim arbitrary identities. Claims collide-protected against world-def entities (e.g. NPCs).\n\nThe backing `sessions` row is revocable: revoking it makes the JWT unusable immediately.","parameters":[{"schema":{"type":"string","description":"World instance ID (default: first world)","example":"spacepod"},"required":false,"description":"World instance ID (default: first world)","name":"worldId","in":"query"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSessionBody"}}}},"responses":{"201":{"description":"Session created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionBundle"}}}},"403":{"description":"Claiming a stableId requires builder auth","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"World not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"stableId collides with an existing world-def entity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/sessions/me":{"get":{"tags":["sessions"],"summary":"Inspect the current session","description":"Requires a valid Bearer JWT. Returns the session row plus the resolved `entityStableId`.","responses":{"200":{"description":"Current session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"401":{"description":"Missing or invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/sessions/refresh":{"post":{"tags":["sessions"],"summary":"Rotate an old session for a new one","description":"Accepts an expired JWT (signature-only check) as long as its original `iat` is within the 30-day refresh window. Returns a fresh JWT and revokes the old session with reason `\"refreshed\"`.\n\nSessions revoked for any other reason (logout, admin, compromise) cannot be refreshed — 401 is returned.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshSessionBody"}}}},"responses":{"200":{"description":"Rotated session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionBundle"}}}},"401":{"description":"Token cannot be refreshed (malformed, expired beyond the refresh window, revoked, or racing another refresh)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/sessions/revoke":{"post":{"tags":["sessions"],"summary":"Revoke the current session (logout)","description":"Requires a valid Bearer JWT. Flips `revokedAt` on the backing row so the token is rejected on the next request.","responses":{"200":{"description":"Session revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ok"}}}},"401":{"description":"Missing or invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"501":{"description":"Persistence not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/world/standing/me":{"get":{"tags":["standing"],"summary":"« Your standing »: the state, the two counters, the history with reasons and expiry (OC-2)","responses":{"200":{"description":"The caller's standing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Standing"}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off (no persistence)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/accounts/{account}":{"get":{"tags":["standing"],"summary":"An account's standing (operator: the moderators' view)","parameters":[{"schema":{"type":"string"},"required":true,"name":"account","in":"path"}],"responses":{"200":{"description":"The standing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Standing"}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/marks/{id}/appeal":{"post":{"tags":["standing"],"summary":"Appeal a warning or a strike: a different person than the one who decided reviews it (§4.2)","parameters":[{"schema":{"type":"string","description":"Mark id"},"required":true,"description":"Mark id","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"statement":{"type":"string","minLength":1,"maxLength":2000}},"required":["statement"]}}}},"responses":{"201":{"description":"Filed","content":{"application/json":{"schema":{"type":"object","properties":{"appeal":{"type":"object","properties":{"id":{"type":"number"},"status":{"type":"string"}},"required":["id","status"]}},"required":["appeal"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"403":{"description":"Not your mark","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"404":{"description":"Mark not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"409":{"description":"Already appealed, or no longer counting","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/marks/{id}/counter-notice":{"post":{"tags":["standing"],"summary":"Counter-notice on a copyright mark: the thing returns unless the claimant goes to court in time (§4.1)","parameters":[{"schema":{"type":"string","description":"Mark id"},"required":true,"description":"Mark id","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CounterNoticeBody"}}}},"responses":{"201":{"description":"Filed","content":{"application/json":{"schema":{"type":"object","properties":{"counterNotice":{"type":"object","properties":{"id":{"type":"number"},"status":{"type":"string"},"restoreAfter":{"type":"number"}},"required":["id","status","restoreAfter"]}},"required":["counterNotice"]}}}},"400":{"description":"The signature must be the name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"403":{"description":"Not your mark","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"404":{"description":"Mark not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"409":{"description":"Not a copyright mark, or already filed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/appeals":{"get":{"tags":["standing"],"summary":"The open appeals (operator: the moderators' queue)","responses":{"200":{"description":"Open appeals, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"appeals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"markId":{"type":"number"},"account":{"type":"string"},"statement":{"type":"string"},"filedAt":{"type":"number"},"decidedBy":{"type":"string"},"reason":{"type":"string"}},"required":["id","markId","account","statement","filedAt","decidedBy","reason"]}}},"required":["appeals"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/appeals/{id}/review":{"post":{"tags":["standing"],"summary":"Review an appeal (a person other than the one who decided): grant erases the mark and brings the thing back","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["grant","deny"]},"reviewer":{"type":"string","minLength":1,"maxLength":200,"description":"The person reviewing. Must differ from the one who decided the mark."}},"required":["decision","reviewer"]}}}},"responses":{"200":{"description":"Reviewed","content":{"application/json":{"schema":{"type":"object","properties":{"appeal":{"type":"object","properties":{"id":{"type":"number"},"status":{"type":"string"}},"required":["id","status"]},"state":{"type":"string"},"restored":{"type":"boolean"}},"required":["appeal","state","restored"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"404":{"description":"Appeal not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"409":{"description":"Same person who decided, or already reviewed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/counter-notices":{"get":{"tags":["standing"],"summary":"The pending counter-notices, with the ones whose waiting time is over (operator)","responses":{"200":{"description":"Pending, soonest first","content":{"application/json":{"schema":{"type":"object","properties":{"counterNotices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"markId":{"type":"number"},"account":{"type":"string"},"fullName":{"type":"string"},"statement":{"type":"string"},"filedAt":{"type":"number"},"restoreAfter":{"type":"number"},"due":{"type":"boolean"}},"required":["id","markId","account","fullName","statement","filedAt","restoreAfter","due"]}}},"required":["counterNotices"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/counter-notices/{id}/resolve":{"post":{"tags":["standing"],"summary":"Resolve a counter-notice: restore (only once its waiting time is over) or the claimant went to court","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["restore","court_filed"]},"moderator":{"type":"string","minLength":1,"maxLength":200}},"required":["outcome","moderator"]}}}},"responses":{"200":{"description":"Resolved","content":{"application/json":{"schema":{"type":"object","properties":{"counterNotice":{"type":"object","properties":{"id":{"type":"number"},"status":{"type":"string"}},"required":["id","status"]},"restored":{"type":"boolean"}},"required":["counterNotice","restored"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"409":{"description":"Too early, or already resolved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/accounts/{account}/close":{"post":{"tags":["standing"],"summary":"Close an account for the floor (§4.3): off the scale, decided by a person (operator)","parameters":[{"schema":{"type":"string"},"required":true,"name":"account","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"moderator":{"type":"string","minLength":1,"maxLength":200},"note":{"type":"string","maxLength":2000}},"required":["moderator"]}}}},"responses":{"200":{"description":"Closed","content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string"}},"required":["state"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/standing/links":{"post":{"tags":["standing"],"summary":"Tie a world account to its verified e-mail (operator attests it); a closed e-mail closes it (§3)","description":"Only a hash of the e-mail is kept. The attesting caller (the daemon after a kami.bot sign-in) is the operator.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"accountStableId":{"type":"string","minLength":1},"email":{"type":"string","format":"email"}},"required":["accountStableId","email"]}}}},"responses":{"200":{"description":"Linked","content":{"application/json":{"schema":{"type":"object","properties":{"closed":{"type":"boolean"}},"required":["closed"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Standing off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/world/sessions/account":{"post":{"tags":["standing"],"summary":"Tie this world session to the kami.bot account it signed in with (D12): adding needs it","description":"Kami World's server sends the visitor's kami.bot session; this server checks it with the daemon itself (`GET /api/me`) and never takes an account id from the client. Several sessions of one account share one standing. The account's verified e-mail (only a hash is kept) is checked against the closed ones: a closed e-mail closes it (§3).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"kamiSession":{"type":"string","minLength":1,"maxLength":4096}},"required":["kamiSession"]}}}},"responses":{"200":{"description":"Linked","content":{"application/json":{"schema":{"type":"object","properties":{"account":{"type":"string"},"closed":{"type":"boolean"}},"required":["account","closed"]}}}},"401":{"description":"No world session, or the kami.bot session is not a signed-in person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Accounts cannot be verified here (no persistence or no daemon configured)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"503":{"description":"The daemon never answered (unreachable or timed out, retried once): code `daemon_unreachable`, the session may well be signed in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/claims/things":{"get":{"tags":["claims"],"summary":"The things in a place that carry a file, for the claim form to pick from","parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"worldId","in":"query"}],"responses":{"200":{"description":"The place and its things","content":{"application/json":{"schema":{"type":"object","properties":{"place":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}},"required":["id","title"]},"things":{"type":"array","items":{"type":"object","properties":{"stableId":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["model","image","video","sound"]}},"required":["stableId","name","kind"]}}},"required":["place","things"]}}}},"404":{"description":"No such place","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/claims":{"post":{"tags":["claims"],"summary":"File a copyright claim (the public form, §4.1): a rights holder needs no account","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CopyrightClaimBody"}}}},"responses":{"201":{"description":"Filed","content":{"application/json":{"schema":{"type":"object","properties":{"claim":{"type":"object","properties":{"id":{"type":"number"},"status":{"type":"string"}},"required":["id","status"]}},"required":["claim"]}}}},"400":{"description":"The thing is not in that place, or the signature is not the name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"404":{"description":"Place not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"429":{"description":"Too many claims from this address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Claims off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}},"get":{"tags":["claims"],"summary":"The open copyright claims (operator)","responses":{"200":{"description":"Open claims, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"claims":{"type":"array","items":{"$ref":"#/components/schemas/CopyrightClaimView"}}},"required":["claims"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Claims off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/claims/{id}/decide":{"post":{"tags":["claims"],"summary":"Decide a claim (a person): remove takes the thing and its copies down and posts a copyright mark on whoever added it","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["remove","dismiss"]},"moderator":{"type":"string","minLength":1,"maxLength":200}},"required":["decision","moderator"]}}}},"responses":{"200":{"description":"Decided","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"alreadyDecided":{"type":"boolean"},"strike":{"type":"object","properties":{"posted":{"type":"boolean"},"account":{"type":["string","null"]},"kind":{"type":["string","null"]},"state":{"type":["string","null"]}},"required":["posted","account","kind","state"]}},"required":["status","alreadyDecided"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"404":{"description":"Claim or thing not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"409":{"description":"Cannot remove the thing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Claims off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/claims/{id}/retract":{"post":{"tags":["claims"],"summary":"The claimant retracts (recorded by a person): the mark is erased and the thing comes back","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"moderator":{"type":"string","minLength":1,"maxLength":200}},"required":["moderator"]}}}},"responses":{"200":{"description":"Retracted","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"restored":{"type":"boolean"}},"required":["status","restored"]}}}},"403":{"description":"Operator only","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"404":{"description":"Claim not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}},"501":{"description":"Claims off","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandingError"}}}}}}},"/me/looks/from-photo":{"post":{"tags":["Looks"],"summary":"Start making your look from a photo of you (OP-2, off unless WORLD_LOOKS_FROM_PHOTO)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"photo":{"type":"string","description":"The photo itself, as a `data:image/...;base64,` URL. A link is refused."},"key":{"type":"string","pattern":"^[A-Za-z0-9._:-]{8,128}$","description":"Idempotency key: the same key never starts a second job."},"style":{"type":"string","maxLength":64},"prompt":{"type":"string","maxLength":500}},"required":["photo","key"]}}}},"responses":{"202":{"description":"The job, accepted","content":{"application/json":{"schema":{"type":"object","properties":{"job":{"$ref":"#/components/schemas/LookJob"}},"required":["job"]}}}},"400":{"description":"Not a photo you sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}},"403":{"description":"A Kami account is required (`account_required`), or this account made all the looks it gets (`looks_quota_reached`)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}},"409":{"description":"This key already started another job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}},"413":{"description":"Photo too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}},"502":{"description":"The maker did not answer; retry with the same key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}}}}},"/me/looks/jobs/{id}":{"get":{"tags":["Looks"],"summary":"Your look job, moved forward by this read","parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"The job","content":{"application/json":{"schema":{"type":"object","properties":{"job":{"$ref":"#/components/schemas/LookJob"}},"required":["job"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}},"403":{"description":"A Kami account is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}},"404":{"description":"No such job of yours","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}}}}},"/me/looks":{"get":{"tags":["Looks"],"summary":"« Yours »: the looks you made from a photo, newest first, as `look.set` takes them","responses":{"200":{"description":"Your looks","content":{"application/json":{"schema":{"type":"object","properties":{"looks":{"type":"array","items":{"$ref":"#/components/schemas/MadeLookRef"}}},"required":["looks"]}}}},"401":{"description":"A session is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}},"403":{"description":"A Kami account is required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookJobError"}}}}}}}},"webhooks":{}}