# Using the data with an agent

Practical guide to brvmdata public interfaces: catalog, CSV, chart JSON, dated observations, official-news RSS feeds and original-source citations.

 

Public GET access without authentication. These are documents and files: no server-query API, remote SQL or mutation endpoint. Observations are periodic, not guaranteed real-time. No investment advice.

 

## Start here

- [Complete site index](<https://brvmdata.com/en/plan/>)
- [Markdown index](<https://brvmdata.com/en/plan/index.md>)
- [Page index (JSON)](<https://brvmdata.com/data/pages.json>)
- [Dataset catalog v1](<https://brvmdata.com/data/catalog.json>)
- [JSON Schema 2020-12](<https://brvmdata.com/data/catalog.schema.json>)
- [Sources, files and terms](<https://brvmdata.com/en/donnees/>)
- [This guide in Markdown](<https://brvmdata.com/en/agents/index.md>)
- [Official news RSS feed](<https://brvmdata.com/en/actualites/rss.xml>)
- [Proposed discovery: llms.txt](<https://brvmdata.com/llms.txt>)
- [Guide and full dataset summaries](<https://brvmdata.com/llms-full.txt>)

llms.txt is a proposed discovery convention, not a universal API standard, reuse permission or a guarantee of indexing or ranking.

 

## Formats and edition consistency

The catalog versions its contract (schema\_version), not download URLs. data\_edition\_at identifies the data edition; metadata\_generated\_at dates the description. Each dataset gives actual exported columns, row count, known units, coverage, join hints and existing files with size and SHA-256. A stable URL can change content; several GETs are not an atomic transaction. Verify size and digest; on mismatch refetch catalog and file without stale cache rather than mixing editions.

CSV: UTF-8, comma separator, decimal point, first-row header. storage\_type is the declared storage type, type its affinity; encoding is CSV text. Read identifiers as strings first. compression=null means uncompressed CSV; gzip means a .csv.gz file to decompress. The digest covers downloaded file bytes before decompression. Unknown unit or basis is null. primary\_key=null means no general uniqueness guarantee.

```
import csv, gzip, hashlib, io, json
from urllib.request import urlopen

BASE = "https://brvmdata.com"
def get_json(path):
    with urlopen(BASE + path, timeout=30) as response:
        return json.load(response)

catalog = get_json("/data/catalog.json")
assert catalog["schema_version"] == 1
datasets = {d["table"]: d for d in catalog["datasets"]}

def rows(name):
    dataset = datasets[name]
    variants = dataset["distributions"]
    download = next((d for d in variants if d["compression"] is None), variants[0])
    with urlopen(download["download_url"], timeout=60) as response:
        raw = response.read()
    if (len(raw) != download["byte_size"] or
            hashlib.sha256(raw).hexdigest() != download["sha256"]):
        raise RuntimeError("Edition changed: refetch catalog and file without stale cache")
    if download["compression"] == "gzip":
        raw = gzip.decompress(raw)
    return list(csv.DictReader(io.StringIO(raw.decode("utf-8"))))
```

 

## 1. Resolve SNTS, then read its history

search.json is a list: u=canonical French path, n=name, k=kind, s=symbol, i=ISIN, x=extra text; empty keys are omitted. Do not confuse an equity symbol with a bond symbol. In the chart: s=symbol, d=dates, c=closes, v=volumes; arrays align by position. Optional prov is the first provisional date. Optional e lists the company's official events within the chart's period, oldest first: \[publication date, type (results, dividend, agm, capital or listing), title as published, original document URL or null\]; at most the latest 300. Equity closes and volumes are split-adjusted and merge BOC, bfin and provisional closes; this is neither raw CSV nor a dividend-reinvested total-return series.

```
search = get_json("/data/search.json")
security = next(item for item in search
                if item.get("s") == "SNTS" and item["k"] in ("action", "radiee"))
print(BASE + security["u"], security["n"], security.get("i"))
chart = get_json("/data/actions/" + security["s"].lower() + ".json")
if chart["d"]:
    print(chart["s"], chart["d"][-1], chart["c"][-1], chart["v"][-1])
```

For indices choose a k=indice result and use the slug in u: /data/indices/&lt;slug&gt;.json (example below). s is the index name, c its levels, v is optional. Some v zeroes also represent missing or provisional volume: do not automatically read them as no trading. Old index families and new bases cannot be spliced without a method.

[BRVM COMPOSITE JSON](<https://brvmdata.com/data/indices/brvm-composite.json>)

 

## 2. Latest official equity board

Filter boc\_equities on its maximum date after keeping active bulletins. This is the latest available bulletin session, not necessarily the newest intraday observation. Preserve missing values, document\_id and bulletin parse status; do not copy a prior quote as a new close.

```
bulletins = {r["document_id"]: r for r in rows("boc_bulletins")
             if r["status"] == "active"}
quotes = [r for r in rows("boc_equities") if r["document_id"] in bulletins]
latest_date = max(r["trading_date"] for r in quotes)
board = [r for r in quotes if r["trading_date"] == latest_date]
print("Official bulletin board:", latest_date)
for quote in board:
    print(quote["symbol"], quote["close_price"] or None,
          quote["volume"] or None, quote["document_id"])
```

 

## 3. Cite the original document

Join document\_id to id in the same source's &lt;prefix&gt;\_documents registry (here boc\_documents). IDs are not global. A citation preserves the original PDF URL, session, document date, retrieval and data edition; it can also link the brvmdata dataset landing page. Actually check the document: a recorded URL or HTTP 200 does not prove a complete PDF is available.

```
quote = next(r for r in board if r["symbol"] == "SNTS")
documents = {r["id"]: r for r in rows("boc_documents")}
document = documents[quote["document_id"]]
print({"symbol": quote["symbol"], "session_date": quote["trading_date"],
       "close_price_xof": quote["close_price"] or None,
       "source_url": document["source_url"], "document_date": document["doc_date"],
       "retrieved_at": document["retrieved_at"],
       "data_edition_at": catalog["data_edition_at"],
       "dataset_url": datasets["boc_equities"]["landing_urls"]["en"]})
```

[AMF document-check sample](<https://brvmdata.com/en/donnees/#disponibilite>)

 

## 4. Read a /live.json v2 observation

The document separates market state from the last observation of each symbol or index. equities is keyed by symbol, indices by name (an entry may be null). Their observed\_at, fetched\_at, session\_date and basis belong to each observation. basis is intraday, closing or unknown. Never re-date a quote with the top-level clock or turn closed into closing; an empty closing screen may retain an older intraday quote. Session indicators, bulletin ratios and histories retain their own dates.

```
live = get_json("/live.json")
assert live["schema_version"] == 2
quote = live.get("equities", {}).get("SNTS")
if quote is not None:
    print({key: quote.get(key) for key in
           ("price_last", "change_pct", "volume", "observed_at", "fetched_at",
            "session_date", "basis", "market_status")})
# live["observed_at"] describes the market-state screen, not every quote.
# basis is intraday, closing or unknown; closed alone does not imply closing.
```

price\_last, price\_prev and price\_open are XOF per share, change\_pct is percent, volume is a security count; level is an index level. paths contains observed intraday \[HH:MM UTC, price\] pairs for the top-level screen date only; not a continuous history or a manufactured close. A missing symbol means unavailable observation, not zero.

 

## 5. Follow official news (RSS)

RSS 2.0 feeds: /actualites/rss.xml (the latest 100 items, every source) and /actions/&lt;lower-case symbol&gt;/rss.xml (a company's latest 50), French labels; the same paths under /en/ for English labels. Every listed or delisted share has a feed, possibly empty. An item gives the title as published, link = the original document's URL at its source, pubDate = publication date (midnight UTC when only the day is known), a stable non-permalink guid (brvmdata:&lt;source&gt;:&lt;id&gt;), category = type, description = type · company (symbol) · source · also: other sources of the same event · via brvmdata. No document body is copied. lastBuildDate is the feed's newest publication, not the generation time.

Official sources only: listed-company filings and announcements and BRVM notices, the official bulletin, AMF-UMOA, debt offices, BCEAO. Company links come from the source's explicit key or the exact name printed by the BRVM; an ambiguous name (group, missing country) stays unlinked, so a missing symbol does not prove a document concerns no company. One event published by several sources is one item, with the company document's guid; a bulletin notice published before that document can therefore give way to a new guid. Bond coupon and redemption payment notices are left out (coupon calendar on /obligations/). Poll at most a few times an hour, with If-None-Match or If-Modified-Since.

- [All official news](<https://brvmdata.com/en/actualites/rss.xml>)
- [One company: SNTS](<https://brvmdata.com/en/actions/snts/rss.xml>)

 

## Interpretation rules

- Dates: trading session, observation, publication, effective date, ex-date, maturity, retrieval and metadata generation are distinct. Coverage bounds do not guarantee continuity; schedules may extend into the future.
- Joins: preserve source identifiers and dates. Normalize case/whitespace when comparing ISINs, never arbitrarily strip characters or join on a name alone. Check cardinality before aggregating; link\_issuer\_symbols carries method and confidence. For fund\_annual/fund\_quarterly, source refers to fil\_filings.filing\_id, then document\_id to fil\_documents.id.
- Missing values: null and empty cells are not zero. An explicit zero also does not prove no activity where the chart contract documents a placeholder. Do not interpolate missing sessions, yields or quotes.
- Units: \_xof is XOF; \_millions is XOF millions; \_bn is XOF billions. Accounts are in millions, per-share dividends in XOF. A page may display a different scale from its CSV. For com\_commodity\_monthly.value and macro indicators, read unit on every row; never assume USD or XOF for an entire table.
- Dividends and accounts: distinguish gross, net, tax/IRVM, shareholder category, standalone/consolidated accounts and pre/post-split share basis. An announced amount is not automatically net. Preserve cumulative status, fiscal year, period, source and confidence; never add overlapping cumulative periods.
- Point-in-time history: published\_date\_imputed, published\_date\_evidence, pit\_excluded, restated\_values and flags identify limitations and revisions. An imputed publication date does not prove historical availability; pit\_excluded=true excludes an observation from point-in-time analysis. The fund datasets are closed; a new catalog edition does not mean new accounts.
- Bulletins and approvals: official history is incomplete, parse\_status may be partial; check the PDF. Provisional sessions are not official bulletins. amf\_issue\_visas retains raw versions: conflicting amounts and repeated approvals are not additive; the New issues page reconciles approvals but does not turn approval into completed fundraising.

 

## Bounded requests and reuse

Choose needed files from the catalog, bound concurrent requests, reuse a local copy and honor Cache-Control. File responses may provide ETag and Last-Modified: reuse these validators with If-None-Match or If-Modified-Since and accept 304. Do not assume external sources support those headers; inspect their responses. No guaranteed quota or high-frequency query service is advertised.

Access to brvmdata is free; this is not a redistribution licence for its sources. Publicly accessible documents are not automatically openly licensed. The review below distinguishes express permissions, restrictions and rights not established. Cite the original source and brvmdata without implying endorsement.

Permission not established does not mean a proven prohibition. For restricted or uncertain uses, the publisher must establish the applicable basis: a contract or permission covering public display, histories, CSV files and intraday data, or legal advice on the permitted scope. Attribution alone does not replace required permission. Third-party rights and privacy obligations still apply.

No warranty: the data is reproduced and normalised automatically and may contain errors; check any figure against the source document before relying on it. Nothing here is investment advice.

[Detailed source-specific terms](<https://brvmdata.com/en/donnees/#licence>)

 

Catalog metadata generated at 2026-11-10T22:47:50+00:00; data edition: 2026-11-10T22:45:15+00:00

---

[Canonical page](<https://brvmdata.com/en/agents/>)
