{
  "openapi": "3.1.0",
  "info": {
    "title": "ZeroRank REST API",
    "version": "1.0.0",
    "description": "The public ZeroRank REST API. Every request uses a workspace API key (Bearer `zr_live_…`) and only ever sees that one workspace. Use it to read your results and manage your prompts, brands, tags, and topics from your own scripts and tools."
  },
  "servers": [
    {
      "url": "https://api.zerorank.ai/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    { "name": "Workspace", "description": "The workspace, plan, and key behind your request." },
    { "name": "Prompts", "description": "The questions ZeroRank asks AI engines for you." },
    { "name": "Brands", "description": "The brands you track, including competitors." },
    { "name": "Tags", "description": "Labels you put on prompts." },
    { "name": "Topics", "description": "Groups you sort prompts into." },
    { "name": "Analytics", "description": "Read-only results: sources, chats, and rankings." }
  ],
  "paths": {
    "/workspace": {
      "get": {
        "tags": ["Workspace"],
        "summary": "Get workspace context",
        "description": "Returns the workspace this key belongs to, the plan, the key's own scopes, and the key's rate limit. A good first call to check that a key works.",
        "operationId": "getWorkspace",
        "responses": {
          "200": {
            "description": "Workspace context.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "$ref": "#/components/schemas/WorkspaceContext" },
                    "message": { "type": "string", "example": "Workspace retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/SubscriptionRequired" },
          "403": { "$ref": "#/components/responses/ApiAccessDisabled" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/prompts": {
      "get": {
        "tags": ["Prompts"],
        "summary": "List prompts",
        "description": "Returns a paginated list of prompts in your workspace. By default it returns your real prompts and leaves out AI-suggested and rejected ones. Ask for those with `status=suggested` or `status=rejected`.",
        "operationId": "listPrompts",
        "parameters": [
          { "$ref": "#/components/parameters/Page" },
          { "$ref": "#/components/parameters/Limit100" },
          {
            "name": "status",
            "in": "query",
            "description": "Only return prompts with this status.",
            "required": false,
            "schema": { "$ref": "#/components/schemas/PromptStatus" }
          },
          {
            "name": "topicId",
            "in": "query",
            "description": "Only return prompts in this topic.",
            "required": false,
            "schema": { "type": "integer" }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Only return prompts whose text contains this word or phrase.",
            "required": false,
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of prompts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "$ref": "#/components/schemas/PaginatedPrompts" },
                    "message": { "type": "string", "example": "Prompts retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "tags": ["Prompts"],
        "summary": "Create prompts",
        "description": "Creates one prompt or many at once. Send a single prompt object, or a `prompts` array (up to 500). New prompts are turned on and queued for a first run. Needs a key with the `write` scope.",
        "operationId": "createPrompts",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  { "$ref": "#/components/schemas/PromptCreateItem" },
                  { "$ref": "#/components/schemas/PromptBulkCreate" }
                ]
              },
              "examples": {
                "single": {
                  "summary": "One prompt",
                  "value": { "text": "What is the best CRM for small teams?", "location": "United States", "topic": "CRM", "tags": ["pricing"] }
                },
                "bulk": {
                  "summary": "Many prompts",
                  "value": { "prompts": [{ "text": "Best CRM for startups?" }, { "text": "Cheapest CRM with email?" }] }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Prompts created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "$ref": "#/components/schemas/PromptCreateResult" },
                    "message": { "type": "string", "example": "2 prompts created" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/prompts/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/IdPath" }],
      "get": {
        "tags": ["Prompts"],
        "summary": "Get a prompt",
        "description": "Returns one prompt, with its topic and tags.",
        "operationId": "getPrompt",
        "responses": {
          "200": { "$ref": "#/components/responses/PromptOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "put": {
        "tags": ["Prompts"],
        "summary": "Update a prompt",
        "description": "Updates a prompt's text, status, location, tags, or topic. `PATCH` works the same way. Needs a key with the `write` scope.",
        "operationId": "updatePrompt",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/PromptUpdate" }
            }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/PromptOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "patch": {
        "tags": ["Prompts"],
        "summary": "Update a prompt (PATCH)",
        "description": "Same as `PUT /prompts/{id}`. Updates a prompt's text, status, location, tags, or topic. Needs a key with the `write` scope.",
        "operationId": "patchPrompt",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/PromptUpdate" }
            }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/PromptOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "delete": {
        "tags": ["Prompts"],
        "summary": "Delete a prompt",
        "description": "Deletes a prompt for good. Needs a key with the `write` scope.",
        "operationId": "deletePrompt",
        "responses": {
          "200": { "$ref": "#/components/responses/Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/prompts/{id}/run": {
      "parameters": [{ "$ref": "#/components/parameters/IdPath" }],
      "post": {
        "tags": ["Prompts"],
        "summary": "Run a prompt now",
        "description": "Runs an existing prompt right now across your workspace's active AI models, or just the models you list. Each run counts against your monthly answer runs. Needs a key with the `write` scope.",
        "operationId": "runPrompt",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "models": {
                    "type": "array",
                    "items": { "type": "string", "maxLength": 100 },
                    "minItems": 1,
                    "description": "Optional list of model keys to run. Leave it out to run every active model."
                  }
                }
              },
              "examples": {
                "allModels": { "summary": "Run every active model", "value": {} },
                "someModels": { "summary": "Run only these models", "value": { "models": ["chatgpt", "perplexity"] } }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The run was queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "type": "object", "description": "Details about the queued run.", "additionalProperties": true },
                    "message": { "type": "string", "example": "Prompt run queued" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/brands": {
      "get": {
        "tags": ["Brands"],
        "summary": "List brands",
        "description": "Returns every brand in your workspace, both your own brands and competitors.",
        "operationId": "listBrands",
        "responses": {
          "200": {
            "description": "Your brands.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Brand" } },
                    "message": { "type": "string", "example": "Brands retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "tags": ["Brands"],
        "summary": "Create a brand",
        "description": "Adds a brand to track. Needs a key with the `write` scope.",
        "operationId": "createBrand",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/BrandCreate" },
              "example": { "name": "Acme", "domains": ["acme.com"], "color": "#FF4D00" }
            }
          }
        },
        "responses": {
          "201": { "$ref": "#/components/responses/BrandCreated" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/brands/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/IdPath" }],
      "get": {
        "tags": ["Brands"],
        "summary": "Get a brand",
        "description": "Returns one brand.",
        "operationId": "getBrand",
        "responses": {
          "200": { "$ref": "#/components/responses/BrandOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "put": {
        "tags": ["Brands"],
        "summary": "Update a brand",
        "description": "Updates a brand's names, domains, status, type, or color. `PATCH` works the same way. Needs a key with the `write` scope.",
        "operationId": "updateBrand",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/BrandUpdate" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/BrandOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "patch": {
        "tags": ["Brands"],
        "summary": "Update a brand (PATCH)",
        "description": "Same as `PUT /brands/{id}`. Needs a key with the `write` scope.",
        "operationId": "patchBrand",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/BrandUpdate" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/BrandOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "delete": {
        "tags": ["Brands"],
        "summary": "Delete a brand",
        "description": "Deletes a brand for good. Needs a key with the `write` scope.",
        "operationId": "deleteBrand",
        "responses": {
          "200": { "$ref": "#/components/responses/Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/brands/{id}/toggle-visibility": {
      "parameters": [{ "$ref": "#/components/parameters/IdPath" }],
      "post": {
        "tags": ["Brands"],
        "summary": "Hide or show a brand",
        "description": "Hides a brand from your charts, or shows it again. Needs a key with the `write` scope.",
        "operationId": "toggleBrandVisibility",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "hide": { "type": "boolean", "default": true, "description": "`true` hides the brand, `false` shows it." }
                }
              },
              "example": { "hide": true }
            }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/BrandOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/brands/merge": {
      "post": {
        "tags": ["Brands"],
        "summary": "Merge brands",
        "description": "Joins one or more brands into a single brand. The target brand keeps its place and takes on the names and domains of the others, which are then deleted. Needs a key with the `write` scope.",
        "operationId": "mergeBrands",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["targetBrandId", "sourceBrandIds"],
                "properties": {
                  "targetBrandId": { "type": "integer", "minimum": 1, "description": "The brand that survives the merge." },
                  "sourceBrandIds": {
                    "type": "array",
                    "items": { "type": "integer", "minimum": 1 },
                    "minItems": 1,
                    "maxItems": 50,
                    "description": "The brands merged into the target. They are deleted after the merge."
                  }
                }
              },
              "example": { "targetBrandId": 12, "sourceBrandIds": [34, 56] }
            }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/BrandOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/tags": {
      "get": {
        "tags": ["Tags"],
        "summary": "List tags",
        "description": "Returns every tag in your workspace, with how many prompts use each one.",
        "operationId": "listTags",
        "responses": {
          "200": {
            "description": "Your tags.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Tag" } },
                    "message": { "type": "string", "example": "Tags retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "tags": ["Tags"],
        "summary": "Create a tag",
        "description": "Adds a new tag. Needs a key with the `write` scope.",
        "operationId": "createTag",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TagCreate" },
              "example": { "name": "pricing", "color": "blue" }
            }
          }
        },
        "responses": {
          "201": { "$ref": "#/components/responses/TagCreated" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/tags/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/IdPath" }],
      "put": {
        "tags": ["Tags"],
        "summary": "Update a tag",
        "description": "Renames a tag or changes its color. `PATCH` works the same way. Needs a key with the `write` scope.",
        "operationId": "updateTag",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/TagUpdate" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/TagOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "patch": {
        "tags": ["Tags"],
        "summary": "Update a tag (PATCH)",
        "description": "Same as `PUT /tags/{id}`. Needs a key with the `write` scope.",
        "operationId": "patchTag",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/TagUpdate" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/TagOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "delete": {
        "tags": ["Tags"],
        "summary": "Delete a tag",
        "description": "Deletes a tag. Needs a key with the `write` scope.",
        "operationId": "deleteTag",
        "responses": {
          "200": { "$ref": "#/components/responses/Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/topics": {
      "get": {
        "tags": ["Topics"],
        "summary": "List topics",
        "description": "Returns every topic in your workspace.",
        "operationId": "listTopics",
        "responses": {
          "200": {
            "description": "Your topics.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Topic" } },
                    "message": { "type": "string", "example": "Topics retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "tags": ["Topics"],
        "summary": "Create a topic",
        "description": "Adds a new topic. Needs a key with the `write` scope.",
        "operationId": "createTopic",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/TopicCreate" },
              "example": { "name": "CRM" }
            }
          }
        },
        "responses": {
          "201": { "$ref": "#/components/responses/TopicCreated" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/topics/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/IdPath" }],
      "put": {
        "tags": ["Topics"],
        "summary": "Update a topic",
        "description": "Renames a topic. `PATCH` works the same way. Needs a key with the `write` scope.",
        "operationId": "updateTopic",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/TopicUpdate" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/TopicOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "patch": {
        "tags": ["Topics"],
        "summary": "Update a topic (PATCH)",
        "description": "Same as `PUT /topics/{id}`. Needs a key with the `write` scope.",
        "operationId": "patchTopic",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/TopicUpdate" } }
          }
        },
        "responses": {
          "200": { "$ref": "#/components/responses/TopicOk" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "delete": {
        "tags": ["Topics"],
        "summary": "Delete a topic",
        "description": "Deletes a topic. A topic that still has prompts cannot be deleted — move or delete its prompts first. Needs a key with the `write` scope.",
        "operationId": "deleteTopic",
        "responses": {
          "200": { "$ref": "#/components/responses/Deleted" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/InsufficientScope" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/sources": {
      "get": {
        "tags": ["Analytics"],
        "summary": "List top source domains",
        "description": "Returns the websites AI engines cite most often when they answer your prompts.",
        "operationId": "listSources",
        "parameters": [{ "$ref": "#/components/parameters/Limit100Default20" }],
        "responses": {
          "200": {
            "description": "Top source domains.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/SourceDomain" } },
                    "message": { "type": "string", "example": "Sources retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/source-urls": {
      "get": {
        "tags": ["Analytics"],
        "summary": "List top source URLs",
        "description": "Returns the exact pages AI engines cite most often. Add `domain` to see only the pages from one website.",
        "operationId": "listSourceUrls",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "description": "Only return pages from this website (for example `wikipedia.org`).",
            "required": false,
            "schema": { "type": "string" }
          },
          { "$ref": "#/components/parameters/Limit100Default20" }
        ],
        "responses": {
          "200": {
            "description": "Top source URLs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/SourceUrl" } },
                    "message": { "type": "string", "example": "Source URLs retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/chats": {
      "get": {
        "tags": ["Analytics"],
        "summary": "List recent chats",
        "description": "Returns recent answers AI engines gave back for your prompts. Add `promptId` to see only one prompt's chats.",
        "operationId": "listChats",
        "parameters": [
          {
            "name": "promptId",
            "in": "query",
            "description": "Only return chats for this prompt.",
            "required": false,
            "schema": { "type": "integer" }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "How many chats to return (1–50). Defaults to 20.",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 50, "default": 20 }
          }
        ],
        "responses": {
          "200": {
            "description": "Recent chats.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Chat" } },
                    "message": { "type": "string", "example": "Chats retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/chats/{id}": {
      "parameters": [{ "$ref": "#/components/parameters/ChatIdPath" }],
      "get": {
        "tags": ["Analytics"],
        "summary": "Get a chat",
        "description": "Returns one chat in full: the complete AI answer (Markdown) together with every source it cited.\n\nEach source includes the cited URL, its clean domain, and a 1-based `position`. `position` is a stable citation index — identical on every request — but not necessarily the order the links appear in the answer text.",
        "operationId": "getChat",
        "responses": {
          "200": {
            "description": "The chat, its full answer, and its cited sources.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "$ref": "#/components/schemas/ChatDetail" },
                    "message": { "type": "string", "example": "Chat retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/rankings": {
      "get": {
        "tags": ["Analytics"],
        "summary": "Get brand rankings",
        "description": "Returns how your brands rank over a recent window of days, including mentions, sentiment, visibility, and growth.",
        "operationId": "getRankings",
        "parameters": [
          {
            "name": "days",
            "in": "query",
            "description": "How many days back to look (1–90). Defaults to 7 when left out or invalid.",
            "required": false,
            "schema": { "type": "integer", "minimum": 1, "maximum": 90, "default": 7 }
          }
        ],
        "responses": {
          "200": {
            "description": "Brand rankings.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/BrandRanking" } },
                    "message": { "type": "string", "example": "Rankings retrieved successfully" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Send your workspace API key as `Authorization: Bearer zr_live_…`."
      }
    },
    "parameters": {
      "IdPath": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The numeric id of the item.",
        "schema": { "type": "integer" }
      },
      "ChatIdPath": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The chat's UUID. Get chat ids from `GET /chats`.",
        "schema": { "type": "string", "format": "uuid" }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "required": false,
        "description": "Which page to return. Defaults to 1.",
        "schema": { "type": "integer", "minimum": 1, "default": 1 }
      },
      "Limit100": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "How many items per page (1–100). Defaults to 20.",
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
      },
      "Limit100Default20": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "How many items to return (1–100). Defaults to 20.",
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "The API key is missing, invalid, revoked, or expired.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "success": false, "message": "Invalid, revoked, or expired API key", "code": "API_KEY_INVALID" }
          }
        }
      },
      "InsufficientScope": {
        "description": "This key is read-only. A key with the `write` scope is required.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "success": false, "message": "This API key is read-only; a key with the \"write\" scope is required", "code": "INSUFFICIENT_SCOPE" }
          }
        }
      },
      "SubscriptionRequired": {
        "description": "The workspace has no active subscription or trial.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "success": false, "message": "An active subscription or trial is required to use the API", "code": "SUBSCRIPTION_REQUIRED" }
          }
        }
      },
      "ApiAccessDisabled": {
        "description": "API access is not available on this plan.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "success": false, "message": "API access is not available on this plan", "code": "API_ACCESS_DISABLED" }
          }
        }
      },
      "NotFound": {
        "description": "The item was not found in your workspace.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "success": false, "message": "Prompt not found" }
          }
        }
      },
      "ValidationError": {
        "description": "The request body did not pass validation.",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "success": false, "message": "Validation failed", "errors": [{ "field": "text", "message": "The text field is required" }] }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests. Slow down and retry after the time in the `Retry-After` header.",
        "headers": {
          "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying." },
          "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Your per-minute limit." },
          "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Requests left in this window." },
          "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix time when the window resets." }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "success": false, "message": "API rate limit exceeded. Please slow down.", "code": "RATE_LIMIT_EXCEEDED", "retryAfter": 30 }
          }
        }
      },
      "Deleted": {
        "description": "The item was deleted.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": { "type": "boolean", "example": true },
                "message": { "type": "string", "example": "Resource deleted successfully" }
              }
            }
          }
        }
      },
      "PromptOk": {
        "description": "A prompt.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": { "type": "boolean", "example": true },
                "data": { "$ref": "#/components/schemas/Prompt" },
                "message": { "type": "string", "example": "Prompt retrieved successfully" }
              }
            }
          }
        }
      },
      "BrandOk": {
        "description": "A brand.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": { "type": "boolean", "example": true },
                "data": { "$ref": "#/components/schemas/Brand" },
                "message": { "type": "string", "example": "Brand retrieved successfully" }
              }
            }
          }
        }
      },
      "BrandCreated": {
        "description": "The brand was created.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": { "type": "boolean", "example": true },
                "data": { "$ref": "#/components/schemas/Brand" },
                "message": { "type": "string", "example": "Brand created successfully" }
              }
            }
          }
        }
      },
      "TagOk": {
        "description": "A tag.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": { "type": "boolean", "example": true },
                "data": { "$ref": "#/components/schemas/Tag" },
                "message": { "type": "string", "example": "Tag updated successfully" }
              }
            }
          }
        }
      },
      "TagCreated": {
        "description": "The tag was created.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": { "type": "boolean", "example": true },
                "data": { "$ref": "#/components/schemas/Tag" },
                "message": { "type": "string", "example": "Tag created successfully" }
              }
            }
          }
        }
      },
      "TopicOk": {
        "description": "A topic.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": { "type": "boolean", "example": true },
                "data": { "$ref": "#/components/schemas/Topic" },
                "message": { "type": "string", "example": "Topic updated successfully" }
              }
            }
          }
        }
      },
      "TopicCreated": {
        "description": "The topic was created.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "success": { "type": "boolean", "example": true },
                "data": { "$ref": "#/components/schemas/Topic" },
                "message": { "type": "string", "example": "Topic created successfully" }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "PromptStatus": {
        "type": "string",
        "enum": ["draft", "active", "paused", "suggested", "rejected"],
        "description": "Where a prompt is in its life: draft, active, paused, suggested (AI-proposed), or rejected."
      },
      "Prompt": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "example": 101 },
          "text": { "type": "string", "example": "What is the best CRM for small teams?" },
          "status": { "$ref": "#/components/schemas/PromptStatus" },
          "location": { "type": ["string", "null"], "example": "United States" },
          "workspaceId": { "type": "integer", "example": 7 },
          "topicId": { "type": ["integer", "null"], "example": 3 },
          "lastScheduledAt": { "type": ["string", "null"], "format": "date-time" },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" },
          "topic": { "oneOf": [{ "$ref": "#/components/schemas/Topic" }, { "type": "null" }] },
          "tags": { "type": "array", "items": { "$ref": "#/components/schemas/Tag" } }
        }
      },
      "PaginatedPrompts": {
        "type": "object",
        "properties": {
          "data": { "type": "array", "items": { "$ref": "#/components/schemas/Prompt" } },
          "total": { "type": "integer", "example": 42, "description": "Total prompts that match." },
          "page": { "type": "integer", "example": 1 },
          "perPage": { "type": "integer", "example": 20 },
          "lastPage": { "type": "integer", "example": 3 }
        }
      },
      "PromptCreateItem": {
        "type": "object",
        "required": ["text"],
        "properties": {
          "text": { "type": "string", "minLength": 1, "maxLength": 5000, "description": "The question to ask AI engines." },
          "location": { "type": "string", "maxLength": 255, "description": "Optional country or place to ask from." },
          "topic": { "type": "string", "maxLength": 100, "description": "Optional topic name. A new topic is created if it does not exist." },
          "tags": { "type": "array", "items": { "type": "string", "maxLength": 100 }, "description": "Optional tag names." }
        }
      },
      "PromptBulkCreate": {
        "type": "object",
        "required": ["prompts"],
        "properties": {
          "prompts": {
            "type": "array",
            "minItems": 1,
            "maxItems": 500,
            "items": { "$ref": "#/components/schemas/PromptCreateItem" }
          }
        }
      },
      "PromptUpdate": {
        "type": "object",
        "description": "Send only the fields you want to change.",
        "properties": {
          "text": { "type": "string", "minLength": 1, "maxLength": 5000 },
          "status": { "$ref": "#/components/schemas/PromptStatus" },
          "location": { "type": "string", "maxLength": 255 },
          "tags": {
            "type": "array",
            "items": { "oneOf": [{ "type": "string", "maxLength": 100 }, { "type": "integer" }] },
            "description": "Tag names or tag ids. Replaces the prompt's current tags."
          },
          "topicId": { "type": ["integer", "null"], "description": "Move to this topic, or `null` to remove the topic." },
          "topicName": { "type": "string", "maxLength": 100, "description": "Topic name to move to (created if needed)." }
        }
      },
      "PromptCreateResult": {
        "type": "object",
        "properties": {
          "created": { "type": "integer", "example": 2, "description": "How many prompts were created." },
          "failed": { "type": "integer", "example": 0, "description": "How many were skipped or failed." },
          "prompts": { "type": "array", "items": { "$ref": "#/components/schemas/Prompt" } },
          "errors": { "type": "array", "items": { "type": "object", "additionalProperties": true }, "description": "Details for any items that failed." }
        }
      },
      "Brand": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "example": 12 },
          "name": { "type": "string", "example": "Acme" },
          "trackedNames": { "type": ["array", "null"], "items": { "type": "string" }, "description": "Other names that count as this brand." },
          "nameRegex": { "type": ["string", "null"], "description": "Advanced matching pattern." },
          "useRegex": { "type": "boolean", "example": false },
          "domains": { "type": ["array", "null"], "items": { "type": "string" }, "example": ["acme.com"] },
          "domain": { "type": ["string", "null"], "description": "The first domain.", "example": "acme.com" },
          "logoUrl": { "type": ["string", "null"] },
          "industry": { "type": ["string", "null"] },
          "description": { "type": ["string", "null"] },
          "status": { "type": "string", "enum": ["active", "hidden"], "example": "active" },
          "type": { "type": "string", "enum": ["own", "competitor"], "description": "`own` is your brand; `competitor` is a rival.", "example": "own" },
          "color": { "type": ["string", "null"], "example": "#FF4D00" },
          "relevancyScore": { "type": "number", "example": 87 },
          "relevancyCalculatedAt": { "type": ["string", "null"], "format": "date-time" },
          "workspaceId": { "type": "integer", "example": 7 },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "BrandCreate": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 255, "description": "The brand's main name." },
          "trackedNames": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 255 }, "maxItems": 50 },
          "nameRegex": { "type": "string", "maxLength": 500 },
          "useRegex": { "type": "boolean" },
          "domains": { "type": "array", "items": { "type": "string", "minLength": 1, "maxLength": 255 }, "maxItems": 20 },
          "status": { "type": "string", "enum": ["active", "hidden"] },
          "color": { "type": "string", "pattern": "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", "description": "A hex color like `#FF4D00`." }
        }
      },
      "BrandUpdate": {
        "type": "object",
        "description": "Send only the fields you want to change.",
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 255 },
          "trackedNames": { "type": ["array", "null"], "items": { "type": "string", "minLength": 1, "maxLength": 255 }, "maxItems": 50 },
          "nameRegex": { "type": ["string", "null"], "maxLength": 500 },
          "useRegex": { "type": "boolean" },
          "domains": { "type": ["array", "null"], "items": { "type": "string", "minLength": 1, "maxLength": 255 }, "maxItems": 20 },
          "status": { "type": "string", "enum": ["active", "hidden"] },
          "type": { "type": "string", "enum": ["own", "competitor"] },
          "color": { "type": ["string", "null"], "pattern": "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$" }
        }
      },
      "Tag": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "example": 5 },
          "name": { "type": "string", "example": "pricing" },
          "color": { "$ref": "#/components/schemas/TagColor" },
          "hexColor": { "type": "string", "description": "The tag color as a hex value.", "example": "#3b82f6" },
          "promptCount": { "type": "integer", "description": "How many prompts use this tag (included when listing tags).", "example": 8 },
          "workspaceId": { "type": "integer", "example": 7 },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "TagColor": {
        "type": "string",
        "enum": ["red", "orange", "amber", "yellow", "lime", "green", "emerald", "teal", "cyan", "sky", "blue", "indigo", "violet", "purple", "fuchsia", "pink", "rose", "slate", "gray", "zinc"],
        "description": "One of ZeroRank's named tag colors."
      },
      "TagCreate": {
        "type": "object",
        "required": ["name", "color"],
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100 },
          "color": { "$ref": "#/components/schemas/TagColor" }
        }
      },
      "TagUpdate": {
        "type": "object",
        "description": "Send only the fields you want to change.",
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100 },
          "color": { "$ref": "#/components/schemas/TagColor" }
        }
      },
      "Topic": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "example": 3 },
          "name": { "type": "string", "example": "CRM" },
          "workspaceId": { "type": "integer", "example": 7 },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "TopicCreate": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100 }
        }
      },
      "TopicUpdate": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "minLength": 1, "maxLength": 100 }
        }
      },
      "WorkspaceContext": {
        "type": "object",
        "properties": {
          "workspace": {
            "type": "object",
            "properties": {
              "id": { "type": "integer", "example": 7 },
              "name": { "type": "string", "example": "Acme Marketing" }
            }
          },
          "organization": {
            "type": "object",
            "properties": {
              "plan": { "type": "string", "description": "The base plan name.", "example": "pro" },
              "subscriptionStatus": { "type": "string", "example": "active" }
            }
          },
          "apiKey": {
            "type": ["object", "null"],
            "properties": {
              "id": { "type": "integer", "example": 4 },
              "name": { "type": "string", "example": "Production server" },
              "prefix": { "type": "string", "example": "zr_live_a1b2c3" },
              "last4": { "type": "string", "example": "9f2e" },
              "scopes": { "type": "array", "items": { "$ref": "#/components/schemas/ApiKeyScope" } }
            }
          },
          "rateLimitPerMinute": { "type": "integer", "description": "How many requests this key may make per minute.", "example": 120 }
        }
      },
      "ApiKeyScope": {
        "type": "string",
        "enum": ["read", "write"],
        "description": "`read` allows GET requests; `write` allows create, update, delete, and run."
      },
      "SourceDomain": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "domain": { "type": "string", "example": "wikipedia.org" },
          "domainType": { "type": "string", "description": "What kind of site this is.", "example": "reference" },
          "usage": { "type": "string", "description": "The share of your answers that cited this domain, as a percentage string.", "example": "4.1%" },
          "avgCitations": { "type": "number", "description": "Average citations per answer that cited this domain.", "example": 2.4 },
          "urlCount": { "type": "string", "description": "How many times this domain was cited, as a string (the count behind the usage share). Despite the name, this is a usage count, not a number of distinct pages.", "example": "128" }
        }
      },
      "SourceUrl": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "sourceUrl": { "type": "string", "example": "https://en.wikipedia.org/wiki/Customer_relationship_management" },
          "sourceDomain": { "type": "string", "example": "wikipedia.org" },
          "domainType": { "type": "string", "example": "reference" },
          "urlType": { "type": "string", "example": "article" },
          "totalUsage": { "type": "number", "example": 36 },
          "totalCitations": { "type": "number", "example": 42 },
          "uniqueChats": { "type": "number", "example": 30 },
          "usagePercentage": { "type": "number", "example": 4.1 },
          "lastUpdated": { "type": "string", "format": "date-time" },
          "brandIds": { "type": "array", "items": { "type": "integer" } },
          "isAnalyzed": { "type": "integer", "description": "`1` if ZeroRank has analyzed this page, else `0`.", "example": 1 }
        }
      },
      "Chat": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "promptId": { "type": "integer", "example": 101 },
          "question": { "type": "string", "example": "What is the best CRM for small teams?" },
          "aiModel": { "type": "string", "example": "chatgpt" },
          "location": { "type": "string", "example": "United States" },
          "sourceCount": { "type": "integer", "example": 6 },
          "citationCount": { "type": "integer", "example": 6 },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "ChatSource": {
        "type": "object",
        "properties": {
          "position": { "type": "integer", "description": "1-based stable citation index. Identical on every request, but not necessarily the order the links appear in the answer text.", "example": 1 },
          "url": { "type": "string", "example": "https://www.reddit.com/r/CRM/comments/best_crm_small_teams" },
          "domain": { "type": "string", "description": "The clean host of the cited URL.", "example": "reddit.com" },
          "domainType": { "type": "string", "description": "Corporate, Editorial, Institutional, UGC, Reference, Competitor, or Other.", "example": "UGC" },
          "urlType": { "type": "string", "description": "Homepage, Category, Product, Listicle, Comparison, Profile, Alternative, Discussion, HowToGuide, Article, or Other.", "example": "Discussion" }
        }
      },
      "ChatDetail": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "promptId": { "type": "integer", "example": 101 },
          "question": { "type": "string", "example": "What is the best CRM for small teams?" },
          "answer": { "type": "string", "description": "The full AI answer, in Markdown." },
          "aiModel": { "type": "string", "example": "chatgpt" },
          "location": { "type": "string", "example": "United States" },
          "status": { "type": "string", "example": "completed" },
          "sourceCount": { "type": "integer", "example": 6 },
          "citationCount": { "type": "integer", "example": 6 },
          "webSearchTriggered": { "type": "boolean", "example": true },
          "createdAt": { "type": "string", "format": "date-time" },
          "sources": {
            "type": "array",
            "description": "Every URL the answer cited, in stable citation order.",
            "items": { "$ref": "#/components/schemas/ChatSource" }
          }
        }
      },
      "BrandRanking": {
        "type": "object",
        "properties": {
          "id": { "type": "integer", "example": 12 },
          "rank": { "type": "integer", "example": 1 },
          "name": { "type": "string", "example": "Acme" },
          "type": { "type": "string", "example": "own" },
          "mentions": { "type": "integer", "example": 240 },
          "sentiment": { "type": "number", "description": "Average sentiment score.", "example": 0.62 },
          "visibilityPercentage": { "type": "number", "description": "Share of answers that mention this brand.", "example": 38.5 },
          "growth": { "type": "number", "description": "Change versus the period before.", "example": 4.2 },
          "color": { "type": "string", "example": "#FF4D00" },
          "domain": { "type": ["string", "null"], "example": "acme.com" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "message": { "type": "string", "description": "A human-readable explanation." },
          "code": { "type": "string", "description": "A short error code, when one applies." },
          "errors": { "description": "Field-level details, on validation errors." }
        }
      }
    }
  }
}
