Быстрый старт
Эта страница проведёт вас от API-ключа до статистики NDVI по реальному полю. Понадобятся ключ и терминал с curl, Python 3 с библиотекой requests или Node.js 18 и новее.
-
Сохраните ключ в переменной окружения.
Не держите ключ в коде и в системе контроля версий.
export AGROSAT_API_KEY="ags_..." -
Проверьте, что ключ работает.
GET /v1/pingвозвращает организацию, которой принадлежит ключ. Юниты не расходуются.curl https://api.agrosat.uz/v1/ping \-H "X-API-Key: $AGROSAT_API_KEY"import osimport requestsAPI = "https://api.agrosat.uz/v1"session = requests.Session()session.headers["X-API-Key"] = os.environ["AGROSAT_API_KEY"]r = session.get(f"{API}/ping", timeout=30)print(r.status_code, r.json())// Node.js 18+, файл quickstart.mjsconst API = "https://api.agrosat.uz/v1";const headers = { "X-API-Key": process.env.AGROSAT_API_KEY };const res = await fetch(`${API}/ping`, { headers });console.log(res.status, await res.json());Действующий ключ получает ответ
200:{ "success": true, "data": { "organization_id": "cmf1q2w3e0000ab12cd34ef56" } }Ответ
401 invalid_api_keyозначает, что ключ не передан, введён с ошибкой, отозван или истёк. -
Зарегистрируйте поле.
Передайте границу как GeoJSON
PolygonилиMultiPolygonв WGS84 и свой идентификатор вexternal_id. В примере поле площадью 41 га в Сырдарьинской области.curl https://api.agrosat.uz/v1/fields \-H "X-API-Key: $AGROSAT_API_KEY" \-H "Content-Type: application/json" \-d '{"name": "Северный участок 3","external_id": "f-1001","geometry": {"type": "Polygon","coordinates": [[[68.552, 40.3084], [68.560, 40.3084], [68.560, 40.3139], [68.552, 40.3139], [68.552, 40.3084]]]}}'field = {"name": "Северный участок 3","external_id": "f-1001","geometry": {"type": "Polygon","coordinates": [[[68.552, 40.3084], [68.560, 40.3084], [68.560, 40.3139],[68.552, 40.3139], [68.552, 40.3084]]],},}r = session.post(f"{API}/fields", json=field, timeout=30)field_id = r.json()["data"]["id"]print(r.status_code, field_id)const field = {name: "Северный участок 3",external_id: "f-1001",geometry: {type: "Polygon",coordinates: [[[68.552, 40.3084], [68.560, 40.3084], [68.560, 40.3139], [68.552, 40.3139], [68.552, 40.3084]]],},};const created = await fetch(`${API}/fields`, {method: "POST",headers: { ...headers, "Content-Type": "application/json" },body: JSON.stringify(field),});const fieldId = (await created.json()).data.id;console.log(created.status, fieldId);В ответ придёт
201и новое поле. Пока AgroSat готовит снимки и статистику, егоstatusравенpending:{"success": true,"data": {"id": "cmgz7k2qv0004l8p3a9d1x6rt","external_id": "f-1001","name": "Северный участок 3","area_ha": 41.53,"status": "pending","created_at": "2026-04-28T09:14:03.512Z"}}Повторять запрос безопасно: тот же
external_idс той же геометрией вернёт уже существующее поле с кодом200. -
Запросите статистику NDVI.
Окно может быть длиной до 366 дней. Пока поле в статусе
pending, API отвечает202с заголовкомRetry-After: подождите указанное число секунд и повторите запрос. Ответ202ничего не стоит.curl -i "https://api.agrosat.uz/v1/fields/cmgz7k2qv0004l8p3a9d1x6rt/statistics?index=ndvi&from=2026-05-01&to=2026-05-31" \-H "X-API-Key: $AGROSAT_API_KEY"import timeparams = {"index": "ndvi", "from": "2026-05-01", "to": "2026-05-31"}while True:r = session.get(f"{API}/fields/{field_id}/statistics", params=params, timeout=60)if r.status_code != 202:breaktime.sleep(int(r.headers.get("Retry-After", "30")))body = r.json()if not body["success"]:raise RuntimeError(body["error"])print("израсходовано юнитов:", r.headers["X-AgroSat-Units"])for row in body["data"]["data"]:print(row["date"], row["mean"], row["valid_fraction"])const url = new URL(`${API}/fields/${fieldId}/statistics`);url.search = new URLSearchParams({ index: "ndvi", from: "2026-05-01", to: "2026-05-31" });let res = await fetch(url, { headers });while (res.status === 202) {const wait = Number(res.headers.get("Retry-After") ?? 30);await new Promise((resolve) => setTimeout(resolve, wait * 1000));res = await fetch(url, { headers });}const body = await res.json();if (!body.success) throw new Error(`${body.error.code}: ${body.error.message}`);console.log("израсходовано юнитов:", res.headers.get("X-AgroSat-Units"));for (const row of body.data.data) console.log(row.date, row.mean, row.valid_fraction);Когда данные готовы, вы получаете по строке на каждую дату со снимком, от старых к новым:
{"success": true,"data": {"field_id": "cmgz7k2qv0004l8p3a9d1x6rt","index": "ndvi","data": [{"date": "2026-05-04","mean": 0.5871, "median": 0.6012, "min": 0.1544, "max": 0.7785,"std": 0.0962, "p10": 0.4518, "p90": 0.6973,"valid_fraction": 0.9934, "cloud_fraction": 0.0066, "cloud_mask": "scl_cld"},{"date": "2026-05-09","mean": null, "median": null, "min": null, "max": null,"std": null, "p10": null, "p90": null,"valid_fraction": 0, "cloud_fraction": 1, "cloud_mask": "scl_cld"},{"date": "2026-05-14","mean": 0.6124, "median": 0.6347, "min": 0.1812, "max": 0.8021,"std": 0.0938, "p10": 0.4783, "p90": 0.7214,"valid_fraction": 0.9871, "cloud_fraction": 0.0129, "cloud_mask": "scl_cld"}],"unavailable_dates": []}}9 мая поле было полностью закрыто облаками, поэтому значения равны
null. Этот ответ стоилceil(41,53 × 3 / 10) = 13юнитов; число приходит вX-AgroSat-Units.
