NAV Navbar
php csharp

Introduction

Welcome to the Companion API! You can use our REST API to access Companion API endpoints, which can get information on observations in our database.

You can view code examples in PHP and C# in the dark area to the right.

Replace {{SERVER_PREFIX}} in the described webservices by the right value (depending on the server you are requesting):

Please refer to your point of contact if you have any problem.

Authentication

Companion uses JSON Web Token (JWT) authentication. Companion expects for a JWT to be included in all API requests to the server in a header that looks like the following.

Authorization: Bearer myjwttoken

See how you can generate your JWT below.

Please note that the algorithm used to sign the token is HMAC-SHA256.

Generate JWT

// package NuGet jose-jwt is used here

string payload = JsonConvert.SerializeObject(
    new {
        iss = "your_api_key", // TODO replace value with your credentials
        iat = DateTimeOffset.ToUnixTimeSeconds() // current timestamp
    }
);

string jwt = Jose.JWT.Encode(
    payload,
    System.Text.UTF8Encoding.Default.GetBytes(
        "PleaseKeepItSecret!" // TODO replace value with your credentials
    ),
    JwsAlgorithm.HS256
);

// In this example,
// jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ5b3VyX2FwaV9rZXkiLCJpYXQiOjE1MTYyMzkwMjJ9.hBBy96qEfmEW9OJyaOU5Lcbahszst8KEXFaxlbcvrJk"
<?php
use \Firebase\JWT\JWT; // The following code works with firebase/php-jwt

$payload = [
    'iss' => 'your_api_key', // TODO replace value with your credentials
    'iat' => time() // current timestamp
];

$jwt = JWT::encode(
    $payload,
    'PleaseKeepItSecret!', // TODO replace value with your credentials
    'HS256'
);

// In this example,
// $jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ5b3VyX2FwaV9rZXkiLCJpYXQiOjE1MTYyMzkwMjJ9.81E1KKRWJk92Qxo6o5sqPk-b583QSfKcbhE0cxsgzy8"
?>

There are three parameters you will need to define to generate a JWT.

The two following data have to be put in what is called the payload, it enables Companion API to identify the access rights for the JWT.

Parameter Description
iss "Issuer": Your api key provided by your point of contact
iat "Issued at": Timestamp (unix time) identifying the time at which the JWT was issued (you should set it to current timestamp when generating JWT)

Then you need to use your secret key provided by your point of contact.

Following the previous indications, you can follow the example on the dark area to generate your JWT.

Your JWT should look like the following: xxxxx.yyyyy.zzzzz

Referential

Crops

The request returns JSON structured like this:

[
    {
        "crop_code": "1101",
        "crop_name": "Orge",
        "crop_picture_path": "https://companion.basf.com/images/images/crops/barley.jpg",
        "pests": null,
        "seeds": null,
        "stages": null
    },
    {
        "crop_code": "1112",
        "crop_name": "Blé tendre d'hiver",
        "crop_picture_path": "https://companion.basf.com/images/images/crops/sww.jpg",
        "pests": null,
        "seeds": null,
        "stages": null
    }
]

HTTP Request

GET {{SERVER_PREFIX}}/api/v1/crops

Headers

Key Prefix Format Description
Authorization Bearer Authorization: Bearer myjwttoken myjwttoken should be replaced by the JWT generated previously.

Response

Name Description
crop_code Crop code in Companion
Example: 1112
crop_name Crop name
Example: Wheat
crop_picture_path Absolute URL to crop picture
pests null (used for other webservices)
seeds null (used for other webservices)
stages null (used for other webservices)

Pests

The request returns JSON structured like this:

[
    {
        "crop_code": "1101",
        "crop_name": "Orge",
        "crop_picture_path": "https://companion.basf.com/images/images/crops/barley.jpg",
        "pests": [
            {
                "pest_code": "00048",
                "pest_name": "Fusariose ",
                "pest_picture_path": "https://companion.basf.com/images/images/pests/barley_fusariose_icon.jpg"
            },
            {
                "pest_code": "00055",
                "pest_name": "Helminthosporiose ",
                "pest_picture_path": "https://companion.basf.com/images/images/pests/barley_helminthosporiose_icon.jpg"
            }
        ],
        "seeds": null,
        "stages": null
    }
]

HTTP Request

GET {{SERVER_PREFIX}}/api/v1/pests

Headers

Key Prefix Format Description
Authorization Bearer Authorization: Bearer myjwttoken myjwttoken should be replaced by the JWT generated previously.

Response

Pests are grouped by crops, so the results have arrays of pests inside of of arrays of crops.

Name Description
crop_code Crop code in Companion
Example: 1112
crop_name Crop name
Example: Wheat
crop_picture_path Absolute URL to crop picture
pests See below
seeds null (used for other webservices)
stages null (used for other webservices)

Pests elements are filled with:

Name Description
pest_code Pest code in Companion
Example: BASF39
pest_name Pest name
Example: Oidium (Leaves)
pest_picture_path Absolute URL to pest picture

Seeds

The request returns JSON structured like this:

[
    {
        "crop_code": "1101",
        "crop_name": "Orge",
        "crop_picture_path": "https://companion.basf.com/images/images/crops/barley.jpg",
        "pests": null,
        "seeds": [
            {
                "seed_id": 1,
                "seed_name": "06 JS 206"
            },
            {
                "seed_id": 2,
                "seed_name": "091027-526"
            },
            {
                "seed_id": 3,
                "seed_name": "093028-521"
            }
        },
        "stages": null
    }
]

HTTP Request

GET {{SERVER_PREFIX}}/api/v1/seeds

Headers

Key Prefix Format Description
Authorization Bearer Authorization: Bearer myjwttoken myjwttoken should be replaced by the JWT generated previously.

Response

Seeds are grouped by crops, so the results have arrays of seeds inside of of arrays of crops.

Name Description
crop_code Crop code in Companion
Example: 1112
crop_name Crop name
Example: Wheat
crop_picture_path Absolute URL to crop picture
pests null (used for other webservices)
seeds See below
stages null (used for other webservices)

Seeds elements are filled with:

Name Description
seed_id ID of the seed related to the pest
Can be null.
seed_name Name of the seed related to the pest
Example: ALIGATOR
Can be null.

Growth stages

The request returns JSON structured like this:

[
    {
        "crop_code": "1101",
        "crop_name": "Orge",
        "crop_picture_path": "https://companion.basf.com/images/images/crops/barley.jpg",
        "pests": null,
        "seeds": null,
        "stages": [
            {
                "stage_code": "1",
                "stage_bbch": "0",
                "stage_name": "Pré-semis",
                "stage_order": 10
            },
            {
                "stage_code": "2",
                "stage_bbch": "1",
                "stage_name": "Pré-levée",
                "stage_order": 20
            }
        ]
    }
]

HTTP Request

GET {{SERVER_PREFIX}}/api/v1/stages

Headers

Key Prefix Format Description
Authorization Bearer Authorization: Bearer myjwttoken myjwttoken should be replaced by the JWT generated previously.

Response

Stages are grouped by crops, so the results have arrays of stages inside of of arrays of crops.

Name Description
crop_code Crop code in Companion
Example: 1112
crop_name Crop name
Example: Wheat
crop_picture_path Absolute URL to crop picture
pests null (used for other webservices)
seeds null (used for other webservices)
stages See below

Stages elements are filled with:

Name Description
stage_code Crop's growth stage code in Companion
Can be null.
stage_bbch BBCH code
stage_name Crop's growth stage name
Example: 1 node
Can be null.
stage_order Order in crop

Metos

The request returns JSON structured like this:

[
    {
        "meto_code": 4,
        "meto_name": "Sur 20 pieds, combien sont concernés ?",
        "meto_unit": "Pied(s) concerné(s) sur 20 pieds observés.",
        "meto_unit_short": null
    },
    {
        "meto_code": 10,
        "meto_name": "Sur 10 siliques, combien sont touchées ?",
        "meto_unit": "Silique(s) touchée(s) sur 10 siliques observées.",
        "meto_unit_short": null
    }
]

HTTP Request

GET {{SERVER_PREFIX}}/api/v1/metos

Headers

Key Prefix Format Description
Authorization Bearer Authorization: Bearer myjwttoken myjwttoken should be replaced by the JWT generated previously.

Response

Name Description
meto_code Meto code in Companion
meto_name Meto name
meto_unit Unit
meto_unit_short Short unit used in expert protocol. Can be null.

Notas

The request returns JSON structured like this:

[
    {
        "nota_code": -28,
        "nota_name": "Attaque forte"
    },
    {
        "nota_code": 14,
        "nota_name": "1 à 9"
    }
]

HTTP Request

GET {{SERVER_PREFIX}}/api/v1/notas

Headers

Key Prefix Format Description
Authorization Bearer Authorization: Bearer myjwttoken myjwttoken should be replaced by the JWT generated previously.

Response

Name Description
nota_code Nota code in Companion
nota_name Nota name

Observations

Get All Observations

The request returns JSON structured like this:

[
    {
        "id": 57174,
        "observation_date": "2019-05-15T10:10:56",
        "latitude": 45.6885045,
        "longitude": 4.7677997,
        "postal_code": "69540",
        "city": "Irigny",
        "user_id": 10053,
        "user_email": "AnonUser10053@gmail.com",
        "username": "AnonUser10053",
        "user_profession": "GROWER",
        "user_photo_path": null,
        "crop_code": "1112",
        "crop_name": "BTH",
        "crop_picture_path": "https://companion.basf.com/images/crops/sww.jpg",
        "seed_id": null,
        "seed_name": null,
        "sowing_date": null,
        "growthstage_code": 4,
        "growthstage_name": "3 feuilles",
        "growthstage_picture_path": "https://companion.basf.com/images/images/growthstages/sww_3leaves_out.jpg",
        "pest_code": "BASF16",
        "pest_name": "Cicadelles",
        "pest_picture_path": "https://companion.basf.com/images/pests/sww_cicadelle_icon.jpg",
        "is_expert_protocol": true,
        "responses": [
            {
                "meto_code": 112,
                "meto_name": "Quelle est la classe majoritaire ?",
                "meto_unit": null,
                "notas": [
                    {
                        "characteristic": "",
                        "nota_code": -10,
                        "nota_name": "Limaces noires jeunes"
                    }
                ]
            },
            {
                "meto_code": 113,
                "meto_name": "Sur 10 plantules successives de 5 lignes de semis différentes, quel est % de plantules attaquées ?",
                "meto_unit": "% de plantules attaquées",
                "notas": [
                    {
                        "characteristic": "",
                        "nota_code": 0,
                        "nota_name": "7"
                    }
                ]
            },
            {
                "meto_code": 180,
                "meto_name": "Quelle est la somme des 4 comptages de piège INRA ? (Nombre / m²)",
                "meto_unit": "Nombre / m²",
                "notas": [
                    {
                        "characteristic": "[Grises - jeunes (<1 cm)]",
                        "nota_code": 0,
                        "nota_name": "73"
                    },
                    {
                        "characteristic": "[Grises - adultes]",
                        "nota_code": 0,
                        "nota_name": "66"
                    },
                    {
                        "characteristic": "[Noires - jeunes (<1 cm)]",
                        "nota_code": 0,
                        "nota_name": "50"
                    },
                    {
                        "characteristic": "[Noires - adultes]",
                        "nota_code": 0,
                        "nota_name": "70"
                    },
                    {
                        "characteristic": "[Autres - jeunes (<1 cm)]",
                        "nota_code": 0,
                        "nota_name": "0"
                    },
                    {
                        "characteristic": "[Autres - adultes]",
                        "nota_code": 0,
                        "nota_name": "68"
                    }
                ]
            }
        ],
        "risk_level": 1,
        "comment": null,
        "photo_path": null
    },
    {
        "id": 57175,
        "observation_date": "2019-05-16T15:10:56",
        "latitude": 45.6885045,
        "longitude": 4.7677997,
        "postal_code": "69540",
        "city": "Irigny",
        "user_id": 10053,
        "user_email": "AnonUser10053@gmail.com",
        "username": "AnonUser10053",
        "user_profession": "GROWER",
        "user_photo_path": null,
        "crop_code": "1112",
        "crop_name": "BTH",
        "crop_picture_path": "https://companion.basf.com/images/crops/sww.jpg",
        "seed_id": 1905,
        "seed_name": "ULI 12",
        "sowing_date": "2019-05-16T15:11:02",
        "growthstage_code": 31,
        "growthstage_name": "Début tallage",
        "growthstage_picture_path": "https://companion.basf.com/images/growthstages/sww_tillering.jpg",
        "pest_code": "BASF16",
        "pest_name": "Cicadelles",
        "pest_picture_path": "https://companion.basf.com/images/pests/sww_limace_icon.jpg",
        "pest_code": "15774",
        "pest_name": "Limaces / escargots",
        "is_expert_protocol": false,
        "responses": [
            {
                "meto_code": 26,
                "meto_name": "Sur 10 feuilles, combien sont touchées ?",
                "meto_unit": "Feuille(s) touchée(s) sur 10 feuilles observées.",
                "notas": [
                    {
                        "characteristic": "",
                        "nota_code": 43,
                        "nota_name": "1 à 3"
                    }
                ]
            }
        ],
        "risk_level": 2,
        "risk_level": 1,
        "comment": null,
        "photo_path": null
    }
]

This endpoint retrieves all observations that you can access.

HTTP Request

GET {{SERVER_PREFIX}}/api/v1/observations

Headers

Key Prefix Format Description
Authorization Bearer Authorization: Bearer myjwttoken myjwttoken should be replaced by the JWT generated previously.

Query Parameters

All parameters are optional.

Parameter Description
fromDate Format: yyyyMMdd. If defined, observations made before the fromDate won't be returned.
toDate Format: yyyyMMdd. If defined, observations made after the toDate won't be returned.

Response

Name Description
id
observation_date Date when observation was made
Format: yyyy-MM-dd'T'HH:mm:ss
latitude Location's latitude of the observation
longitude Location's longitude of the observation
postal_code Postal code of the observation
city City of the observation
user_id User ID who made the observation
user_email User email
username Username in Companion
user_profession User's profession
Possible values: GROWER, CROP_ADVISOR, OTHER.
user_photo_path Absolute URL to user profile photo
Can be null if user does not have a profile photo.
crop_code Crop code in Companion
Example: 1112
crop_name Crop name
Example: Wheat
crop_picture_path Absolute URL to crop picture
seed_id ID of the seed related to the pest
Can be null.
seed_name Name of the seed related to the pest
Example: ALIGATOR
Can be null.
sowing_date Sowing date
Format: yyyy-MM-dd'T'HH:mm:ss
growthstage_code Crop's growth stage code in Companion
Can be null.
growthstage_name Crop's growth stage name
Example: 1 node
Can be null.
growthstage_picture_path Absolute URL to growth stage picture
Can be null.
pest_code Pest code in Companion
Example: BASF39
pest_name Pest name
Example: Oidium (Leaves)
pest_picture_path Absolute URL to pest picture
risk_level Value from 0 to 3 (lowest to highest).
Example: 2
Can be null.
comment Comment made by the user
Can be null if user has not posted any comment.
photo_path Absolute URL to the observation picture
Can be null if user has not taken any photo.
is_expert_protocol Indicates whether the observation was made with Companion PRO expert function
responses List of values set by user. Each question is structured with Meto structure

Meto structure

Name Description
meto_code Methodology code in Companion
Example: 4
Can be null.
meto_name Methodology (usually a question).
Example: Out of 20 stalks, how many are affected ?
Can be null.
meto_unit Methodology unit.
Example: Affected plant base(s) out of 20 observed bases.
Can be null.
notas List of answers for the question. Each answer is structured with Nota structure

Nota structure

Name Description
characteristic Useful when the question is for several characteristics.
Empty if the question does not affect different characteristics.
nota_code Nota code in Companion
Example: 14
= 0 if no nota code associated (often when in expert protocol).
nota_name Notation value (according to methodology).
Example: 1 to 9
Can be null.

Errors

Companion API uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, a charge failed, etc.). Codes in the 5xx range indicate an error with Stripe's servers (these are rare).

Error Code Meaning
400 Bad Request -- Your request is invalid.
This error has different reasons:
- Token could not be read
- Wrong api key in token (which means your api key is not found in Companion database)
- Bad token (which means your JWT generated seems not good, please ensure you use the right secret key)
- Expired token
- fromDate does not conform to expected format : "yyyyMMdd"
- toDate does not conform to expected format : "yyyyMMdd"
401 Unauthorized -- Your authorization key is wrong.
403 Forbidden -- The access to the endpoint requires specific rights.
You can also have this error the case you have tried to call our API at least 10 times during the last hour.
429 Too Many Requests -- You're requesting the server too many times! Slow down!
500 Internal Server Error -- We had a problem with our server. Try again later or refer to your point of access.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.