{"openapi":"3.1.0","info":{"title":"Naqua Purification API","version":"1.0.0","description":"Stock purification rates for Saudi (Tadawul) companies, and a calculator for the amount to purify. Every error carries a stable `code` and a message in Arabic and English. Requests under /v1 are limited to 60 per minute per IP."},"paths":{"/v1/companies":{"get":{"tags":["Companies"],"operationId":"companies.list","parameters":[],"security":[],"responses":{"200":{"description":"All companies, sorted by ticker, with the years that have a rate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyList"}}}},"429":{"description":"`RATE_LIMITED`: `Retry-After` says when to try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedEncoded"}}}}},"summary":"Every company in the database"}},"/v1/companies/{ticker}":{"get":{"tags":["Companies"],"operationId":"companies.detail","parameters":[{"name":"ticker","in":"path","schema":{"type":"string","pattern":"^[+-]?\\d*\\.?\\d+(?:[Ee][+-]?\\d+)?$"},"required":true}],"security":[],"responses":{"200":{"description":"The company and everything known about each year.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyDetail"}}}},"400":{"description":"`VALIDATION_ERROR`: `details` lists the invalid fields, at most 20.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorEncoded"}}}},"404":{"description":"`UNKNOWN_TICKER`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnknownTickerEncoded"}}}},"409":{"description":"`AMBIGUOUS_TICKER`: the data lists several companies under this ticker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AmbiguousTickerEncoded"}}}},"429":{"description":"`RATE_LIMITED`: `Retry-After` says when to try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedEncoded"}}}}},"summary":"One company and everything known about each year"}},"/v1/companies/{ticker}/rates/{year}":{"get":{"tags":["Companies"],"operationId":"companies.rate","parameters":[{"name":"ticker","in":"path","schema":{"type":"string","pattern":"^[+-]?\\d*\\.?\\d+(?:[Ee][+-]?\\d+)?$"},"required":true},{"name":"year","in":"path","schema":{"type":"string","pattern":"^[+-]?\\d*\\.?\\d+(?:[Ee][+-]?\\d+)?$"},"required":true}],"security":[],"responses":{"200":{"description":"The rate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rate"}}}},"400":{"description":"`VALIDATION_ERROR`: `details` lists the invalid fields, at most 20.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorEncoded"}}}},"404":{"description":"`UNKNOWN_TICKER` | `RATE_NOT_AVAILABLE`: no rate is published for that year.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/UnknownTickerEncoded"},{"$ref":"#/components/schemas/RateNotAvailableEncoded_1"}]}}}},"409":{"description":"`AMBIGUOUS_TICKER`: the data lists several companies under this ticker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AmbiguousTickerEncoded"}}}},"429":{"description":"`RATE_LIMITED`: `Retry-After` says when to try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedEncoded"}}}}},"summary":"A company's purification rate for one year"}},"/v1/purification/calculate":{"post":{"tags":["Purification"],"operationId":"purification.calculate","parameters":[],"security":[],"responses":{"200":{"description":"The per-year breakdown and total, in SAR.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationResponse"}}}},"400":{"description":"`VALIDATION_ERROR`: `details` lists the invalid fields, at most 20.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrorEncoded"}}}},"404":{"description":"`UNKNOWN_TICKER`","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnknownTickerEncoded"}}}},"409":{"description":"`AMBIGUOUS_TICKER`: the data lists several companies under this ticker.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AmbiguousTickerEncoded"}}}},"413":{"description":"`PAYLOAD_TOO_LARGE`: the body is over 100 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PayloadTooLargeEncoded"}}}},"422":{"description":"`RATE_NOT_AVAILABLE`: no rate is published for that year.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateNotAvailableEncoded_1"}}}},"429":{"description":"`RATE_LIMITED`: `Retry-After` says when to try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedEncoded"}}}}},"description":"Each holding is split into calendar years and each year is prorated: `shares × ratePerShare × daysOwned / 365`. The request is all-or-nothing: if any entry cannot be calculated, nothing is returned and `details.entryIndex` names the entry.","summary":"Calculate the purification amount for a set of holdings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculationRequest"}}},"required":true}}},"/v1/meta":{"get":{"tags":["Meta"],"operationId":"meta.meta","parameters":[],"security":[],"responses":{"200":{"description":"Metadata.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Meta"}}}},"429":{"description":"`RATE_LIMITED`: `Retry-After` says when to try again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitedEncoded"}}}}},"summary":"Data coverage, version, limits and the formula"}},"/health":{"get":{"tags":["Health"],"operationId":"health.health","parameters":[],"security":[],"responses":{"200":{"description":"The service is up.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]}},"required":["status"],"additionalProperties":false,"description":"The service is up."}}}}},"summary":"Liveness check"}}},"components":{"schemas":{"RateLimitedEncoded":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["RATE_LIMITED"]},"message":{"type":"object","properties":{"ar":{"type":"string"},"en":{"type":"string"}},"required":["ar","en"],"additionalProperties":false},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"Meta":{"type":"object","properties":{"apiVersion":{"type":"string"},"dataVersion":{"type":"string","description":"Changes whenever the underlying data does."},"coverage":{"type":"object","properties":{"start":{"type":"string","examples":["2015-01-01"]},"end":{"type":"string","examples":["2024-12-31"]},"years":{"type":"array","items":{"type":"integer"}}},"required":["start","end","years"],"additionalProperties":false},"unit":{"type":"string"},"formula":{"type":"string"},"companyCount":{"type":"integer"},"unresolvedTickers":{"type":"array","items":{"type":"integer"},"description":"Tickers the data assigns to more than one company; lookups on them return 409."},"rateLimit":{"type":"object","properties":{"requestsPerMinute":{"type":"integer"}},"required":["requestsPerMinute"],"additionalProperties":false},"maxEntriesPerRequest":{"type":"integer"}},"required":["apiVersion","dataVersion","coverage","unit","formula","companyCount","unresolvedTickers","rateLimit","maxEntriesPerRequest"],"additionalProperties":false,"description":"Metadata."},"PayloadTooLargeEncoded":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["PAYLOAD_TOO_LARGE"]},"message":{"type":"object","properties":{"ar":{"type":"string"},"en":{"type":"string"}},"required":["ar","en"],"additionalProperties":false},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"ValidationErrorEncoded":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["VALIDATION_ERROR"]},"message":{"type":"object","properties":{"ar":{"type":"string"},"en":{"type":"string"}},"required":["ar","en"],"additionalProperties":false},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"RateNotAvailableEncoded_1":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["RATE_NOT_AVAILABLE"]},"message":{"type":"object","properties":{"ar":{"type":"string"},"en":{"type":"string"}},"required":["ar","en"],"additionalProperties":false},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"AmbiguousTickerEncoded":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["AMBIGUOUS_TICKER"]},"message":{"type":"object","properties":{"ar":{"type":"string"},"en":{"type":"string"}},"required":["ar","en"],"additionalProperties":false},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"UnknownTickerEncoded":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["UNKNOWN_TICKER"]},"message":{"type":"object","properties":{"ar":{"type":"string"},"en":{"type":"string"}},"required":["ar","en"],"additionalProperties":false},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"CalculationResponse":{"type":"object","properties":{"currency":{"type":"string","enum":["SAR"]},"totalPurificationAmount":{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]},"entries":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","description":"Position of the entry in the request."},"ticker":{"type":"integer"},"companyName":{"type":"string"},"shares":{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]},"purificationAmount":{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]},"years":{"type":"array","items":{"$ref":"#/components/schemas/CalculationYear"}}},"required":["index","ticker","companyName","shares","purificationAmount","years"],"additionalProperties":false}}},"required":["currency","totalPurificationAmount","entries"],"additionalProperties":false,"description":"The per-year breakdown and total, in SAR."},"CalculationYear":{"type":"object","properties":{"year":{"type":"integer"},"daysOwned":{"type":"integer"},"ratePerShare":{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]},"status":{"$ref":"#/components/schemas/Status"},"purificationAmount":{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]}},"required":["year","daysOwned","ratePerShare","status","purificationAmount"],"additionalProperties":false},"Status":{"anyOf":[{"type":"string","enum":["pure","mixed","non-pure","public-sector"]},{"type":"null"}],"description":"Shariah classification for the year: `pure` (نقية), `mixed` (مختلطة), `non-pure` (غير متوافقة), or `public-sector` (القطاع العام — state-owned, treated as permissible). Null when the source does not say."},"CalculationRequest":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/CalculationEntry"},"minItems":1,"maxItems":100}},"required":["entries"],"additionalProperties":false,"examples":[{"entries":[{"ticker":2330,"shares":100,"purchaseDate":"2021-03-01","saleDate":"2023-06-30"},{"ticker":2222,"shares":10,"purchaseDate":"2023-01-01","stillOwned":true},{"ticker":2001,"shares":50,"year":2022,"daysOwned":200}]}]},"CalculationEntry":{"type":"object","properties":{"ticker":{"type":"integer","exclusiveMinimum":0,"examples":[2330]},"shares":{"type":"number","exclusiveMinimum":0,"maximum":1000000000000,"description":"Number of shares held.","examples":[100]},"purchaseDate":{"type":"string","description":"Date mode. YYYY-MM-DD, between 2015-01-01 and 2024-12-31.","examples":["2021-03-01"]},"saleDate":{"type":"string","description":"Date mode. After `purchaseDate`; the sale day itself is not counted. Omit when `stillOwned` is true.","examples":["2023-06-30"]},"stillOwned":{"type":"boolean","description":"Date mode. The holding runs until 2024-12-31, the last day of the data, which like a sale day is not counted."},"year":{"type":"integer","description":"Days mode. The year the holding started (2015–2024).","examples":[2022]},"daysOwned":{"type":"integer","exclusiveMinimum":0,"description":"Days mode. Split into consecutive 365-day years starting at `year`; leap days are not observed.","examples":[200]}},"required":["ticker","shares"],"additionalProperties":false},"Rate":{"type":"object","properties":{"ticker":{"type":"integer","description":"Tadawul ticker.","examples":[2330]},"name":{"type":"string","description":"Arabic name.","examples":["المتقدمة"]},"year":{"type":"integer","examples":[2023]},"ratePerShare":{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]},"status":{"$ref":"#/components/schemas/Status"}},"required":["ticker","name","year","ratePerShare","status"],"additionalProperties":false,"description":"The rate."},"CompanyDetail":{"type":"object","properties":{"ticker":{"type":"integer","description":"Tadawul ticker.","examples":[2330]},"name":{"type":"string","description":"Arabic name.","examples":["المتقدمة"]},"aliases":{"type":"array","items":{"type":"string"},"description":"Former or alternative Arabic names.","examples":[[]]},"overallStatus":{"anyOf":[{"type":"string","enum":["pure","mixed","non-pure","public-sector","varies"]},{"type":"null"}],"description":"The status if it was the same in every year with a known status, `varies` if it changed."},"years":{"type":"array","items":{"$ref":"#/components/schemas/CompanyYear"}}},"required":["ticker","name","aliases","overallStatus","years"],"additionalProperties":false,"description":"The company and everything known about each year."},"CompanyYear":{"type":"object","properties":{"year":{"type":"integer","examples":[2023]},"ratePerShare":{"anyOf":[{"anyOf":[{"type":"number"},{"type":"string","enum":["Infinity","-Infinity","NaN"]}]},{"type":"null"}],"description":"SAR to purify per share held for the whole year. Null when none was published.","examples":[0.0203]},"status":{"$ref":"#/components/schemas/Status"}},"required":["year","ratePerShare","status"],"additionalProperties":false},"CompanyList":{"type":"object","properties":{"count":{"type":"integer"},"companies":{"type":"array","items":{"$ref":"#/components/schemas/CompanySummary"}}},"required":["count","companies"],"additionalProperties":false,"description":"All companies, sorted by ticker, with the years that have a rate."},"CompanySummary":{"type":"object","properties":{"ticker":{"type":"integer","description":"Tadawul ticker.","examples":[2330]},"name":{"type":"string","description":"Arabic name.","examples":["المتقدمة"]},"aliases":{"type":"array","items":{"type":"string"},"description":"Former or alternative Arabic names.","examples":[[]]},"overallStatus":{"anyOf":[{"type":"string","enum":["pure","mixed","non-pure","public-sector","varies"]},{"type":"null"}],"description":"The status if it was the same in every year with a known status, `varies` if it changed."},"availableYears":{"type":"array","items":{"type":"integer"},"description":"Years with a published rate.","examples":[[2022,2023,2024]]}},"required":["ticker","name","aliases","overallStatus","availableYears"],"additionalProperties":false}},"securitySchemes":{}},"security":[],"tags":[{"name":"Companies"},{"name":"Purification"},{"name":"Meta"},{"name":"Health"}],"servers":[{"url":"https://api.trynaqua.com"}]}