{
	"openapi": "3.1.0",
	"info": {
		"title": "QuiVad",
		"version": "1.0.0",
		"summary": "Net short positions disclosed to nineteen market regulators, since 2010.",
		"description": "No key and no account. Every figure here was published by a regulator; whoever republishes it should say so, and every answer carries the sentence to do it with.",
		"license": {
			"name": "Public registers of the market authorities",
			"url": "https://www.quivad.de/sources"
		},
		"contact": {
			"name": "QuiVad",
			"url": "https://www.quivad.de/api"
		}
	},
	"servers": [
		{
			"url": "https://www.quivad.de"
		}
	],
	"security": [],
	"externalDocs": {
		"description": "Human-readable documentation",
		"url": "https://www.quivad.de/api"
	},
	"paths": {
		"/api/moves": {
			"get": {
				"summary": "What moved over the last thirty days, qualified.",
				"description": "Each row carries a kind: opening, increase, reduction, below_threshold. A market the drift rules flag is held back rather than served wrong, and named in held_back.",
				"parameters": [
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 12000,
							"default": 1000
						},
						"description": "How many rows to return. Anything unreadable falls back to the default."
					},
					{
						"name": "offset",
						"in": "query",
						"required": false,
						"schema": {
							"type": "integer",
							"minimum": 0,
							"default": 0
						},
						"description": "Where to start. The page block of the answer carries total, more, next and previous; an offset past the end is an empty list, never an error."
					}
				],
				"responses": {
					"200": {
						"description": "The moves of one page.",
						"content": {
							"application/json": {
								"schema": {
									"type": "object"
								}
							}
						}
					},
					"429": {
						"description": "A refusal, in the shape of RFC 9457.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					}
				}
			}
		},
		"/api/company/{slug}": {
			"get": {
				"summary": "One company: who is short of it now, and its whole archive.",
				"parameters": [
					{
						"name": "slug",
						"in": "path",
						"required": true,
						"schema": {
							"type": "string"
						},
						"description": "The address of the company page, and the second field of /api/isins."
					},
					{
						"name": "limit",
						"in": "query",
						"required": false,
						"schema": {
							"type": "integer",
							"minimum": 1,
							"maximum": 12000,
							"default": 1000
						},
						"description": "How many rows to return. Anything unreadable falls back to the default."
					},
					{
						"name": "offset",
						"in": "query",
						"required": false,
						"schema": {
							"type": "integer",
							"minimum": 0,
							"default": 0
						},
						"description": "Where to start. The page block of the answer carries total, more, next and previous; an offset past the end is an empty list, never an error."
					}
				],
				"responses": {
					"200": {
						"description": "The company, with one page of its history.",
						"content": {
							"application/json": {
								"schema": {
									"type": "object"
								}
							}
						}
					},
					"404": {
						"description": "A refusal, in the shape of RFC 9457.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					},
					"429": {
						"description": "A refusal, in the shape of RFC 9457.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					}
				}
			}
		},
		"/api/fund/{slug}": {
			"get": {
				"summary": "One fund: every company it is short of, across every register.",
				"parameters": [
					{
						"name": "slug",
						"in": "path",
						"required": true,
						"schema": {
							"type": "string"
						}
					}
				],
				"responses": {
					"200": {
						"description": "The fund and its open positions.",
						"content": {
							"application/json": {
								"schema": {
									"type": "object"
								}
							}
						}
					},
					"404": {
						"description": "A refusal, in the shape of RFC 9457.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					},
					"429": {
						"description": "A refusal, in the shape of RFC 9457.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					}
				}
			}
		},
		"/api/isins": {
			"get": {
				"summary": "One line per declared company: its ISIN and the address of its page.",
				"responses": {
					"200": {
						"description": "A lookup table.",
						"content": {
							"text/plain": {
								"schema": {
									"type": "string"
								}
							}
						}
					}
				}
			}
		},
		"/api/positions.jsonl.gz": {
			"get": {
				"summary": "Every open position, one JSON object per line, gzipped.",
				"description": "The whole base in one request. Rebuilt after each collection; x-quivad-lines and x-quivad-built-on say what the file holds without opening it.",
				"responses": {
					"200": {
						"description": "The file.",
						"content": {
							"application/gzip": {
								"schema": {
									"type": "string",
									"format": "binary"
								}
							}
						}
					},
					"503": {
						"description": "A refusal, in the shape of RFC 9457.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					}
				}
			}
		}
	},
	"components": {
		"schemas": {
			"Problem": {
				"type": "object",
				"description": "Error format, following RFC 9457 (Problem Details for HTTP APIs).",
				"required": [
					"type",
					"title",
					"status",
					"detail"
				],
				"properties": {
					"type": {
						"type": "string",
						"format": "uri",
						"description": "A documentation anchor that answers.",
						"enum": [
							"https://www.quivad.com/api#company-not-found",
							"https://www.quivad.com/api#fund-not-found",
							"https://www.quivad.com/api#no-such-endpoint",
							"https://www.quivad.com/api#method-not-allowed",
							"https://www.quivad.com/api#rate-limit-exceeded",
							"https://www.quivad.com/api#not-ready"
						]
					},
					"title": {
						"type": "string"
					},
					"status": {
						"type": "integer"
					},
					"detail": {
						"type": "string"
					},
					"instance": {
						"type": "string",
						"description": "The path that was requested."
					}
				}
			}
		}
	},
	"x-rate-limit": {
		"requests": 120,
		"window": "1 minute",
		"scope": "per calling address, on /api only",
		"headers": [
			"ratelimit-limit",
			"ratelimit-remaining",
			"ratelimit-reset",
			"retry-after"
		],
		"note": "Behind the edge cache the headers travel on the 429 alone - stored ones would tell every caller the quota of the first - and a cached answer does not consume quota."
	},
	"x-mcp": {
		"endpoint": "https://www.quivad.de/mcp",
		"transport": "Streamable HTTP, POST only. There is no stream to open and no session to end.",
		"protocol_versions": [
			"2026-07-28",
			"2025-11-25",
			"2025-06-18",
			"2025-03-26"
		],
		"tools": [
			"search_short_positions",
			"get_company_short_positions",
			"get_fund_short_positions",
			"get_most_shorted_companies",
			"get_short_position_moves"
		],
		"note": "The same figures as the addresses above, for an assistant rather than for a program: it answers in English, needs no key, and counts against the same rate limit."
	},
	"x-stability": "No version in the address and none in the body, because nothing will break: fields are added, never removed or renamed under a caller, and addresses do not move."
}
