Python SDK & CLI
pip install -U sahmk
pip install sahmk --upgrade
export SAHMK_API_KEY="your_api_key"
sahmk quote 2222Python SDK:
from sahmk import SahmkClient
client = SahmkClient(api_key="YOUR_API_KEY")
print(client.quote("2222"))Full examples: github.com/sahmk-sa/sahmk-python • PyPI: pypi.org/project/sahmk
Getting Started
Welcome to the SAHMK API. Access real-time and historical Saudi stock market data for all 350+ companies listed on TASI and Nomu.
Quick Start
- Create a free account
- Get your API key from the dashboard
- Make your first API request
- Browse code examples on GitHub
Base URL
https://app.sahmk.sa/api/v1Your First Request
curl -X GET "https://app.sahmk.sa/api/v1/quote/2222/" \
-H "X-API-Key: YOUR_API_KEY"Full examples available on GitHub →
Authentication
All API requests require authentication using an API key. Include your key in the X-API-Key header.
X-API-Key: YOUR_API_KEYAPI Key Types:
• shmk_live_* — Production keys
• shmk_test_* — Test keys (same data, separate quota)
curl -X GET "https://app.sahmk.sa/api/v1/quote/2222/" \
-H "X-API-Key: YOUR_API_KEY"Stocks
Get real-time stock quotes and prices for individual or multiple stocks.
GET /quote/{symbol}/
FreeGet current price and trading data for a single stock.
Path Parameters:
symbol— Stock ticker (e.g., 2222 for Aramco)
View Response
{
"symbol": "2222",
"name": "أرامكو السعودية",
"name_en": "Saudi Arabian Oil Co",
"price": 25.86,
"change": 0.18,
"change_percent": 0.7,
"open": 25.6,
"high": 25.86,
"low": 25.6,
"previous_close": 25.68,
"volume": 9803705,
"value": 252308343.0,
"bid": 25.82,
"ask": 25.86,
"liquidity": {
"inflow_value": 184950463.03,
"inflow_volume": 7182468,
"inflow_trades": 7261,
"outflow_value": 67357881.91,
"outflow_volume": 2621237,
"outflow_trades": 5028,
"net_value": 117592581.12
},
"updated_at": "2026-02-10T12:19:22+00:00",
"is_delayed": false
}Liquidity Fields:
inflow_value— Total SAR value of buy ordersoutflow_value— Total SAR value of sell ordersnet_value— Net liquidity (inflow - outflow)
GET /quotes/
Starter+Get quotes for multiple stocks in a single request. Requires Starter plan or higher.
Note: This bulk endpoint requires a Starter plan or higher. Free-tier users can use GET /quote/{symbol}/ for individual stock quotes.
Query Parameters:
symbols— Comma-separated tickers (max 50)
Pro Tip: Use this batch endpoint instead of polling individual /quote/{symbol}/ calls — it's more efficient and counts as a single API request.
View Response
{
"quotes": [
{
"symbol": "2222",
"name": "أرامكو السعودية",
"name_en": "Saudi Arabian Oil Co",
"price": 25.86,
"change": 0.18,
"change_percent": 0.7,
"volume": 9803705,
"net_liquidity": 117592581.12,
"updated_at": "2026-02-10T12:19:22+00:00",
"is_delayed": false
},
{
"symbol": "1120",
"name": "الراجحي",
"name_en": "Al Rajhi Banking & Investment Corp SJSC",
"price": 108.6,
"change": 0.2,
"change_percent": 0.18,
"volume": 4023570,
"net_liquidity": 45230000.50,
"updated_at": "2026-02-10T12:18:56+00:00",
"is_delayed": false
}
],
"count": 2
}net_liquidity — Net money flow (buy value - sell value) in SAR
Market
Get market-wide data including index values, top movers, and sector performance.
GET /market/summary/
FreeGet TASI index value, volume, and market sentiment.
View Response
{
"timestamp": "2026-01-28T12:20:00+00:00",
"index_value": 11458.11,
"index_change": 76.28,
"index_change_percent": 0.67,
"total_volume": 279874553,
"advancing": 117,
"declining": 139,
"unchanged": 14,
"market_mood": "bullish"
}GET /market/gainers/
FreeGet top gaining stocks by percentage change.
Query Parameters:
limit— Number of results (default: 10, max: 50)
View Response
{
"gainers": [
{
"symbol": "4194",
"name": "مجموعة منزل التسويق للتجارة",
"name_en": "Maison Marketing Trade Group",
"price": 59.5,
"change": 4.9,
"change_percent": 8.97,
"volume": 611349,
"updated_at": "2026-01-28T12:19:50+00:00"
}
],
"count": 10
}GET /market/losers/
FreeGet top losing stocks by percentage change.
Query Parameters:
limit— Number of results (default: 10, max: 50)
View Response
{
"losers": [
{
"symbol": "9639",
"name": "شركة أنماط التقنية للتجارة",
"name_en": "Anmat Technology Trading Co",
"price": 8.2,
"change": -0.8,
"change_percent": -8.89,
"volume": 9206,
"updated_at": "2026-01-28T12:10:18+00:00"
}
],
"count": 10
}GET /market/volume/
FreeGet top stocks by trading volume.
Query Parameters:
limit— Number of results (default: 10, max: 50)
View Response
{
"stocks": [
{
"symbol": "2222",
"name": "أرامكو السعودية",
"name_en": "Saudi Arabian Oil Co",
"price": 25.64,
"change": 0.38,
"change_percent": 1.5,
"volume": 15738067,
"updated_at": "2026-01-28T12:19:48+00:00"
}
],
"count": 10
}GET /market/value/
FreeGet top stocks by trading value (SAR).
Query Parameters:
limit— Number of results (default: 10, max: 50)
View Response
{
"stocks": [
{
"symbol": "2222",
"name": "أرامكو السعودية",
"name_en": "Saudi Arabian Oil Co",
"price": 25.64,
"change": 0.38,
"change_percent": 1.5,
"volume": 15738067,
"value": 402108076.72,
"updated_at": "2026-01-28T12:19:48+00:00"
}
],
"count": 10
}GET /market/sectors/
FreeGet sector performance and statistics.
View Response
{
"sectors": [
{
"id": "TBNI",
"name": "Banks",
"change_percent": 0.45,
"avg_change_percent": 0.38,
"volume": 45027873,
"num_stocks": 10
}
],
"count": 20
}Company Info
Get detailed company information including fundamentals, technicals, and valuation data.
GET /company/{symbol}/
FreeGet company information. Response varies by plan.
Data Available by Plan:
- Free: Name, sector, industry, description, website
- Starter: + Full fundamentals (PE, EPS, book value, beta, week/month/52w ranges)
- Pro: + Technicals, valuation, analyst consensus
New: week_high/low, month_high/low — Price levels in last 7/30 days
View Response (Pro)
{
"symbol": "2222",
"name": "أرامكو السعودية",
"name_en": "Saudi Arabian Oil Co",
"current_price": 25.64,
"sector": "Energy",
"industry": "Oil & Gas",
"description": "Saudi Aramco is the world's largest oil producer...",
"website": "https://www.aramco.com",
"country": "Saudi Arabia",
"currency": "SAR",
"fundamentals": {
"market_cap": 6258120000000,
"pe_ratio": 16.77,
"forward_pe": 15.48,
"eps": 1.54,
"book_value": 6.16,
"price_to_book": 4.19,
"beta": 0.104,
"shares_outstanding": 242000000000,
"float_shares": 5969578000,
"week_high": 26.10,
"week_low": 25.40,
"month_high": 27.20,
"month_low": 24.80,
"fifty_two_week_high": 27.85,
"fifty_two_week_low": 23.04
},
"technicals": {
"rsi_14": 55.3,
"macd_line": 0.12,
"macd_signal": 0.08,
"macd_histogram": 0.04,
"fifty_day_average": 26.1,
"technical_strength": 0.65,
"price_direction": "bullish",
"updated_at": "2026-01-28T10:00:00+03:00"
},
"valuation": {
"fair_price": 28.50,
"fair_price_confidence": 0.85,
"calculated_at": "2026-01-28T10:00:00+03:00"
},
"analysts": {
"target_mean": 29.5,
"target_median": 29.0,
"target_high": 35.0,
"target_low": 24.0,
"consensus": "buy",
"consensus_score": 2.1,
"num_analysts": 15
}
}Historical Data
Access historical OHLCV (Open, High, Low, Close, Volume) data for technical analysis and backtesting.
GET /historical/{symbol}/
Starter+Get historical price data for a stock.
Query Parameters:
from— Start date YYYY-MM-DD (default: 30 days ago)to— End date YYYY-MM-DD (default: today)interval— Data interval: 1d, 1w, 1m (default: 1d)
View Response
{
"symbol": "2222",
"interval": "1d",
"from": "2026-01-01",
"to": "2026-01-28",
"count": 20,
"data": [
{
"date": "2026-01-28",
"open": 25.3,
"high": 25.68,
"low": 25.3,
"close": 25.64,
"volume": 15738067,
"adjusted_close": 25.64,
"turnover": 402108076.72
}
]
}Financials
Access financial statements including income statements, balance sheets, and cash flow data.
GET /financials/{symbol}/
Starter+Get financial statements for a company.
View Response
{
"symbol": "2222",
"income_statements": [
{
"report_date": "2025-09-30",
"total_revenue": 418116750000.0,
"gross_profit": 215000000000.0,
"operating_income": 180000000000.0,
"net_income": 105000000000.0
}
],
"balance_sheets": [
{
"report_date": "2025-09-30",
"total_assets": 2516431000000.0,
"total_liabilities": 1026431000000.0,
"stockholders_equity": 1490000000000.0,
"total_debt": 356540000000.0
}
],
"cash_flows": [
{
"report_date": "2025-09-30",
"operating_cash_flow": 135375000000.0,
"investing_cash_flow": -45000000000.0,
"financing_cash_flow": -82337000000.0,
"free_cash_flow": 88500000000.0
}
]
}Dividends
Get dividend history, upcoming distributions, and trailing yield for a stock.
GET /dividends/{symbol}/
Starter+Get dividend history and yield information.
View Response
{
"symbol": "2222",
"current_price": 25.64,
"trailing_12m_yield": 4.2,
"trailing_12m_dividends": 1.60,
"payments_last_year": 4,
"upcoming": [
{
"value": 0.40,
"period": "Q4",
"eligibility_date": "2026-03-15",
"distribution_date": "2026-04-01"
}
],
"history": [
{
"value": 0.40,
"value_percent": 1.5,
"period": "Q3",
"fiscal_year": 2025,
"announcement_date": "2025-09-01",
"eligibility_date": "2025-09-15",
"distribution_date": "2025-10-01"
}
]
}Stock Events
Get AI-generated summaries of significant stock events and news (Arabic only).
GET /events/
Pro+Get stock events with AI-generated analysis.
Query Parameters:
symbol— Filter by stock ticker (optional)limit— Number of results (default: 20)
Note: Event descriptions are in Arabic only. Event types are UPPERCASE (e.g., FINANCIAL_REPORT, DIVIDEND_ANNOUNCEMENT).
View Response
{
"events": [
{
"symbol": "4190",
"stock_name": "جرير للتسويق",
"event_type": "FINANCIAL_REPORT",
"importance": "important",
"sentiment": "positive",
"description": "شركة جرير للتسويق تعلن عن نتائج مالية قياسية للربع الرابع 2025...",
"article_date": "2026-01-29T17:10:06+00:00",
"created_at": "2026-01-29T17:10:12+00:00"
}
],
"count": 1,
"available_types": [
"FINANCIAL_REPORT", "DIVIDEND_ANNOUNCEMENT", "STOCK_SPLIT",
"MERGER_ACQUISITION", "MANAGEMENT_CHANGE", "NEW_LISTING",
"REGULATORY_ACTION", "PARTNERSHIP", "MARKET_EXPANSION",
"RESTRUCTURING", "EARNINGS_SURPRISE", "PRODUCT_LAUNCH", "OTHER"
]
}importance: critical, important, regular
sentiment: very_positive, positive, slightly_positive, neutral, slightly_negative, negative, very_negative
WebSocket Streaming
Real-time stock price streaming via WebSocket, with market updates pushed as soon as they change.
Connection
Pro+WebSocket URL:
wss://app.sahmk.sa/ws/v1/stocks/?api_key=YOUR_API_KEYPro/Enterprise Only: WebSocket streaming requires Pro or Enterprise plan. Updates are delivered during market hours (Sun-Thu, 10:00-15:30 Saudi time). Enterprise connection limits are contract-based.
Subscription Limits
| Plan | Max symbols/connection | Max symbols/call | Subscribe all (*) |
|---|---|---|---|
| Pro | 60 | 20 | ✗ |
| Enterprise | Custom | Custom | ✓ |
Tip: Use multiple connections to track more than 60 symbols on Pro plan.
Client → Server Messages
| Action | Message | Description |
|---|---|---|
| Subscribe | {"action": "subscribe", "symbols": ["2222", "1120"]} | Subscribe to specific stocks |
| Subscribe All | {"action": "subscribe", "symbols": ["*"]} | Subscribe to all stocks (Enterprise only) |
| Unsubscribe | {"action": "unsubscribe", "symbols": ["2222"]} | Stop receiving updates |
| Ping | {"action": "ping"} | Keep-alive |
Server → Client Messages
| Type | Description |
|---|---|
| connected | Connection confirmed with plan info |
| subscribed | Subscription confirmed with symbol list |
| quote | Real-time price update |
| pong | Ping response |
| error | Error message |
View Connected Message Format
{
"type": "connected",
"plan": "pro",
"limits": {
"max_symbols_per_connection": 60,
"max_symbols_per_call": 20
},
"message": "Connected to SAHMK real-time stock stream",
"timestamp": "2026-02-10T10:00:00.000Z"
}View Quote Message Format
{
"type": "quote",
"symbol": "2222",
"timestamp": "2026-02-10T10:30:15.123Z",
"data": {
"price": 25.86,
"open": 25.60,
"high": 25.86,
"low": 25.60,
"close": 25.86,
"change": 0.18,
"change_percent": 0.7,
"previous_close": 25.68,
"volume": 9803705,
"value": 252308343.0,
"bid": 25.82,
"ask": 25.86,
"liquidity": {
"inflow_value": 184950463.03,
"inflow_volume": 7182468,
"outflow_value": 67357881.91,
"outflow_volume": 2621237,
"net_value": 117592581.12
},
"trade_time": "2026-02-10T10:30:12+00:00"
}
}Code Examples
const API_KEY = 'shmk_live_xxxxxxxxxxxxxxxx';
const ws = new WebSocket(`wss://app.sahmk.sa/ws/v1/stocks/?api_key=${API_KEY}`);
ws.onopen = () => {
console.log('Connected');
ws.send(JSON.stringify({
action: 'subscribe',
symbols: ['2222', '1120', '4191']
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'quote') {
console.log(`${msg.symbol}: ${msg.data.price} (${msg.data.change_percent}%)`);
}
};
// Keep-alive ping every 30 seconds
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ action: 'ping' }));
}
}, 30000);View more examples on GitHub →
REST vs WebSocket Comparison
| Metric | REST Polling | WebSocket |
|---|---|---|
| Latency | 1-60+ seconds | <1 second |
| API calls/day | Thousands | 1 connection |
| Missed updates | Possible | None |
| Complexity | Simple | Slightly more |
WebSocket Error Codes
| Code | Meaning |
|---|---|
| 4001 | Invalid or missing API key |
| 4003 | Free plan — upgrade required |
| 4004 | Account inactive or expired |
Webhooks Pro+
Register webhook URLs to receive real-time HTTP POST callbacks when price alert conditions are met during trading hours. Pro plans support up to 3 webhooks; Enterprise limits are custom (contract-based).
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/webhooks/ | List registered webhooks |
POST | /api/v1/webhooks/ | Register a new webhook URL |
DELETE | /api/v1/webhooks/{id}/ | Remove webhook and all its alerts |
POST | /api/v1/webhooks/{id}/verify/ | Retry webhook verification |
Register a Webhook
curl -X POST "https://app.sahmk.sa/api/v1/webhooks/" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/callback",
"name": "My Production Hook"
}'Verification: On creation, SAHMK sends a POST to your URL with { "event": "webhook.verify", "challenge": "..." }. Respond with HTTP 200 to verify. Alerts won't fire until the webhook is verified.
Safety Features
- • HTTPS-only webhook URLs required
- • Webhooks auto-disabled after 3 consecutive delivery failures
- • 3 retry attempts with backoff (2s, 10s, 60s) if delivery fails
- • Duplicate URLs are rejected (409 DUPLICATE)
Price Alerts Pro+
Create price alerts that fire webhook callbacks when conditions are met. Pro plans support up to 10 active alerts; Enterprise limits are custom (contract-based).
Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/alerts/ | List alerts (filter: ?status=active|triggered|all) |
POST | /api/v1/alerts/ | Create a price alert |
DELETE | /api/v1/alerts/{id}/ | Delete an alert |
Create an Alert
curl -X POST "https://app.sahmk.sa/api/v1/alerts/" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"symbol": "2222",
"condition": "price_below",
"value": 28.50,
"webhook_id": 1,
"once": true
}'Alert Conditions
| Condition | Description | Example |
|---|---|---|
| price_above | Fires when stock price goes above the value | value: 30.00 |
| price_below | Fires when stock price goes below the value | value: 28.50 |
| pct_change | Fires when daily % change exceeds ±value | value: 3.0 (means ±3%) |
once parameter: When true, the alert fires once then auto-deactivates. When false, it keeps firing with a 5-minute cooldown between triggers.
Webhook Payload
When an alert triggers, your webhook URL receives a POST request with this payload:
{
"event": "price_alert",
"alert_id": 42,
"symbol": "2222",
"condition": "price_below",
"threshold": 28.5,
"current_price": 28.40,
"pct_change": -1.5,
"volume": 12500000,
"high": 29.8,
"low": 28.2,
"change": -0.45,
"triggered_at": "2026-02-21T12:30:15+03:00"
}Error Responses
403PLAN_LIMITFree/Starter tried to access webhooks, or alert/webhook limit reached.
400VALIDATIONMissing or invalid fields in the request body.
404NOT_FOUNDWebhook or alert doesn't belong to this developer.
409DUPLICATEWebhook URL already registered.
Webhook & Alert Limits
| Plan | Webhooks | Active Alerts |
|---|---|---|
| Free | ✗ | ✗ |
| Starter | ✗ | ✗ |
| Pro | 3 | 10 |
| Enterprise | Custom | Custom |
See Rate Limits for the full plan comparison including API quotas, burst limits, and API keys.
Rate Limits
API access is rate-limited based on your subscription plan. There are two types of limits: daily quotas and per-minute burst limits.
Full Plan Comparison
| Plan | Daily Limit | Burst Limit | API Keys | WebSocket | Webhooks | Alerts |
|---|---|---|---|---|---|---|
| Free | 100/day | 10/min | 1 | ✗ | ✗ | ✗ |
| Starter | 5,000/day | 100/min | 3 | ✗ | ✗ | ✗ |
| Pro | 50,000/day | 500/min | 10 | ✓ | 3 | 10 |
| Enterprise A (Shared) | High-volume (Custom) | Custom | Custom | ✓ | Custom | Custom |
| Enterprise B (Dedicated) | Scales with resources | Scales with resources | Custom | ✓ | Custom | Custom |
Burst Protection: To prevent abuse, all plans have per-minute burst limits. Requests exceeding the burst limit will receive a 429 response. Daily limits reset at midnight (UTC+3). Enterprise limits are contract-based and may be designed as monthly quotas or resource-based.
Rate Limit Headers
Each response includes headers to help track your usage:
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4987
X-RateLimit-Reset: 2026-01-30T00:00:00+03:00Error Codes
The API uses standard HTTP status codes and returns structured JSON error responses.
401INVALID_API_KEYAPI key is missing, invalid, or revoked.
403PLAN_LIMITEndpoint requires a higher plan (e.g., historical data requires Starter+).
404INVALID_SYMBOLStock symbol not found in TASI or Nomu.
429RATE_LIMITDaily quota or per-minute burst limit exceeded.
500SERVER_ERRORInternal server error. Please retry or contact support.
Error Response Format
{
"error": {
"code": "RATE_LIMIT",
"message": "Daily request limit exceeded. Resets at midnight UTC+3."
}
}Market Data Usage
Sahmk market data may be used within your applications, tools, or products.
Developer plans are intended for development, internal tools, and small-scale applications.
Large-scale public market data platforms, commercial display services, or data redistribution may require an enterprise agreement.
Reselling market data or providing it as a standalone API or data feed is not permitted without a separate agreement with Sahmk.
Need More Help?
Check the machine-readable docs at /api-docs.md, browse examples on GitHub, or contact our team.