# Advanced Browser Investigation Log

Interactive recon of `www.sgx.com` to understand how SGX's own frontend calls the documented/undocumented APIs.

## Loading SGX — `appconfig.json` and the `v` parameter

When the browser loads `https://www.sgx.com/`, the React frontend fetches its configuration before issuing any data API calls:

1. `https://www.sgx.com/config/appconfig.js?v=e6235fc4` — a one-line shim that queries the `<sgx-config-service>` DOM element.
2. `https://www.sgx.com/config/appconfig.json?v=e6235fc4` — the real configuration object.

The `v` query parameter is a cache-bust / build version (currently `e6235fc4`). It is important to record and track because:

- The frontend appends it to every static asset and CMS call (`locales/en.json?v=e6235fc4`, etc.).
- It likely changes with each frontend deploy. When it changes, `CMS_VERSION` and the set of available CMS operations may also change.
- Any automation that replays the URLs below should first fetch the current `appconfig.json`, extract `CMS_VERSION`, and reconstruct CMS URLs with that version. Using an outdated version can cause `queryId` errors or missing operations.

Relevant fields in the current `appconfig.json`:

- `CMS_VERSION`: `70f75ec90c030bab34d750ee55d74b016f70d4b6` — used as the `queryId` prefix for `api2.sgx.com/content-api`.
- `APP_CONFIG_URL` / `APP_CONFIG`: `https://www.sgx.com/config/appconfig.json`.

Captured payload: `payloads/resp_23_appconfig_fresh.json`.

## Method

- Chrome launched with `--remote-debugging-port=9222`.
- Navigated interactively to SGX pages.
- All network requests with `Content-Type: application/json` are captured.
- Request metadata logged in this file; full request/response bodies saved under `payloads/`.

## Session details

- Date: 2026-06-25
- Browser: Google Chrome 149 / Linux
- Origin page: `https://www.sgx.com/`
- CMS version from appconfig: `70f75ec90c030bab34d750ee55d74b016f70d4b6`

---

## Page 1 — Homepage (`https://www.sgx.com/`)

A total of 66 requests were observed on first load. The JSON calls below are the ones relevant to the trader objectives and to resolving the previously blocked endpoints.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 1 | Homepage | `APP_CONFIG_URL` | `https://www.sgx.com/config/appconfig.json?v=e6235fc4` | GET | 200 | `application/json` | `payloads/resp_23_appconfig.json` | Master endpoint inventory; includes `CMS_VERSION` hash. |
| 2 | Homepage | `CMS_API_URL` | `https://api2.sgx.com/content-api/?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6:we_chat_qr_validator` | GET | 200 | `application/json` | `payloads/resp_25_cms_wechat.json` | Source of the `authorizationtoken` for `api.sgx.com/announcements/v1.1/*`. Response contains `data.qrValidator`, which is ROT13-encoded; decoding it yields the token (see Appendix A). |
| 3 | Homepage | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Aall_menus&variables=%7B%22lang%22%3A%22EN%22%7D` | GET | 304 | `application/json` | `payloads/resp_27_cms_allmenus.json` | Site navigation tree returned as nested GraphQL-like CMS data. |
| 4 | Homepage | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Apage&variables=%7B%22path%22%3A%22%2F%22%2C%22lang%22%3A%22EN%22%7D` | GET | 304 | `application/json` | `payloads/resp_29_cms_page.json` | Landing-page CMS content (`/singapore-exchange`). |
| 5 | Homepage | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/aggregate/` | GET | 200 | `application/json` | `payloads/resp_36_securities_aggregate.json` | Market aggregate: total volume, value, advancers/decliners count. |
| 6 | Homepage | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/advancers/stocks/7/v?params=nc,adjusted-vwap,bond_accrued_interest,bond_clean_price,bond_dirty_price,bond_date,b,bv,p,c,change_vs_pc,change_vs_pc_percentage,cx,cn,dp,dpc,du,ed,fn,h,iiv,iopv,lt,l,o,p_,pv,ptd,s,sv,trading_time,v_,v,vl,vwap,vwap-currency` | GET | 200 | `application/json` | `payloads/resp_37_securities_advancers_stocks.json` | Top 7 advancing stocks by value. |
| 7 | Homepage | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/advancers/reits/7/v?params=...` | GET | 200 | `application/json` | `payloads/resp_38_securities_advancers_reits.json` | Top 7 advancing REITs by value. |
| 8 | Homepage | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/advancers/etfs/7/v?params=...` | GET | 200 | `application/json` | `payloads/resp_39_securities_advancers_etfs.json` | Top 7 advancing ETFs by value. |
| 9 | Homepage | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/advancers/structuredwarrants/7/v?params=...` | GET | 200 | `application/json` | `payloads/resp_40_securities_advancers_structuredwarrants.json` | Top 7 advancing structured warrants by value. |
| 10 | Homepage | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/advancers/dlcertificates/7/v?params=...` | GET | 200 | `application/json` | `payloads/resp_41_securities_advancers_dlcertificates.json` | Top 7 advancing daily leverage certificates by value. |
| 11 | Homepage | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1?params=nc,n,type,ls,m,sc,bl,sip,ex,ej,clo,cr,cur,el,r,i,cc,ig,lf` | GET | 200 | `application/json` | `payloads/resp_52_securities_reference.json` | Static-ish reference table (security type, listing status, market, sector, currency, etc.). |
| 12 | Homepage | `METADATA_API_URL` | `https://api.sgx.com/marketmetadata/v2` | GET | 200 | `application/json` | `payloads/resp_53_marketmetadata.json` | ~11 MB instrument master metadata. |
| 13 | Homepage | `DERIVATIVES_API_URL` | `https://api.sgx.com/derivatives/v1.0?aggregate=true&aggregate-option=total-volume` | GET | 200 | `application/json` | `payloads/resp_42_derivatives_aggregate.json` | Returns a single aggregate number (`data`: total volume). |
| 14 | Homepage | `DERIVATIVES_API_URL` | `https://api.sgx.com/derivatives/v1.0?groupby=cc&category=futures` | GET | 200 | `application/json` | `payloads/resp_43_derivatives_groupby_cc.json` | All futures contracts grouped by commodity code (~1.4 MB). |
| 15 | Homepage | `DERIVATIVES_API_URL` | `https://api.sgx.com/derivatives/v1.0/history/symbol/CNM26?days=10d&category=futures&params=base-date,total-volume,last-traded-price-abs` | GET | 200 | `application/json` | `payloads/resp_54_derivatives_history_CNM26.json` | 10-day historical OHLC-like data for a single future (CNM26). |
| 16 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/charts/intraday/pid/.STI/5d?params=lp,trading_time,vl` | GET | 200 | `application/json` | `payloads/resp_55_indices_sti_intraday.json` | 5-day intraday STI index chart (1,590 data points). |
| 17 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/pid/.STI/` | GET | 200 | `application/json` | `payloads/resp_56_indices_meta_sti.json` | STI index metadata/last value. |
| 18 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/pid/SGN50N/` | GET | 200 | `application/json` | `payloads/resp_57_indices_meta_sgn50n.json` | iEdge SG Enhanced N50 index metadata. |
| 19 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/pid/.SREIT/` | GET | 200 | `application/json` | `payloads/resp_58_indices_meta_sreit.json` | iEdge S-REIT index metadata. |
| 20 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/pid/SGLC40CN/` | GET | 200 | `application/json` | `payloads/resp_59_indices_meta_sglc40cn.json` | iEdge SG China Focus index metadata. |
| 21 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/pid/.APACFINN/` | GET | 200 | `application/json` | `payloads/resp_60_indices_meta_apacfinn.json` | iEdge Asia Pacific Ex-Japan Financials index metadata. |
| 22 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/pid/.EMASIAUN/` | GET | 200 | `application/json` | `payloads/resp_61_indices_meta_emasiaun.json` | iEdge Emerging Asia index metadata. |
| 23 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/pid/ASIATECN/` | GET | 200 | `application/json` | `payloads/resp_62_indices_meta_asiatecn.json` | iEdge Asia Tech index metadata. |
| 24 | Homepage | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/charts/intraday/pid/.STI/5d?params=lp,trading_time,vl` | GET | 200 | `application/json` | `payloads/resp_63_indices_sti_intraday_dup.json` | Duplicate of #16. |
| 25 | Homepage | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1?params=nc,adjusted-vwap,bond_accrued_interest,bond_clean_price,bond_dirty_price,bond_date,b,bv,p,c,change_vs_pc,change_vs_pc_percentage,cx,cn,dp,dpc,du,ed,fn,h,iiv,iopv,lt,l,o,p_,pv,ptd,s,sv,trading_time,v_,v,vl,vwap,vwap-currency` | GET | 200 | `application/json` | `payloads/resp_64_securities_fullquote.json` | Full securities snapshot (~1 MB) with pricing/volume fields. |

---

## Page 2 — Securities Prices (`https://www.sgx.com/stock-exchange/securities-prices`)

This page is the main securities screener/table.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 26 | Securities Prices | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Apage&variables=%7B%22path%22%3A%22%2Fstock-exchange%2Fsecurities-prices%22%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_72_cms_page_securities_prices.json` | CMS page content for the screener. |
| 27 | Securities Prices | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Aalerts&variables=%7B%22lang%22%3A%22EN%22%7D` | GET | 304 | `application/json` | `payloads/resp_28_cms_alerts.json` | Global alert banners. |
| 28 | Securities Prices | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Aderivatives_products_list&variables=%7B%22limit%22%3A100%2C%22offset%22%3A0%2C%22lang%22%3A%22EN%22%7D` | GET | 304 | `application/json` | `payloads/resp_44_cms_derivatives_products_list.json` | CMS list of derivatives products. |
| 29 | Securities Prices | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1?excludetypes=bonds&params=nc,adjusted-vwap,...,vwap-currency` | GET | 200 | `application/json` | `payloads/resp_74_securities_screener.json` | Screener snapshot excluding bonds. |
| 30 | Securities Prices | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/circuitbreaker` | GET | 200 | `application/json` | `payloads/resp_75_securities_circuitbreaker.json` | Active circuit-breaker records (empty at capture time). |
| 31 | Securities Prices | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1?excludetypes=bonds&pagestart=0&pagesize=500&sort=vl&sortdir=desc&params=nc,adjusted-vwap,...,vwap-currency` | GET | 200 | `application/json` | `payloads/resp_80_securities_screener_paginated.json` | Paginated/sorted screener call (top 500 by value). |

Additional `excludetypes=bonds` calls (reqids 81, 83, 84) were polling/refreshes of the same screener data.

---

## Page 3 — Indices (`https://www.sgx.com/indices`)

This page lists SGX and third-party indices and renders historic charts.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 32 | Indices | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Apage&variables=%7B%22path%22%3A%22%2Findices%22%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_114_cms_page_indices.json` | CMS page content for indices. |
| 33 | Indices | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Aindex_list&variables=%7B%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_124_cms_index_list.json` | CMS-driven index taxonomy/list (~73 KB). |
| 34 | Indices | `THIRDPARTY_INDICES_API_URL` | `https://api.sgx.com/thirdpartyindices/v1.0/chinabonds` | GET | 200 | `application/json` | `payloads/resp_125_thirdpartyindices_chinabonds.json` | ChinaBond third-party indices. |
| 35 | Indices | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/` | GET | 200 | `application/json` | `payloads/resp_126_indices_base.json` | Master index list with current OHLC/change (~50 KB, 854 items). |
| 36 | Indices | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/charts/historic/pid/.STI/1m?params=lp,trading_time,vl` | GET | 200 | `application/json` | `payloads/resp_127_indices_historic_sti_1m.json` | 1-month daily STI history. |
| 37 | Indices | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/charts/historic/pid/SGN50N/1m?params=lp,trading_time,vl` | GET | 200 | `application/json` | `payloads/resp_128_indices_historic_sgn50n_1m.json` | 1-month daily SGN50N history. |
| 38 | Indices | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/charts/historic/pid/IEVNTR/1m?params=lp,trading_time,vl` | GET | 200 | `application/json` | `payloads/resp_135_indices_historic_ievntr_1m.json` | 1-month daily IEVNTR history. |

Additional historic-chart calls on this page used PIDs: `SGN50N`, `SGN50LN`, `SGLC40CN`, `SREITLSP`, `AGREITSN`, `.APACFINN`, `ASIATECN`, `IEVNTR`. Pattern is `/indices/v1.0/charts/historic/pid/{pid}/{period}?params=lp,trading_time,vl`.

---

## Page 4 — Stock Exchange Overview (`https://www.sgx.com/stock-exchange`)

This is the Stock Exchange landing page. It shows sector heatmap, market performance, top movers, and corporate-announcement summaries.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 39 | Stock Exchange | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Apage&variables=%7B%22path%22%3A%22%2Fstock-exchange%22%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | (observed but not saved; same shape as other `page` calls) | CMS page content. |
| 40 | Stock Exchange | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Amarket_updates_list&variables=%7B%22category%22%3A%2226%22%2C%22limit%22%3A6%2C%22categoryFilterEnabled%22%3Atrue%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_263_cms_market_updates_list.json` | CMS market updates list. |
| 41 | Stock Exchange | `IPO_PROSPECTUS_API_URL` | `https://api.sgx.com/ipoprospectus/v1.0/?closing_time=20260624_160000` | GET | 200 | `application/json` | `payloads/resp_251_ipoprospectus.json` | IPO prospectus open/closed issues (empty at capture time). |
| 42 | Stock Exchange | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/advancers/stocks/5/v?params=nc,adjusted-vwap,...,vwap-currency` | GET | 200 | `application/json` | `payloads/resp_258_securities_advancers_stocks_5v.json` | Top 5 advancing stocks. |
| 43 | Stock Exchange | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/aggregate/volume?securitytype=stocks` | GET | 200 | `application/json` | `payloads/resp_259_securities_aggregate_volume.json` | Today's total stock volume. |
| 44 | Stock Exchange | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/aggregate/value?securitytype=stocks` | GET | 200 | `application/json` | `payloads/resp_260_securities_aggregate_value.json` | Today's total stock value. |
| 45 | Stock Exchange | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/sectorbreakdown` | GET | 200 | `application/json` | `payloads/resp_262_securities_sectorbreakdown.json` | Sector heatmap: 20 SSIC sectors with change/changePercentage. |
| 46 | Stock Exchange | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/summary/company?periodstart=20260624_050955&cat=CACT` | GET | 200 | `application/json` | `payloads/resp_264_announcements_summary_cact.json` | Summary of corporate-action announcements (CACT). |
| 47 | Stock Exchange | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/summary/company?periodstart=20260624_160000&cat=TRAD` | GET | 200 | `application/json` | `payloads/resp_265_announcements_summary_trad.json` | Summary of trading-status announcements (TRAD). |
| 48 | Stock Exchange | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/summary/company?periodstart=20260624_160000&cat=ANNC%2CCACT%2CPLST%2CTRAD` | GET | 200 | `application/json` | `payloads/resp_266_announcements_summary_all.json` | Combined announcement summary. |
| 49 | Stock Exchange | `INDICES_API_URL` | `https://api.sgx.com/indices/v1.0/pid/.STI/`, `.../.FTFSTM/`, `.../.FTFSTS/` | GET | 200 | `application/json` | `payloads/resp_56_indices_meta_sti.json` (already saved on Page 1) and `payloads/resp_254_indices_meta_ftfstm.json`, `payloads/resp_255_indices_meta_ftfsts.json` | Large/mid/small cap index metadata. |

---

## Page 5 — Company Announcements (`https://www.sgx.com/stock-exchange/company-announcements`)

Full searchable announcement feed.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 50 | Company Announcements | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Apage&variables=%7B%22path%22%3A%22%2Fstock-exchange%2Fcompany-announcements%22%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_303_cms_page_company_announcements.json` | CMS page content. |
| 51 | Company Announcements | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Ataxonomy_terms&variables=%7B%22vid%22%3A%22company_announcements_categories%22%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_312_cms_taxonomy_terms.json` | Announcement category taxonomy (ANNC, CACT, PLST, TRAD, etc.). |
| 52 | Company Announcements | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/companylist` | GET | 200 | `application/json` | `payloads/resp_313_announcements_companylist.json` | Filter dropdown: all issuing companies. |
| 53 | Company Announcements | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/securitylist` | GET | 200 | `application/json` | `payloads/resp_314_announcements_securitylist.json` | Filter dropdown: all securities. |
| 54 | Company Announcements | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/count?periodstart=20060624_160000&periodend=20260625_155959` | GET | 200 | `application/json` | `payloads/resp_317_announcements_count.json` | Total count of announcements in the date window. |
| 55 | Company Announcements | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/?periodstart=20060624_160000&periodend=20260625_155959&pagestart=0&pagesize=20` | GET | 200 | `application/json` | `payloads/resp_318_announcements_list.json` | Paginated announcement records with title, issuer, security, category, URL, dates. |

---

## Page 6 — ETF Screener (`https://www.sgx.com/stock-exchange/etf-screener`)

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 56 | ETF Screener | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Apage&variables=%7B%22path%22%3A%22%2Fstock-exchange%2Fetf-screener%22%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_358_cms_page_etf_screener.json` | CMS page content. |
| 57 | ETF Screener | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/etfs?params=n,nc,cx,lt,c,p,vl,v,sc` | GET | 200 | `application/json` | `payloads/resp_365_securities_etfs.json` | ETF price snapshot. |
| 58 | ETF Screener | `ETF_API_URL` | `https://api.sgx.com/etfscreener/v1.0/documents` | GET | 200 | `application/json` | `payloads/resp_371_etfscreener_documents.json` | ETF screener document metadata (factsheets, CSVs, etc.). |

Also observed: `https://api2.sgx.com/sites/default/files/2026-06/May_2026_ETF%20Screener.csv` — a monthly CSV dump surfaced by the screener.

---

## Page 7 — IPO Performance (`https://www.sgx.com/stock-exchange/ipo-performance`)

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 59 | IPO Performance | `IPO_PERFORMANCE_API_URL` | `https://api.sgx.com/ipoperformance/v1.0/yearlist` | GET | 200 | `application/json` | `payloads/resp_426_ipoperformance_yearlist.json` | Available years for filtering. |
| 60 | IPO Performance | `IPO_PERFORMANCE_API_URL` | `https://api.sgx.com/ipoperformance/v1.0/issuerlist` | GET | 200 | `application/json` | `payloads/resp_427_ipoperformance_issuerlist.json` | Issuer filter dropdown. |
| 61 | IPO Performance | `IPO_PERFORMANCE_API_URL` | `https://api.sgx.com/ipoperformance/v1.0/companylist` | GET | 200 | `application/json` | `payloads/resp_428_ipoperformance_companylist.json` | Company filter dropdown. |
| 62 | IPO Performance | `IPO_PERFORMANCE_API_URL` | `https://api.sgx.com/ipoperformance/v1.0?year=2026` | GET | 200 | `application/json` | `payloads/resp_430_ipoperformance_year_2026.json` | IPO performance data for 2026. |

---

## Page 8 — Investor Portal Per-Stock Page (`https://investors.sgx.com/market/security-details/stocks/AWX?from=/market/securities`)

The investor portal (`investors.sgx.com`) uses a different CMS `queryId` hash (`9b5f40321735d88857c12bd08459b5aba7fe2d1e`) and sends `Origin: https://investors.sgx.com`. It exposes per-stock fundamentals, analyst data, shareholder holdings, and stock charts that are not visible on `www.sgx.com`.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 63 | Investor Portal | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=0c6b763562fa9ad6d4b40558d2670db60437f7a6:document_list&variables=%7B%22namefilter%22:%22IP-CA-TABLE%22,%22lang%22:%22EN%22%7D` | GET | 304 | `application/json` | `payloads/resp_174_cms_document_list_ip_ca_table.json` | CMS document list for corporate-actions table widget. |
| 64 | Investor Portal | (static JSON) | `https://api2.sgx.com/sites/default/files/2026-06/IP-CA-TABLE-20260619_1.json` | GET | 304 | `application/json` | `payloads/resp_176_ip_ca_table_json.json` | Static rendered corporate-actions table JSON. |
| 65 | Investor Portal | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1?excludetypes=bonds&params=n,nc,adjusted-vwap,...,issuer-name,ig,r,i,ls,sc,bl,clo,ej,ex` | GET | 200 | `application/json` | (not saved; same shape as Page 2 screener) | Full screener snapshot used by investor portal. |
| 66 | Investor Portal | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/stocks/code/AWX?ts={timestamp}` | GET | 200 | `application/json` | `payloads/resp_177_securities_stocks_code_awx.json` | Per-stock quote/details for code `AWX`. |
| 67 | Investor Portal | `METADATA_API_URL` | `https://api.sgx.com/marketmetadata/v2?stock-code=AWX` | GET | 200 | `application/json` | `payloads/resp_178_marketmetadata_stockcode_awx.json` | Metadata scoped to single stock code. |
| 68 | Investor Portal | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1//charts/historic/stocks/code/AWX/1y?params=trading_time,vl,lt` | GET | 200 | `application/json` | `payloads/resp_182_securities_charts_historic_awx_1y.json` | 1-year historic OHLC-like chart for stock `AWX`. |
| 69 | Investor Portal | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1//charts/historic/stocks/code/AWX/1w` | GET | 200 | `application/json` | (not saved; same pattern as 1y) | 1-week historic chart (no `params` supplied by frontend). |
| 70 | Investor Portal | `RATIOS_REPORTS_API_URL` | `https://api.sgx.com/ratiosreports/v2.0/countryCode/SGP/stockCode/AWX?params=noOfAnalysts,consensusRecommendation,targetPrice,currencyIdForConsensus` | GET | 200 | `application/json` | `payloads/resp_185_ratiosreports_analyst_awx.json` | Analyst consensus and target price. |
| 71 | Investor Portal | `SHAREHOLDERS_REPORTS_API_URL` | `https://api.sgx.com/shareholdersreports/v2.0/stockCode/AWX?params=investorName,investorType,investorHoldingsDate,pctOfSharesOutstanding,sharesHeld,sharesHeldChange,turnoverRating` | GET | 200 | `application/json` | `payloads/resp_187_shareholdersreports_awx.json` | Major shareholder holdings. |
| 72 | Investor Portal | `RATIOS_REPORTS_API_URL` | `https://api.sgx.com/ratiosreports/v2.0/countryCode/SGP/stockCode/AWX?params=beta,average3MonthVolume,totalMarketCap,fiftyTwoWeekHigh,...,currencyIdForProfitability` | GET | 200 | `application/json` | `payloads/resp_191_ratiosreports_full_awx.json` | Full ratio/fundamental snapshot (market cap, P/E, dividend yield, EPS, margins, etc.). |
| 73 | Investor Portal | `SNAPSHOT_REPORTS_API_URL` | `https://api.sgx.com/snapshotreports/v2.0/countryCode/SGP/stockCode/AWX?params=enterpriseValue,returnOnEquity,companyName,stockCode,sectorName,industryName,reportingCurrency,tradedCurrency,currentFiscalYear,currentFiscalYearEndMonth,currencyIdForMarketCap` | GET | 200 | `application/json` | `payloads/resp_192_snapshotreports_awx.json` | Enterprise value, ROE, sector/industry, reporting/traded currency. |
| 74 | Investor Portal | `CORPORATE_ACTIONS_API_URL` | `https://api.sgx.com/corporateactions/v1.0?pagesize=10&pagestart=0&ibmcode=1BA1&params=id,anncType,dateAnnc,exDate,name,particulars,recDate,datePaid&order=desc&orderBy=dateAnnc` | GET | 200 | `application/json` | `payloads/resp_194_corporateactions_ibmcode_awx.json` | Corporate actions for IBM code `1BA1` (AEM Holdings). |
| 75 | Investor Portal | `FINANCIAL_STATEMENT_REPORTS_API_URL` | `https://api.sgx.com/financialstatementreports/v2.0/balanceSheet/countryCode/SGP/stockCode/AWX?params=all` | GET | 200 | `application/json` | `payloads/resp_195_financialstatement_balance_awx.json` | Balance sheet (`params=all`). |
| 76 | Investor Portal | `FINANCIAL_STATEMENT_REPORTS_API_URL` | `https://api.sgx.com/financialstatementreports/v2.0/cashFlow/countryCode/SGP/stockCode/AWX?params=all` | GET | 200 | `application/json` | `payloads/resp_197_financialstatement_cashflow_awx.json` | Cash flow statement. |
| 77 | Investor Portal | `FINANCIAL_STATEMENT_REPORTS_API_URL` | `https://api.sgx.com/financialstatementreports/v2.0/incomeStatement/countryCode/SGP/stockCode/AWX?params=all` | GET | 200 | `application/json` | `payloads/resp_198_financialstatement_income_awx.json` | Income statement. |
| 78 | Investor Portal | `STOCKSCREENER_API_URL` | `https://api.sgx.com/stockscreener/v2.0/all?params=exchange,exchangeCountryCode,companyName,stockCode,marketCapitalization,salesTTM,priceToEarningsRatio,dividendYield,fourWeekPricePercentChange,thirteenWeekPricePercentChange,twentySixWeekPricePercentChange,fiftyTwoWeekPricePercentChange,netProfitMargin,returnOnAvgCommonEquity,priceToCashFlowPerShareRatio,totalDebtToTotalEquityRatio,salesPercentageChange,sector,priceToBookRatio,priceCurrCode` | GET | 200 | `application/json` | `payloads/resp_196_stockscreener_v2.json` | ~701-stock quant screener with market cap, P/E, yield, returns, sector, etc. |
| 79 | Investor Portal | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1//charts/intraday/stocks/code/AWX/1d?params=trading_time,vl,lt` | GET | 200 | `application/json` | `payloads/resp_200_securities_charts_intraday_awx_1d.json` | 1-day intraday chart. |
| 80 | Investor Portal | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1//charts/historic/stocks/code/AWX/1m?params=trading_time,vl,lt` | GET | 200 | `application/json` | `payloads/resp_220_securities_charts_historic_awx_1m.json` | 1-month historic chart. |
| 81 | Investor Portal | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1//charts/historic/stocks/code/AWX/5y?params=trading_time,vl,lt` | GET | 200 | `application/json` | `payloads/resp_225_securities_charts_historic_awx_5y.json` | 5-year historic chart. |
| 82 | Investor Portal | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/securitycode?value=AWX&cat=ANNC&securityCodeParams=securitycode&sub=ANNC17&pagestart=0&pagesize=250&periodstart={ts}` | GET | 200 | `application/json` | `payloads/resp_190_announcements_securitycode_awx.json` | Per-stock announcements filtered by security code. |

Notes:
- `we_chat_qr_validator` calls with queryId `9b5f40321735d88857c12bd08459b5aba7fe2d1e` were also observed on every investor-portal page load.
- Several calls (`snapshotreports`, `announcements/securitycode`) carried the same `authorizationtoken` header used on `www.sgx.com`.

---

## Page 9 — Fixed Income / Additional `www.sgx.com` patterns (`https://www.sgx.com/fixed-income`)

This page revealed bond-specific securities sub-paths, additional CMS operations, and legacy infofeed calls with a `noCache` parameter.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 83 | Fixed Income | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Adata_settlement_prices_list&variables=%7B%22limit%22%3A0%2C%22offset%22%3A0%2C%22underlyingProductsCategory%22%3A%22191%22%2C%22underlyingProductsCategoryFilterEnabled%22%3Atrue%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_766_cms_data_settlement_prices_list.json` | CMS settlement-prices document list for derivatives category 191. |
| 84 | Fixed Income | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Aprices_list&variables=%7B%22limit%22%3A0%2C%22offset%22%3A0%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | `payloads/resp_768_cms_prices_list.json` | CMS prices document list. |
| 85 | Fixed Income | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/bonds?params=nc%2Cadjusted-vwap%2Cbond_accrued_interest%2Cbond_clean_price%2Cbond_dirty_price%2Cbond_date%2Cb%2Cbv%2Cp%2Cc%2Cchange_vs_pc%2Cchange_vs_pc_percentage%2Ccx%2Ccn%2Cdp%2Cdpc%2Cdu%2Ced%2Cfn%2Ch%2Ciiv%2Ciopv%2Clt%2Cl%2Co%2Cp_%2Cpv%2Cptd%2Cs%2Csv%2Ctrading_time%2Cv_%2Cv%2Cvl%2Cvwap%2Cvwap-currency` | GET | 200 | `application/json` | `payloads/resp_796_securities_bonds.json` | All bonds snapshot. |
| 86 | Fixed Income | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/charts/historic/retailbonds/code/91DB/1y` | GET | 200 | `application/json` | `payloads/resp_803_securities_charts_historic_retailbonds_91DB_1y.json` | 1-year historic chart for retail bond `91DB`. |
| 87 | Fixed Income | `SECURITIES_API_URL` | `https://api.sgx.com/securities/v1.1/retailbonds/code/91DB?params=...` | GET | 200 | `application/json` | `payloads/resp_804_securities_retailbonds_91DB.json` | Retail bond `91DB` detail snapshot. |
| 88 | Fixed Income | `ANNOUNCEMENTS_API_URL` | `https://api.sgx.com/announcements/v1.1/summary/company?periodstart=20260526_052303&sub=CACT22%2CCACT10%2CCACT23%2CCACT15` | GET | 200 | `application/json` | `payloads/resp_799_announcements_summary_cact_sub.json` | Corporate-action summary filtered by `sub` categories. |
| 89 | Fixed Income | `V1_DERIVATIVES_DAILY_LIST_URL` | `https://api3.sgx.com/infofeed/Apps?A=COW_Infopubdtstat_Content&B=DailyDataDownload&S_T=1&C_T=60&noCache={timestamp}` | GET | 200 | `text/plain` | (not saved; text/plain) | Legacy derivatives daily list with `noCache` anti-cache param. |
| 90 | Fixed Income | `V1_DERIVATIVES_HISTORICAL_LIST_URL` | `https://api3.sgx.com/infofeed/Apps?A=COW_Tickdownload_Content&B=TimeSalesData&C_T=20&noCache={timestamp}` | GET | 200 | `text/plain` | (not saved; text/plain) | Legacy derivatives historical list with `noCache` param. |

Bond-related sub-paths observed: `/securities/v1.1/bonds`, `/securities/v1.1/retailbonds/code/{code}`, `/securities/v1.1/retailpreferenceshares/code/{code}`, `/securities/v1.1/charts/historic/retailbonds/code/{code}/{period}`.

---

## Page 10 — Remaining `www.sgx.com` endpoints (`/stock-exchange/corporate-actions`, `/stock-exchange/meeting-schedules`, `/stock-exchange/corporate-information`, `/fixed-income/wholesale-bonds`, `/fixed-income/evaluated-bond-prices`, `/derivatives/daily-margining`, `/stock-exchange/circulars`, `/derivatives/negotiated-large-trades`, `/derivatives/structured-products`)

This round targeted endpoints that were still listed as blocked or unresolved after Pages 1–9.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 91 | Corporate Actions | `CMS_API_URL` | `https://api2.sgx.com/content-api?queryId=70f75ec90c030bab34d750ee55d74b016f70d4b6%3Apage&variables=%7B%22path%22%3A%22%2Fstock-exchange%2Fcorporate-actions%22%2C%22lang%22%3A%22EN%22%7D` | GET | 200 | `application/json` | (observed; same `page` shape as prior CMS calls) | CMS page wrapper for the corporate-actions table. |
| 92 | Corporate Actions | `CORPORATE_ACTIONS_API_URL` | `https://api.sgx.com/corporateactions/v1.0/metalist` | GET | 200 | `application/json` | `payloads/resp_1185_corporateactions_metalist.json` | ~112 KB gzipped list of `companyName` filter values. |
| 93 | Corporate Actions | `CORPORATE_ACTIONS_API_URL` | `https://api.sgx.com/corporateactions/v1.0?pagestart=0&pagesize=20&params=id%2CanncType%2CdatePaid%2CexDate%2Cname%2Cparticulars%2CrecDate` | GET | 200 | `application/json` | `payloads/resp_1188_corporateactions_list.json` | Paginated global corporate-actions feed (39,302 records). Fields include `id`, `anncType`, `datePaid`, `exDate`, `name`, `particulars`, `recDate`. |
| 94 | Meeting Schedules | `MEETING_SCHEDULES_API_URL` | `https://api.sgx.com/meetingschedules/v1.0/metalist` | GET | 200 | `application/json` | `payloads/resp_868_meetingschedules_metalist.json` | `issuerName`, `securityName`, `anncType` filter lists. |
| 95 | Meeting Schedules | `MEETING_SCHEDULES_API_URL` | `https://api.sgx.com/meetingschedules/v1.0?pagestart=0&pagesize=20&params=issuerName%2CsecurityName%2CmeetingDateTime%2CanncType%2CanncTitle%2CrecDateTime` | GET | 200 | `application/json` | `payloads/resp_871_meetingschedules_list.json` | Paginated AGM/EGM schedule records. |
| 96 | Corporate Information | `CORPORATE_INFORMATION_API_URL` | `https://api.sgx.com/corporateinformation/v1.0/metalist` | GET | 200 | `application/json` | `payloads/resp_909_corporateinformation_metalist.json` | `issuerName`, `securityName`, `industry`, `country` filter lists. |
| 97 | Corporate Information | `CORPORATE_INFORMATION_API_URL` | `https://api.sgx.com/corporateinformation/v1.0?pagestart=0&pagesize=20&params=issuerName%2CsecurityName%2Cindustry%2Ccountry%2CincorporationDate%2ClistedDate%2CtradingCurrency%2Curl%2Cemail` | GET | 200 | `application/json` | `payloads/resp_912_corporateinformation_list.json` | Paginated issuer profile records with incorporation/listing dates, currency, contact URL. |
| 98 | Wholesale Bonds | `WHOLESALE_BONDS_API_URL` | `https://api.sgx.com/wholesalebonds/v1.0/metalist` | GET | 200 | `application/json` | `payloads/resp_1030_wholesalebonds_metalist.json` | `issuerName`, `securityName` filter lists. |
| 99 | Wholesale Bonds | `WHOLESALE_BONDS_API_URL` | `https://api.sgx.com/wholesalebonds/v1.0?pagestart=0&pagesize=20&params=issuerName%2CsecurityName%2CbondType%2ClastTradedPrice%2ClastTradedDate%2ClastTradedYield%2CcouponRate%2CmaturityDate%2CbondPriceType` | GET | 200 | `application/json` | `payloads/resp_1032_wholesalebonds_list.json` | Paginated wholesale bond price/yield records. |
| 100 | Evaluated Bond Prices | `EVALUATED_BONDS_PRICES_API_URL` | `https://api.sgx.com/evaluatedbondprices/v1.0/metalist` | GET | 200 | `application/json` | `payloads/resp_1071_evaluatedbondprices_metalist.json` | `issuerName`, `securityName` filter lists. |
| 101 | Evaluated Bond Prices | `EVALUATED_BONDS_PRICES_API_URL` | `https://api.sgx.com/evaluatedbondprices/v1.0?pagestart=0&pagesize=20&params=issuerName%2CsecurityName%2CcleanPrice%2CdirtyPrice%2CevaluatedPriceDate%2CbidPrice%2CofferPrice%2Cyield%2CcouponRate%2CmaturityDate` | GET | 200 | `application/json` | `payloads/resp_1073_evaluatedbondprices_list.json` | Paginated evaluated bond prices. |
| 102 | Daily Margining | `DAILY_MARGINING_API_URL` | `https://api.sgx.com/dailymargining/v1.0/outright` | GET | 200 | `application/json` | `payloads/resp_dailymargining_outright.json` | Outright margin requirements per contract (~558 records). No `authorizationtoken` needed for this sub-path. |
| 103 | Daily Margining | `DAILY_MARGINING_API_URL` | `https://api.sgx.com/dailymargining/v1.0/intracomm` | GET | 200 | `application/json` | `payloads/resp_dailymargining_intracomm.json` | Intra-commodity spread margin offsets (~1,343 records). |
| 104 | Daily Margining | `DAILY_MARGINING_API_URL` | `https://api.sgx.com/dailymargining/v1.0/intercomm` | GET | 200 | `application/json` | `payloads/resp_dailymargining_intercomm.json` | Inter-commodity spread margin offsets (~6,170 records). |
| 105 | Circulars | `CIRCULARS_API_URL` | `https://api.sgx.com/circulars/v1.0/metalist` | GET | 200 | `application/json` | `payloads/resp_1203_circulars_metalist.json` | `companyName` filter list (this endpoint returns prospectuses and supplement documents, not only circulars). |
| 106 | Circulars | `CIRCULARS_API_URL` | `https://api.sgx.com/circulars/v1.0?pagestart=0&pagesize=5` | GET | 200 | `application/json` | `payloads/resp_1202_circulars_list.json` | Paginated prospectus/circular records: `id`, `documentDate`, `prospectusType`, `subject`, `companyName`. |
| 107 | Negotiated Large Trades | `NLT_API_URL` | `https://api.sgx.com/negotiatedlargetrades/v1.0?pagestart=0&pagesize=20` | GET | 200 | `application/json` | `payloads/resp_1201_negotiatedlargetrades_list.json` | Paginated NLT records: `contractCode`, `instrumentGroup`, `category`, `month`, `year`, `strikePrice`, `quantity`, `businessDate`, `tradedDate`, `clearedOnDate`, `premium`, `session`. |
| 108 | Structured Warrants | `STRUCTURED_PRODUCTS_API_URL` | `https://api.sgx.com/marketmetadata/v2/structure-warrants?pagestart=0&pagesize=5` | GET | 200 | `application/json` | `payloads/resp_1204_structurewarrants_meta.json` | Structured-warrant instrument metadata (1,183 records). |
| 109 | Freight Forward Agreements | `FFA_API_URL` | `https://api.sgx.com/ffa/products` | GET | 200 | `application/json` | `payloads/resp_ffa_products.json` | Product list: `["CW","PW","SW"]` (capesize, panamax, supramax). |
| 110 | Freight Forward Agreements | `FFA_API_URL` | `https://api.sgx.com/ffa/prices?product_code={CW,PW,SW}&time_period={TODAY,YESTERDAY}` | GET | 200 | `application/json` | `payloads/resp_ffa_prices_CW_TODAY.json`, `resp_ffa_prices_PW_TODAY.json`, `resp_ffa_prices_SW_TODAY.json` | Forward curve prices per product. `time_period` also accepts `PREVIOUS_WEEK`, `PREVIOUS_MONTH`, `PREVIOUS_YEAR`, but those currently return 500. No `authorizationtoken` needed for `/products` or `/prices`. |

Additional observations from this round:

- `/derivatives/daily-margining` (the CMS page) has no JSON data API on first load; the underlying `DAILY_MARGINING_API_URL` works if the correct sub-paths (`/outright`, `/intracomm`, `/intercomm`) are used. The base URL (`/v1.0`) and a guessed `/intercommodity` path still return `Missing Authentication Token`.
- `/derivatives/structured-products` is a 404 CMS route, but `STRUCTURED_PRODUCTS_API_URL` (`/marketmetadata/v2/structure-warrants`) works directly.
- `/derivatives/freight-forward-agreements` is a 404 CMS route, but `FFA_API_URL` works if the correct sub-paths are used: `/products` and `/prices?product_code={CW,PW,SW}&time_period={TODAY,YESTERDAY}`. The base URL (`/ffa`) and `/reports/24-hour` still return `Missing Authentication Token`.
- `V1_CHART_API_URL` (`https://api3.sgx.com/JsonRead/chartdata`) still returns `Not a valid request !` for guessed parameters (`qryId=STI`, `code=STI`, `code=Z74.SI&noCache=...`). Correct query parameters were not identified; the current `www.sgx.com` frontend does not appear to call this endpoint.
- Base `links.sgx.com/1.0.0/*` paths (corporate-actions, securities-historical, derivatives-daily, warrants, etc.) all return 404. Individual detail links such as `https://links.sgx.com/1.0.0/corporate-actions/{id}` work as HTML detail pages.

---

## Page 11 — Financial Reports (`FINANCIAL_REPORTS_API_URL`)

`FINANCIAL_REPORTS_API_URL` was exempt from the original discovery run, so it was investigated manually after the browser recon round. It provides a paginated metadata list of financial/periodic reports filed by SGX-listed entities.

| # | Page | Endpoint Key | URL | Method | Status | Content-Type | Response File | Notes |
|---|------|--------------|-----|--------|--------|--------------|---------------|-------|
| 108 | Financial Reports | `FINANCIAL_REPORTS_API_URL` | `https://api.sgx.com/financialreports/v1.0/metalist` | GET | 200 | `application/json` | `payloads/resp_1302_financialreports_metalist.json` | `companyName` filter list for the UI dropdown. |
| 109 | Financial Reports | `FINANCIAL_REPORTS_API_URL` | `https://api.sgx.com/financialreports/v1.0?pagestart=1&pagesize=10&params=id%2CcompanyName%2CdocumentDate%2CsecurityName%2Ctitle%2Curl` | GET | 200 | `application/json` | `payloads/resp_1300_financialreports_page1.json` | Page 1 of the report metadata list. Returns `id`, `companyName`, `documentDate` (ms epoch), `securityName`, `title`, and a `url` pointing to a `links.sgx.com` HTML detail page. Total items: 13,348. |
| 110 | Financial Reports | `FINANCIAL_REPORTS_API_URL` | `https://api.sgx.com/financialreports/v1.0?pagestart=2&pagesize=10&params=id%2CcompanyName%2CdocumentDate%2CsecurityName%2Ctitle%2Curl` | GET | 200 | `application/json` | `payloads/resp_1301_financialreports_page2.json` | Page 2 confirming pagination works. |

Usage notes:

- **Pagination:** `pagestart` begins at 1. `pagesize=2000` is the documented bulk size; at that size the full corpus is ~7 pages (13,348 records). The small `pagesize=10` captures above were made for payload-size convenience.
- **Field projection:** The endpoint requires/strongly prefers a `params` list. The useful fields are `id,companyName,documentDate,securityName,title,url`.
- **Document retrieval:** Each `url` is a `https://links.sgx.com/1.0.0/corporate-announcements/{id}/{hash}` HTML detail page. That page hosts the actual PDF attachment(s); the API itself returns metadata only.
- **Headers:** Include `Origin: https://www.sgx.com` and `Referer: https://www.sgx.com/`.
- **Filter dependent call:** `.../metalist` returns the `companyName` dropdown values, useful for per-company filtering if the API supports it.

---

## Key findings across all pages

### 1. Many "blocked" endpoints were simply called without required sub-paths

During the first discovery run the raw appconfig URLs such as `https://api.sgx.com/securities/v1.1` and `https://api.sgx.com/derivatives/v1.0` returned errors. The browser reveals that the frontend never calls those bare URLs directly; it always appends resource paths or query parameters.

Examples now proven working:

- `SECURITIES_API_URL`:
  - `/aggregate/`
  - `/aggregate/volume?securitytype={type}` and `/aggregate/value?securitytype={type}`
  - `/sectorbreakdown`
  - `/circuitbreaker`
  - `/advancers/{stocks,reits,etfs,structuredwarrants,dlcertificates}/{5,7}/v?params=...`
  - `/etfs?params=...`
  - `?params=nc,n,type,ls,m,sc,bl,sip,ex,ej,clo,cr,cur,el,r,i,cc,ig,lf` (reference)
  - `?params=nc,adjusted-vwap,bond_accrued_interest,...,vwap-currency` (full quote)
  - `?excludetypes=bonds&params=...` (screener)
- `DERIVATIVES_API_URL`:
  - `?aggregate=true&aggregate-option=total-volume`
  - `?groupby=cc&category=futures`
  - `/history/symbol/{symbol}?days=10d&category=futures&params=...`
- `INDICES_API_URL`:
  - `/` — master list of all indices
  - `/pid/{pid}/`
  - `/charts/intraday/pid/{pid}/{period}?params=...`
  - `/charts/historic/pid/{pid}/{period}?params=...`
- `ANNOUNCEMENTS_API_URL`:
  - `/companylist`, `/securitylist`
  - `/summary/company?periodstart={ts}&cat={cat}`
  - `/count?periodstart={ts}&periodend={ts}`
  - `/?periodstart={ts}&periodend={ts}&pagestart=0&pagesize=20`
- `IPO_PERFORMANCE_API_URL`:
  - `/yearlist`, `/issuerlist`, `/companylist`
  - `/?year={yyyy}`
- `IPO_PROSPECTUS_API_URL`:
  - `/?closing_time={yyyyMMdd_HHmmss}`
- `ETF_API_URL`:
  - `/documents`
- `THIRDPARTY_INDICES_API_URL`:
  - `/chinabonds`
- `FINANCIAL_REPORTS_API_URL`:
  - `/metalist`
  - `/?pagestart={n}&pagesize=2000&params=id,companyName,documentDate,securityName,title,url`
- `CORPORATE_ACTIONS_API_URL`:
  - `/metalist`
  - `/?pagestart=0&pagesize=20&params=id,anncType,datePaid,exDate,name,particulars,recDate` (global feed)
  - `/?pagesize=10&pagestart=0&ibmcode={ibmcode}&params=...` (per-stock investor-portal call)
- `CIRCULARS_API_URL`:
  - `/metalist`
  - `/?pagestart=0&pagesize=5` (prospectus/circular feed)
- `NLT_API_URL`:
  - `/?pagestart=0&pagesize=20` (negotiated large trades)
- `MEETING_SCHEDULES_API_URL`:
  - `/metalist`
  - `/?pagestart=0&pagesize=20&params=issuerName,securityName,meetingDateTime,anncType,anncTitle,recDateTime`
- `CORPORATE_INFORMATION_API_URL`:
  - `/metalist`
  - `/?pagestart=0&pagesize=20&params=issuerName,securityName,industry,country,incorporationDate,listedDate,tradingCurrency,url,email`
- `WHOLESALE_BONDS_API_URL`:
  - `/metalist`
  - `/?pagestart=0&pagesize=20&params=issuerName,securityName,bondType,lastTradedPrice,lastTradedDate,lastTradedYield,couponRate,maturityDate,bondPriceType`
- `EVALUATED_BONDS_PRICES_API_URL`:
  - `/metalist`
  - `/?pagestart=0&pagesize=20&params=issuerName,securityName,cleanPrice,dirtyPrice,evaluatedPriceDate,bidPrice,offerPrice,yield,couponRate,maturityDate`
- `STRUCTURED_PRODUCTS_API_URL`:
  - `/marketmetadata/v2/structure-warrants?pagestart=0&pagesize=...`
- `DAILY_MARGINING_API_URL`:
  - `/outright` — per-contract outright margin requirements
  - `/intracomm` — intra-commodity spread margin offsets
  - `/intercomm` — inter-commodity spread margin offsets
- `FFA_API_URL`:
  - `/products` — product list (`CW`, `PW`, `SW`)
  - `/prices?product_code={CW,PW,SW}&time_period={TODAY,YESTERDAY}` — forward curve prices
  - `/reports/24-hour` — blocked (still requires an unknown token)
- New `api.sgx.com` v2.0 per-stock/fundamental endpoints (not in original appconfig):
  - `/ratiosreports/v2.0/countryCode/SGP/stockCode/{code}?params=...`
  - `/snapshotreports/v2.0/countryCode/SGP/stockCode/{code}?params=...`
  - `/shareholdersreports/v2.0/stockCode/{code}?params=...`
  - `/financialstatementreports/v2.0/{balanceSheet,cashFlow,incomeStatement}/countryCode/SGP/stockCode/{code}?params=all`
  - `/stockscreener/v2.0/all?params=marketCapitalization,priceToEarningsRatio,dividendYield,sector,...`
- Stock charts on `SECURITIES_API_URL`:
  - `/charts/historic/stocks/code/{code}/{period}?params=...`
  - `/charts/intraday/stocks/code/{code}/{period}?params=...`
- Bond sub-paths on `SECURITIES_API_URL`:
  - `/bonds?params=...`
  - `/retailbonds/code/{code}?params=...`
  - `/retailpreferenceshares/code/{code}?params=...`
  - `/charts/historic/retailbonds/code/{code}/{period}?params=...`
- Additional CMS operations:
  - `data_settlement_prices_list`
  - `prices_list`

### 2. `ANNOUNCEMENTS_API_URL` requires an `authorizationtoken` header

All `api.sgx.com/announcements/v1.1/*` calls carry an `authorizationtoken` header. This is almost certainly why the original discovery run for `ANNOUNCEMENTS_API_URL` returned HTTP 401.

The token is **not** hard-coded in the main JS bundle. It is fetched from the CMS and decoded by the frontend:

1. Request `https://api2.sgx.com/content-api/?queryId={CMS_VERSION}:we_chat_qr_validator` (with matching `Origin`/`Referer`).
2. The response JSON contains `data.qrValidator`, a ROT13-encoded string.
3. Apply ROT13 to `data.qrValidator` to obtain the raw `authorizationtoken` value.
4. Include that value as the `authorizationtoken` header on every `api.sgx.com/announcements/v1.1/*` request.

The same token is required by some investor-portal calls (e.g. `/snapshotreports/v2.0/...`, `/announcements/v1.1/securitycode`). On `investors.sgx.com` the frontend calls `we_chat_qr_validator` with that site's own `CMS_VERSION`, and the decoded token is used for the investor-portal API calls.

See Appendix A for a worked example and implementation notes.

### 3. `CMS_API_URL` is GraphQL-ish but uses `queryId` hashes

The actual host is `api2.sgx.com/content-api`. Calls look like:

```
https://api2.sgx.com/content-api?queryId={CMS_VERSION}:{operation}&variables={urlencoded_json}
```

Operations seen on `www.sgx.com` (queryId = `{CMS_VERSION}` from appconfig, currently `70f75ec90c030bab34d750ee55d74b016f70d4b6`):

- `we_chat_qr_validator`
- `all_menus`
- `alerts`
- `page`
- `advertisement_list`
- `derivatives_products_list`
- `index_list`
- `market_updates_list`
- `taxonomy_terms`

The investor portal (`investors.sgx.com`) uses a different `queryId` prefix (`9b5f40321735d88857c12bd08459b5aba7fe2d1e`) and a `document_list` operation with `namefilter`. A third CMS prefix (`0c6b763562fa9ad6d4b40558d2670db60437f7a6`) was used for the `IP-CA-TABLE` document list.

Required headers for CORS: `Origin: https://www.sgx.com` / `https://investors.sgx.com`, and matching `Referer`.

### 4. Parameter `params` controls field projection

Every securities/derivatives/indices GET accepts a `params` query string of comma-separated field abbreviations. This is how the frontend trades payload size against field richness. Replaying a request without `params` may fail or return a different shape.

### 5. `METADATA_API_URL` is the instrument master

`/marketmetadata/v2` returns ~11 MB of instrument metadata. The browser's compressed response was ~480 KB but the expanded JSON is ~11 MB. This is the authoritative mapping of symbols, names, sectors, currencies, listing status, etc.

### 6. `links.sgx.com` is the document delivery layer

Announcement and financial-report payloads contain `url` fields pointing to `https://links.sgx.com/1.0.0/...`. These are pre-signed/document-store URLs, not API endpoints to be scraped blindly.

### 7. `FINANCIAL_REPORTS_API_URL` is paginated

Although exempt from the original discovery run, manual probing confirmed the modern endpoint works as a paginated metadata list:

- `https://api.sgx.com/financialreports/v1.0?pagestart={n}&pagesize=2000&params=id,companyName,documentDate,securityName,title,url`
- `pagestart` begins at 1. At `pagesize=2000` the corpus is ~7 pages (13,348 records as of 2026-06-25).
- A `.../metalist` sub-path returns the `companyName` filter values.
- Each record's `url` points to a `links.sgx.com/1.0.0/corporate-announcements/{id}/{hash}` HTML detail page hosting the PDF attachment(s).
- Captured payloads: `payloads/resp_1300_financialreports_page1.json`, `payloads/resp_1301_financialreports_page2.json`, `payloads/resp_1302_financialreports_metalist.json`.

---

## Appendix A — How to obtain the `authorizationtoken`

Several `api.sgx.com` endpoints require an `authorizationtoken` header, notably:

- `https://api.sgx.com/announcements/v1.1/*`
- some `investors.sgx.com` calls such as `/snapshotreports/v2.0/...` and `/announcements/v1.1/securitycode`

The token is **not** hard-coded in the main JS bundle. The frontend retrieves it from the CMS and decodes it before use:

1. Call the CMS validator endpoint:

   ```
   GET https://api2.sgx.com/content-api/?queryId={CMS_VERSION}:we_chat_qr_validator
   ```

   with `Origin: https://www.sgx.com` and `Referer: https://www.sgx.com/`.

2. The response contains:

   ```json
   {"data":{"qrValidator":"<ROT13-encoded-token>"}}
   ```

3. Apply ROT13 to the value of `data.qrValidator` to obtain the raw `authorizationtoken`.

4. Send that value as the request header:

   ```
   authorizationtoken: <decoded-value>
   ```

Example (captured 2026-06-25):

- CMS response `qrValidator`: `RGxg1OtusGizp5RJaKN6BZ7w6wV1bEFPHhjPCqRQjoBKnjng8/2FSP9NdyWN0BBtiADW/mgRpnICrITvD5ILplGJRZvIA74QPJDxfvb+XeeRUSrZL/l+scNZyrotV4mn9g2K4YscUQ==`
- ROT13 decode: `ETkt1BghfTvmc5EWnXA6OM7j6jI1oRSCUuwCPdEDwbOXawat8/2SFC9AqlJA0OOgvNQJ/ztEcaVPeVGiQ5VYcyTWEMiVN74DCWQksio+KrrEHFeMY/y+fpAMlebgI4za9t2X4LfpHD==`
- This decoded value is exactly what the announcements API requests send as `authorizationtoken`.

The same `we_chat_qr_validator` call is made on `investors.sgx.com` with that site's `CMS_VERSION` (`9b5f40321735d88857c12bd08459b5aba7fe2d1e`) and produces the token used by the investor-portal API calls. Treat the decoded token as a short-lived credential; do not commit it to the repository in plain text.

---

## Appendix B — CORS headers

All `api.sgx.com`, `api2.sgx.com`, and `api3.sgx.com` calls carried an `Origin`/`Referer` matching the calling site:

```
Origin: https://www.sgx.com          # when called from www.sgx.com
Referer: https://www.sgx.com/

Origin: https://investors.sgx.com    # when called from investors.sgx.com
Referer: https://investors.sgx.com/
```

Replaying requests without the matching `Origin`/`Referer` may result in 403/401 responses.

---

## Still to investigate

- `STOCKS_API_URL` / `THIRDPARTY_INDICES_API_URL` full Refinitiv/TRKD usage — direct calls to `apitrkd.trkd-hs.com` remain unresolved.
- `V1_CHART_API_URL` — legacy chart endpoint (`api3.sgx.com/JsonRead/chartdata`). Correct query parameters not identified; current frontend does not appear to use it.

---

## Files in this directory

- `investigation.md` — this log.
- `payloads/` — full JSON request/response bodies captured from the browser.
