Organised Smallholders (OSH)

Overview
| Property |
Value |
| Endpoint |
GET https://api.mspots.org.my/api/osh/all-smallholder |
| Portal URL |
https://emspo.org.my/public/osh |
| Total Records |
~47,500 |
| Update Frequency |
Daily |
| Authentication |
None (public) |
Parameters
| Parameter |
Type |
Required |
Default |
Description |
state |
integer |
No |
- |
Filter by state ID (ignored - returns all) |
page |
integer |
No |
1 |
Page number (ignored - returns all) |
pageSize |
integer |
No |
10 |
Records per page (ignored - returns all) |
Note: Like other public endpoints, this returns ALL records (~47.5k) in a single response regardless of parameters.
Response Structure
Important: OSH uses .data.data instead of .data.results like other endpoints.
{
"data": {
"page_size": 10,
"data": [
{
"entity_smallholder_id": 474748,
"entity_code": "ORS15721",
"entity_name": "FELDA LOK HENG BARAT",
"mpob_no": null,
"planted_area": "3.9520",
"certified_area": "3.9520",
"gps_coordinate_lat": "1.70941",
"gps_coordinate_long": "104.08802",
"name": "A.LATIF BIN BENU",
"stateId": 1,
"state": "Johor",
"daerahId": 4,
"daerah": "KOTA TINGGI",
"lot_no": "5722",
"cert_status": "EXPIRED",
"cert_no": "MYMS12195673",
"created_at": "2025-10-29T03:15:10.612Z",
"updated_at": "2024-07-24T01:17:06.101Z",
"track_id": "MTS0000014"
}
]
}
}
Response Fields
| Field |
Type |
Description |
entity_smallholder_id |
integer |
Unique smallholder plot ID |
entity_code |
string |
Entity code (e.g., "ORS15721") |
entity_name |
string |
Organisation/scheme name (FELDA, FELCRA, etc) |
mpob_no |
string/null |
MPOB registration number (often null for OSH) |
planted_area |
string |
Total planted area in hectares |
certified_area |
string |
MSPO certified area in hectares |
gps_coordinate_lat |
string |
GPS latitude |
gps_coordinate_long |
string |
GPS longitude |
name |
string |
Smallholder name |
stateId |
integer |
Malaysian state ID |
state |
string |
Malaysian state name |
daerahId |
integer/null |
District ID |
daerah |
string/null |
District name |
lot_no |
string |
Land lot number |
cert_status |
string |
Certification status (ACTIVE/EXPIRED/DELAYED) |
cert_no |
string |
MSPO certificate number |
created_at |
string |
Record creation timestamp (ISO 8601) |
updated_at |
string |
Last update timestamp (ISO 8601) |
track_id |
string |
Tracking ID |
Key Differences from Other Smallholder Endpoints
| Aspect |
SPOC (Independent) |
Group Manager |
OSH (Organised) |
| Records |
~306k |
~2.3k |
~47.5k |
| Identifier |
spoc_code |
gm_code |
entity_code |
| Management |
SPOC clusters |
Private companies |
FELDA/FELCRA/etc |
| Response Key |
.data.results |
.data.results |
.data.data |
Has mpob_no |
Yes |
Yes |
Often null |
Organisation Types (entity_name)
Common organisations managing OSH smallholders:
| Organisation |
Description |
| FELDA |
Federal Land Development Authority |
| FELCRA |
Federal Land Consolidation and Rehabilitation Authority |
| RISDA |
Rubber Industry Smallholders Development Authority |
| KESEDAR |
South Kelantan Development Authority |
| KEJORA |
Johor Regional Development Authority |
| KETENGAH |
Terengganu Tengah Development Authority |
| KEDA |
Kedah Regional Development Authority |
GCS Storage
gs://calee_data/raw/mspo/api/smallholders/osh/all-smallholder/
└── YYYYMMDD/
└── all-smallholder.parquet # ~2-3MB compressed (zstd)
Example Code
Python
import requests
import polars as pl
def fetch_osh_smallholders():
"""Fetch all Organised Smallholders."""
url = "https://api.mspots.org.my/api/osh/all-smallholder"
response = requests.get(url, params={"page": 1, "pageSize": 10}, verify=False)
response.raise_for_status()
# Note: OSH uses .data.data instead of .data.results
results = response.json()["data"]["data"]
print(f"Fetched {len(results):,} records")
return results
# Fetch and analyze
records = fetch_osh_smallholders()
df = pl.DataFrame(records, infer_schema_length=10000)
# Summary by organisation
print(df.group_by("entity_name").agg([
pl.count().alias("smallholders"),
pl.col("certified_area").cast(pl.Float64).sum().alias("total_ha")
]).sort("total_ha", descending=True).head(10))
DuckDB Query
-- Query Organised Smallholders by scheme
SELECT
entity_name as organisation,
state,
COUNT(*) as smallholders,
SUM(CAST(certified_area AS DOUBLE)) as total_ha
FROM read_parquet('gs://calee_data/raw/mspo/api/smallholders/osh/all-smallholder/*/*.parquet')
GROUP BY entity_name, state
ORDER BY total_ha DESC;
Data Quality Notes
- MPOB number often null: Unlike SPOC/GM, OSH records frequently have null
mpob_no
- Entity code format: Prefix "ORS" followed by numbers (e.g., "ORS15721")
- Response key difference: Uses
.data.data instead of .data.results
- Scheme-managed: All entries are managed by government-linked organisations