Skip to content

KAP API Reference

financelib.kap.client.KAP(download_delay: int = 15)

KAP (Public Disclosure Platform) PDF downloader.

Downloads disclosure PDFs from the KAP website for Turkish publicly traded companies.

Parameters:

Name Type Description Default
download_delay int

Seconds to wait between PDF downloads to avoid rate limiting.

15
Example

kap = KAP() kap.download_pdfs_via_date_ranges("2025-01-01", "2025-01-21", "pdfs") kap.download_pdf_via_disclosure_no(123456, "pdfs")

Source code in financelib/kap/client.py
def __init__(self, download_delay: int = 15) -> None:
    self.download_delay = download_delay

Functions

download_pdf_via_disclosure_no(disclosure_no: int, desired_path: str = '') -> Optional[str]

Download a single PDF by disclosure number.

Parameters:

Name Type Description Default
disclosure_no int

KAP disclosure number.

required
desired_path str

Directory to save the PDF.

''

Returns:

Type Description
Optional[str]

Path to the downloaded file, or None on failure.

Source code in financelib/kap/client.py
def download_pdf_via_disclosure_no(
    self, disclosure_no: int, desired_path: str = ""
) -> Optional[str]:
    """Download a single PDF by disclosure number.

    Args:
        disclosure_no: KAP disclosure number.
        desired_path: Directory to save the PDF.

    Returns:
        Path to the downloaded file, or None on failure.
    """
    if desired_path and not desired_path.endswith("/"):
        desired_path += "/"

    if desired_path and not os.path.exists(desired_path):
        os.makedirs(desired_path, exist_ok=True)

    pdf_url = f"{_PDF_BASE}/{disclosure_no}"

    try:
        response = requests.get(pdf_url, timeout=30)
        if response.status_code == 200:
            filepath = f"{desired_path}{disclosure_no}.pdf"
            with open(filepath, "wb") as pdf_file:
                pdf_file.write(response.content)
            logger.info(f"Downloaded: {filepath}")
            return filepath
        else:
            logger.warning(
                f"Failed to download disclosure {disclosure_no}: "
                f"HTTP {response.status_code}"
            )
            return None
    except requests.exceptions.RequestException as e:
        logger.error(f"Download failed for disclosure {disclosure_no}: {e}")
        return None

download_pdfs_via_date_ranges(date_from: str = '', date_to: str = '', desired_path: str = '') -> List[str]

Download all disclosure PDFs within a date range.

Parameters:

Name Type Description Default
date_from str

Start date (YYYY-MM-DD format). Defaults to today.

''
date_to str

End date (YYYY-MM-DD format). Defaults to today.

''
desired_path str

Directory to save PDFs. Created if it doesn't exist.

''

Returns:

Type Description
List[str]

List of downloaded file paths.

Raises:

Type Description
DataFetchError

If the API request fails.

Source code in financelib/kap/client.py
def download_pdfs_via_date_ranges(
    self,
    date_from: str = "",
    date_to: str = "",
    desired_path: str = "",
) -> List[str]:
    """Download all disclosure PDFs within a date range.

    Args:
        date_from: Start date (YYYY-MM-DD format). Defaults to today.
        date_to: End date (YYYY-MM-DD format). Defaults to today.
        desired_path: Directory to save PDFs. Created if it doesn't exist.

    Returns:
        List of downloaded file paths.

    Raises:
        DataFetchError: If the API request fails.
    """
    if not date_from:
        date_from = today_str()
    if not date_to:
        date_to = today_str()

    # Ensure path ends with separator
    if desired_path and not desired_path.endswith("/"):
        desired_path += "/"

    randint = random.randint(10000000000, 99999999999)
    api_url = f"{_API_BASE}?ts={randint}&fromDate={date_from}&toDate={date_to}"

    try:
        response = requests.get(api_url, timeout=30)
        response.raise_for_status()
        data = response.json()
    except requests.exceptions.RequestException as e:
        logger.error(f"KAP API request failed: {e}")
        raise DataFetchError(f"Failed to fetch KAP disclosures: {e}") from e

    if not data:
        logger.info(f"No disclosures found between {date_from} and {date_to}")
        return []

    # Extract data
    basic_list = [item["basic"] for item in data]
    disclosure_indexes = [item["disclosureIndex"] for item in basic_list]
    company_codes = [item["stockCodes"] for item in basic_list]
    titles = [item["title"] for item in basic_list]

    # Create output directory
    if desired_path and not os.path.exists(desired_path):
        os.makedirs(desired_path, exist_ok=True)
        logger.info(f"Directory created: {desired_path}")

    logger.info(f"Downloading {len(basic_list)} PDFs...")
    downloaded_files: List[str] = []

    for i in range(len(basic_list)):
        pdf_url = f"{_PDF_BASE}/{disclosure_indexes[i]}"

        try:
            pdf_response = requests.get(pdf_url, timeout=30)
            if pdf_response.status_code == 200:
                safe_title = titles[i].replace("/", "-").replace("\\", "-")
                filename = f"{company_codes[i]}-{safe_title}-{disclosure_indexes[i]}.pdf"
                filepath = f"{desired_path}{filename}"

                with open(filepath, "wb") as pdf_file:
                    pdf_file.write(pdf_response.content)

                logger.info(f"Downloaded: {filepath}")
                downloaded_files.append(filepath)
            else:
                logger.warning(
                    f"Failed to download PDF {disclosure_indexes[i]}: "
                    f"HTTP {pdf_response.status_code}"
                )
        except requests.exceptions.RequestException as e:
            logger.error(f"Download failed for {disclosure_indexes[i]}: {e}")

        if i < len(basic_list) - 1:
            time.sleep(self.download_delay)

    logger.info(f"Downloaded {len(downloaded_files)}/{len(basic_list)} PDFs")
    return downloaded_files