{
  "openapi": "3.1.0",
  "info": {
    "title": "WKT Studio REST API",
    "version": "1.0.0",
    "description": "Programmatically read and write geographic features in your WKT Studio projects. All responses are GeoJSON or JSON. Requires a Pro plan API key.",
    "contact": {
      "name": "WKT Studio",
      "url": "https://wktstudio.com"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    { "url": "https://wktstudio.com", "description": "Production" }
  ],
  "security": [{ "bearerAuth": [] }],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API Key",
        "description": "Your WKT Studio API key. Generate one at https://wktstudio.com/settings under API Keys."
      }
    },
    "schemas": {
      "GeoJSONGeometry": {
        "type": "object",
        "description": "A GeoJSON geometry object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["Point","LineString","Polygon","MultiPoint","MultiLineString","MultiPolygon","GeometryCollection"]
          },
          "coordinates": { "type": "array" }
        },
        "required": ["type"]
      },
      "Feature": {
        "type": "object",
        "properties": {
          "type": { "type": "string", "enum": ["Feature"] },
          "geometry": { "$ref": "#/components/schemas/GeoJSONGeometry" },
          "properties": { "type": "object", "nullable": true }
        },
        "required": ["type", "geometry"]
      },
      "FeatureCollection": {
        "type": "object",
        "properties": {
          "type": { "type": "string", "enum": ["FeatureCollection"] },
          "features": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Feature" }
          }
        },
        "required": ["type", "features"]
      },
      "FeaturesListResponse": {
        "type": "object",
        "properties": {
          "type": { "type": "string", "enum": ["FeatureCollection"] },
          "features": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/Feature" }
          },
          "meta": {
            "type": "object",
            "properties": {
              "total": { "type": "integer" },
              "limit": { "type": "integer" },
              "offset": { "type": "integer" },
              "hasMore": { "type": "boolean" },
              "projectId": { "type": "string" },
              "projectName": { "type": "string" }
            },
            "required": ["total", "limit", "offset", "hasMore", "projectId", "projectName"]
          }
        },
        "required": ["type", "features", "meta"]
      },
      "LayerMetadata": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "visible": { "type": "boolean" }
        },
        "required": ["id", "name", "visible"]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": { "type": "string" }
        }
      }
    }
  },
  "paths": {
    "/api/v1/projects/{projectId}/features": {
      "parameters": [
        {
          "name": "projectId",
          "in": "path",
          "required": true,
          "schema": { "type": "string" },
          "description": "The ID of the project"
        }
      ],
      "get": {
        "summary": "List features",
        "description": "Returns features from all layers in the project as a GeoJSON FeatureCollection with meta data.",
        "operationId": "listFeatures",
        "tags": ["Features"],
        "parameters": [
          {
            "name": "layer",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Filter results to a single layer by ID"
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Filter results by name case-insensitive substring match"
          },
          {
            "name": "bbox",
            "in": "query",
            "required": false,
            "schema": { "type": "string" },
            "description": "Geographic bounding box filter: minLng,minLat,maxLng,maxLat"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": { "type": "integer" },
            "description": "Max results per page. Default 100, max 1000."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": { "type": "integer" },
            "description": "Pagination offset. Default 0."
          }
        ],
        "responses": {
          "200": {
            "description": "A GeoJSON FeatureCollection with metadata",
            "headers": {
              "X-Rate-Limit-Remaining": {
                "schema": { "type": "integer" },
                "description": "API calls remaining this month"
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/FeaturesListResponse" },
                "example": {
                  "type": "FeatureCollection",
                  "features": [
                    {
                      "type": "Feature",
                      "id": "feature_abc123",
                      "geometry": {
                        "type": "Polygon",
                        "coordinates": [[[-77.03,-12.04],[-77.02,-12.04],[-77.02,-12.03],[-77.03,-12.03],[-77.03,-12.04]]]
                      },
                      "properties": {
                        "name": "Zone A",
                        "color": "#6366f1",
                        "_layerId": "layer_1",
                        "_layerName": "Capa 1",
                        "_wkt": "POLYGON((-77.03 -12.04, -77.02 -12.04, -77.02 -12.03, -77.03 -12.03, -77.03 -12.04))"
                      }
                    }
                  ],
                  "meta": {
                    "total": 1,
                    "limit": 100,
                    "offset": 0,
                    "hasMore": false,
                    "projectId": "abc123",
                    "projectName": "My Logistics Project"
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "403": { "description": "API access requires a Pro plan", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "404": { "description": "Project not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Monthly API limit reached", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      },
      "post": {
        "summary": "Add features",
        "description": "Adds GeoJSON Features to a specific layer in the project.",
        "operationId": "addFeatures",
        "tags": ["Features"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["layerId", "features"],
                "properties": {
                  "layerId": { "type": "string", "description": "The layer to add the features to" },
                  "features": {
                    "type": "array",
                    "items": { "$ref": "#/components/schemas/Feature" },
                    "description": "An array of GeoJSON Features to add"
                  }
                }
              },
              "example": {
                "layerId": "layer_1",
                "features": [
                  {
                    "type": "Feature",
                    "geometry": { "type": "Point", "coordinates": [-77.03, -12.04] },
                    "properties": { 
                      "name": "My point",
                      "color": "#ff5733"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Features added successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "added": { "type": "integer" },
                    "total": { "type": "integer" },
                    "featureIds": {
                      "type": "array",
                      "items": { "type": "string" }
                    }
                  }
                },
                "example": {
                  "added": 1,
                  "total": 5,
                  "featureIds": ["fid_1234567890abcdef"]
                }
              }
            }
          },
          "400": { "description": "Invalid JSON or parameter shape", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "401": { "description": "Missing or invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "422": { "description": "Limit exceeded", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "429": { "description": "Monthly API limit reached", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      },
      "delete": {
        "summary": "Delete a feature",
        "description": "Removes a feature from a layer by id or index (deprecated).",
        "operationId": "deleteFeature",
        "tags": ["Features"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["layerId"],
                "properties": {
                  "layerId": { "type": "string" },
                  "featureId": { "type": "string", "description": "Firestore document ID of the feature to delete (recommended)" },
                  "featureIndex": { "type": "integer", "description": "Zero-based index of the feature to delete (deprecated; use featureId)" }
                }
              },
              "example": {
                "layerId": "layer_1",
                "featureId": "fid_1234567890abcdef"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feature deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": { "type": "boolean" },
                    "featureId": { "type": "string" }
                  }
                },
                "example": {
                  "deleted": true,
                  "featureId": "fid_1234567890abcdef"
                }
              }
            }
          },
          "401": { "description": "Missing or invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } },
          "404": { "description": "Project or feature not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }
        }
      }
    },
    "/api/v1/projects/{projectId}/layers": {
      "parameters": [
        {
          "name": "projectId",
          "in": "path",
          "required": true,
          "schema": { "type": "string" }
        }
      ],
      "get": {
        "summary": "List layers",
        "description": "Returns all layers in the project (metadata only, no features).",
        "operationId": "listLayers",
        "tags": ["Layers"],
        "responses": {
          "200": {
            "description": "Array of layers (metadata only)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "layers": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/LayerMetadata" }
                    }
                  }
                },
                "example": {
                  "layers": [
                    { "id": "layer_123", "name": "Lima polygons", "visible": true }
                  ]
                }
              }
            }
          },
          "401": { "description": "Unauthorized" }
        }
      },
      "post": {
        "summary": "Create a layer",
        "description": "Creates a new layer in the project, optionally pre-populated with features stored in the features subcollection.",
        "operationId": "createLayer",
        "tags": ["Layers"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": { "type": "string" },
                  "features": {
                    "type": "array",
                    "items": { "$ref": "#/components/schemas/Feature" },
                    "description": "Optional initial features to store in the subcollection"
                  }
                }
              },
              "example": { "name": "Lima polygons", "features": [] }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Layer created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "layerId": { "type": "string" },
                    "name": { "type": "string" },
                    "featuresAdded": { "type": "integer" }
                  }
                },
                "example": {
                  "layerId": "layer_1748000000000",
                  "name": "Lima polygons",
                  "featuresAdded": 0
                }
              }
            }
          },
          "401": { "description": "Unauthorized" }
        }
      }
    }
  },
  "tags": [
    { "name": "Features", "description": "Read and write geographic features" },
    { "name": "Layers", "description": "Manage project layers" }
  ]
}
