{"openapi":"3.1.0","info":{"title":"Virtuaaa","version":"1.0","description":"Virtuaaa turns 360° panoramas into 3D virtual tours. These tools act on the tours of the connected Virtuaaa account.\nHow tours work: each tour has panoramas (points of view). The engine computes where each panorama is from the photos;\npanoramas it could connect form groups. A good assembly is one group, no doubtful link, every panorama placed.\n\nFixing an assembly (the most common request):\n- Diagnose: get_links (groups, doubtful links, panoramas not placed) and view_plan (top view, one colour per group).\n- Two groups showing the same room: same_room with the panoramas of both groups. The engine measures and places; if it\n  finds no reliable match, the groups are not in the same room or overlap too little.\n- Two groups joined by a door, corridor or stairs: find the two panoramas on each side (compare_panoramas), then\n  link_panoramas. Without a photo measure the placement is estimated: check view_plan and undo if it looks wrong.\n- Doubtful link (red on the plan): compare_panoramas; if they are not the same space and do not see each other,\n  unlink_panoramas.\n- After several changes, recompute_positions, then check again.\nRules: link only what you can see in the images; a wrong link is worse than a missing one. When unsure, ask the user.\nYou never give coordinates: the engine computes positions. Every link change can be undone with undo_last_link_change.\nPanorama ids look like vx_<tour>_07; the short number (7 or 07) is accepted too.\nAsk the user before removing panoramas or starting an assembly. Publishing to Google and payments are done by the user in\nthe Virtuaaa app, not here.\nCreate an API key at https://app.virtuaaa.com/ia/."},"servers":[{"url":"https://app.virtuaaa.com"}],"paths":{"/ia/api/list_tours":{"post":{"operationId":"list_tours","summary":"List the tours of the connected Virtuaaa account (id, title, state, number of panoramas, paid or not).","description":"List the tours of the connected Virtuaaa account (id, title, state, number of panoramas, paid or not).","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{},"title":"list_toursArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/get_tour":{"post":{"operationId":"get_tour","summary":"Details of one tour: panoramas with their names, groups, start panorama, links and links to open it in the app.","description":"Details of one tour: panoramas with their names, groups, start panorama, links and links to open it in the app.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"get_tourArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/view_panorama":{"post":{"operationId":"view_panorama","summary":"Look at one panorama (equirectangular JPEG, 1536 x 768): recognise the room, a duplicate, a bad shot.","description":"Look at one panorama (equirectangular JPEG, 1536 x 768): recognise the room, a duplicate, a bad shot.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"panorama":{"title":"Panorama","type":"string"}},"required":["tour_id","panorama"],"title":"view_panoramaArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/tour_status":{"post":{"operationId":"tour_status","summary":"Assembly state of a tour (waiting for panoramas, in assembly, ready, error) and exposure correction state.","description":"Assembly state of a tour (waiting for panoramas, in assembly, ready, error) and exposure correction state.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"tour_statusArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/get_links":{"post":{"operationId":"get_links","summary":"State of the assembly: groups of connected panoramas (one group = the whole tour is connected), links, links the\n    eng","description":"State of the assembly: groups of connected panoramas (one group = the whole tour is connected), links, links the\n    engine finds doubtful (its photo measure disagrees with the positions), panoramas not placed, and the state of a running\n    calculation or same-room search. Start here to diagnose a tour.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"get_linksArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/view_plan":{"post":{"operationId":"view_plan","summary":"Top view of where the engine placed each panorama: one colour per group, links as lines (red = doubtful),\n    panorama n","description":"Top view of where the engine placed each panorama: one colour per group, links as lines (red = doubtful),\n    panorama numbers. Use it to spot a group placed on top of another, a panorama far away, or a missing link.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"view_planArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/compare_panoramas":{"post":{"operationId":"compare_panoramas","summary":"Both panoramas in one image (a above, b below), to judge whether they show the same room, see each other or\n    are conn","description":"Both panoramas in one image (a above, b below), to judge whether they show the same room, see each other or\n    are connected by a door, before linking or unlinking them.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"panorama_a":{"title":"Panorama A","type":"string"},"panorama_b":{"title":"Panorama B","type":"string"}},"required":["tour_id","panorama_a","panorama_b"],"title":"compare_panoramasArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/link_panoramas":{"post":{"operationId":"link_panoramas","summary":"Link two panoramas that see each other or are connected by a door","description":"Link two panoramas that see each other or are connected by a door. The group of panorama_b is then moved as a\n    block next to panorama_a: from the photo measure when the engine has one, otherwise estimated. For two groups in the\n    same room prefer same_room (always measured). Undo with undo_last_link_change.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"panorama_a":{"title":"Panorama A","type":"string"},"panorama_b":{"title":"Panorama B","type":"string"}},"required":["tour_id","panorama_a","panorama_b"],"title":"link_panoramasArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/unlink_panoramas":{"post":{"operationId":"unlink_panoramas","summary":"Remove a wrong link between two panoramas (two different rooms that look alike, a doubtful link you checked with\n    com","description":"Remove a wrong link between two panoramas (two different rooms that look alike, a doubtful link you checked with\n    compare_panoramas).","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"panorama_a":{"title":"Panorama A","type":"string"},"panorama_b":{"title":"Panorama B","type":"string"}},"required":["tour_id","panorama_a","panorama_b"],"title":"unlink_panoramasArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/same_room":{"post":{"operationId":"same_room","summary":"Two groups that show the same room: the engine measures matching points between their panoramas, then links the\n    reli","description":"Two groups that show the same room: the engine measures matching points between their panoramas, then links the\n    reliable pairs and places group_b exactly (nothing is linked if no reliable match is found). Takes from one to a few\n    minutes, 10 searches per hour. Give the panoramas of each group (from get_links).","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"group_a":{"items":{"type":"string"},"title":"Group A","type":"array"},"group_b":{"items":{"type":"string"},"title":"Group B","type":"array"}},"required":["tour_id","group_a","group_b"],"title":"same_roomArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/same_room_result":{"post":{"operationId":"same_room_result","summary":"Result of a same_room search still running: links the reliable pairs it found and places the group.","description":"Result of a same_room search still running: links the reliable pairs it found and places the group.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"same_room_resultArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/recompute_positions":{"post":{"operationId":"recompute_positions","summary":"Recompute all positions from the photos and every link (yours included), like « Recalculate with my links » in\n    the a","description":"Recompute all positions from the photos and every link (yours included), like « Recalculate with my links » in\n    the app. Use after several link changes when the plan still looks wrong. Takes a few minutes; undoable.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"recompute_positionsArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/undo_last_link_change":{"post":{"operationId":"undo_last_link_change","summary":"Undo the last change made to the links of the tour (by you or in the app), placement included.","description":"Undo the last change made to the links of the tour (by you or in the app), placement included.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"undo_last_link_changeArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/rename_tour":{"post":{"operationId":"rename_tour","summary":"Change the title of a tour (list, receipts and title shown in the tour).","description":"Change the title of a tour (list, receipts and title shown in the tour).","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"title":{"title":"Title","type":"string"}},"required":["tour_id","title"],"title":"rename_tourArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/name_panoramas":{"post":{"operationId":"name_panoramas","summary":"Give names to panoramas (shown in the tour menu), for example {\"07\": \"Kitchen\", \"08\": \"Living room\"}.\n    Look at each p","description":"Give names to panoramas (shown in the tour menu), for example {\"07\": \"Kitchen\", \"08\": \"Living room\"}.\n    Look at each panorama with view_panorama before naming it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"names":{"additionalProperties":{"type":"string"},"title":"Names","type":"object"}},"required":["tour_id","names"],"title":"name_panoramasArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/set_start_panorama":{"post":{"operationId":"set_start_panorama","summary":"Choose the panorama where the tour starts","description":"Choose the panorama where the tour starts. The viewing direction can be adjusted afterwards in the editor.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"panorama":{"title":"Panorama","type":"string"}},"required":["tour_id","panorama"],"title":"set_start_panoramaArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/set_panorama_order":{"post":{"operationId":"set_panorama_order","summary":"Order of the panoramas in the tour","description":"Order of the panoramas in the tour. Panoramas not listed keep their place after the listed ones.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"order":{"items":{"type":"string"},"title":"Order","type":"array"}},"required":["tour_id","order"],"title":"set_panorama_orderArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/remove_panoramas":{"post":{"operationId":"remove_panoramas","summary":"Take panoramas out of the tour (bad shot, duplicate)","description":"Take panoramas out of the tour (bad shot, duplicate). Reversible with restore_panoramas. Ask the user first.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"panoramas":{"items":{"type":"string"},"title":"Panoramas","type":"array"}},"required":["tour_id","panoramas"],"title":"remove_panoramasArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/restore_panoramas":{"post":{"operationId":"restore_panoramas","summary":"Put back panoramas that were removed with remove_panoramas (or in the app).","description":"Put back panoramas that were removed with remove_panoramas (or in the app).","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"panoramas":{"items":{"type":"string"},"title":"Panoramas","type":"array"}},"required":["tour_id","panoramas"],"title":"restore_panoramasArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/harmonize_exposure":{"post":{"operationId":"harmonize_exposure","summary":"Even out the brightness of all panoramas of the tour (runs in the background; undo=true restores the originals).","description":"Even out the brightness of all panoramas of the tour (runs in the background; undo=true restores the originals).","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"},"undo":{"default":false,"title":"Undo","type":"boolean"}},"required":["tour_id"],"title":"harmonize_exposureArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/create_tour":{"post":{"operationId":"create_tour","summary":"Create an empty tour","description":"Create an empty tour. Panoramas are then uploaded by a script or the app (see upload_instructions), then\n    start_assembly builds the tour.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"title":{"title":"Title","type":"string"}},"required":["title"],"title":"create_tourArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/upload_instructions":{"post":{"operationId":"upload_instructions","summary":"How to upload panoramas (JPEG equirectangular, up to 50 per tour) to a tour waiting for them","description":"How to upload panoramas (JPEG equirectangular, up to 50 per tour) to a tour waiting for them. Large files do\n    not go through the conversation: a script or Claude Code sends them with an API key.","x-openai-isConsequential":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"upload_instructionsArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}},"/ia/api/start_assembly":{"post":{"operationId":"start_assembly","summary":"Start building a tour once its panoramas are uploaded (counts as one assembly of the account)","description":"Start building a tour once its panoramas are uploaded (counts as one assembly of the account). Ask the user first.","requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"tour_id":{"title":"Tour Id","type":"string"}},"required":["tour_id"],"title":"start_assemblyArguments","type":"object"}}}},"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Refused (message in 'error')"},"401":{"description":"API key missing or removed"}}}}},"components":{"securitySchemes":{"cle":{"type":"http","scheme":"bearer"}}},"security":[{"cle":[]}]}