{
  "components": {
    "schemas": {
      "Breaker": {
        "properties": {
          "actions": {
            "type": "object"
          },
          "cooldown_ms": {
            "default": 0,
            "type": "integer"
          },
          "eval_interval_ms": {
            "type": "integer"
          },
          "half_open_backoff_cap_ms": {
            "type": "integer"
          },
          "half_open_backoff_enabled": {
            "default": true,
            "type": "boolean"
          },
          "half_open_confirmation_ms": {
            "description": "Computed: (steps + 1) * eval_interval_ms",
            "readOnly": true,
            "type": "integer"
          },
          "half_open_indeterminate_policy": {
            "enum": [
              "optimistic",
              "conservative",
              "pessimistic"
            ],
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "description": "Aggregation kind for evaluation",
            "enum": [
              "error_rate",
              "avg",
              "p95",
              "max",
              "min",
              "sum",
              "stddev",
              "count",
              "percentile",
              "consecutive_failures",
              "delta"
            ],
            "type": "string"
          },
          "kind_params": {
            "type": "object"
          },
          "metadata": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "User-defined key/value pairs (string keys and values; max 20 keys; key max 64 chars; value max 255 chars). Tripswitch stores and returns metadata but does not interpret it.",
            "maxProperties": 20,
            "type": "object"
          },
          "metric": {
            "description": "Metric identifier to monitor",
            "type": "string"
          },
          "min_count": {
            "description": "Minimum samples for evaluation",
            "type": "integer"
          },
          "min_state_duration_ms": {
            "default": 60000,
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "op": {
            "description": "Comparison operator",
            "enum": [
              "gt",
              "lt",
              "gte",
              "lte"
            ],
            "type": "string"
          },
          "recovery_allow_rate_ramp_steps": {
            "default": 5,
            "description": "Number of recovery ramp steps. Drives half_open_confirmation_ms and recovery_window_ms.",
            "maximum": 10,
            "minimum": 1,
            "type": "integer"
          },
          "recovery_window_ms": {
            "description": "Computed: steps * eval_interval_ms",
            "readOnly": true,
            "type": "integer"
          },
          "router_id": {
            "format": "uuid",
            "type": "string"
          },
          "threshold": {
            "description": "Threshold value",
            "type": "number"
          },
          "window_ms": {
            "description": "Evaluation window in milliseconds",
            "type": "integer"
          }
        },
        "required": [
          "metric",
          "kind",
          "op",
          "threshold"
        ],
        "type": "object"
      },
      "BreakerEvent": {
        "properties": {
          "agg": {
            "properties": {
              "avg": {
                "type": "number"
              },
              "count": {
                "type": "integer"
              },
              "error_count": {
                "type": "integer"
              },
              "p95": {
                "type": "number"
              }
            },
            "type": "object"
          },
          "breaker_id": {
            "format": "uuid",
            "type": "string"
          },
          "curr": {
            "enum": [
              "closed",
              "open",
              "half_open"
            ],
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "prev": {
            "enum": [
              "closed",
              "open",
              "half_open"
            ],
            "type": "string"
          },
          "rule": {
            "properties": {
              "kind": {
                "type": "string"
              },
              "metric": {
                "type": "string"
              },
              "tags": {
                "type": "object"
              },
              "threshold": {
                "type": "number"
              },
              "window_ms": {
                "type": "integer"
              }
            },
            "type": "object"
          },
          "transition_seq": {
            "type": "integer"
          },
          "ts_ms": {
            "type": "integer"
          }
        },
        "type": "object"
      },
      "BreakerMetadata": {
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "metadata": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "User-defined key/value pairs (string keys and values; max 20 keys; key max 64 chars; value max 255 chars).",
            "maxProperties": 20,
            "type": "object"
          },
          "name": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "BreakerStateBatchItem": {
        "properties": {
          "breaker_id": {
            "format": "uuid",
            "type": "string"
          },
          "evaluated_at_ms": {
            "description": "Unix timestamp (ms) of last evaluation",
            "nullable": true,
            "type": "integer"
          },
          "min_count": {
            "description": "Minimum samples required for evaluation",
            "nullable": true,
            "type": "integer"
          },
          "observed": {
            "description": "Whether breaker has been observed (has samples)",
            "type": "boolean"
          },
          "reason_code": {
            "description": "Why breaker is in current state",
            "enum": [
              "insufficient_samples",
              "threshold_exceeded",
              null
            ],
            "nullable": true,
            "type": "string"
          },
          "sample_count": {
            "description": "Number of samples in current window",
            "nullable": true,
            "type": "integer"
          },
          "state": {
            "description": "Current breaker state",
            "enum": [
              "closed",
              "open",
              "half_open"
            ],
            "type": "string"
          },
          "threshold": {
            "description": "Configured threshold value",
            "type": "number"
          },
          "window_ms": {
            "description": "Evaluation window duration in milliseconds",
            "type": "integer"
          }
        },
        "required": [
          "breaker_id",
          "state",
          "observed",
          "threshold"
        ],
        "type": "object"
      },
      "BreakerStateLookup": {
        "properties": {
          "breaker_id": {
            "format": "uuid",
            "type": "string"
          },
          "indeterminate": {
            "description": "True if evaluation had insufficient data",
            "type": "boolean"
          },
          "indeterminate_reason": {
            "description": "Reason for indeterminate status",
            "enum": [
              "insufficient_samples",
              null
            ],
            "nullable": true,
            "type": "string"
          },
          "last_eval_ms": {
            "description": "Unix timestamp (ms) of last evaluation",
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "next_eval_ms": {
            "description": "Unix timestamp (ms) of next scheduled evaluation",
            "nullable": true,
            "type": "integer"
          },
          "state": {
            "description": "Current breaker state",
            "enum": [
              "closed",
              "open",
              "half_open"
            ],
            "type": "string"
          },
          "state_since_ms": {
            "description": "Unix timestamp (ms) when breaker entered current state",
            "type": "integer"
          }
        },
        "required": [
          "breaker_id",
          "name",
          "state",
          "indeterminate"
        ],
        "type": "object"
      },
      "Error": {
        "properties": {
          "details": {
            "type": "object"
          },
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "MetricSample": {
        "properties": {
          "metric": {
            "description": "Metric name",
            "maxLength": 128,
            "type": "string"
          },
          "ok": {
            "default": true,
            "description": "Success indicator for consecutive_failures",
            "type": "boolean"
          },
          "router_id": {
            "description": "Router to route sample to",
            "format": "uuid",
            "type": "string"
          },
          "tags": {
            "additionalProperties": {
              "type": "string"
            },
            "maxProperties": 32,
            "type": "object"
          },
          "trace_id": {
            "description": "Trace identifier",
            "type": "string"
          },
          "ts_ms": {
            "description": "Unix timestamp in milliseconds",
            "type": "integer"
          },
          "value": {
            "description": "Metric value",
            "type": "number"
          }
        },
        "required": [
          "router_id",
          "metric",
          "ts_ms",
          "value"
        ],
        "type": "object"
      },
      "NotificationChannel": {
        "properties": {
          "channel": {
            "enum": [
              "slack",
              "pagerduty",
              "email",
              "webhook"
            ],
            "type": "string"
          },
          "config": {
            "type": "object"
          },
          "enabled": {
            "default": true,
            "type": "boolean"
          },
          "events": {
            "items": {
              "enum": [
                "trip",
                "recover"
              ],
              "type": "string"
            },
            "type": "array"
          },
          "id": {
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "channel",
          "config"
        ],
        "type": "object"
      },
      "Project": {
        "properties": {
          "enable_signed_ingest": {
            "default": false,
            "type": "boolean"
          },
          "ingest_secret": {
            "description": "Returned on create/rotate only",
            "type": "string"
          },
          "name": {
            "nullable": true,
            "type": "string"
          },
          "project_id": {
            "format": "uuid",
            "type": "string"
          },
          "slack_webhook_url": {
            "nullable": true,
            "type": "string"
          },
          "trace_id_url_template": {
            "nullable": true,
            "type": "string"
          },
          "workspace_id": {
            "description": "Workspace this project belongs to",
            "format": "uuid",
            "type": "string"
          }
        },
        "type": "object"
      },
      "ProjectStatus": {
        "properties": {
          "closed_count": {
            "type": "integer"
          },
          "last_eval_ms": {
            "type": "integer"
          },
          "open_count": {
            "type": "integer"
          }
        },
        "type": "object"
      },
      "Router": {
        "properties": {
          "breakers": {
            "items": {
              "properties": {
                "id": {
                  "format": "uuid",
                  "type": "string"
                },
                "name": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "created_by": {
            "enum": [
              "system",
              "user"
            ],
            "type": "string"
          },
          "enabled": {
            "default": true,
            "type": "boolean"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "metadata": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "User-defined key/value pairs (string keys and values; max 20 keys; key max 64 chars; value max 255 chars). Tripswitch stores and returns metadata but does not interpret it.",
            "maxProperties": 20,
            "type": "object"
          },
          "mode": {
            "default": "static",
            "enum": [
              "static",
              "canary",
              "weighted"
            ],
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "RouterMetadata": {
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "metadata": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "User-defined key/value pairs (string keys and values; max 20 keys; key max 64 chars; value max 255 chars).",
            "maxProperties": 20,
            "type": "object"
          },
          "name": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "Workspace": {
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "slug": {
            "description": "URL-safe identifier",
            "type": "string"
          }
        },
        "required": [
          "name",
          "slug"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "description": "User API key",
        "scheme": "bearer",
        "type": "http"
      },
      "hmacAuth": {
        "description": "HMAC signature for metric ingestion. See signed_ingest docs.",
        "in": "header",
        "name": "X-EB-Signature",
        "type": "apiKey"
      }
    }
  },
  "info": {
    "description": "Circuit breaker and alerting API for Tripswitch.",
    "title": "Tripswitch API",
    "version": "1.0.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/v1/projects": {
      "get": {
        "operationId": "list_projects",
        "parameters": [
          {
            "description": "Filter projects by workspace ID",
            "in": "query",
            "name": "workspace_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "projects": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "List of projects"
          },
          "401": {
            "description": "Missing or invalid API key"
          }
        },
        "summary": "List all projects for the authenticated org",
        "tags": [
          "Projects"
        ]
      },
      "post": {
        "operationId": "post_projects",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "name": {
                    "description": "Human-readable project name",
                    "type": "string"
                  },
                  "workspace_id": {
                    "description": "Workspace to assign the project to",
                    "type": "string"
                  }
                },
                "required": [
                  "workspace_id"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "ingest_secret": {
                      "description": "Secret for HMAC-signed metric ingestion",
                      "type": "string"
                    },
                    "name": {
                      "description": "Project name",
                      "type": "string"
                    },
                    "project_id": {
                      "format": "uuid",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Project created successfully"
          },
          "400": {
            "description": "Invalid request payload"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "422": {
            "description": "Missing required workspace_id"
          }
        },
        "summary": "Create a new project",
        "tags": [
          "Projects"
        ]
      }
    },
    "/v1/projects/{id}": {
      "get": {
        "operationId": "get_projects",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "enable_signed_ingest": {
                      "description": "Whether HMAC-signed ingestion is required",
                      "type": "string"
                    },
                    "name": {
                      "description": "Project name (nullable)",
                      "type": "string"
                    },
                    "project_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "slack_webhook_url": {
                      "description": "Legacy Slack webhook URL (nullable)",
                      "type": "string"
                    },
                    "trace_id_url_template": {
                      "description": "URL template for trace links (nullable)",
                      "type": "string"
                    },
                    "workspace_id": {
                      "format": "uuid",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Project details"
          },
          "404": {
            "description": "Project not found"
          }
        },
        "summary": "Retrieve a project",
        "tags": [
          "Projects"
        ]
      },
      "patch": {
        "operationId": "patch_projects",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "enable_signed_ingest": {
                    "description": "Require HMAC-signed ingestion",
                    "type": "boolean"
                  },
                  "name": {
                    "description": "New project name",
                    "type": "string"
                  },
                  "slack_webhook_url": {
                    "description": "Slack webhook URL for notifications (null to clear)",
                    "type": "string"
                  },
                  "trace_id_url_template": {
                    "description": "URL template for trace links (use {{value}} placeholder)",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "enable_signed_ingest": {
                      "description": "Current setting",
                      "type": "string"
                    },
                    "name": {
                      "description": "Updated name",
                      "type": "string"
                    },
                    "project_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "slack_webhook_url": {
                      "description": "Current webhook URL",
                      "type": "string"
                    },
                    "trace_id_url_template": {
                      "description": "Trace link template (null if unset)",
                      "type": "string"
                    },
                    "workspace_id": {
                      "format": "uuid",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Project updated"
          },
          "404": {
            "description": "Project not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Update project settings",
        "tags": [
          "Projects"
        ]
      }
    },
    "/v1/projects/{id}/ingest_secret/rotate": {
      "post": {
        "operationId": "post_rotate",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "ingest_secret": {
                      "description": "New ingest secret",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Secret rotated"
          },
          "404": {
            "description": "Project not found"
          }
        },
        "summary": "Rotate the project's ingest secret",
        "tags": [
          "Projects"
        ]
      }
    },
    "/v1/projects/{project_id}/breakers": {
      "get": {
        "operationId": "list_breakers",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "breakers": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "hash": {
                      "description": "Content hash for change detection",
                      "type": "string"
                    },
                    "updated_at": {
                      "format": "date-time",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "List of breakers"
          },
          "304": {
            "description": "Not modified (ETag match)"
          }
        },
        "summary": "List all breakers for a project",
        "tags": [
          "Breakers"
        ]
      },
      "post": {
        "operationId": "create_breaker",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "actions": {
                    "description": "Actions to execute on state changes",
                    "type": "object"
                  },
                  "cooldown_ms": {
                    "description": "Minimum time in open before entering half_open",
                    "type": "integer"
                  },
                  "eval_interval_ms": {
                    "description": "Custom evaluation interval. For stable behavior, ensure window_ms >= 3× eval_interval_ms.",
                    "type": "integer"
                  },
                  "half_open_backoff_cap_ms": {
                    "description": "Maximum backoff cap in milliseconds",
                    "type": "integer"
                  },
                  "half_open_backoff_enabled": {
                    "description": "Whether exponential backoff is enabled (default true)",
                    "type": "boolean"
                  },
                  "half_open_indeterminate_policy": {
                    "description": "Policy when data is indeterminate (count < min_count) in half-open: optimistic, conservative (default), or pessimistic",
                    "type": "string"
                  },
                  "id": {
                    "description": "Breaker UUID (server-generated if not provided)",
                    "type": "string"
                  },
                  "kind": {
                    "description": "Breaker kind: error_rate, avg, p95, count, max, min, sum, stddev, percentile, consecutive_failures, delta",
                    "type": "string"
                  },
                  "kind_params": {
                    "description": "Kind-specific configuration. For delta: {delta_of, alpha}. For percentile: {percentile}",
                    "type": "object"
                  },
                  "metadata": {
                    "description": "User-defined key/value pairs (string keys and values; max 20 keys; key max 64 chars; value max 255 chars). Tripswitch stores and returns metadata but does not interpret it.",
                    "type": "object"
                  },
                  "metric": {
                    "description": "Metric to monitor",
                    "type": "string"
                  },
                  "min_count": {
                    "description": "Minimum samples required for evaluation",
                    "type": "integer"
                  },
                  "min_state_duration_ms": {
                    "description": "Minimum time in current state before transition",
                    "type": "integer"
                  },
                  "name": {
                    "description": "Human-readable name",
                    "type": "string"
                  },
                  "op": {
                    "description": "Comparison operator: gt, lt, gte, lte",
                    "type": "string"
                  },
                  "recovery_allow_rate_ramp_steps": {
                    "description": "Number of recovery ramp steps (1-10, default 5). Controls the half-open confirmation and recovery windows: half_open_confirmation_ms = (steps + 1) * eval_interval_ms, recovery_window_ms = steps * eval_interval_ms.",
                    "type": "integer"
                  },
                  "threshold": {
                    "description": "Threshold value to compare against",
                    "type": "number"
                  },
                  "window_ms": {
                    "description": "Evaluation window in milliseconds. Recommended >= 3× eval_interval_ms for stable behavior. Not used by consecutive_failures.",
                    "type": "integer"
                  }
                },
                "required": [
                  "kind",
                  "metric",
                  "op",
                  "threshold"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "breaker": {
                      "description": "Created breaker object",
                      "type": "object"
                    },
                    "router_id": {
                      "format": "uuid",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Breaker created"
          },
          "409": {
            "description": "Breaker with this ID already exists"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Create a single breaker",
        "tags": [
          "Breakers"
        ]
      },
      "put": {
        "operationId": "put_breakers",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "breakers": {
                    "description": "Array of breaker objects to set",
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "required": [
                  "breakers"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "changed": {
                      "description": "Whether the set changed",
                      "type": "string"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "duration_ms": {
                      "description": "Operation duration",
                      "type": "string"
                    },
                    "hash": {
                      "description": "New content hash",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Breakers replaced"
          },
          "409": {
            "description": "Guardrail blocked destructive change"
          },
          "412": {
            "description": "Precondition failed (If-Match header mismatch)"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Replace all breakers (bulk sync)",
        "tags": [
          "Breakers"
        ]
      }
    },
    "/v1/projects/{project_id}/breakers/metadata": {
      "get": {
        "description": "Returns id, name, and metadata for all breakers. Supports ETag/If-None-Match for conditional requests. Also responds to HEAD. Accepts a project API key (eb_pk_) for runtime access.",
        "operationId": "list_breaker_metadata",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "breakers": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "project_id": {
                      "description": "Project ID",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Breaker metadata list. Response includes a weak ETag header for conditional requests."
          },
          "304": {
            "description": "Not Modified (when If-None-Match matches current ETag)"
          }
        },
        "summary": "List metadata for all breakers in a project",
        "tags": [
          "Breaker Metadata"
        ]
      }
    },
    "/v1/projects/{project_id}/breakers/state:batch": {
      "post": {
        "operationId": "post_state_batch",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "breaker_ids": {
                    "description": "Array of breaker UUIDs to look up",
                    "items": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "router_ids": {
                    "description": "Array of router UUIDs (resolves to linked breakers)",
                    "items": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "states": {
                      "items": {
                        "$ref": "#/components/schemas/BreakerStateBatchItem"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Batch state lookup"
          },
          "422": {
            "description": "Validation failed (must provide breaker_ids or router_ids)"
          }
        },
        "summary": "Get current state of multiple breakers",
        "tags": [
          "Breakers"
        ]
      }
    },
    "/v1/projects/{project_id}/breakers/state:stream": {
      "get": {
        "operationId": "get_state_stream",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Server-Sent Events stream",
            "headers": {
              "Cache-Control": {
                "description": "no-cache",
                "schema": {
                  "type": "string"
                }
              },
              "Connection": {
                "description": "keep-alive",
                "schema": {
                  "type": "string"
                }
              },
              "Content-Type": {
                "description": "text/event-stream",
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "summary": "SSE stream of breaker state changes (SDK endpoint)",
        "tags": [
          "Breakers"
        ]
      }
    },
    "/v1/projects/{project_id}/breakers/{breaker_id}": {
      "delete": {
        "operationId": "delete_breaker",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Breaker ID",
            "in": "path",
            "name": "breaker_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Breaker deleted"
          },
          "404": {
            "description": "Breaker not found"
          }
        },
        "summary": "Delete a breaker",
        "tags": [
          "Breakers"
        ]
      },
      "get": {
        "operationId": "get_breaker",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Breaker ID",
            "in": "path",
            "name": "breaker_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "breaker": {
                      "description": "Breaker object",
                      "type": "object"
                    },
                    "router_id": {
                      "format": "uuid",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Breaker details"
          },
          "404": {
            "description": "Breaker not found"
          }
        },
        "summary": "Get a single breaker",
        "tags": [
          "Breakers"
        ]
      },
      "patch": {
        "operationId": "patch_breakers",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Breaker ID",
            "in": "path",
            "name": "breaker_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "actions": {
                    "type": "object"
                  },
                  "cooldown_ms": {
                    "type": "integer"
                  },
                  "eval_interval_ms": {
                    "type": "integer"
                  },
                  "half_open_backoff_cap_ms": {
                    "type": "integer"
                  },
                  "half_open_backoff_enabled": {
                    "type": "boolean"
                  },
                  "half_open_indeterminate_policy": {
                    "type": "string"
                  },
                  "kind": {
                    "type": "string"
                  },
                  "kind_params": {
                    "type": "object"
                  },
                  "metadata": {
                    "description": "User-defined key/value pairs (string keys and values; max 20 keys; key max 64 chars; value max 255 chars). Tripswitch stores and returns metadata but does not interpret it.",
                    "type": "object"
                  },
                  "metric": {
                    "type": "string"
                  },
                  "min_count": {
                    "type": "integer"
                  },
                  "min_state_duration_ms": {
                    "type": "integer"
                  },
                  "name": {
                    "type": "string"
                  },
                  "op": {
                    "type": "string"
                  },
                  "recovery_allow_rate_ramp_steps": {
                    "type": "integer"
                  },
                  "threshold": {
                    "type": "number"
                  },
                  "window_ms": {
                    "type": "integer"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "breaker": {
                      "description": "Updated breaker object",
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Breaker updated"
          },
          "404": {
            "description": "Breaker not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Update a breaker",
        "tags": [
          "Breakers"
        ]
      }
    },
    "/v1/projects/{project_id}/breakers/{breaker_id}/metadata": {
      "patch": {
        "description": "Merges keys into existing metadata. Keys not in the payload are preserved. Set a key to null to remove it. Requires an admin API key (eb_admin_).",
        "operationId": "update_breaker_metadata",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Breaker ID",
            "in": "path",
            "name": "breaker_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "metadata": {
                    "description": "Key/value pairs to merge. String keys and string values; set value to null to delete a key. Max 20 keys after merge; key max 64 chars; value max 255 chars.",
                    "type": "object"
                  }
                },
                "required": [
                  "metadata"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "id": {
                      "description": "Breaker ID",
                      "type": "string"
                    },
                    "metadata": {
                      "description": "Updated metadata object",
                      "type": "object"
                    },
                    "name": {
                      "description": "Breaker name",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Updated breaker metadata"
          },
          "404": {
            "description": "Breaker not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Merge keys into breaker metadata",
        "tags": [
          "Breaker Metadata"
        ]
      }
    },
    "/v1/projects/{project_id}/breakers/{breaker_id}/state": {
      "get": {
        "operationId": "get_state",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Breaker ID",
            "in": "path",
            "name": "breaker_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "breaker_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "indeterminate": {
                      "type": "boolean"
                    },
                    "indeterminate_reason": {
                      "description": "Reason for indeterminate (insufficient_samples or null)",
                      "type": "string"
                    },
                    "last_eval_ms": {
                      "description": "Timestamp of last evaluation",
                      "type": "string"
                    },
                    "name": {
                      "description": "Breaker name",
                      "type": "string"
                    },
                    "next_eval_ms": {
                      "description": "Timestamp of next scheduled evaluation",
                      "type": "string"
                    },
                    "state": {
                      "description": "Current state (closed, open, half_open)",
                      "type": "string"
                    },
                    "state_since_ms": {
                      "description": "Timestamp when breaker entered current state",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Breaker state lookup"
          },
          "404": {
            "description": "Breaker not found"
          }
        },
        "summary": "Get current state of a single breaker",
        "tags": [
          "Breakers"
        ]
      }
    },
    "/v1/projects/{project_id}/events": {
      "get": {
        "operationId": "get_events",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Return events newer than this timestamp",
            "in": "query",
            "name": "since_ms",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "description": "Filter to a specific breaker",
            "in": "query",
            "name": "breaker_id",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Pagination cursor from previous response",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Max events to return (default 50, max 200)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "events": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "next_cursor": {
                      "description": "Cursor for next page (null if no more)",
                      "type": "string"
                    },
                    "returned": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "List of events"
          },
          "400": {
            "description": "Invalid parameter"
          },
          "429": {
            "description": "Rate limited"
          }
        },
        "summary": "List recent breaker state transitions",
        "tags": [
          "Events"
        ]
      }
    },
    "/v1/projects/{project_id}/ingest": {
      "post": {
        "operationId": "post_ingest",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "samples": {
                    "description": "Array of metric samples (or send array directly as body)",
                    "items": {
                      "$ref": "#/components/schemas/MetricSample"
                    },
                    "type": "array"
                  }
                },
                "required": [
                  "samples"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "accepted": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Samples accepted"
          },
          "400": {
            "description": "Invalid payload"
          },
          "401": {
            "description": "Invalid HMAC signature"
          },
          "413": {
            "description": "Batch too large (max 1000 samples)"
          },
          "422": {
            "description": "Validation error (invalid_router_id, invalid_metric, invalid_ts_ms, ts_ms_too_old, ts_ms_in_future, invalid_ok)"
          },
          "429": {
            "description": "Rate limited (check Retry-After header)",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying",
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        },
        "security": [
          {
            "hmacAuth": []
          }
        ],
        "summary": "Ingest metric samples",
        "tags": [
          "Metrics"
        ]
      }
    },
    "/v1/projects/{project_id}/notification-channels": {
      "get": {
        "operationId": "get_notification_channels",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "channels": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "List of channels"
          }
        },
        "summary": "List notification channels",
        "tags": [
          "Notification Channels"
        ]
      },
      "post": {
        "operationId": "post_notification_channels",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "channel": {
                    "description": "Channel type (slack, pagerduty, email, webhook)",
                    "type": "string"
                  },
                  "config": {
                    "description": "Channel-specific configuration",
                    "type": "object"
                  },
                  "enabled": {
                    "description": "Whether channel is active",
                    "type": "boolean"
                  },
                  "events": {
                    "description": "Events to notify on (trip, recover)",
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "required": [
                  "channel",
                  "config"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "channel": {
                      "description": "Created channel object",
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Channel created"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Create a notification channel",
        "tags": [
          "Notification Channels"
        ]
      }
    },
    "/v1/projects/{project_id}/notification-channels/{id}": {
      "delete": {
        "operationId": "delete_notification_channels",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Channel ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Channel deleted"
          },
          "404": {
            "description": "Channel not found"
          }
        },
        "summary": "Delete a notification channel",
        "tags": [
          "Notification Channels"
        ]
      },
      "patch": {
        "operationId": "patch_notification_channels",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Channel ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "config": {
                    "type": "object"
                  },
                  "enabled": {
                    "type": "boolean"
                  },
                  "events": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "channel": {
                      "description": "Updated channel object",
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Channel updated"
          },
          "404": {
            "description": "Channel not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Update a notification channel",
        "tags": [
          "Notification Channels"
        ]
      }
    },
    "/v1/projects/{project_id}/notification-channels/{id}/test": {
      "post": {
        "operationId": "post_test",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Channel ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "message": {
                      "description": "Confirmation message",
                      "type": "string"
                    },
                    "status": {
                      "description": "ok",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Test notification sent"
          },
          "404": {
            "description": "Channel not found"
          },
          "422": {
            "description": "Send failed"
          }
        },
        "summary": "Send a test notification",
        "tags": [
          "Notification Channels"
        ]
      }
    },
    "/v1/projects/{project_id}/routers": {
      "get": {
        "operationId": "list_routers",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "routers": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "List of routers with breaker counts"
          }
        },
        "summary": "List all routers for a project",
        "tags": [
          "Routers"
        ]
      },
      "post": {
        "operationId": "post_routers",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "breaker_ids": {
                    "description": "Breaker IDs to link on creation",
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "metadata": {
                    "description": "User-defined key/value pairs (string keys and values; max 20 keys; key max 64 chars; value max 255 chars). Tripswitch stores and returns metadata but does not interpret it.",
                    "type": "object"
                  },
                  "mode": {
                    "description": "Routing mode: static (default), canary, or weighted",
                    "type": "string"
                  },
                  "name": {
                    "description": "Human-readable router name",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "router": {
                      "description": "Created router object with linked breakers",
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Router created"
          },
          "404": {
            "description": "Project or breaker not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Create a new router",
        "tags": [
          "Routers"
        ]
      }
    },
    "/v1/projects/{project_id}/routers/metadata": {
      "get": {
        "description": "Returns id, name, and metadata for all routers. Supports ETag/If-None-Match for conditional requests. Also responds to HEAD. Accepts a project API key (eb_pk_) for runtime access.",
        "operationId": "list_router_metadata",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "project_id": {
                      "description": "Project ID",
                      "type": "string"
                    },
                    "routers": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Router metadata list. Response includes a weak ETag header for conditional requests."
          },
          "304": {
            "description": "Not Modified (when If-None-Match matches current ETag)"
          }
        },
        "summary": "List metadata for all routers in a project",
        "tags": [
          "Router Metadata"
        ]
      }
    },
    "/v1/projects/{project_id}/routers/{router_id}": {
      "delete": {
        "operationId": "delete_routers",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Router ID",
            "in": "path",
            "name": "router_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Router deleted"
          },
          "404": {
            "description": "Router not found"
          },
          "409": {
            "description": "Router has linked breakers (unlink them first)"
          }
        },
        "summary": "Delete a router (must unlink breakers first)",
        "tags": [
          "Routers"
        ]
      },
      "get": {
        "operationId": "get_router",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Router ID",
            "in": "path",
            "name": "router_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "router": {
                      "description": "Router object with breakers array",
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Router details with linked breakers"
          },
          "404": {
            "description": "Router not found"
          }
        },
        "summary": "Retrieve a router with linked breakers",
        "tags": [
          "Routers"
        ]
      },
      "patch": {
        "operationId": "patch_routers",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Router ID",
            "in": "path",
            "name": "router_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "enabled": {
                    "description": "Enable or disable routing",
                    "type": "boolean"
                  },
                  "metadata": {
                    "description": "User-defined key/value pairs (string keys and values; max 20 keys; key max 64 chars; value max 255 chars). Tripswitch stores and returns metadata but does not interpret it.",
                    "type": "object"
                  },
                  "mode": {
                    "description": "Routing mode: static, canary, or weighted",
                    "type": "string"
                  },
                  "name": {
                    "description": "New router name",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "router": {
                      "description": "Updated router object",
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Router updated"
          },
          "404": {
            "description": "Router not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Update router properties",
        "tags": [
          "Routers"
        ]
      }
    },
    "/v1/projects/{project_id}/routers/{router_id}/breakers": {
      "post": {
        "operationId": "link_breakers",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Router ID",
            "in": "path",
            "name": "router_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "breaker_ids": {
                    "description": "Breaker IDs to link",
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "required": [
                  "breaker_ids"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "router": {
                      "description": "Updated router with all linked breakers",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Breakers linked"
          },
          "404": {
            "description": "Router or breaker not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Link breakers to a router",
        "tags": [
          "Routers"
        ]
      }
    },
    "/v1/projects/{project_id}/routers/{router_id}/breakers/{breaker_id}": {
      "delete": {
        "operationId": "unlink_breaker",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Router ID",
            "in": "path",
            "name": "router_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Breaker ID to unlink",
            "in": "path",
            "name": "breaker_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Breaker unlinked"
          },
          "404": {
            "description": "Router or breaker not found"
          }
        },
        "summary": "Unlink a breaker from a router",
        "tags": [
          "Routers"
        ]
      }
    },
    "/v1/projects/{project_id}/routers/{router_id}/metadata": {
      "patch": {
        "description": "Merges keys into existing metadata. Keys not in the payload are preserved. Set a key to null to remove it. Requires an admin API key (eb_admin_).",
        "operationId": "update_router_metadata",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Router ID",
            "in": "path",
            "name": "router_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "metadata": {
                    "description": "Key/value pairs to merge. String keys and string values; set value to null to delete a key. Max 20 keys after merge; key max 64 chars; value max 255 chars.",
                    "type": "object"
                  }
                },
                "required": [
                  "metadata"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "id": {
                      "description": "Router ID",
                      "type": "string"
                    },
                    "metadata": {
                      "description": "Updated metadata object",
                      "type": "object"
                    },
                    "name": {
                      "description": "Router name",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Updated router metadata"
          },
          "404": {
            "description": "Router not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Merge keys into router metadata",
        "tags": [
          "Router Metadata"
        ]
      }
    },
    "/v1/projects/{project_id}/status": {
      "get": {
        "operationId": "get_status",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "closed_count": {
                      "type": "integer"
                    },
                    "last_eval_ms": {
                      "description": "Timestamp of last evaluation",
                      "type": "string"
                    },
                    "open_count": {
                      "type": "integer"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Project status"
          },
          "304": {
            "description": "Not modified (ETag match)"
          }
        },
        "summary": "Get project health status",
        "tags": [
          "Status"
        ]
      },
      "head": {
        "operationId": "head_status",
        "parameters": [
          {
            "description": "Project ID",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status check (headers only)",
            "headers": {
              "ETag": {
                "description": "Weak ETag for conditional requests",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "304": {
            "description": "Not modified (ETag match)"
          }
        },
        "summary": "Check project status (headers only, no body)",
        "tags": [
          "Status"
        ]
      }
    },
    "/v1/workspaces": {
      "get": {
        "operationId": "list_workspaces",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "workspaces": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "List of workspaces"
          },
          "401": {
            "description": "Missing or invalid API key"
          }
        },
        "summary": "List all workspaces for the authenticated org",
        "tags": [
          "Workspaces"
        ]
      },
      "post": {
        "operationId": "post_workspaces",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "name": {
                    "description": "Human-readable workspace name",
                    "type": "string"
                  },
                  "slug": {
                    "description": "URL-safe identifier (lowercase, hyphens allowed)",
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "slug"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "inserted_at": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "name": {
                      "description": "Workspace name",
                      "type": "string"
                    },
                    "org_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "slug": {
                      "description": "Workspace slug",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Workspace created successfully"
          },
          "400": {
            "description": "Invalid request payload"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "422": {
            "description": "Validation failed (e.g. duplicate slug)"
          }
        },
        "summary": "Create a new workspace",
        "tags": [
          "Workspaces"
        ]
      }
    },
    "/v1/workspaces/{id}": {
      "delete": {
        "operationId": "delete_workspaces",
        "parameters": [
          {
            "description": "Workspace ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Workspace deleted"
          },
          "404": {
            "description": "Workspace not found"
          }
        },
        "summary": "Delete a workspace",
        "tags": [
          "Workspaces"
        ]
      },
      "get": {
        "operationId": "get_workspaces",
        "parameters": [
          {
            "description": "Workspace ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "inserted_at": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "name": {
                      "description": "Workspace name",
                      "type": "string"
                    },
                    "org_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "slug": {
                      "description": "Workspace slug",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Workspace details"
          },
          "404": {
            "description": "Workspace not found"
          }
        },
        "summary": "Retrieve a workspace",
        "tags": [
          "Workspaces"
        ]
      },
      "patch": {
        "operationId": "patch_workspaces",
        "parameters": [
          {
            "description": "Workspace ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "name": {
                    "description": "New workspace name",
                    "type": "string"
                  },
                  "slug": {
                    "description": "New URL-safe slug",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "inserted_at": {
                      "format": "date-time",
                      "type": "string"
                    },
                    "name": {
                      "description": "Updated name",
                      "type": "string"
                    },
                    "org_id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "slug": {
                      "description": "Updated slug",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Workspace updated"
          },
          "404": {
            "description": "Workspace not found"
          },
          "422": {
            "description": "Validation failed"
          }
        },
        "summary": "Update a workspace",
        "tags": [
          "Workspaces"
        ]
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "servers": [
    {
      "description": "Production",
      "url": "https://api.tripswitch.dev"
    },
    {
      "description": "Local development",
      "url": "http://localhost:4009"
    }
  ]
}