To access the NIAB-CUF Potato Yield API, register by contacting us at pym@niab.com.
The NIAB-CUF Potato Yield API uses Bearer Authentication. Bearer authentication (also called token authentication) is an HTTP authentication scheme that involves security tokens called bearer tokens. The user must send this token in the Authorization header when making requests to protected resources:
Authorization: Bearer <token>
To try some API calls described below, download the Postman Collection here.
The NIAB Variety API is an additional API service developed by NIAB in order to store and deliver variety specific crop parameters to a number of models under development.
Note: this API does not require a token to access the basic list of varieties.
To access a list of accepted varieties available for use in the NIAB-CUF Potato Yield API, send a HTTP GET
requests to:
https://variety.niabdev.co.uk/api/variety/potato/pym
This will return a JSON document with a list of varieties and a link to use in model input (See section Constructing your own input).
[
{
"variety":"aba",
"embeddableLink":"https://variety.niabdev.co.uk/api/variety/potato/pym/dbb35eb6-0263-4687-8bb3-c599be370907"
},
{ "variety":"abbot",
"embeddableLink":"https://variety.niabdev.co.uk/api/variety/potato/pym/5735c523-d700-4352-9876-e736f3ac6a0f"
},
{ "variety":"abby",
"embeddableLink":"https://variety.niabdev.co.uk/api/variety/potato/pym/b0c0407a-4946-47bd-bef4-37a35ad737f5"
},
...
]
Note: Some varieties may be subject to quality control measures during the model run.
To submit input to and execute the NIAB-CUF Potato Yield Model, the following endpoint of the GMS is used:
https://prod.niab.com/gms/api/v1/models/pym/jobs?persist=true&webhook=https://www.niab.com
There are 2 parameters to supply with this call: webhook
and persist
.
webhook
is optional and can be set to a URL that will recieve a POST
request with the response once the model run has completed.
persist
is optional and can be set to true or false to allow or prevent the results to persist on the GMS. Set this to true for this example.
Note: if webhook
is empty, persist
must be set to true
Using the Postman Collection navigate to the createJob
request.
If not already completed, fill out your API token in the Authorzation
header. Ensure the Content-Type
header is set to application/json
.
The main input to the model is a structured JSON document inserted in the body of the API call. In this example, a copy the example is already in the request body of the Postman Collection.
When ready, press the send button to make the API call.
If successful you should receive a 202 Accepted
status.
The important information in the response is contained in the Location
header.
Location /models/pym/jobs/4RXMJedaPpcz53/status
The string 4RXMJedaPpcz53
represents the unique identifier of the model job and the URL /models/pym/jobs/4RXMJedaPpcz53/status
is a link to check the status of the job.
Your location string will be different to the example above. Use your location in the following API calls.
To check the status of a job the following endpoint is used:
https://prod.niab.com/gms/api/v1/models/pym/jobs/{{jobId}}/status
Using the Postman Collection, navigate to the getJobStatus
request.
Set jobId
to the unique location string in the previous call (in our case 4RXMJedaPpcz53
).
If not already completed, fill out your API token in the Authorzation
header. Ensure the Content-Type
header is set to application/json
.
When ready, press the send button to make the API call.
If successful you should receive a 200 OK
status and the following response:
{
"_links": {
"parent": {
"href": "/models/pym/jobs/oS7Sv7LPmbB1cB1kcaL1YJ"
},
"self": {
"href": "/models/pym/jobs/oS7Sv7LPmbB1cB1kcaL1YJ/status"
}
},
"status": "published"
}
There are 4 possible kinds of status returned: published
, failed
, requiresQC
and submitted
.
To get the results of a job use the following endpoint:
https://prod.niab.com/gms/api/v1/models/results/pym/{{jobId}}
You will only be able to get results from jobs that are in the published
state.
Using the Postman Collection, navigate to the getResults
request.
Set jobId
to the unique location string in the previous call (in our case 4RXMJedaPpcz53
).
If not already completed, fill out your API token in the Authorzation
header. Ensure the Content-Type
header is set to application/json
.
When ready, press the send button to make the API call.
If successful you should receive a 200 OK
status and the following response (truncated):
{
"validationErrors": [
"Date planted is not within 6 months past and now",
"Interval between surveys should be at most 1 week",
"A survey should exist that is within one week of the model run date",
"Some model parameters are not within expected bounds. You may wish to have this job QC'd"
],
"cropId": "0aef8c2c-3197-11e7-8ac8-f23c9118e215",
"about": {
"credit": {
"text": "Modelled by NIAB-CUF",
"url": "http://www.niab.com",
"imageUrl": "http://pym.niabdev.co.uk/niabcuf_logo.png",
"imageCaption": "NIAB-CUF Potato Yield Model"
},
"terms": {
"termsUrl": "http://pym.niabdev.co.uk/terms/",
"technicalUrl": "http://pym.niabdev.co.uk/technical/",
"apiUrl": "http://pym.niabdev.co.uk/api/"
},
"version": "1.24"
},
"modelPredictionData":[...]
}
As you gather more data about your potato crop (e.g. more canopy data or a new sample dig), this can be added as a new run for the same job. This helps to keep your data organised.
To submit a new run for an existing job, using the Postman Collection, navigate to the runExistingJob
endpoint.
Follow the instructions for sumbitting a new job (see above). You will also need to add the existing jobId (e.g. 4RXMJedaPpcz53
) in the to the endpoint.
https://prod.niab.com/gms/api/v1/models/pym/jobs/{{jobId}}
Note: when resubmitting a job, the original webhook
will be used if supplied.
When ready, press the send button to make the API call.
If successful you should receive a 202 Accepted
status and the same response as the createJob
endpoint.
When requesting the results of a job with multiple runs, only the most recent run will be returned.
The structure of the JSON input object is defined by the JSON Schema found here.
It is strongly recommended to use a validation tool to validate constructed model inputs before submitting to the model.
Examples of full and partial model inputs can be found below:
An example of a client output can be found below:
The JSON Schema definitions for input and output can be found below:
The NIAB GMS requires the JSON input to have a top level data
object. Below this is the modelInput
object which in turn has 4 parameters:
{"data": {
"modelInput": {
"modelMetadata": {...},
"crop": {...},
"survey": [...],
"sample": [...],
"nitrogenSampleReplicates": [...]
}
}
}
The ‘modelMetadata’ object contains information to control the model run. It is required and the model execution will apply defaults if sub-objects are absent.
The modelMetadata
object has 4 parameters:
"modelMetadata": {
"bypassManualQC": true,
"modelDate": "2018-10-10",
"contact": {...},
"gradingParameters": {...}
}
bypassManualQC
- true/false - optional - bypasses manual quality controlmodelDate
- date - optional - allows the model to be run at a specific date, ignoring data supplied after this datecontact
- object - required - an object containing contact details for supportgradingParameters
- object - optional - customises the grade sizes of the outputgradingParameters
contains 2 parameters:
"gradingParameters": {
"gradeSizeUnit": "mm",
"grades": [0,10,20,30,40,50,60,70,80,90,100]
}
gradeSizeUnit
- string - required - the units of the grade sizes, Note: only millimetres (“mm”) are currently supportedgrades
- list of numbers - required - represents the grade size categories of the output, e.g. [0,25,50] -> [0-25], [25-50]The contact
object contains the following parameters:
"contact": {
"email": "user@email.com"
}
email
- string - required - the email address of the user’s main contactThe crop
object contains information regarding the particular potato crop to be modelled.
The crop
object contains the following parameters:
"crop": {
"dateEmergence": "2017-05-03",
"description": "Seed crop",
"variety": "https://variety.niabdev.co.uk/api/variety/potato/pym/fb70f9b0-aaee-4948-ba79-85602215f955",
"dateHarvest": "2018-09-10",
"dateDefoliation": "2018-08-14",
"datePlanted": "2017-03-31",
"id": "0aef8c2c-3197-11e7-8ac8-f23c9118e215",
"name": "PLOT-2016-17-0273",
"org": "a59346f3-93ca-40af-af02-d7612d0d8706",
"location": {...}
}
dateEmergence
- date - required - the date on which 50% of plants have emergeddescription
- string - optional - a generic description of the cropvariety
- string - required - URL to embedded link from the NIAB Variety APIdateHarvest
- date - optional - the date of final harvestdateDefoliation
- date - optional - the date on which the crop was defoliateddatePlanted
- date - required - the date on which the crop was plantedid
- string - required - a user generated UUID for the cropname
- string - required - a name for the croporg
- string - required - a user generated UUID for the end userlocation
- required - an object containing the location of the cropThe location
object contains geographic information about the crop.
The location
object contains the following parameters:
"location": {
"latitude": 51.123,
"longitude": 1.0234
}
latitude
- number - required - the decimal representation of latitudelongitude
- number - required - the decimal representation of longitudeThe survey
list contains all data points relating to the growth and senescence of the potato canopy.
survey
is a list of objects containing the following parameters:
"survey": [
{
"surveyDate": "2017-05-09",
"groundcover": 1.0
},
{
"surveyDate": "2017-05-09",
"groundcover": 2.0
}
]
surveyDate
- date - required - the date of the ground cover observationgroundcover
- number - required - the percentatge of ground covered by living foliageThe sample
list contains all data points relating to the sample yield digs performed on a crop.
sample
is a list of objects containing the following parameters:
"sample": [
{
"rowLength": 2.0,
"numberRows": 1.0,
"rowUnit": "cm",
"sampleDate": "2017-10-07",
"rowLengthUnit": "m",
"rowWidth": 91.44,
"weightUnit": "g",
"sampleReplicates": [...]
},
{
"rowLength": 2.0,
"numberRows": 1.0,
"rowUnit": "cm",
"sampleDate": "2017-06-23",
"rowLengthUnit": "m",
"rowWidth": 91.44,
"weightUnit": "g",
"sampleReplicates": [...]
}
]
weightUnit
- string - required - the units used to measure the weight of the yield dig samplerowLength
- number - required - the length of the sampled areanumberRows
- integer - required - the number of rows of potatoes in the sample arearowUnit
- string - required - the units used to measure the distance between rowssampleDate
- date - required - the date of the sample digrowLengthUnit
- string - required - the units used to measure the length of the sampled areasampleReplicates
- list - required - a list of objects containing yield sample informationThe sampleReplicates
list contains the following parameters:
"sampleReplicates": [
{
"plantsHarvested": 6.0,
"mainStems": 21.0,
"gradeValues": [...],
"secondaryStems": 15,
"dryMatterPercent": 30.0
},
{
"plantsHarvested": 6.0,
"mainStems": 21.0,
"gradeValues": [...],
"secondaryStems": 15,
"dryMatterPercent": 30.0
}
]
plantsHarvested
- integer - required - the number of plants in the sampled areamainStems
- integer - required - the total number of main stems in the sampled areasecondaryStems
- integer - optional - the total number of secondary stems in the sampled areadryMatterPercent
- number - optional - the percentage dry matter of the tuber samplegradeValues
- list - a list of objects containing graded yield sample informationThe gradeValues
object contains the following parameters:
"gradeValues": [
{
"tuberNumber": 0,
"gradeSize": {...},
"weight": 0.0
},
{
"tuberNumber": 0,
"gradeSize": {...},
"weight": 0.0
},
]
tuberNumber
- integer - required - the number of tubers counted in the size fractionweight
- number - required - the total weight of the tubers in the size fractiongradeSize
- object - required - a object containing the size parameters of the gradeThe gradeSize
object contains the following parameters:
"gradeSize": {
"lowerBound": 0.0,
"upperBound": 15.0
}
lowerBound
- number - required - the lower end of the size gradeupperBound
- number - required - the upper end of the size gradeNote: The upper bound of the final grade size should not try to accommodate a large size band into a single grade fraction.
The nitrogenSampleReplicates
list contains all data points relating to the nitrogen sampling performed on a crop.
nitrogenSampleReplicates
is a list of objects containing the following parameters:
[
{
"replicateNo": 1,
"sampleDate": "2017-07-07",
"numberOfStems": 4,
"totalNUnits": "m",
"totalVineFwYieldWeight": 2.5,
"subSampleFwReplicate": 2.5,
"subSampleDwReplicate": 2.5,
"tuberNContentReplicate": 2.5,
"tuberNConcentrationReplicate": 2.5
},
{
"replicateNo": 2,
"sampleDate": "2017-07-07",
"numberOfStems": 4,
"totalNUnits": "m",
"totalVineFwYieldWeight": 2.5,
"subSampleFwReplicate": 2.5,
"subSampleDwReplicate": 2.5,
"tuberNContentReplicate": 2.5,
"tuberNConcentrationReplicate": 2.5
},
{
"replicateNo": 3,
"sampleDate": "2017-07-07",
"numberOfStems": 4,
"totalNUnits": "m",
"totalVineFwYieldWeight": 2.5,
"subSampleFwReplicate": 2.5,
"subSampleDwReplicate": 2.5,
"tuberNContentReplicate": 2.5,
"tuberNConcentrationReplicate": 2.5
}
]
replicateNo
- integer - the replicate numbersampleDate
- date - the date of the samplenumberOfStems
- integer - the number of stems in the sample replicatetotalNUnits
- string - the units of NtotalVineFwYieldWeight
- number - the total fresh weight of the samplesubSampleFwReplicate
- number - the fresh weight of the sub-samplesubSampleDwReplicate
- number - the dry weight of the sub-sampletuberNContentReplicate
- number - the tuber N content of the sampletuberNConcentrationReplicate
- number - the tuber N concentration of the sampleThe output of the PYM contains 4 top level objects:
{
"cropId": "0aef8c2c-3197-11e7-8ac8-f23c9118e215",
"about": {...},
"validationErrors": {...},
"nitrogenModel": {...},
"modelPredictionData": {...}
}
cropId
- string - the UUID of the cropabout
- object - information and links to T&CsvalidationErrors
- list - a list of error and warningsmodelPredictionData
- list - a list of yield/ground cover objectsnitrogenModel
- object - an object containing nitrogen outputThis cropId
is the user generated UUID submitted with the model input.
The about
object contains information relating to terms and conditions:
{
"terms": {
"termsUrl": "https://niabdev.co.uk/pym/terms",
"apiUrl": "https://niabdev.co.uk/pym/api",
"technicalUrl": "https://niabdev.co.uk/pym/technical"
},
"credit": {
"imageCaption": "NIAB-CUF Potato Yield Model",
"imageUrl": "https://niabdev.co.uk/pym/pym_logo.png",
"text": "Modelled by NIAB-CUF",
"url": "http://www.niab.com"
},
"version": "1.18"
}
termsUrl
- URL - the URL of the terms and conditions of the PYMapiUrl
- URL - the URL of the terms and conditions of the APItechnical
- URL - the URL of technical information about the PYMimageCaption
- string - caption text for imagesimageUrl
- string - URL to image to display with resultstext
- string - text descriptionurl
- URL - link back to www.niab.comSome inputs may trigger validity warnings which are provided in the validationErrors
list:
"validationErrors": [
"Date planted is not within 6 months past and now",
"Interval between surveys should be at most 1 week",
"A survey should exist that is within one week of the model run date"
]
validationErrors
- list - a list of error message stringsnitrogenModel
is an object which contains:
{
"variates":[
{
"sampleDate": "2017-06-23",
"meanTotalNUptake": 69.1511111
},
{
"sampleDate": "2017-08-15",
"meanTotalNUptake": 88.0
}
],
"seasonLongPotentialRadiationAbsorption" : 6.319489800033206,
"radiationAbsorptionAchievedDate" : "2017-06-25"
}
variates
- list - a listsampleDate
- string - the date of the sample, YYYY-MM-DDmeanTotalNUptake
- number - average total N uptakeseasonLongPotentialRadiationAbsorption
- number - potential radiation absorptionradiationAbsorptionAchievedDate
- number - date of achieved radiation absorptionmodelPredictionData
is a list of yield/ground cover objects:
[
{...},
{...},
{...},
...
]
The yield/ground cover object contains the observed and forecasted yield and canopy data:
{
"date": "2017-10-06",
"radiation": 12.07,
"ltaRadiation": 7.603714285714285,
"gcLower": 96.9102448357476,
"gcUpper": 100.0,
"gcMean": 98.9102448357476,
"gcModelled": 0.00010777474372503093,
"gcCombined": 98.9102448357476,
"tuberPartitionPredictionData": [...],
"fwYieldMean": 43.64274499419973
}
date
- string - the date of the time series data (YYYY-MM-DD)raditation
- number - the total solar radiation receipt for the dateltaRadiation
- number - the long term average solar radiation for the datetuberPartitionPredictionData
- list - a list of yields by grade size objectsgcLower
- number - the minimum ground cover observation for the date (absent after last observation)gcUpper
- number - the maximum ground cover observation for the date (absent after last observation)gcMean
- number - the mean observed ground cover (absent after last observation)gcModelled
- number - the predicted ground cover value for the dategcCombined
- number - a mix of observed (for dates before last observation) and predicted ground cover (for dates after)fwYieldMean
- number - the fresh weight yield prediction (t/ha) for the datetuberPartitionPredictionData
is a list of objects:
[
{
"upperSizeBound": 10,
"weight": 0,
"lowerSizeBound": 0
},
...,
{
"upperSizeBound": 100,
"weight": 0,
"lowerSizeBound": 90
},
{
"weight": 0,
"lowerSizeBound": 100
}
]
upperSizeBound
- number - the upper size limit of the grade, in mm (note absence from largest grade size)lowerSizeBound
- number - the lower size limit of the grade, in mmweight
- number - the fresh yield contained within the grade size, t/ha, on the date