{"openapi":"3.1.0","info":{"title":"POST /api/v1/dashboards/{dashboard_id}/versions/{version_id}/restore","version":"1.0.0","description":"Restore a dashboard version"},"servers":[{"url":"https://api.ondayzero.com","description":"Production"}],"paths":{"/api/v1/dashboards/{dashboard_id}/versions/{version_id}/restore":{"post":{"tags":["dashboards"],"summary":"Restore a dashboard version","description":"Roll the dashboard back to a stored version. The version's spec is re-validated against the current schema first (a 400 means the version predates an incompatible schema change), and the state being overwritten is saved as a new version first — so the restore itself is undoable via `undo_version_number`.","operationId":"restore_dashboard_version_api_v1_dashboards__dashboard_id__versions__version_id__restore_post","parameters":[{"name":"dashboard_id","in":"path","required":true,"schema":{"type":"string","title":"Dashboard Id"}},{"name":"version_id","in":"path","required":true,"schema":{"type":"string","title":"Version Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}},{"name":"x-business-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Business-Id"}}],"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessEnvelope_RestoreVersionResponse_"}}}},"400":{"description":"Bad Request - Invalid input","content":{"application/json":{"example":{"detail":"Invalid request parameters"}}}},"401":{"description":"Unauthorized - Authentication required","content":{"application/json":{"example":{"detail":"Not authenticated"}}}},"403":{"description":"Forbidden - Insufficient permissions","content":{"application/json":{"example":{"detail":"Not enough permissions"}}}},"404":{"description":"Not Found - Resource does not exist","content":{"application/json":{"example":{"detail":"Resource not found"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"ChartWidget":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","maxLength":200,"title":"Title"},"layout":{"$ref":"#/components/schemas/WidgetLayout"},"source":{"anyOf":[{"$ref":"#/components/schemas/WidgetSource"},{"type":"null"}]},"snapshot":{"$ref":"#/components/schemas/WidgetSnapshot"},"last_refresh_error":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Last Refresh Error"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"},"widget_type":{"type":"string","const":"chart","title":"Widget Type","default":"chart"}},"additionalProperties":false,"type":"object","required":["id","title","snapshot"],"title":"ChartWidget"},"DashboardSpec":{"properties":{"version":{"type":"integer","const":1,"title":"Version","default":1},"id":{"type":"string","title":"Id"},"title":{"type":"string","maxLength":200,"title":"Title"},"description":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Description"},"visibility":{"type":"string","enum":["private","assigned","business"],"title":"Visibility","default":"private"},"widgets":{"items":{"oneOf":[{"$ref":"#/components/schemas/ChartWidget"},{"$ref":"#/components/schemas/TableWidget"},{"$ref":"#/components/schemas/MetricWidget"},{"$ref":"#/components/schemas/GaugeWidget"},{"$ref":"#/components/schemas/TimelineWidget"},{"$ref":"#/components/schemas/TextWidget"}],"discriminator":{"propertyName":"widget_type","mapping":{"chart":"#/components/schemas/ChartWidget","gauge":"#/components/schemas/GaugeWidget","metric":"#/components/schemas/MetricWidget","table":"#/components/schemas/TableWidget","text":"#/components/schemas/TextWidget","timeline":"#/components/schemas/TimelineWidget"}}},"type":"array","maxItems":24,"title":"Widgets"},"assigned_user_ids":{"items":{"type":"string"},"type":"array","title":"Assigned User Ids"},"created_by_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created By User Id"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"}},"additionalProperties":false,"type":"object","required":["id","title","created_at"],"title":"DashboardSpec","description":"The full dashboard payload — exactly what the FE renderer consumes."},"GaugeWidget":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","maxLength":200,"title":"Title"},"layout":{"$ref":"#/components/schemas/WidgetLayout"},"source":{"anyOf":[{"$ref":"#/components/schemas/WidgetSource"},{"type":"null"}]},"snapshot":{"$ref":"#/components/schemas/WidgetSnapshot"},"last_refresh_error":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Last Refresh Error"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"},"widget_type":{"type":"string","const":"gauge","title":"Widget Type","default":"gauge"}},"additionalProperties":false,"type":"object","required":["id","title","snapshot"],"title":"GaugeWidget","description":"A linear meter showing a single value against a min/max range."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"MetricWidget":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","maxLength":200,"title":"Title"},"layout":{"$ref":"#/components/schemas/WidgetLayout"},"source":{"anyOf":[{"$ref":"#/components/schemas/WidgetSource"},{"type":"null"}]},"snapshot":{"$ref":"#/components/schemas/WidgetSnapshot"},"last_refresh_error":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Last Refresh Error"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"},"widget_type":{"type":"string","const":"metric","title":"Widget Type","default":"metric"}},"additionalProperties":false,"type":"object","required":["id","title","snapshot"],"title":"MetricWidget","description":"A single headline number (e.g. cash on hand, total AR)."},"RestoreVersionResponse":{"properties":{"dashboard":{"$ref":"#/components/schemas/DashboardSpec"},"restored_from_version_number":{"type":"integer","title":"Restored From Version Number"},"undo_version_number":{"type":"integer","title":"Undo Version Number"}},"additionalProperties":false,"type":"object","required":["dashboard","restored_from_version_number","undo_version_number"],"title":"RestoreVersionResponse","description":"Result of restoring a version.\n\n``undo_version_number`` is the pre-restore snapshot written before the\ndashboard was mutated — surfacing it is what makes a mis-click recoverable\nwithout leaving the panel."},"SuccessEnvelope_RestoreVersionResponse_":{"properties":{"success":{"type":"boolean","title":"Success","default":true},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message"},"code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"},"data":{"anyOf":[{"$ref":"#/components/schemas/RestoreVersionResponse"},{"type":"null"}]}},"additionalProperties":true,"type":"object","title":"SuccessEnvelope[RestoreVersionResponse]"},"TableWidget":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","maxLength":200,"title":"Title"},"layout":{"$ref":"#/components/schemas/WidgetLayout"},"source":{"anyOf":[{"$ref":"#/components/schemas/WidgetSource"},{"type":"null"}]},"snapshot":{"$ref":"#/components/schemas/WidgetSnapshot"},"last_refresh_error":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Last Refresh Error"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"},"widget_type":{"type":"string","const":"table","title":"Widget Type","default":"table"}},"additionalProperties":false,"type":"object","required":["id","title","snapshot"],"title":"TableWidget"},"TextWidget":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","maxLength":200,"title":"Title"},"layout":{"$ref":"#/components/schemas/WidgetLayout"},"source":{"anyOf":[{"$ref":"#/components/schemas/WidgetSource"},{"type":"null"}]},"snapshot":{"anyOf":[{"$ref":"#/components/schemas/WidgetSnapshot"},{"type":"null"}]},"last_refresh_error":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Last Refresh Error"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"},"widget_type":{"type":"string","const":"text","title":"Widget Type","default":"text"},"body":{"type":"string","maxLength":8000,"title":"Body","default":""}},"additionalProperties":false,"type":"object","required":["id","title"],"title":"TextWidget","description":"Free-form markdown note; has no data snapshot requirement."},"TimelineWidget":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","maxLength":200,"title":"Title"},"layout":{"$ref":"#/components/schemas/WidgetLayout"},"source":{"anyOf":[{"$ref":"#/components/schemas/WidgetSource"},{"type":"null"}]},"snapshot":{"$ref":"#/components/schemas/WidgetSnapshot"},"last_refresh_error":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Last Refresh Error"},"last_refreshed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Refreshed At"},"widget_type":{"type":"string","const":"timeline","title":"Widget Type","default":"timeline"}},"additionalProperties":false,"type":"object","required":["id","title","snapshot"],"title":"TimelineWidget","description":"Chronological event list with status indicators."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"WidgetLayout":{"properties":{"x":{"type":"integer","maximum":11.0,"minimum":0.0,"title":"X","default":0},"y":{"type":"integer","maximum":999.0,"minimum":0.0,"title":"Y","default":0},"w":{"type":"integer","maximum":12.0,"minimum":1.0,"title":"W","default":6},"h":{"type":"integer","maximum":12.0,"minimum":1.0,"title":"H","default":4}},"additionalProperties":false,"type":"object","title":"WidgetLayout","description":"Position on a 12-column grid."},"WidgetSnapshot":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data"},"ui_hint":{"type":"string","maxLength":60,"minLength":1,"title":"Ui Hint"},"captured_at":{"type":"string","format":"date-time","title":"Captured At"}},"type":"object","required":["data","ui_hint","captured_at"],"title":"WidgetSnapshot","description":"The captured chat payload the widget renders from.\n\n``data`` is intentionally open-shaped (chat payloads vary per tool), so no\n``extra=\"forbid\"`` here — only the size guard applies."},"WidgetSource":{"properties":{"tool_name":{"type":"string","maxLength":120,"minLength":1,"title":"Tool Name"},"params":{"additionalProperties":true,"type":"object","title":"Params"},"refreshable":{"type":"boolean","title":"Refreshable","default":true},"scope":{"type":"string","enum":["business","firm"],"title":"Scope","default":"business"},"firm_business_ids":{"items":{"type":"string"},"type":"array","maxItems":500,"title":"Firm Business Ids"}},"additionalProperties":false,"type":"object","required":["tool_name"],"title":"WidgetSource","description":"The READ tool invocation that can re-produce this widget's data.\n\n``scope`` records the breadth the widget was *created* at. A\n``\"business\"`` widget resolves against the dashboard's own business; a\n``\"firm\"`` widget aggregates across ``firm_business_ids`` — the client\nbusinesses the creator could reach at capture time.\n\n``firm_business_ids`` is a security input, not a display field: at\nview/refresh time it is intersected against the *current* viewer's firm\naccess so a widget can never keep surfacing a client the viewer has since\nlost access to. It is deliberately stored on the widget (rather than\nre-derived) so a shrinking firm roster narrows the widget instead of\nsilently re-broadening it."}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Token","description":"API token authentication. Format: `Bearer dz_...`"}}},"security":[{"BearerAuth":[]}]}