{
	"openapi": "3.1.0",
	"info": {
		"title": "titelia",
		"summary": "Which funds hold a listed company, and what a fund holds.",
		"description": "Read from the filings funds make to their regulators, and from the reports they publish themselves. No key, no account. Figures belong to the funds that filed them; name the original source when republishing.",
		"version": "1.0.0",
		"license": {
			"name": "Public filings, republished with attribution"
		}
	},
	"servers": [
		{
			"url": "https://titelia.com"
		}
	],
	"security": [],
	"externalDocs": {
		"description": "Human-readable documentation",
		"url": "https://titelia.com/en/api"
	},
	"paths": {
		"/api/company/{isin}": {
			"get": {
				"summary": "The funds holding one company.",
				"parameters": [
					{
						"name": "isin",
						"in": "path",
						"required": true,
						"schema": {
							"type": "string"
						},
						"description": "ISO 6166 code, or the page identifier that ends with one."
					},
					{
						"name": "limit",
						"in": "query",
						"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",
						"schema": {
							"type": "integer",
							"minimum": 0,
							"default": 0
						},
						"description": "Where to start. Read `more` to know whether anything follows."
					}
				],
				"responses": {
					"200": {
						"description": "The answer, with a `page` block (total, limit, offset, more, next, previous) on every cut collection, and the sentence a citation needs.",
						"content": {
							"application/json": {
								"schema": {
									"type": "object"
								}
							}
						}
					},
					"304": {
						"description": "The caller already holds this answer."
					},
					"404": {
						"description": "Nothing here answers to that identifier.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					},
					"429": {
						"description": "Too many requests. `retry-after` says when to come back.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					}
				}
			}
		},
		"/api/company/{isin}.csv": {
			"get": {
				"summary": "The same table, as a file.",
				"parameters": [
					{
						"name": "isin",
						"in": "path",
						"required": true,
						"schema": {
							"type": "string"
						},
						"description": "ISO 6166 code, or the page identifier that ends with one."
					},
					{
						"name": "limit",
						"in": "query",
						"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",
						"schema": {
							"type": "integer",
							"minimum": 0,
							"default": 0
						},
						"description": "Where to start. Read `more` to know whether anything follows."
					},
					{
						"name": "lang",
						"in": "query",
						"schema": {
							"type": "string",
							"enum": [
								"fr",
								"en",
								"de"
							]
						},
						"description": "Writes the column heads in that language, and separates with the character its spreadsheets expect. English by default."
					}
				],
				"responses": {
					"200": {
						"description": "The same table, as a file a spreadsheet opens.",
						"content": {
							"text/csv": {
								"schema": {
									"type": "string"
								}
							}
						}
					},
					"404": {
						"description": "Nothing here answers to that identifier.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					},
					"429": {
						"description": "Too many requests.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					}
				}
			}
		},
		"/api/fund/{id}": {
			"get": {
				"summary": "What one fund holds.",
				"parameters": [
					{
						"name": "id",
						"in": "path",
						"required": true,
						"schema": {
							"type": "string"
						},
						"description": "The fund identifier the site uses: a SEC series id, an ISIN, or a slug."
					},
					{
						"name": "limit",
						"in": "query",
						"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",
						"schema": {
							"type": "integer",
							"minimum": 0,
							"default": 0
						},
						"description": "Where to start. Read `more` to know whether anything follows."
					}
				],
				"responses": {
					"200": {
						"description": "The answer, with a `page` block (total, limit, offset, more, next, previous) on every cut collection, and the sentence a citation needs.",
						"content": {
							"application/json": {
								"schema": {
									"type": "object"
								}
							}
						}
					},
					"304": {
						"description": "The caller already holds this answer."
					},
					"404": {
						"description": "Nothing here answers to that identifier.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					},
					"429": {
						"description": "Too many requests. `retry-after` says when to come back.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					}
				}
			}
		},
		"/api/fund/{id}.csv": {
			"get": {
				"summary": "The same table, as a file.",
				"parameters": [
					{
						"name": "id",
						"in": "path",
						"required": true,
						"schema": {
							"type": "string"
						},
						"description": "The fund identifier the site uses: a SEC series id, an ISIN, or a slug."
					},
					{
						"name": "limit",
						"in": "query",
						"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",
						"schema": {
							"type": "integer",
							"minimum": 0,
							"default": 0
						},
						"description": "Where to start. Read `more` to know whether anything follows."
					},
					{
						"name": "lang",
						"in": "query",
						"schema": {
							"type": "string",
							"enum": [
								"fr",
								"en",
								"de"
							]
						},
						"description": "Writes the column heads in that language, and separates with the character its spreadsheets expect. English by default."
					}
				],
				"responses": {
					"200": {
						"description": "The same table, as a file a spreadsheet opens.",
						"content": {
							"text/csv": {
								"schema": {
									"type": "string"
								}
							}
						}
					},
					"404": {
						"description": "Nothing here answers to that identifier.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					},
					"429": {
						"description": "Too many requests.",
						"content": {
							"application/problem+json": {
								"schema": {
									"$ref": "#/components/schemas/Problem"
								}
							}
						}
					}
				}
			}
		},
		"/api/isins": {
			"get": {
				"summary": "Every company served, one ISIN and its address per line.",
				"responses": {
					"200": {
						"description": "Plain text, one pair per line."
					},
					"304": {
						"description": "The caller already holds this answer."
					}
				}
			}
		}
	},
	"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://titelia.com/en/api#company-not-found",
							"https://titelia.com/en/api#fund-not-found",
							"https://titelia.com/en/api#not-found",
							"https://titelia.com/en/api#no-such-endpoint",
							"https://titelia.com/en/api#method-not-allowed",
							"https://titelia.com/en/api#rate-limit-exceeded",
							"https://titelia.com/en/api#server-error"
						]
					},
					"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": "The headers travel on every answer while the process answers alone; behind a shared cache they would lie, and travel on the 429 only. Cached answers do not consume quota."
	},
	"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. A figure keeps the currency it was filed in, stated beside it."
}
