Files

501 lines
53 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 19.
| # | 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.