{
  "openapi": "3.1.0",
  "info": {
    "title": "Adlicio Export API",
    "version": "1.0.0",
    "description": "The read-only export surface for comments and scrapes an account has already collected. For interactive research, use the Adlicio MCP server at https://mcp.tryadlicio.com/mcp (manifest: https://tryadlicio.com/.well-known/mcp.json). For scripted collection and research, install the CLI with `npm install -g commentscraper`."
  },
  "servers": [
    {
      "url": "https://tryadlicio.com"
    }
  ],
  "security": [
    {
      "deviceToken": []
    }
  ],
  "paths": {
    "/api/v1/export/scrapes": {
      "get": {
        "operationId": "exportScrapes",
        "summary": "Export collected scrapes",
        "description": "Returns the authenticated account's collected scrape-history rows in reverse chronological order. Each record includes its normalized comments. NDJSON is streamed one scrape per line; JSON wraps the records in a data array with the next cursor.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Since"
          },
          {
            "$ref": "#/components/parameters/Until"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Format"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of scrape records. With `format=json`, the cursor is in `next_cursor`. With `format=ndjson`, each line is one scrape and the next cursor is returned in `x-next-cursor` when another page may exist.",
            "headers": {
              "x-next-cursor": {
                "description": "Opaque cursor for the next page. Present only for NDJSON responses when the page contains exactly the requested limit.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScrapeJsonResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/x-ndjson",
                  "description": "Newline-delimited ScrapeExportRecord objects, one JSON object per line.",
                  "x-ndjson-item-schema": {
                    "$ref": "#/components/schemas/ScrapeExportRecord"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/v1/export/comments": {
      "get": {
        "operationId": "exportComments",
        "summary": "Export collected comments",
        "description": "Returns comments from the authenticated account's collected scrapes in a flat record shape suitable for data pipelines. Pagination selects scrape-history rows, then emits every normalized comment in those scrapes, so a page can contain more comment records than the requested scrape limit. NDJSON is streamed one comment per line; JSON wraps the records in a data array with the next cursor.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Since"
          },
          {
            "$ref": "#/components/parameters/Until"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Format"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of flattened comment records. With `format=json`, the cursor is in `next_cursor`. With `format=ndjson`, each line is one comment and the next cursor is returned in `x-next-cursor` when another scrape page may exist.",
            "headers": {
              "x-next-cursor": {
                "description": "Opaque cursor for the next scrape page. Present only for NDJSON responses when the scrape page contains exactly the requested limit.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentJsonResponse"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "type": "string",
                  "contentMediaType": "application/x-ndjson",
                  "description": "Newline-delimited CommentExportRecord objects, one JSON object per line.",
                  "x-ndjson-item-schema": {
                    "$ref": "#/components/schemas/CommentExportRecord"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "deviceToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "CLI device token or adl_ API key",
        "description": "CLI device token. Get one by installing the CLI (`npm install -g commentscraper`) and running `commentscraper login`; the token is minted by `commentscraper login`. Account API keys beginning with `adl_` are also accepted and can be created from the Adlicio account page."
      }
    },
    "parameters": {
      "Since": {
        "name": "since",
        "in": "query",
        "required": false,
        "description": "Include scrapes whose `scraped_at` value is on or after this ISO 8601 date or timestamp. Date-only values such as `2026-07-01` are accepted.",
        "schema": {
          "type": "string",
          "examples": [
            "2026-07-01",
            "2026-07-01T00:00:00Z"
          ]
        }
      },
      "Until": {
        "name": "until",
        "in": "query",
        "required": false,
        "description": "Include scrapes whose `scraped_at` value is on or before this ISO 8601 date or timestamp. Date-only values such as `2026-07-31` are accepted.",
        "schema": {
          "type": "string",
          "examples": [
            "2026-07-31",
            "2026-07-31T23:59:59Z"
          ]
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Number of scrape-history rows to select for this page. For the comments endpoint, every comment from those selected scrapes is emitted, so the number of comment records can exceed this value.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 500,
          "default": 100
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "Opaque base64url cursor returned by the previous page. It encodes the server-side offset; pass it back unchanged. In JSON it is returned as `next_cursor`; in NDJSON it is returned in the `x-next-cursor` header.",
        "schema": {
          "type": "string"
        }
      },
      "Format": {
        "name": "format",
        "in": "query",
        "required": false,
        "description": "Response serialization. `ndjson` streams one record per line. `json` returns one object with `data` and `next_cursor`. CSV is not supported by the export API.",
        "schema": {
          "type": "string",
          "enum": [
            "ndjson",
            "json"
          ],
          "default": "ndjson"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "A date, limit, cursor, or format query parameter is invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ExportError"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The bearer token is missing or invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ExportError"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The account's plan does not include the export API.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ExportError"
            }
          }
        }
      },
      "RateLimited": {
        "description": "The bearer token has exceeded the export rate limit.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ExportError"
            }
          }
        }
      },
      "InternalError": {
        "description": "The export could not be completed because of an internal error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ExportError"
            }
          }
        }
      }
    },
    "schemas": {
      "NormalizedComment": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "body",
          "author",
          "score",
          "permalink"
        ],
        "properties": {
          "body": {
            "type": "string"
          },
          "author": {
            "type": [
              "string",
              "null"
            ]
          },
          "score": {
            "type": [
              "number",
              "null"
            ]
          },
          "permalink": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ScrapeExportRecord": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "type",
          "platform",
          "thread_title",
          "thread_url",
          "keyword",
          "comment_count",
          "scraped_at",
          "comments"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": [
              "string",
              "null"
            ]
          },
          "platform": {
            "type": [
              "string",
              "null"
            ],
            "description": "The stored source/platform value from the scrape history row."
          },
          "thread_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "thread_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "keyword": {
            "type": [
              "string",
              "null"
            ]
          },
          "comment_count": {
            "type": "integer",
            "minimum": 0
          },
          "scraped_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "comments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NormalizedComment"
            }
          }
        }
      },
      "CommentExportRecord": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "scrape_id",
          "scraped_at",
          "type",
          "platform",
          "thread_title",
          "thread_url",
          "keyword",
          "comment_index",
          "body",
          "author",
          "score",
          "permalink"
        ],
        "properties": {
          "scrape_id": {
            "type": "string"
          },
          "scraped_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "type": {
            "type": [
              "string",
              "null"
            ]
          },
          "platform": {
            "type": [
              "string",
              "null"
            ],
            "description": "The stored source/platform value from the scrape history row."
          },
          "thread_title": {
            "type": [
              "string",
              "null"
            ]
          },
          "thread_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "keyword": {
            "type": [
              "string",
              "null"
            ]
          },
          "comment_index": {
            "type": "integer",
            "minimum": 0,
            "description": "Zero-based position of the normalized comment within its scrape."
          },
          "body": {
            "type": "string"
          },
          "author": {
            "type": [
              "string",
              "null"
            ]
          },
          "score": {
            "type": [
              "number",
              "null"
            ]
          },
          "permalink": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ScrapeJsonResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScrapeExportRecord"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "CommentJsonResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "data",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CommentExportRecord"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ExportError": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}
