{
  "openapi": "3.1.0",
  "info": {
    "title": "Coco Search API",
    "version": "1.0.0",
    "description": "A search API for AI agents: ask anything, get back pages, articles, videos, papers, code, files and apps, each with a link. Free. Without a key: 10 questions a minute and 100 a day per address. With a free key (POST /v1/keys, sent to your mailbox): 60 a minute and 1,000 a day.",
    "contact": {
      "email": "lc@linearcode.io",
      "url": "https://linearcode.io"
    }
  },
  "paths": {
    "/v1/search": {
      "get": {
        "summary": "Search the index",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "The question, in any language, at most 300 characters. Every term is required; a Chinese term is matched as a phrase of its characters.",
            "schema": {
              "type": "string",
              "maxLength": 300
            }
          },
          {
            "name": "kind",
            "in": "query",
            "description": "Only resources of this kind.",
            "schema": {
              "$ref": "#/components/schemas/Kind"
            }
          },
          {
            "name": "topic",
            "in": "query",
            "description": "Only resources on this topic; GET /v1/topics lists them.",
            "schema": {
              "type": "string",
              "enum": [
                "finance",
                "stocks",
                "banking",
                "crypto",
                "tech",
                "ai",
                "ai-research",
                "tesla",
                "elon-musk",
                "healthcare",
                "biotech",
                "cancer",
                "alzheimers",
                "education"
              ]
            }
          },
          {
            "name": "lang",
            "in": "query",
            "description": "Only resources in this language (a primary tag: en, zh, …).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "site",
            "in": "query",
            "description": "Only resources from this site (its subdomains included).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "description": "Only resources published since: a span back (24h, 7d, 2w) or a date (2026-11-01). Resources without a known date are left out.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Results on this page, 1–50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 10
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Results to skip, at most 500.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 500,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Answer"
                }
              }
            }
          },
          "400": {
            "description": "A question that cannot be asked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many questions from this address; see Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "A key that is unknown or was replaced",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {},
          {
            "key": []
          }
        ]
      },
      "post": {
        "summary": "Search the index (agents): the same as GET, the question in a JSON body",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "q"
                ],
                "properties": {
                  "q": {
                    "type": "string",
                    "maxLength": 300,
                    "description": "The question, in any language, at most 300 characters. Every term is required; a Chinese term is matched as a phrase of its characters."
                  },
                  "kind": {
                    "$ref": "#/components/schemas/Kind",
                    "description": "Only resources of this kind."
                  },
                  "topic": {
                    "type": "string",
                    "enum": [
                      "finance",
                      "stocks",
                      "banking",
                      "crypto",
                      "tech",
                      "ai",
                      "ai-research",
                      "tesla",
                      "elon-musk",
                      "healthcare",
                      "biotech",
                      "cancer",
                      "alzheimers",
                      "education"
                    ],
                    "description": "Only resources on this topic; GET /v1/topics lists them."
                  },
                  "lang": {
                    "type": "string",
                    "description": "Only resources in this language (a primary tag: en, zh, …)."
                  },
                  "site": {
                    "type": "string",
                    "description": "Only resources from this site (its subdomains included)."
                  },
                  "since": {
                    "type": "string",
                    "description": "Only resources published since: a span back (24h, 7d, 2w) or a date (2026-11-01). Resources without a known date are left out."
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 50,
                    "default": 10,
                    "description": "Results on this page, 1–50."
                  },
                  "offset": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 500,
                    "default": 0,
                    "description": "Results to skip, at most 500."
                  }
                }
              },
              "example": {
                "q": "bitcoin ETF flows",
                "topic": "crypto",
                "since": "7d",
                "limit": 5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Answer"
                }
              }
            }
          },
          "400": {
            "description": "A question that cannot be asked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many questions from this address; see Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "A key that is unknown or was replaced",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        },
        "security": [
          {},
          {
            "key": []
          }
        ]
      }
    },
    "/v1/topics": {
      "get": {
        "summary": "The topics, their names in English and Chinese, and how many resources each holds",
        "responses": {
          "200": {
            "description": "The topics",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/stats": {
      "get": {
        "summary": "What the index holds",
        "responses": {
          "200": {
            "description": "Counts by kind, language and site",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/v1/keys": {
      "post": {
        "summary": "A free key, sent to your mailbox (one active key per email; asking again replaces it)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              },
              "example": {
                "email": "you@example.org"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Sent: check your mailbox",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sent_to": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not an email, or a disposable one",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Three key emails a day from one address or to one mailbox",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/v1/usage": {
      "get": {
        "summary": "Your key's questions today and its limits",
        "security": [
          {
            "key": []
          }
        ],
        "responses": {
          "200": {
            "description": "Today's use",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": {
                      "type": "string"
                    },
                    "today": {
                      "type": "integer"
                    },
                    "per_day": {
                      "type": "integer"
                    },
                    "per_minute": {
                      "type": "number"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or an unknown one"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Kind": {
        "type": "string",
        "enum": [
          "page",
          "article",
          "video",
          "audio",
          "file",
          "paper",
          "code",
          "app",
          "feed"
        ]
      },
      "Answer": {
        "type": "object",
        "required": [
          "query",
          "results",
          "more",
          "took_ms"
        ],
        "properties": {
          "query": {
            "type": "string"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Resource"
            }
          },
          "more": {
            "type": "boolean",
            "description": "More results lie past this page."
          },
          "took_ms": {
            "type": "integer"
          }
        }
      },
      "Resource": {
        "type": "object",
        "required": [
          "url",
          "kind",
          "title",
          "snippet",
          "site",
          "fetched",
          "score"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The link to the content."
          },
          "kind": {
            "$ref": "#/components/schemas/Kind"
          },
          "title": {
            "type": "string"
          },
          "snippet": {
            "type": "string",
            "description": "A line around the first match, HTML-escaped, matches in <b>."
          },
          "site": {
            "type": "string"
          },
          "lang": {
            "type": "string"
          },
          "published": {
            "type": "string",
            "description": "When it was published, as its source said."
          },
          "fetched": {
            "type": "string",
            "format": "date-time"
          },
          "image": {
            "type": "string",
            "format": "uri"
          },
          "media_type": {
            "type": "string",
            "description": "A file's or a media item's type."
          },
          "size": {
            "type": "integer",
            "description": "A file's size in bytes, when its server said."
          },
          "content_url": {
            "type": "string",
            "format": "uri",
            "description": "The thing itself when it is not the link: a podcast's audio, a video's player, a paper's PDF."
          },
          "topics": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The topics its words give it."
          },
          "score": {
            "type": "number"
          }
        }
      },
      "Problem": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      }
    },
    "securitySchemes": {
      "key": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your key, coco_…, from POST /v1/keys (it arrives by email)."
      }
    }
  }
}
