{"openapi": "3.1.0", "info": {"title": "ST IT Phone Mockups", "version": "1.1.0", "description": "Create immutable hosted live 3D phone mockups. No authentication. Content is accessible to anyone with its URL. 60 creations/hour/IP; 256 KiB JSON body. Live embeds and asynchronous PNG/WebP exports. Exports fetch public HTTPS resources in an isolated renderer, without authentication or writes."}, "servers": [{"url": "https://mockups.sandbox.stit.tech"}], "paths": {"/api/v1/mockups": {"post": {"operationId": "createMockup", "summary": "Save a mockup and get preview URL and embed HTML", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Mockup"}}}}, "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Result"}}}}, "400": {"description": "Invalid config"}, "413": {"description": "Body exceeds 256 KiB"}, "415": {"description": "Use application/json"}, "429": {"description": "60 creations/hour/IP exceeded"}, "507": {"description": "Service storage capacity reached"}}}}, "/api/v1/mockups/{id}": {"get": {"operationId": "getMockup", "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string", "pattern": "^[a-f0-9]{32}$"}}], "responses": {"200": {"description": "Result fields plus normalized config", "content": {"application/json": {"schema": {"allOf": [{"$ref": "#/components/schemas/Result"}, {"type": "object", "properties": {"config": {"$ref": "#/components/schemas/Mockup"}}}]}}}}, "404": {"description": "Not found"}}}}, "/api/v1/mockups/{id}/exports": {"post": {"operationId": "exportMockup", "summary": "Create or reuse a PNG and WebP snapshot job", "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExportOptions"}}}}, "responses": {"202": {"description": "Rendering: poll statusUrl", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExportJob"}}}}, "200": {"description": "Cached export ready", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExportJob"}}}}, "400": {"description": "Invalid options"}, "404": {"description": "Mockup not found"}, "429": {"description": "20 new exports/hour/IP exceeded"}, "503": {"description": "Renderer busy: retry later"}, "507": {"description": "500 export storage limit reached"}}}}, "/api/v1/exports/{id}": {"get": {"operationId": "getExport", "summary": "Poll an export until ready or failed", "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "responses": {"200": {"description": "Export status; image URLs appear when ready", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ExportJob"}}}}, "404": {"description": "Export not found"}}}}}, "components": {"schemas": {"Mockup": {"type": "object", "additionalProperties": false, "required": ["screen"], "properties": {"device": {"type": "string", "enum": ["iphone-18-pro"], "default": "iphone-18-pro"}, "finish": {"type": "string", "enum": ["silver", "black", "glacier", "burgundy"], "default": "silver"}, "rotation": {"type": "object", "additionalProperties": false, "properties": {"x": {"type": "number", "minimum": -36000, "maximum": 36000}, "y": {"type": "number", "minimum": -36000, "maximum": 36000}, "z": {"type": "number", "minimum": -36000, "maximum": 36000}}, "default": {"x": -6, "y": -20, "z": -4}}, "background": {"type": "string", "pattern": "^(transparent|#[0-9a-fA-F]{6})$", "default": "transparent"}, "interactive": {"type": "boolean", "default": true, "description": "true: interact with screen; false: drag phone freely"}, "screenPadding": {"type": "boolean", "default": true, "description": "52px top and 17px bottom within 402×874 logical screen"}, "screen": {"oneOf": [{"type": "object", "additionalProperties": false, "required": ["type", "url"], "properties": {"type": {"type": "string", "enum": ["url", "image"]}, "url": {"type": "string", "format": "uri", "pattern": "^https://", "maxLength": 8192}}}, {"type": "object", "additionalProperties": false, "required": ["type", "html"], "properties": {"type": {"const": "html"}, "html": {"type": "string", "minLength": 1}, "css": {"type": "string", "default": ""}}}]}}}, "Result": {"type": "object", "required": ["id", "previewUrl", "configUrl", "contentUrl", "embedHtml"], "properties": {"id": {"type": "string"}, "previewUrl": {"type": "string"}, "configUrl": {"type": "string"}, "contentUrl": {"type": "string"}, "embedHtml": {"type": "string"}, "exportEndpoint": {"type": "string", "format": "uri"}}}, "ExportOptions": {"type": "object", "additionalProperties": false, "properties": {"width": {"type": "integer", "minimum": 320, "maximum": 2400, "default": 1200}, "height": {"type": "integer", "minimum": 320, "maximum": 2400, "default": 1520}, "waitMs": {"type": "integer", "minimum": 0, "maximum": 10000, "default": 1000}, "refresh": {"type": "boolean", "default": false}}, "description": "Maximum 4 million pixels. Identical options reuse a pending/ready export. refresh creates a new snapshot of mutable content."}, "ExportJob": {"type": "object", "required": ["id", "status", "statusUrl", "mockupId"], "properties": {"id": {"type": "string"}, "mockupId": {"type": "string"}, "status": {"type": "string", "enum": ["pending", "ready", "failed"]}, "statusUrl": {"type": "string", "format": "uri"}, "pngUrl": {"type": "string", "format": "uri"}, "webpUrl": {"type": "string", "format": "uri"}, "warnings": {"type": "array", "items": {"type": "string"}}, "error": {"type": "string"}, "width": {"type": "integer"}, "height": {"type": "integer"}, "waitMs": {"type": "integer"}}}}}}