{
  "openapi": "3.1.0",
  "info": {
    "title": "Checkmark Web API",
    "version": "1.0.0",
    "description": "Measure and improve how AI assistants (ChatGPT, Perplexity, Claude, Gemini, Copilot, Google AI Overviews) mention and recommend a brand. Authenticate with an API key created in Checkmark under Settings. All calls act as the key's owner and respect that account's plan limits.",
    "contact": {
      "url": "https://checkmark.to/docs/api"
    }
  },
  "servers": [
    {
      "url": "https://checkmark.to/api/public/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Send `Authorization: Bearer ck_...` using a key from Checkmark Settings."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "Brand": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "market": {
            "type": "string"
          },
          "competitors": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Question": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "text": {
            "type": "string"
          },
          "locale": {
            "type": "string",
            "enum": [
              "es",
              "pt",
              "en"
            ]
          },
          "is_active": {
            "type": "boolean"
          }
        }
      },
      "Report": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "done",
              "error"
            ]
          },
          "visibility_score": {
            "type": "integer",
            "description": "0-100 visibility score."
          },
          "mention_rate": {
            "type": "number",
            "description": "Share of answers that mention the brand."
          },
          "sentiment_avg": {
            "type": "number"
          },
          "engines": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "answer_count": {
            "type": "integer"
          }
        }
      }
    }
  },
  "paths": {
    "/me": {
      "get": {
        "operationId": "getAccount",
        "summary": "Plan, limits and current usage for the key's account",
        "responses": {
          "200": {
            "description": "Account snapshot"
          },
          "401": {
            "description": "Invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/brands": {
      "get": {
        "operationId": "listBrands",
        "summary": "List the brands this account tracks",
        "responses": {
          "200": {
            "description": "Brands"
          }
        }
      },
      "post": {
        "operationId": "createBrand",
        "summary": "Create a brand to track",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "domain"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "domain": {
                    "type": "string",
                    "example": "acme.com"
                  },
                  "category": {
                    "type": "string",
                    "example": "CRM for clinics"
                  },
                  "market": {
                    "type": "string",
                    "example": "Mexico"
                  },
                  "competitors": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 10
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Brand created"
          },
          "402": {
            "description": "Plan limit reached"
          }
        }
      }
    },
    "/brands/{brandId}/questions": {
      "parameters": [
        {
          "name": "brandId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "operationId": "listQuestions",
        "summary": "List the buying questions tracked for a brand",
        "responses": {
          "200": {
            "description": "Questions"
          }
        }
      },
      "post": {
        "operationId": "addQuestions",
        "summary": "Add buying questions (not brand-name searches) to a brand",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "questions"
                ],
                "properties": {
                  "questions": {
                    "type": "array",
                    "maxItems": 20,
                    "items": {
                      "type": "string",
                      "maxLength": 300
                    },
                    "example": [
                      "best CRM for dental clinics in Mexico"
                    ]
                  },
                  "locale": {
                    "type": "string",
                    "enum": [
                      "es",
                      "pt",
                      "en"
                    ],
                    "default": "es"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Questions added"
          },
          "402": {
            "description": "Plan limit reached"
          }
        }
      }
    },
    "/brands/{brandId}/runs": {
      "parameters": [
        {
          "name": "brandId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "get": {
        "operationId": "listReports",
        "summary": "List recent visibility reports for a brand",
        "responses": {
          "200": {
            "description": "Reports"
          }
        }
      },
      "post": {
        "operationId": "startVisibilityCheck",
        "summary": "Start a visibility check",
        "description": "Returns immediately with a run id. Call POST /runs/{runId}/advance repeatedly until status is \"done\": each call asks one question on one assistant, so no request runs long.",
        "responses": {
          "202": {
            "description": "Check started"
          },
          "402": {
            "description": "Plan limit reached"
          }
        }
      }
    },
    "/runs/{runId}/advance": {
      "parameters": [
        {
          "name": "runId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        }
      ],
      "post": {
        "operationId": "advanceVisibilityCheck",
        "summary": "Process the next question/assistant pair of a running check",
        "responses": {
          "200": {
            "description": "Progress",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "run_id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "running",
                        "done",
                        "error"
                      ]
                    },
                    "done": {
                      "type": "integer"
                    },
                    "total": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/runs/{runId}": {
      "parameters": [
        {
          "name": "runId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          }
        },
        {
          "name": "include_answer_text",
          "in": "query",
          "schema": {
            "type": "boolean",
            "default": false
          },
          "description": "Include the full assistant answers."
        }
      ],
      "get": {
        "operationId": "getReport",
        "summary": "Read one visibility report with per-question answers, competitors and citations",
        "responses": {
          "200": {
            "description": "Report"
          },
          "400": {
            "description": "Not found"
          }
        }
      }
    },
    "/content": {
      "get": {
        "operationId": "listContent",
        "summary": "List generated answer content",
        "parameters": [
          {
            "name": "brand_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Content assets"
          }
        }
      },
      "post": {
        "operationId": "generateContent",
        "summary": "Generate a citable answer block, FAQ and JSON-LD for one buying question",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "brand_id",
                  "question"
                ],
                "properties": {
                  "brand_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "question": {
                    "type": "string",
                    "maxLength": 300
                  },
                  "competitor_answer": {
                    "type": "string",
                    "maxLength": 6000
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "es",
                      "pt",
                      "en"
                    ],
                    "default": "es"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Content generated"
          },
          "402": {
            "description": "Plan limit reached"
          }
        }
      }
    },
    "/quick-check": {
      "post": {
        "operationId": "quickCheck",
        "summary": "Run a fast one-off AI visibility check on any domain",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "example": "acme.com"
                  },
                  "language": {
                    "type": "string",
                    "enum": [
                      "es",
                      "pt",
                      "en"
                    ],
                    "default": "es"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Quick check result"
          }
        }
      }
    }
  }
}