Skip to main content
Sahmino
What Sahmino does

The API reference

Everything a program can ask «رصد» for: the address, the scope, the cost and the shape of the answer.

This page is generated from the same list the API routes are registered from, so it cannot describe an endpoint that does not exist: 17 endpoints across 9 scopes. Field names and error codes are English and are not translated; a half-translated machine interface is worse than an honest monolingual one.

Getting started

Base address
https://sahmino.com/api/v1
Authentication header
Authorization: Bearer <token>

A token minted for the MCP server is not an API token and will be refused.

A sample request

curl -H "Authorization: Bearer $SAHMINO_TOKEN" \
  https://sahmino.com/api/v1/instruments
240
requests per minute
100
rows per page

Scopes

A scope is fixed when the key is minted and never changes afterwards. Each endpoint declares exactly one and the comparison is literal, which is why an MCP key opens nothing here.

ScopeWhat it reads
api:instrumentsRead the instrument catalog, board rows and one instrument’s profile.
api:pricesRead price history and derived series for one instrument.
api:indicatorsRead computed technical indicators for one instrument.
api:screenerRun a saved screen or an ad-hoc condition set over the universe.
api:filingsRead codal filings and the financial statements parsed from them.
api:valuationsRead saved valuation runs and their inputs.
api:macroRead macroeconomic series.
api:ownershipRead the shareholder register and board composition graph.
api:alertsRead alert rules and their delivery history.

The shape of an answer

  • A single record answers {"data": {…}}.
  • A list answers {"data": [...], "meta": {"page", "perPage", "total", "lastPage"}}. perPage is fixed and is not caller-settable.
  • Every refusal answers {"error": {"code", "message", "detail?"}}. Branch on code; message is prose and may be reworded in any release.

Errors

Branch on code, never on message: the prose may be reworded in any release, the code stays.

CodeHTTP statusWhat it means, and what to do
unauthenticated401No token, an expired one, or one that has been revoked. Mint a new token.
scope_required403The token is valid but was not granted the scope this endpoint declares. Mint one that carries it — a token’s scopes are fixed at mint.
plan_required403The account’s tier does not include API access. Nothing about the token can fix this.
rate_limited429The per-minute ceiling or the day’s request budget. Read Retry-After, and detail.retryAfter on the budget refusal.
not_found404The request was understood and names nothing we hold. An instrument is matched exactly, by id, symbol or slug.
invalid_request422A bad parameter, a missing one, or the wrong shape. detail.fields names each one.
server_error500Us. The message is deliberately generic; report it with the time of the call.

17 of 17 endpoints

instruments

Read the instrument catalog, board rows and one instrument’s profile.

GET/api/v1/instrumentsone pagecost 1api:instruments

The instrument catalog, paged.

Identity, venue and the last price we hold. Both language names travel, always.

Query parameters

ParameterTypeDescription
filter[market]stringOne market type — gold, currency, tse and their like.
filter[board]stringThe listing venue, exactly.bourse · fara · fara_base
filter[q]stringA search term over symbol and name, in either language.
sortstringA sort key; prefix with «-» for descending.
pageintegerWhich page, from one.
GET/api/v1/instruments/{instrument}one recordcost 2api:instruments

One instrument, with its exchange profile.

The catalog row plus the nightly profile reading: free float, market capitalisation, the sector it is filed under.

GET/api/v1/boardone pagecost 1api:instruments

The day’s board — one page of it.

Last, close, previous close, change, volume, value and the retail share of each side.

Query parameters

ParameterTypeDescription
groupstringWhich half of the board.all · equity · fund · fixed_income
exchangestringThe listing venue.bourse · fara · fara_base
industrystringOne industry, as the exchange spells it.
searchstringA term over symbol and name.
sortstringWhat the whole match is ordered by before the page is cut.value · volume · change · last
directionstringAscending or descending.asc · desc
pageintegerWhich page, from one.

prices

Read price history and derived series for one instrument.

GET/api/v1/instruments/{instrument}/pricesone recordcost 2api:prices

Daily history and the window statistics struck from it.

Points are oldest first; a halted session is a row like any other and says so. `unit` is load-bearing — rial and toman differ by a factor of ten.

Query parameters

ParameterTypeDescription
daysintegerRows of daily history, 20 to 365. Default 120.

indicators

Read computed technical indicators for one instrument.

GET/api/v1/instruments/{instrument}/indicatorsone recordcost 2api:indicators

The stored technical readings for one instrument.

Read back, never recomputed: `seriesHash` says which sessions they were struck from. An indicator with no reading is absent rather than null.

screener

Run a saved screen or an ad-hoc condition set over the universe.

GET/api/v1/screener/fieldsone recordcost 1api:screener

Every screenable field, with its group, format and label.

The catalog a client needs before it can write a condition. Generated from the field registry the screener itself draws.

GET/api/v1/screensone recordcost 1api:screener

The caller’s own saved screens.

POST/api/v1/screener/runone recordcost 10api:screener

Run a saved screen, or a set of conditions posted with the request.

A نماد with no reading on a field never passes a condition on it: an absent figure is not a zero. `matched` is how many passed; `data` is how many the plan let travel.

Request body

ParameterTypeDescription
screenIdintegerA saved screen of the caller’s. When present, `screen` and `scope` are ignored.
screenobjectA condition set: `match` of «all» or «any», and up to 24 conditions of field, operator and value.
scopeobjectNarrow the universe first: `group`, `exchange`, `industry`.
fieldsarrayExtra readings each row should carry, beyond the ones it was screened on.
sortBystringA field key the whole match is ordered by.
sortDescendingbooleanLargest first. Default true.

filings

Read codal filings and the financial statements parsed from them.

GET/api/v1/filingsone pagecost 1api:filings

codal letters as filed, newest first.

`periodMonths` is the span the letter reports; comparing a three-month figure with a twelve-month one is the commonest way to publish a wrong number.

Query parameters

ParameterTypeDescription
symbolstringOne نماد, by symbol or slug. An unknown one narrows to nothing.
sincestringOnly letters published on or after this date.
parsedOnlybooleanOnly letters whose statements we have parsed.
pageintegerWhich page, from one.
GET/api/v1/instruments/{instrument}/statementsone recordcost 2api:filings

The financial statements parsed out of one instrument’s filings.

How many periods travel is the tier’s `statement_periods` cell, and `quota` reports it beside the rows: `total` is how many the company filed, `shown` is how many the plan allows.

Query parameters

ParameterTypeDescription
letterintegerOne letter id, to read the grid as that letter filed it.

valuations

Read saved valuation runs and their inputs.

GET/api/v1/valuationsone recordcost 1api:valuations

The caller’s saved valuation runs.

`gapAtSave` is the argument the reader was making; `gapNow` is what the market has done to it since.

GET/api/v1/instruments/{instrument}/valuationsone recordcost 2api:valuations

The caller’s saved runs for one instrument.

macro

Read macroeconomic series.

GET/api/v1/macroone recordcost 1api:macro

Every macro series we declare, with its freshness.

`freshAt` is the last write of the ingest behind the series and `stale` is that clock against the series’ own cadence — a monthly series with no observation this week is not late.

GET/api/v1/macro/seriesone recordcost 1api:macro

The observations of up to 5 series.

Points are oldest first and a day with no observation is absent, never zero. An unknown key is a 404 rather than an empty series.

Query parameters

ParameterTypeDescription
keys[]requiredarraySeries keys, as the catalog spells them.
daysintegerHow far back, up to 3650.

ownership

Read the shareholder register and board composition graph.

GET/api/v1/instruments/{instrument}/ownershipone recordcost 2api:ownership

The shareholder register, the board and everything derived from them.

An individual’s کد ملی is never present: the query nulls it before the DTO is built.

alerts

Read alert rules and their delivery history.

GET/api/v1/alertsone recordcost 1api:alerts

The caller’s alert rules.

Read only. A rule is written through the terminal, where the plan cap and the re-arm rule live.

GET/api/v1/alerts/deliveriesone pagecost 1api:alerts

What has already been sent, newest first.

The feed an integration wants: an alert that fired, so it can reach a system rather than only a person.

Query parameters

ParameterTypeDescription
pageintegerWhich page, from one.