ProPlanta Recommendation API

A single HTTPS endpoint that turns plot & soil data into a fertilizer recommendation. This guide covers everything you need to integrate.

Overview

You send one or more plots (soil analysis, crop, history) in a JSON request; the service runs the agronomic model and returns a recommendation report for each plot. You authenticate with a token we issue to you — there is no sign-up or login flow on your side.

The integration is a single call:

Authentication

Every request must include the token we provide, sent verbatim in the Authorization header. Do not add a Bearer prefix.

Authorization: eyJhbGciOiJIUzI1NiIs...your-token...
Tokens are time-limited. When a token expires (or is missing/invalid) the API responds with 403 Forbidden. Request a fresh token from us and retry — see Errors & retries. Keep your token secret; treat it like a password.

The endpoint

POST https://company.proplanta.atk.hu/pp
HeaderValue
AuthorizationYour token (required)
Content-Typeapplication/json

Request body

The body has two parts: userinfo (the grower/client this recommendation is for) and plotinfo (an array — one object per plot). You may submit several plots in a single request; each is processed independently.

{
  "userinfo": {
    "username": "Példa Gazda Kft.",
    "regid":    "1002456789",
    "address":  "7400 Kaposvár, Fő utca 1.",
    "phone":    "+36 30 123 4567",
    "email":    "iroda@pelda-gazda.hu"
  },
  "plotinfo": [
    {
      "plotname":      "Kaszásmajor",
      "mepar":         "ABCD1-K-12",
      "area":          12.4,
      "soil":          1,
      "samplingdate":  "2024-09-23",
      "humus":         3.1,
      "phkcl":         7.2,
      "alp2o5":        120,
      "alk2o":         145,
      "harvestyear":   2025,
      "plant":         "kukorica",
      "plantid":       1111,
      "planttype":     1,
      "plannedyield":  7.3
    }
  ]
}
Missing fields are filled with defaults. Only send what you have; any field you omit is replaced server-side with a sensible default. For a real recommendation, provide as much soil/crop data as possible.

Client fields (userinfo)

FieldTypeDescription
usernamestringGrower / client name
regidstringRegistration number
addressstringPostal address
phonestringContact phone
emailstringContact email

Plot fields (each item in plotinfo)

Grouped by topic. Types: string, number (decimals allowed), integer (whole numbers / codes).

Plot identity

FieldTypeDescription
plotnamestringPlot name
meparstringMePAR block identifier
serialnr1, serialnr2stringPlot serial numbers
areanumberPlot area
soilintegerSoil type code
no3sensitiveintegerNitrate-sensitive flag (0/1)
akgidintegerAgri-environment scheme id

Soil sample results

FieldTypeDescription
samplingdatestringSampling date (YYYY-MM-DD)
bondindexnumberSoil bond (plasticity) index
humusnumberHumus content (%)
alp2o5numberAL-soluble P₂O₅
alk2onumberAL-soluble K₂O
caco3numberCalcium carbonate content
phkclnumberpH (KCl)
mgkclnumberKCl-soluble Mg (-1 if unknown)
edtazn, edtacu, edtamnnumberEDTA-soluble Zn / Cu / Mn (-1 if unknown)

Crop & production

FieldTypeDescription
harvestyearintegerHarvest year
harvestseasonintegerHarvest season code
plantstringCrop name
plantidintegerCrop id
planttypeintegerCrop type code
plannedyieldnumberPlanned yield
plannedyears, actualyear, plantingyearintegerPerennial planning / planting years

Leaf analysis & orchard/vineyard (perennials)

FieldTypeDescription
leafn, leafp, leafknumberLeaf N / P / K content
treegridstringPlanting grid (e.g. 4x5)
trunkdiameternumberTrunk diameter
grasscoverintegerGrass cover flag (0/1)

Pre-crop

FieldTypeDescription
precropstringPre-crop name
precropidintegerPre-crop id
harvestbefore0915integerHarvested before 15 Sep (0/1)
yieldnumberPre-crop yield
byproductnumberBy-product amount
fateofbyproductintegerBy-product fate code
legumepreprecropstringLegume in the crop before the pre-crop
legumepreprecropidinteger…its id

Nutrients applied this year

FieldTypeDescription
nthisyear, pthisyear, kthisyearnumberN / P / K already applied this year

Organic matter & amendment history

FieldTypeDescription
fym1year … fym4yearintegerFarmyard-manure application year (up to 4 entries)
fym1type … fym4typestringManure type (e.g. cattle)
fym1id … fym4idintegerManure type id
fym1amount … fym4amountnumberAmount applied
lm1year, lm2yearintegerOther organic material application year (up to 2)
lm1type, lm2typestringMaterial type
lm1id, lm2idintegerMaterial type id
lm1amount, lm2amountnumberAmount applied
greenmstringGreen manure
greenmamountnumberGreen-manure amount
znfertyearintegerZinc fertilizer year
znfertamountnumberZinc fertilizer amount
limeyearintegerLiming year
limeamountnumberLime amount
Units & code lists. Numeric units (areas, amounts, yields) and the coded fields (soil, harvestseason, plantid, planttype, fym*id, …) follow ProPlanta conventions. Ask us for the current code tables and unit reference so your values map correctly.

Success response

200 OK — the body is a plain-text report (not JSON), with one section per plot, in the order you sent them. Content type is text/plain.

Per-plot failures are inline. Because results are streamed as they are computed, the HTTP status is always 200 once processing starts. If a single plot fails, that plot's section contains a line beginning error: recommendation failed: … instead of a result — the other plots are unaffected. Always scan each section for that marker.

Ask us for a sample report for your crop set so you can build your parser against the exact output layout.

Status codes

StatusMeaningWhat to do
200Processed. Body holds the report(s) — check each section for an error: line.Parse the body.
400Request body is not valid JSON.Fix the payload; do not retry unchanged.
403Token missing, invalid, or expired.Obtain a new token, then retry.
404Wrong path or method (only POST /pp is supported).Check URL/method.
500Server-side error.Retry with backoff; contact us if it persists.

Errors & retries

Example — cURL

curl -X POST https://company.proplanta.atk.hu/pp \
  -H "Authorization: $PROPLANTA_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @request.json

Example — Python

import requests

resp = requests.post(
    "https://company.proplanta.atk.hu/pp",
    headers={"Authorization": TOKEN, "Content-Type": "application/json"},
    json={
        "userinfo": {"username": "Példa Gazda Kft.", "regid": "1002456789"},
        "plotinfo": [{
            "plotname": "Kaszásmajor", "area": 12.4, "soil": 1,
            "humus": 3.1, "phkcl": 7.2, "alp2o5": 120, "alk2o": 145,
            "harvestyear": 2025, "plant": "kukorica", "plantid": 1111,
            "planttype": 1, "plannedyield": 7.3,
        }],
    },
    timeout=60,
)

if resp.status_code == 403:
    raise SystemExit("Token expired or invalid — request a new one.")
resp.raise_for_status()          # raises on 400/404/500
report = resp.text               # plain-text report, one section per plot
if "error: recommendation failed" in report:
    print("Warning: at least one plot failed — inspect the report.")
print(report)

Example — Node.js

const res = await fetch("https://company.proplanta.atk.hu/pp", {
  method: "POST",
  headers: { "Authorization": process.env.PROPLANTA_TOKEN,
             "Content-Type": "application/json" },
  body: JSON.stringify({
    userinfo: { username: "Példa Gazda Kft.", regid: "1002456789" },
    plotinfo: [{
      plotname: "Kaszásmajor", area: 12.4, soil: 1,
      humus: 3.1, phkcl: 7.2, alp2o5: 120, alk2o: 145,
      harvestyear: 2025, plant: "kukorica", plantid: 1111,
      planttype: 1, plannedyield: 7.3,
    }],
  }),
});

if (res.status === 403) throw new Error("Token expired or invalid.");
if (!res.ok) throw new Error(`Request failed: ${res.status}`);
const report = await res.text();   // plain-text report
console.log(report);