openapi: 3.0.3 info: title: SUBJCT API description: |- ### Automated Linking, Scaled. ## Authentication Subjct supports two authentication methods: 1. **User Authentication** ```bash -H "Authorization: Bearer " ``` 2. **Secret Keys** ```bash -H "X-Secret-Key: " ``` We have done this so that it is easier to integrate with Subjct API's. Most of the endpoints support both authentication methods. termsOfService: http://subjct.ai/terms/ contact: email: ricardo@subjct.ai license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html version: 0.0.3 externalDocs: description: Find out more about SUBJCT url: http://subjct.ai servers: - url: https://api.subjct.ai tags: - name: auth description: Authentication - name: org description: Organisation - name: properties description: Properties - name: search description: Content Search Endpoints - name: article description: Article Endpoints - name: ingest description: Content Ingestion Endpoints - name: analysis description: Content Analysis Endpoints - name: metrics description: Metrics Endpoints - name: autolink description: Autolink Endpoints - name: deals description: Deal Endpoints - name: competitors description: Competitor Endpoints - name: entity-analysis description: Entity Analysis Endpoints - name: tasks description: Task Endpoints - name: google-analytics description: Google Analytics Endpoints - name: webhooks description: Webhook Endpoints paths: /auth/login: post: tags: - auth summary: Login description: Login operationId: login requestBody: $ref: '#/components/requestBodies/LoginRequest' responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/LoginResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /auth/signup: post: tags: - auth summary: Signup description: Signup operationId: signup requestBody: $ref: '#/components/requestBodies/SignupRequest' responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/SignupResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /org: get: security: - Authorization: [] tags: - org summary: Get Organisation description: Returns the organisation info for the current user based on the orgId in the JWT token operationId: getOrganisation responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/OrganisationResponse' '400': description: Invalid token or missing orgId content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organisation not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /org/webhooks: get: tags: - webhooks summary: List Webhooks description: Returns all webhooks configured for the organisation. operationId: listWebhooks security: - Authorization: [] - X-Secret-Key: [] responses: '200': description: List of webhooks content: application/json: schema: type: array items: $ref: '#/components/schemas/Webhook' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' post: tags: - webhooks summary: Create Webhook description: | Creates a new webhook for the organisation. If no secret is provided, one is auto-generated. Valid event types: `article_analysis`, `autolink`, `structured_data`. Leave `subscribedEvents` empty to subscribe to all events. Leave `targetProperties` empty to receive events for all properties. operationId: createWebhook security: - Authorization: [] - X-Secret-Key: [] requestBody: $ref: '#/components/requestBodies/WebhookCreateRequest' responses: '201': description: Webhook created content: application/json: schema: $ref: '#/components/schemas/Webhook' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /org/webhooks/{id}: put: tags: - webhooks summary: Update Webhook description: Updates an existing webhook. Set `enabled` to `true` to re-enable a webhook that was automatically disabled after repeated failures — this also resets the failure counter. operationId: updateWebhook security: - Authorization: [] - X-Secret-Key: [] parameters: - name: id in: path description: Webhook ID required: true schema: type: string format: uuid requestBody: $ref: '#/components/requestBodies/WebhookUpdateRequest' responses: '200': description: Webhook updated content: application/json: schema: $ref: '#/components/schemas/Webhook' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Webhook not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - webhooks summary: Delete Webhook description: Permanently deletes a webhook. operationId: deleteWebhook security: - Authorization: [] - X-Secret-Key: [] parameters: - name: id in: path description: Webhook ID required: true schema: type: string format: uuid responses: '204': description: Webhook deleted '404': description: Webhook not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /org/users: get: security: - Authorization: [] tags: - org summary: Get Organisation Users description: Returns a list of users in the organisation based on the orgId in the JWT token operationId: getOrganisationUsers parameters: - name: page in: query required: false schema: type: integer default: 1 - name: size in: query required: false schema: type: integer default: 20 responses: '200': description: Successful operation headers: X-Total-Count: description: Total number of users schema: type: integer content: application/json: schema: type: array items: $ref: '#/components/schemas/UserResponse' '400': description: Invalid token or pagination parameters content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organisation not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /search/articles: post: tags: - search summary: Search for Articles description: Search for Articles operationId: searchArticles security: - Authorization: [] requestBody: $ref: '#/components/requestBodies/SearchRequest' responses: '200': headers: X-Total-Count: schema: type: integer description: Total number of articles description: Successful operation content: application/json: schema: $ref: '#/components/schemas/SearchResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: Validation exception content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /search/{organisationID}/articles: post: tags: - search summary: Search for Articles in Organisation description: Search for Articles scoped to a specific organisation operationId: searchOrganisationArticles security: - Authorization: [] - X-Secret-Key: [] parameters: - in: path name: organisationID required: true schema: type: string requestBody: $ref: '#/components/requestBodies/SearchRequest' responses: '200': headers: X-Total-Count: schema: type: integer description: Total number of articles description: Successful operation content: application/json: schema: $ref: '#/components/schemas/SearchResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /search/{organisationID}/{propertyID}/topics: post: tags: - search summary: Search for Topics in a Property description: Search for Topics in a specific property operationId: searchTopicsInProperty security: - Authorization: [] - X-Secret-Key: [] parameters: - in: path name: organisationID required: true schema: type: string - in: path name: propertyID required: true schema: type: string requestBody: $ref: '#/components/requestBodies/SearchRequest' responses: '200': headers: X-Total-Count: schema: type: integer description: Total number of topics description: Successful operation content: application/json: schema: $ref: '#/components/schemas/SearchResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /search/{organisationID}/{propertyID}/articles: post: tags: - search summary: Search Article by URL description: Returns the article given a URL operationId: searchArticleByURL security: - Authorization: [] - X-Secret-Key: [] parameters: - in: path name: organisationID required: true schema: type: string - in: path name: propertyID required: true schema: type: string requestBody: content: application/json: schema: type: object required: - url properties: url: type: string responses: '200': headers: X-Total-Count: schema: type: integer description: Total number of matching articles description: Article found content: application/json: schema: $ref: '#/components/schemas/SearchResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Article not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /search/{organisationID}/{propertyID}/articles/resolve: get: tags: - search summary: Resolve article by external id description: | Returns the article for a client-supplied **external id** (the id in the customer's CMS or source system) within the given organisation and property. The response includes SUBJCT's internal `id`, which you can use with other endpoints that expect the internal article id. **Uniqueness:** The external id must be unique per property. If more than one article matches, the API responds with HTTP 409 Conflict. operationId: resolveArticleByExternalId security: - Authorization: [] - X-Secret-Key: [] parameters: - in: path name: organisationID required: true schema: type: string - in: path name: propertyID required: true schema: type: string - in: query name: externalId required: true description: The article id as defined in the client system (ingested as `externalId`). schema: type: string responses: '200': description: Article found content: application/json: schema: $ref: '#/components/schemas/Article' '400': description: Missing or invalid `externalId` content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: No article with this external id in the property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': description: Multiple articles share this external id in the property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /ingest/{organisationID}/{propertyID}/article: post: tags: - ingest summary: Add a new Article to a property description: Add a new Article to a property operationId: addArticle security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid requestBody: $ref: '#/components/requestBodies/ArticleRequest' responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/ArticleResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid Secret Key for Organisation + Property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organisation or Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '409': description: Conflict - Article URL already exists with a different ID content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: Validation exception content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error ingesting article content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /ingest/{organisationID}/{propertyID}/topic: post: tags: - ingest summary: Add a new Topic to a property description: Add a new Topic to a property operationId: addTopic security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid requestBody: $ref: '#/components/requestBodies/TopicRequest' responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/TopicResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid Secret Key for Organisation + Property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organisation or Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: Validation exception content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error ingesting topic content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /ingest/{organisationID}/{propertyID}/scrape: post: tags: - ingest summary: Start a scrape job for a property description: Triggers a new scraping job for a given property based on its existing configuration. This initiates a background job to find and process content. operationId: startPropertyScrape security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property to be scraped required: true schema: type: string format: uuid responses: '200': description: Successful operation, scraping has been initiated. content: text/plain: schema: type: string example: "Scraping of property: 123e4567-e89b-12d3-a456-426614174000 started" '400': description: Bad Request - The property is not configured correctly for scraping (e.g., no parser is set up, or auto-discovery is off and no sitemaps are provided). content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid or missing user credentials. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organisation or Property not found. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error, e.g., failed to publish the job creation message to the orchestrator. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /ingest/{organisationID}/{propertyID}/upload: post: tags: - ingest summary: Upload a file for ingestion or parsing description: Uploads a file to be processed. The type of processing is determined by the `ingestionType` query parameter. operationId: uploadFileForIngestion security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: ingestionType in: query description: The type of ingestion to perform on the uploaded file. required: true schema: type: string enum: [ articles_parse, articles_ingest, topics_parse, topics_ingest ] requestBody: description: The file to be uploaded for ingestion. required: true content: multipart/form-data: schema: type: object properties: file: type: string format: binary description: | - For `articles_parse` or `topics_parse`, a `.txt` file containing URLs. - For `articles_ingest` or `topics_ingest`, a `.csv` or `.jsonl` file with structured data. responses: '200': description: Successful operation, file ingestion has been initiated. content: text/plain: schema: type: string example: "Ingestion: articles_ingest started" '400': description: Bad Request - Missing or invalid `ingestionType`, missing file, incorrect file extension for the given `ingestionType`, or invalid file headers for ingest types. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid or missing user credentials. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organisation or Property not found. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error, e.g., failed to upload the file or publish the job creation message. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /ingest/job/{jobID}/status: get: tags: - ingest summary: Get the status of an ingestion job description: Retrieve the current status, input/output file URLs, and result counts for a specific ingestion job. operationId: getIngestionJobStatus security: - Authorization: [ ] parameters: - name: jobID in: path description: ID of the ingestion job required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/IngestionJobResponse' '401': description: Unauthorized - missing or invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Job not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error fetching job status content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /property/{propertyId}/jobs/active: get: tags: - properties summary: Get active property jobs description: Returns queued and running schema-generation and autolink jobs for the authenticated organisation and property. operationId: getActivePropertyJobs security: - Authorization: [] parameters: - name: propertyId in: path required: true schema: type: string format: uuid responses: '200': description: Active jobs content: application/json: schema: type: object required: [jobs] properties: jobs: type: array items: $ref: '#/components/schemas/PropertyJob' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Failed to fetch active jobs content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /job/{jobId}/status: get: tags: - properties summary: Get a property job status operationId: getPropertyJobStatus security: - Authorization: [] parameters: - name: jobId in: path required: true schema: type: string format: uuid responses: '200': description: Current job status content: application/json: schema: $ref: '#/components/schemas/PropertyJob' '401': description: Unauthorized content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Job not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Failed to fetch job status content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /article/{organisationID}/{propertyID}/{articleID}: get: tags: - article summary: Get Article with Analysis Result description: Get Article with Analysis and Links Result operationId: getArticleWithAnalysisAndLinks security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: articleID in: path description: ID of the Article required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/ArticleWithAnalysisAndLinksResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid Secret Key for Organisation + Property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - Indicates that the article has not been processed yet content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' put: tags: - article summary: Update Article description: | Update an existing article by organisation, property, and article ID. This endpoint also safely handles the `deleted` flag for soft deletion and undeletion: - `{ "deleted": true }` will mark the article as deleted and set `deletedAt`. - `{ "deleted": false }` will undelete the article and clear `deletedAt`. For explicit delete/restore operations, prefer using the dedicated endpoints. operationId: updateArticle security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: articleID in: path description: ID of the Article required: true schema: type: string format: uuid requestBody: description: Updated article data required: true content: application/json: schema: $ref: '#/components/schemas/Article' responses: '200': description: Article updated successfully content: application/json: schema: $ref: '#/components/schemas/Article' '400': description: Invalid request body content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid secret key content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organisation or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error updating article content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - article summary: Soft Delete Article description: | Soft delete an article by setting the `deleted` flag to `true` and recording a `deletedAt` timestamp. The article remains in the system but is marked as deleted. operationId: deleteArticle security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true description: ID of the Organisation schema: type: string format: uuid - name: propertyID in: path required: true description: ID of the Target Property schema: type: string format: uuid - name: articleID in: path required: true description: ID of the Article schema: type: string format: uuid responses: '200': description: Article soft deleted successfully content: application/json: schema: type: object properties: message: type: string articleID: type: string '401': description: Unauthorized - Invalid secret key content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Article not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error deleting article content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /article/{organisationID}/{propertyID}/{articleID}/restore: post: tags: - article summary: Restore (Undelete) Article description: | Restore a previously soft-deleted article by setting `deleted` to `false` and clearing `deletedAt`. This operation is the inverse of the soft delete. operationId: restoreArticle security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true description: ID of the Organisation schema: type: string format: uuid - name: propertyID in: path required: true description: ID of the Target Property schema: type: string format: uuid - name: articleID in: path required: true description: ID of the Article schema: type: string format: uuid responses: '200': description: Article restored successfully content: application/json: schema: type: object properties: message: type: string articleID: type: string '401': description: Unauthorized - Invalid secret key content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Article not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error restoring article content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /article/{organisationID}/{propertyID}/{articleID}/similar_articles: get: tags: - article summary: Get a list of 10 articles with similar summaries description: Get a list of 10 articles with similar summaries operationId: getSimilarArticles security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: articleID in: path description: ID of the Article required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/SimilarArticles' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid Secret Key for Organisation + Property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - Indicates that the article has not been processed yet content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /autolink/{organisationID}/{propertyID}/{articleID}: post: tags: - autolink operationId: autolinkArticle security: - Authorization: [] - X-Secret-Key: [] summary: Trigger process for auto linking the article description: |- Auto linking inserts new links into the article linking entities to topic pages and phrases to other articles. Links are inserted according to rules aimed to maximise the link score of the page and the SEO authority of the site The autolinking process does not remove pre-existing links, but can be rerun which may remove a subjct link from earlier run. The linking process is asyncronous, if triggering is successful, periodically poll See [GET /article/{organisationID}/{propertyID}/{articleID}:](#/article/getArticleWithAnalysisAndLinks) and compare the `article.autoLinked` datetime field to understand when autolinking was last completed The `article.html` is updated adding a `data-subjct` to ALL links in the article, the value of the attribute describes the link type `prior` | `topic` | `phrase-link`. parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: articleID in: path description: ID of the Article required: true schema: type: string format: uuid requestBody: description: Autolink configuration required: false content: application/json: schema: type: object properties: mode: type: string enum: [auto_apply, review_only] default: auto_apply description: | The mode of autolinking. `auto_apply` (default) generates links and automatically merges them into the article's HTML. `review_only` generates candidate links for review but does NOT modify the article's HTML. responses: '200': description: Autolink job queued content: application/json: schema: $ref: '#/components/schemas/PropertyJobAcceptedResponse' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid Secret Key for Organisation + Property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: No such article content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - Indicates that the article has not been processed yet content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal Server Error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/init: post: tags: - fanout summary: Initialize Fan-out Analysis description: | Initialize a new fan-out analysis session for an article. This splits the article into paragraphs, generates embeddings for each paragraph, and prepares the analysis for search query evaluation. operationId: initializeFanoutAnalysis security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FanoutInitRequest' responses: '200': description: Analysis initialized successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/article/{articleID}: get: tags: - fanout summary: Get Fan-out Analysis by Article ID description: | Retrieve the fan-out analysis for an article using the article ID. Returns the same analysis shape as the analysis-ID lookup endpoint, making it possible to fetch an existing analysis without knowing its analysis ID upfront. operationId: getFanoutAnalysisByArticleID security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: articleID in: path description: ID of the Article required: true schema: type: string responses: '200': description: Analysis retrieved successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: No fan-out analysis found for the given article ID content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}: get: tags: - fanout summary: Get Fan-out Analysis with Overall Suggestions description: | Retrieve the full fan-out analysis including all prompts, scores, and LLM-generated overall advice for improving article content coverage. operationId: getFanoutAnalysis security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid responses: '200': description: Analysis retrieved successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}/prompt: post: tags: - fanout summary: Add Search Query Prompt description: | Add a new search query (prompt) to the analysis. The query is expanded into multiple variants, embedded, and scored against all article paragraphs. Paragraphs below the threshold receive improvement suggestions. operationId: addFanoutPrompt security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FanoutPromptRequest' responses: '200': description: Prompt added and analyzed successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}/prompt/{promptID}: put: tags: - fanout summary: Update Search Query Prompt description: | Update an existing prompt with a new search query. This removes the old prompt analysis and re-runs analysis with the new query. operationId: updateFanoutPrompt security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid - name: promptID in: path description: ID of the Prompt to update required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FanoutPromptRequest' responses: '200': description: Prompt updated successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - fanout summary: Delete Search Query Prompt description: Remove a prompt from the analysis and recalculate overall scores. operationId: deleteFanoutPrompt security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid - name: promptID in: path description: ID of the Prompt to delete required: true schema: type: string format: uuid responses: '200': description: Prompt deleted successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}/run-analysis: post: tags: - fanout summary: Re-run Analysis for All Prompts description: | Re-analyze all existing prompts against the article paragraphs. Useful after updating configuration thresholds or when paragraphs have been modified. operationId: runFanoutAnalysis security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid responses: '200': description: Analysis completed successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}/auto-prompts: post: tags: - fanout summary: Generate Auto-suggested Prompts description: | Use LLM to analyze the article content and suggest relevant search queries that the article should rank for. These suggestions help identify gaps in content coverage. operationId: generateFanoutAutoPrompts security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid responses: '200': description: Auto-prompts generated successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}/structural-analysis: post: tags: - fanout summary: Run Structural Analysis description: | Analyze the article's structure including headings, paragraph lengths, and organization. Returns recommendations for structural improvements. operationId: runFanoutStructuralAnalysis security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid responses: '200': description: Structural analysis completed successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}/keyword-analysis: post: tags: - fanout summary: Run Keyword Analysis description: | Extract and analyze keywords from the article. Identifies top keywords, keyword density, and missing keywords that could improve search relevance. operationId: runFanoutKeywordAnalysis security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid responses: '200': description: Keyword analysis completed successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}/config: put: tags: - fanout summary: Update Analysis Configuration description: | Update the threshold configuration for the analysis. Changes affect how paragraphs are evaluated and which ones receive improvement suggestions. operationId: updateFanoutConfig security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FanoutConfig' responses: '200': description: Configuration updated successfully content: application/json: schema: $ref: '#/components/schemas/FanoutAnalysis' '400': description: Invalid input or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /fanout/{organisationID}/{propertyID}/{analysisID}/paragraph/{paragraphID}/review: post: tags: - fanout summary: Review Specific Paragraph description: | Run analysis for a specific paragraph against a search query. Optionally replace an existing prompt with the new query. Returns detailed scoring and suggestions for the paragraph. operationId: reviewFanoutParagraph security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: analysisID in: path description: ID of the Fan-out Analysis required: true schema: type: string format: uuid - name: paragraphID in: path description: Index of the paragraph to review (0-indexed) required: true schema: type: integer requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/FanoutParagraphReviewRequest' responses: '200': description: Paragraph review completed successfully content: application/json: schema: $ref: '#/components/schemas/ParagraphReviewResult' '400': description: Invalid input, property not found, or invalid paragraph ID content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid credentials content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /metrics/{organisationID}: get: tags: - metrics summary: Get organisation-wide metrics description: Returns overall metrics for the organisation, using data from one of its properties. operationId: getOrganisationMetrics security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: UUID of the organisation required: true schema: type: string format: uuid responses: '200': description: Metrics successfully retrieved content: application/json: schema: $ref: '#/components/schemas/MetricsResponse' '400': description: Bad request or invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized or invalid secret key content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - The data is still being processed content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /metrics/{organisationID}/{propertyID}: get: tags: - metrics summary: Get property-level metrics description: Returns metrics for a specific property under a given organisation. operationId: getOrganisationAndPropertyMetrics security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: UUID of the organisation required: true schema: type: string format: uuid - name: propertyID in: path description: UUID of the property required: true schema: type: string format: uuid responses: '200': description: Metrics successfully retrieved content: application/json: schema: $ref: '#/components/schemas/MetricsResponse' '400': description: Bad request or invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized or invalid secret key content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - The data is still being processed content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /metrics/{organisationID}/{propertyID}/article/{articleID}: get: tags: - metrics summary: Get metrics for a specific article description: Returns detailed metrics for a specific article under a property and organisation. operationId: getOrganisationAndPropertyAndArticleMetrics security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: UUID of the organisation required: true schema: type: string format: uuid - name: propertyID in: path description: UUID of the property required: true schema: type: string format: uuid - name: articleID in: path description: UUID of the article required: true schema: type: string format: uuid responses: '200': description: Metrics successfully retrieved content: application/json: schema: $ref: '#/components/schemas/MetricsResponse' '400': description: Bad request or invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized or invalid secret key content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - The article has not been processed yet content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /analysis/{organisationID}/{propertyID}/article/{articleID}: get: tags: - analysis summary: Get Article Analysis Result description: Get Article Analysis Results operationId: getArticleAnalysis security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: articleID in: path description: ID of the Article required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/ArticleAnalysis' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid Secret Key for Organisation + Property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - Indicates that the article has not been processed yet content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /analysis/{organisationID}/{propertyID}/links/{articleID}: get: tags: - analysis summary: Get Article Links Result description: Get Article Links Results operationId: getArticleLinks security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: articleID in: path description: ID of the Article required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/ArticleLinks' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid Secret Key for Organisation + Property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - Indicates that the article has not been processed yet content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /analysis/{organisationID}/{propertyID}/jsonLd/{articleID}: post: tags: - analysis summary: Trigger JSON-LD Generation description: | Triggers JSON-LD generation for the given article. Pass `type` to select one or more schema templates explicitly. Order determines priority and the first eligible value is primary. When omitted, the service classifies the page from its title, URL, and content. If the article has already been processed, an error is returned unless `force` is true. operationId: triggerJsonLdGeneration security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid - name: propertyID in: path description: ID of the Target Property required: true schema: type: string format: uuid - name: articleID in: path description: ID of the Article required: true schema: type: string format: uuid - name: force in: query required: false description: Regenerate and replace an existing generated schema. schema: type: boolean default: false - name: type in: query required: false description: One schema type, a comma-separated ordered list, or a repeated query parameter. schema: type: array items: type: string enum: [product, software_application, faq, about, webpage, news_article, blog_posting, tech_article, item_page, real_estate_listing, article] requestBody: required: false content: application/json: schema: type: object properties: force: type: boolean default: false type: description: One type or an ordered array. Schema.org names such as FAQPage and RealEstateListing are accepted. oneOf: - type: string - type: array items: type: string types: type: array description: Ordered schema types; the first eligible type is primary. software_application is an additional type and must follow product. items: type: string enum: [product, software_application, faq, about, webpage, news_article, blog_posting, tech_article, item_page, real_estate_listing, article] responses: '200': description: Schema-generation job queued content: application/json: schema: $ref: '#/components/schemas/PropertyJobAcceptedResponse' '400': description: JSON-LD already generated or invalid request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Unauthorized - Invalid Secret Key content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Organisation, property, or article not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: None of the requested schema types had enough eligible properties content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /property: get: tags: - properties summary: Get all properties for the authenticated organisation operationId: getProperties security: - Authorization: [] responses: '200': description: A list of properties headers: X-Total-Count: description: Total number of properties schema: type: integer content: application/json: schema: type: array items: $ref: '#/components/schemas/Property' '404': description: Properties not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' post: tags: - properties summary: Create a new property operationId: createProperty security: - Authorization: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Property' responses: '200': description: Successfully created property content: application/json: schema: $ref: '#/components/schemas/Property' '400': description: Invalid input '404': description: Creation failed /property/{id}: get: tags: - properties summary: Get a property by ID operationId: getPropertyById security: - Authorization: [] parameters: - name: id in: path required: true schema: type: string responses: '200': description: Property found content: application/json: schema: $ref: '#/components/schemas/Property' '404': description: Property not found put: tags: - properties summary: Update an existing property operationId: updateProperty security: - Authorization: [] parameters: - name: id in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Property' responses: '200': description: Updated property content: application/json: schema: $ref: '#/components/schemas/Property' '400': description: Invalid input '403': description: Unauthorized '404': description: Property not found '500': description: Internal server error /property/{organisationID}/from/url: post: tags: - properties summary: Create a Property for a given URL operationId: createPropertyFromUrl security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path description: ID of the Organisation required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: type: object properties: url: type: string responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/Property' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '401': description: Invalid Secret Key for Organisation + Property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '425': description: Too Early - Article has not been processed yet content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /property/scraping/suggestion: post: summary: Get suggested scraping configuration for a property tags: - properties security: - Authorization: [] requestBody: required: true content: application/json: schema: type: object required: [ url, category ] properties: url: type: string format: uri example: https://example.com/topic/abc category: type: string enum: [ article, topic ] example: topic responses: '200': description: Suggested scraping configuration and parsed content content: application/json: schema: type: object additionalProperties: type: object properties: selector: type: string content: oneOf: - type: string - type: object - type: array '400': description: Bad request or invalid category content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /property/{id}/scraping/test: post: summary: Test scraping configuration for an existing property tags: - properties security: - Authorization: [] parameters: - name: id in: path required: true description: Property ID schema: type: string requestBody: required: true content: application/json: schema: type: object required: [ url, category ] properties: url: type: string format: uri example: https://example.com/article/123 category: type: string enum: [ article, topic ] example: article responses: '200': description: Suggested scraping configuration and parsed content content: application/json: schema: type: object additionalProperties: type: object properties: selector: type: string content: oneOf: - type: string - type: object - type: array '400': description: Bad request or invalid category content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '403': description: Unauthorized to update this property content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /deals/{organisationID}/{propertyID}/{dealID}: get: tags: - deals summary: Get Deal by ID description: Retrieve a specific deal by its ID operationId: getDealById security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: dealID in: path required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/DealArticleAnalysis' '404': description: Deal not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - deals summary: Delete Deal description: Delete a deal by its ID operationId: deleteDeal security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: dealID in: path required: true schema: type: string format: uuid responses: '200': description: Deal deleted successfully content: application/json: schema: type: object properties: message: type: string '404': description: Deal not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /deals/{organisationID}/{dealID}: get: tags: - deals summary: Get Deal by ID description: Retrieve a specific deal by its ID across the organisation operationId: getDealByOrgAndDealId security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: dealID in: path required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/DealArticleAnalysis' '404': description: Deal not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /deals/{organisationID}/{propertyID}/search: get: tags: - deals summary: Search Deals with Filters description: Search for deals using various filters operationId: searchDeals security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: companyName in: query required: false schema: type: string - name: clientCompanyName in: query required: false schema: type: string - name: sellerCompanyName in: query required: false schema: type: string - name: manufacturerName in: query required: false schema: type: string - name: startDate in: query required: false schema: type: string - name: endDate in: query required: false schema: type: string - name: from in: query required: false schema: type: integer default: 0 - name: size in: query required: false schema: type: integer default: 20 responses: '200': description: Successful operation headers: X-Total-Count: schema: type: integer description: Total number of deals content: application/json: schema: type: array items: $ref: '#/components/schemas/DealArticleAnalysis' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /deals/{organisationID}/{propertyID}: get: tags: - deals summary: List All Deals description: Get all deals for a property with pagination operationId: listAllDeals security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: from in: query required: false schema: type: integer default: 0 - name: size in: query required: false schema: type: integer default: 20 responses: '200': description: Successful operation headers: X-Total-Count: schema: type: integer description: Total number of deals content: application/json: schema: type: array items: $ref: '#/components/schemas/DealArticleAnalysis' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /deals/{organisationID}/{propertyID}/company/{companyName}: get: tags: - deals summary: Search Deals by Company Name description: Search for deals by company name operationId: searchDealsByCompany security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: companyName in: path required: true schema: type: string - name: from in: query required: false schema: type: integer default: 0 - name: size in: query required: false schema: type: integer default: 20 responses: '200': description: Successful operation headers: X-Total-Count: schema: type: integer description: Total number of deals content: application/json: schema: type: array items: $ref: '#/components/schemas/DealArticleAnalysis' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /deals/{organisationID}/{propertyID}/date-range: get: tags: - deals summary: Search Deals by Date Range description: Search for deals within a specific date range operationId: searchDealsByDateRange security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: startDate in: query required: true schema: type: string - name: endDate in: query required: true schema: type: string - name: from in: query required: false schema: type: integer default: 0 - name: size in: query required: false schema: type: integer default: 20 responses: '200': description: Successful operation headers: X-Total-Count: schema: type: integer description: Total number of deals content: application/json: schema: type: array items: $ref: '#/components/schemas/DealArticleAnalysis' '400': description: Bad request - startDate and endDate are required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /competitors/suggest/{organisationID}/{propertyID}: post: tags: - competitors summary: Suggest Competitors description: Use LLM to suggest competitors for a given domain operationId: suggestCompetitors security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompetitorSuggestionRequest' responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/CompetitorSuggestionResponse' '400': description: Invalid input or domain is required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /competitors/{organisationID}/{propertyID}: get: tags: - competitors summary: List Competitors description: Get all competitors for a property operationId: listCompetitors security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: type: array items: $ref: '#/components/schemas/Property' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' post: tags: - competitors summary: Add Competitor description: Add a new competitor to a property operationId: addCompetitor security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompetitorData' responses: '200': description: Competitor added successfully content: application/json: schema: $ref: '#/components/schemas/Property' '400': description: Invalid input - name and URL are required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /competitors/{organisationID}/{propertyID}/{competitorID}: put: tags: - competitors summary: Update Competitor description: Update an existing competitor operationId: updateCompetitor security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: competitorID in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompetitorData' responses: '200': description: Competitor updated successfully content: application/json: schema: $ref: '#/components/schemas/Property' '400': description: Invalid input - name and URL are required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Competitor or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' delete: tags: - competitors summary: Remove Competitor description: Remove a competitor from a property operationId: removeCompetitor security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: competitorID in: path required: true schema: type: string format: uuid responses: '200': description: Competitor removed successfully content: application/json: schema: type: object properties: message: type: string '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Competitor or property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /entity-analysis/{organisationID}/{propertyID}/suggest/{articleID}: get: tags: - entity-analysis summary: Suggest Missing Entities description: Suggest related entities not yet covered in a specific article operationId: suggestMissingEntities security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: articleID in: path required: true schema: type: string description: ID of the article to analyze - name: maxSuggestions in: query required: false schema: type: integer minimum: 1 maximum: 50 description: Maximum number of suggested entities to return responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/EntitySuggestionResponse' '400': description: Missing articleID, invalid maxSuggestions, or article has empty content content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property, article, or article analysis not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /entity-analysis/{organisationID}/{propertyID}/supersuggest/{articleID}: get: tags: - entity-analysis summary: Supersuggest Missing Entities description: Suggest missing entities with explainable scoring, trend momentum, and knowledge graph evidence operationId: superSuggestMissingEntities security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: articleID in: path required: true schema: type: string description: ID of the article to analyze - name: maxSuggestions in: query required: false schema: type: integer minimum: 1 maximum: 50 description: Maximum number of suggestions to return responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/EntitySuperSuggestResponse' '400': description: Missing articleID, invalid maxSuggestions, or article has empty content content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property, article, or article analysis not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /entity-analysis/{organisationID}/{propertyID}: get: tags: - entity-analysis summary: Get Entity Analysis description: Get entity analysis for a property operationId: getEntityAnalysis security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: pageTypes in: query required: false description: Comma-separated list of page types (e.g., "article,topic") schema: type: string responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/EntityAnalysis' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /entity-analysis/{organisationID}/{propertyID}/compare: get: tags: - entity-analysis summary: Compare Entities description: Compare entities between base property and competitors operationId: compareEntities security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: competitors in: query required: true description: Comma-separated list of competitor property IDs schema: type: string - name: pageTypes in: query required: false description: Comma-separated list of page types (e.g., "article,topic") schema: type: string responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/EntityComparison' '400': description: Bad request - competitors parameter is required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /entity-analysis/{organisationID}/{propertyID}/gaps: get: tags: - entity-analysis summary: Get Gap Analysis description: Get entity gap analysis comparing base property with competitors operationId: getEntityGapAnalysis security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: competitors in: query required: true description: Comma-separated list of competitor property IDs schema: type: string - name: pageTypes in: query required: false description: Comma-separated list of page types (e.g., "article,topic") schema: type: string responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/EntityGapAnalysis' '400': description: Bad request - competitors parameter is required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /entity-analysis/{organisationID}/{propertyID}/export: get: tags: - entity-analysis summary: Export Entity Data as CSV description: Export entity analysis data as CSV file operationId: exportEntityData security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: competitors in: query required: false description: Comma-separated list of competitor property IDs schema: type: string - name: pageTypes in: query required: false description: Comma-separated list of page types (e.g., "article,topic") schema: type: string responses: '200': description: Successful operation - CSV file content: text/csv: schema: type: string format: binary '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /entity-analysis/{organisationID}/{propertyID}/topic-map: get: tags: - entity-analysis summary: Get Topic Map description: Get entity analysis data formatted for topic map visualization operationId: getTopicMap security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: competitors in: query required: false description: Comma-separated list of competitor property IDs schema: type: string - name: pageTypes in: query required: false description: Comma-separated list of page types (e.g., "article,topic") schema: type: string responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/EntityAnalysis' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /entity-analysis/{organisationID}/{propertyID}/generate-tasks: post: tags: - entity-analysis summary: Generate Content Strategy Tasks description: Generate content strategy tasks from gap analysis operationId: generateContentStrategyTasks security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid - name: competitors in: query required: true description: Comma-separated list of competitor property IDs schema: type: string - name: pageTypes in: query required: false description: Comma-separated list of page types (e.g., "article,topic") schema: type: string responses: '200': description: Tasks generated successfully content: application/json: schema: type: object properties: message: type: string '400': description: Bad request - competitors parameter is required content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Property not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /task/{orgId}/{propertyId}: get: tags: - tasks summary: Get Open Tasks description: Get all open tasks for a property operationId: getOpenTasks security: - Authorization: [] parameters: - name: orgId in: path required: true schema: type: string format: uuid - name: propertyId in: path required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: $ref: '#/components/schemas/TasksResponse' '404': description: Tasks not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /task/{org_id}/{property_id}: post: tags: - tasks summary: Create Task description: Create a new task operationId: createTask security: - Authorization: [] parameters: - name: org_id in: path required: true schema: type: string format: uuid - name: property_id in: path required: true schema: type: string format: uuid requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Task' responses: '200': description: Task created successfully content: application/json: schema: $ref: '#/components/schemas/Task' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Creation failed content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /task/{org_id}/{property_id}/{task_id}/complete: post: tags: - tasks summary: Complete Task description: Mark a task as completed operationId: completeTask security: - Authorization: [] parameters: - name: org_id in: path required: true schema: type: string format: uuid - name: property_id in: path required: true schema: type: string format: uuid - name: task_id in: path required: true schema: type: string format: uuid responses: '200': description: Task completed successfully content: application/json: schema: $ref: '#/components/schemas/Task' '404': description: Task not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /task/{org_id}/{property_id}/{task_id}/ignore: post: tags: - tasks summary: Ignore Task description: Mark a task as ignored operationId: ignoreTask security: - Authorization: [] parameters: - name: org_id in: path required: true schema: type: string format: uuid - name: property_id in: path required: true schema: type: string format: uuid - name: task_id in: path required: true schema: type: string format: uuid responses: '200': description: Task ignored successfully content: application/json: schema: $ref: '#/components/schemas/Task' '404': description: Task not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /task/{org_id}/{property_id}/{task_id}: delete: tags: - tasks summary: Delete Task description: Delete a task operationId: deleteTask security: - Authorization: [] parameters: - name: org_id in: path required: true schema: type: string format: uuid - name: property_id in: path required: true schema: type: string format: uuid - name: task_id in: path required: true schema: type: string format: uuid responses: '204': description: Task deleted successfully '404': description: Task not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /ga/{organisationID}: get: tags: - google-analytics summary: Get Organisation Google Analytics description: Get Google Analytics data for an organisation operationId: getOrganisationGoogleAnalytics security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: type: array items: $ref: '#/components/schemas/MonthlyStats' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /ga/{organisationID}/{propertyID}: get: tags: - google-analytics summary: Get Property Google Analytics description: Get Google Analytics data for a specific property operationId: getPropertyGoogleAnalytics security: - Authorization: [] - X-Secret-Key: [] parameters: - name: organisationID in: path required: true schema: type: string format: uuid - name: propertyID in: path required: true schema: type: string format: uuid responses: '200': description: Successful operation content: application/json: schema: type: array items: $ref: '#/components/schemas/MonthlyStats' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' components: schemas: # Stubs referenced by Fanout routes (spec previously referenced undefined schemas). FanoutAnalysis: type: object additionalProperties: true FanoutInitRequest: type: object additionalProperties: true FanoutPromptRequest: type: object additionalProperties: true FanoutConfig: type: object additionalProperties: true FanoutParagraphReviewRequest: type: object additionalProperties: true ParagraphReviewResult: type: object additionalProperties: true SignupRequest: type: object properties: email: type: string format: email example: user@example.com password: type: string format: password example: secretPassword123 orgName: type: string description: Organisation name, required if creating a new organisation example: "My Organization" orgId: type: string description: Organisation ID, required if joining an existing organisation example: "123e4567-e89b-12d3-a456-426614174000" required: - email - password oneOf: - required: [ orgName ] - required: [ orgId ] SignupResponse: type: string example: success ErrorResponse: type: object properties: message: type: string Webhook: type: object properties: id: type: string format: uuid orgId: type: string format: uuid url: type: string format: uri secret: type: string enabled: type: boolean extensive: type: boolean description: When true, the full article payload is included in the delivery. failedDeliveryCount: type: integer targetProperties: type: array items: type: string description: Restrict deliveries to these property IDs. Empty means all properties. subscribedEvents: type: array items: type: string enum: [article_analysis, autolink, structured_data] description: Event types to subscribe to. Empty means all events. createdAt: type: string format: date-time updatedAt: type: string format: date-time WebhookInput: type: object required: - url properties: url: type: string format: uri secret: type: string description: Signing secret. Auto-generated if omitted. extensive: type: boolean default: false targetProperties: type: array items: type: string subscribedEvents: type: array items: type: string enum: [article_analysis, autolink, structured_data] WebhookUpdateInput: type: object required: - url properties: url: type: string format: uri secret: type: string enabled: type: boolean extensive: type: boolean targetProperties: type: array items: type: string subscribedEvents: type: array items: type: string enum: [article_analysis, autolink, structured_data] UserResponse: type: object properties: id: type: string format: uuid example: "123e4567-e89b-12d3-a456-426614174000" email: type: string format: email example: "user@example.com" org: type: string format: uuid description: Organisation ID example: "223e4567-e89b-12d3-a456-426614174000" roles: type: array items: type: string example: [ "User", "Admin" ] createdAt: type: string format: date-time example: "2024-07-20T15:00:00Z" updatedAt: type: string format: date-time example: "2024-07-21T10:32:45Z" EntityItem: type: object properties: title: type: string description: Lowercase version of the entity text example: "artificial intelligence" anchor: type: string description: Original case entity text as found in content example: "Artificial Intelligence" category: type: string description: Category of the entity enum: [entities, events, organisations, people, products, locations] example: "entities" occurs: type: integer description: Number of times this entity appears in the article content example: 5 Search: type: object properties: properties: type: array items: type: string format: uuid size: type: integer format: int32 from: type: integer format: int32 query: type: string SearchResponse: type: array items: allOf: - type: object properties: id: type: string format: uuid propertyId: type: string format: uuid organisationId: type: string format: uuid - $ref: '#/components/schemas/Article' ArticleWithAnalysisAndLinksResponse: type: object properties: article: $ref: '#/components/schemas/Article' links: $ref: '#/components/schemas/ArticleLinks' entities: type: array description: Entities extracted from the article content, ordered by occurrence count (highest first) items: $ref: '#/components/schemas/EntityItem' analysis: $ref: '#/components/schemas/ArticleAnalysis' ArticleLinks: type: array items: type: object properties: articleId: type: string format: uuid id: type: string format: uuid anchor: type: string example: Internal Linking Automated isInternal: type: boolean isPrior: type: boolean isPhraseLink: type: boolean isTopic: type: boolean isCandidate: type: boolean startCaret: type: integer endCaret: type: integer url: type: string example: https://subjct.ai/article/test MetricsResponse: type: object properties: metrics: type: object properties: articles: type: integer links: type: object properties: total: type: number internal: type: number external: type: number words: type: object properties: total: type: number minimum: type: number maximum: type: number average: type: number OrganisationResponse: type: object properties: id: type: string format: uuid name: type: string example: Subjct secretKeys: type: array items: type: string example: sk__UUID createdAt: type: string format: date-time updatedAt: type: string format: date-time ArticleAnalysis: type: object properties: id: type: string format: uuid category: type: string createdAt: type: string format: date-time updatedAt: type: string format: date-time summary: type: string sentiment: type: string example: "0.35" entities: type: array items: type: string events: type: array items: type: string organisations: type: array items: type: string people: type: array items: type: string products: type: array items: type: string locations: type: array items: type: string linkedEntities: type: array items: $ref: '#/components/schemas/LinkedEntity' LinkedEntity: type: object properties: category: type: string name: type: string kgId: type: string source: type: string ArticleResponse: type: object properties: id: type: string format: uuid externalId: type: string organisationId: type: string format: uuid propertyId: type: string format: uuid contentHash: type: string htmlHash: type: string Topic: type: object properties: externalId: type: string url: type: string format: url text: type: string TopicResponse: type: object properties: id: type: string format: uuid externalId: type: string organisationId: type: string format: uuid propertyId: type: string format: uuid SimilarArticle: type: object properties: Id: type: string title: type: string href: type: string format: url SimilarArticles: type: array items: allOf: - $ref: '#/components/schemas/SimilarArticle' Article: type: object properties: id: type: string format: uuid organisationId: type: string format: uuid propertyId: type: string format: uuid type: type: string description: Primary schema template type. When omitted during ingestion, the service selects it from the title, URL, and content. enum: [product, faq, about, webpage, news_article, blog_posting, tech_article, item_page, real_estate_listing, article] example: news_article types: type: array description: Ordered schema types. The first eligible value is primary; later eligible values become additional JSON-LD graph nodes. software_application is only retained after product. items: type: string enum: [product, software_application, faq, about, webpage, news_article, blog_posting, tech_article, item_page, real_estate_listing, article] metadata: type: object description: Additional flexible metadata properties based on the article type example: articleSection: "Technology" wordCount: 1200 schemaMetadata: type: object description: Optional metadata keyed by canonical schema type for multi-template generation. additionalProperties: type: object contentHash: type: string htmlHash: type: string evergreen: type: boolean hotPeriodStart: type: string format: date-time nullable: true hotPeriodEnd: type: string format: date-time nullable: true jsonLdGeneratedAt: type: string format: date-time nullable: true externalId: type: string url: type: string format: url datePublished: type: string format: date-time nullable: true dateUpdated: type: string format: date-time dateCreated: type: string format: date-time autoLinked: type: string format: date-time deleted: type: boolean description: Indicates whether the article has been soft deleted example: true deletedAt: type: string format: date-time nullable: true description: | Timestamp when the article was soft deleted. Can be: - a date-time string if deleted, - empty string if not deleted, - null if the field does not exist in the document. example: "" title: type: string language: type: string images: type: array items: type: object properties: title: type: string alt: type: string url: type: string format: url authors: type: array items: type: object properties: name: type: string url: type: string format: url content: type: string html: type: string references: type: string description: Raw HTML from the article references block, when present on source page jsonLd: type: string description: JSON-LD structured metadata, sent as a serialized JSON string example: >- { "@context": "https://schema.org", "@type": "NewsArticle", "@id": "https://www.example.com/articles/12345#article", "isPartOf": { "@id": "https://www.example.com/articles/12345/" }, "author": { "name": "Alex Johnson", "@id": "https://www.example.com/#/schema/person/abc123xyz" }, "headline": "Tech breakthrough reshapes future of clean energy", "datePublished": "2025-06-01T09:30:00+00:00", "mainEntityOfPage": { "@id": "https://www.example.com/articles/12345/" }, "wordCount": 1540, "publisher": { "@id": "https://www.example.com/#organization" }, "image": { "@id": "https://www.example.com/articles/12345/#primaryimage" }, "thumbnailUrl": "https://www.example.com/assets/images/article-thumbnail.jpg", "keywords": [ "Technology", "Renewable Energy", "Innovation", "Climate" ], "articleSection": ["Environment"], "inLanguage": "en-GB", "copyrightYear": "2025", "copyrightHolder": { "@id": "https://www.example.com/#organization" } } breadcrumbs: type: array items: type: object properties: position: type: integer name: type: string url: type: string format: url example: - position: 1 name: "Home" url: "https://example.com" - position: 2 name: "Technology" url: "https://example.com/technology" - position: 3 name: "AI Revolutionizes OpenAPI Schema" url: "https://example.com/technology/ai-openapi" Login: type: object properties: email: type: string format: email password: type: string example: examplePassword LoginResponse: type: object properties: token: type: string example: a long jwt token Property: type: object properties: id: type: string organisationId: type: string icons: type: array items: type: object properties: url: type: string mimetype: type: string extension: type: string width: type: integer height: type: integer hash: type: string target: type: object properties: version: type: string name: type: string url: type: string autoDiscovery: type: boolean rate: type: object properties: mrps: type: integer source: type: object properties: include: type: array items: type: string exclude: type: array items: type: string categories: type: array items: $ref: '#/components/schemas/TargetPath' sitemaps: type: array items: $ref: '#/components/schemas/TargetPath' rss: type: array items: $ref: '#/components/schemas/TargetPath' customSources: type: array items: $ref: '#/components/schemas/TargetPath' crawl: $ref: '#/components/schemas/CrawlConfiguration' type: type: string parser: type: object script: type: object properties: enabled: type: boolean metrics: type: object properties: track: type: array items: type: string linking: type: object properties: articleSelector: type: string jsonLd: type: object properties: articleSchemaName: type: string TargetPath: type: object properties: type: type: string path: type: string regex: type: string filters: type: array items: type: object properties: property: type: string value: type: string operator: type: string CrawlSettings: type: object properties: maxDepth: type: integer maxPages: type: integer maxConcurrency: type: integer respectRobots: type: boolean userAgent: type: string CrawlConfiguration: allOf: - type: object properties: disabled: type: boolean seeds: type: array items: $ref: '#/components/schemas/TargetPath' - $ref: '#/components/schemas/CrawlSettings' IngestionJobResponse: type: object description: Details of an ingestion job, including status, file URLs, and result counts. properties: id: type: string format: uuid description: Unique ID of the ingestion job. example: "f2f3dd28-a46a-4bf6-83a6-ecda5bca8705" organisation_id: type: string format: uuid description: Organisation associated with this job. example: "5658d357-55a3-41b1-8f59-03ff6cdaac42" property_id: type: string format: uuid description: Property associated with this job. example: "3233caf4-ac56-43e6-90bb-5adf4d469c04" ingestion_type: type: string description: Type of ingestion process (e.g., topics_ingest, articles_ingest, ...). example: "topics_ingest" input_file: type: string format: uri description: Signed URL to download the input CSV file. example: "http://localhost:4443/storage/v1/b/subjct-ingestion/o/.../topics_ingest.csv" output_file: type: string format: uri description: Signed URL to download the output CSV file. example: "http://localhost:4443/storage/v1/b/subjct-ingestion/o/.../output.csv" status: type: string description: Current status of the ingestion job. example: "finished" success_count: type: integer description: Number of successfully processed records. example: 11 failure_count: type: integer description: Number of failed records during ingestion. example: 0 ingestion_msg: type: string description: Message describing the ingestion outcome. example: "Successfully Ingested" created_at: type: string format: date-time description: Timestamp of when the job was created. example: "2025-10-20T17:46:44.068679Z" updated_at: type: string format: date-time description: Timestamp of the most recent job update. example: "2025-10-20T17:49:55.02909Z" PropertyJobAcceptedResponse: type: object required: [status, totalItems] properties: jobId: type: string format: uuid description: Present when progress tracking was persisted successfully. status: type: string enum: [queued] totalItems: type: integer minimum: 1 PropertyJobItem: type: object required: [articleId, status, updatedAt] properties: articleId: type: string format: uuid status: type: string enum: [queued, running, completed, failed, no_changes] error: type: string metadata: type: object additionalProperties: true updatedAt: type: string format: date-time PropertyJob: type: object required: [id, organisationId, propertyId, version, jobType, source, status, totalItems, completedItems, failedItems, noChangeItems, createdAt, updatedAt] properties: id: type: string format: uuid organisationId: type: string format: uuid propertyId: type: string format: uuid version: type: string jobType: type: string enum: [schema_generation, autolink] source: type: string status: type: string enum: [queued, running, completed, failed, partial_success] message: type: string totalItems: type: integer completedItems: type: integer failedItems: type: integer noChangeItems: type: integer items: type: array items: $ref: '#/components/schemas/PropertyJobItem' createdAt: type: string format: date-time updatedAt: type: string format: date-time DealArticleAnalysis: type: object properties: id: type: string format: uuid createdAt: type: string format: date-time updatedAt: type: string format: date-time clientCompanyName: type: string clientCompanyUrl: type: string clientContactName: type: string clientContactJobTitle: type: string sellerCompanyName: type: string sellerCompanyUrl: type: string sellerContactName: type: string sellerContactJobTitle: type: string manufacturers: type: array items: $ref: '#/components/schemas/ManufacturerProduct' productCost: type: string projectCompanyName: type: string projectCompanyUrl: type: string projectCompanyContactName: type: string projectCompanyContactJobTitle: type: string projectLocation: type: string projectDetails: type: string ManufacturerProduct: type: object properties: manufacturerName: type: string manufacturerUrl: type: string equipment: type: array items: $ref: '#/components/schemas/EquipmentItem' EquipmentItem: type: object properties: type: type: string model: type: string CompetitorSuggestionRequest: type: object required: - domain properties: domain: type: string description: Domain name to find competitors for example: "example.com" context: type: string description: Optional free-text hint (company name, product category, geography) to disambiguate the business behind the domain example: "Acme Analytics · B2B marketing attribution" CompetitorSuggestionResponse: type: object properties: competitors: type: array items: $ref: '#/components/schemas/CompetitorSuggestion' CompetitorSuggestion: type: object properties: name: type: string website: type: string category: type: string description: type: string key_features: type: array items: type: string ranking: type: integer CompetitorData: type: object required: - name - url properties: name: type: string url: type: string format: uri EntitySuggestionResponse: type: object properties: suggestions: type: array items: $ref: '#/components/schemas/MissingEntitySuggestion' MissingEntitySuggestion: type: object properties: entity: type: string category: type: string why_related: type: string EntitySuperSuggestResponse: type: object properties: articleId: type: string suggestions: type: array items: $ref: '#/components/schemas/SuperSuggestedEntity' missingSignals: type: array items: $ref: '#/components/schemas/SuperSuggestMissingSignal' SuperSuggestedEntity: type: object properties: entity: type: string category: type: string why_related: type: string opportunityScore: type: number format: float signals: type: array items: $ref: '#/components/schemas/SuperSuggestSignalBreakdown' evidence: $ref: '#/components/schemas/SuperSuggestEvidence' SuperSuggestSignalBreakdown: type: object properties: name: type: string rawValue: type: number format: float normalized: type: number format: float weight: type: number format: float contribution: type: number format: float available: type: boolean reason: type: string sources: type: array items: type: string SuperSuggestEvidence: type: object properties: canonicalEntityId: type: string canonicalEntityName: type: string canonicalEntityDescription: type: string canonicalEntityTypes: type: array items: type: string trendSeries: type: array items: type: integer trendWindow: type: string SuperSuggestMissingSignal: type: object properties: name: type: string reason: type: string EntityAnalysis: type: object properties: propertyId: type: string format: uuid entities: type: object additionalProperties: $ref: '#/components/schemas/EntityCategory' totalCount: type: integer format: int64 EntityCategory: type: object properties: entities: type: array items: $ref: '#/components/schemas/EntityCount' category: type: string totalCount: type: integer format: int64 uniqueCount: type: integer EntityCount: type: object properties: name: type: string count: type: integer format: int64 EntityComparison: type: object properties: basePropertyId: type: string format: uuid competitorIds: type: array items: type: string format: uuid comparison: type: object additionalProperties: $ref: '#/components/schemas/EntityComparisonItem' EntityComparisonItem: type: object properties: entityName: type: string category: type: string baseCount: type: integer format: int64 competitorCounts: type: object additionalProperties: type: integer format: int64 totalCompetitorCount: type: integer format: int64 averageCompetitorCount: type: number format: float EntityGapAnalysis: type: object properties: basePropertyId: type: string format: uuid competitorIds: type: array items: type: string format: uuid missingEntities: type: array items: $ref: '#/components/schemas/GapEntity' underperforming: type: array items: $ref: '#/components/schemas/GapEntity' leading: type: array items: $ref: '#/components/schemas/GapEntity' GapEntity: type: object properties: entityName: type: string category: type: string baseCount: type: integer format: int64 competitorCounts: type: object additionalProperties: type: integer format: int64 totalCompetitorCount: type: integer format: int64 gap: type: integer format: int64 Task: type: object properties: id: type: string format: uuid org_id: type: string format: uuid property_id: type: string format: uuid task_type: $ref: '#/components/schemas/TaskType' metadata: type: object description: JSON metadata for the task status: $ref: '#/components/schemas/TaskStatus' created_at: type: string format: date-time updated_at: type: string format: date-time TaskType: type: string enum: - boost_links - missing_links - topic_suggestion - broken_links - content_gap - source_review TaskStatus: type: string enum: - new - completed - ignored TasksResponse: type: object properties: tasks: type: array items: $ref: '#/components/schemas/Task' total: type: integer MonthlyStats: type: object properties: month: type: string pageViews: type: integer engagementRate: type: number format: float scrolledUsers: type: integer requestBodies: LoginRequest: description: Login Object content: application/json: schema: $ref: '#/components/schemas/Login' SignupRequest: description: Signup Object content: application/json: schema: $ref: '#/components/schemas/SignupRequest' SearchRequest: description: Search Object to be searched content: application/json: schema: $ref: '#/components/schemas/Search' required: true ArticleRequest: description: Article Object to be saved and processed content: application/json: schema: $ref: '#/components/schemas/Article' required: true TopicRequest: description: Topic Object to be saved and processed content: application/json: schema: $ref: '#/components/schemas/Topic' required: true WebhookCreateRequest: description: Webhook to be created content: application/json: schema: $ref: '#/components/schemas/WebhookInput' required: true WebhookUpdateRequest: description: Webhook fields to update content: application/json: schema: $ref: '#/components/schemas/WebhookUpdateInput' required: true securitySchemes: Authorization: type: apiKey name: Authorization in: header X-Secret-Key: type: apiKey name: X-Secret-Key in: header