Canonical API is the main observation API that WOW has. It uses data format described in Observation Schema article and exposes REST endpoints for querying, creating, updating and deleting observations.

Following operations can be executed via Canonical API.

Table of Contents

Querying Observations

There are numerous ways to query observations, but the most powerful API is the GetObservationsByVersion. It supports bounding box queries, can show only official or non-official data, can filter by groups, sites, etc. Its response is based on Canonical Observation Schema, so it's easy to parse.

Endpoint: GetObservationsByVersion

Sample request code (in C#) to query official observations at the 19/12/2016:

private static async Task<dynamic> GetObservationsByVersion(string subscriptionKey)
{
    using (var httpClient = new HttpClient())
    {
        httpClient.BaseAddress = new Uri("https://mowowprod.azure-api.net");
        httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);

        using (var response = await httpClient.GetAsync("/api/observations/byversion?start_time=2016-12-19T00:00:00Z&end_time=2016-12-19T23:59:59Z&showWowData=false&showOfficialData=true"))
        {
            response.EnsureSuccessStatusCode();
            return JObject.Parse(await response.Content.ReadAsStringAsync());
        }
    }
}

Response:

[
  {
    "SiteId": "915866001",
    "ReportStartDateTime": "2016-12-19T00:50:00+00:00",
    "ReportEndDateTime": "2016-12-19T00:50:00+00:00",
    "ObservationType": 1,
    "CollectionName": 1,
    "WindDirection": 203.0,
    "WindGust_MilePerHour": 5.61,
    "WindGust_MetrePerSecond": 2.5078902429211332,
    "WindSpeed_MilePerHour": 4.42,
    "WindSpeed_MetrePerSecond": 1.9759135247257413,
    "RelativeHumidity": 85.0,
    "DryBulbTemperature_Fahrenheit": 48.02,
    "DryBulbTemperature_Celsius": 8.9000000000000021,
    "MeanSeaLevelPressure_InchOfMercury": 30.452,
    "MeanSeaLevelPressure_Hectopascal": 1031.22317828,
    "IsPublic": true,
    "IsOfficial": true,
    "Longitude": 3.628,
    "Latitude": 53.269,
    "Height": 42,
    "Id": "201612195fz874qfowe6pfyyyyguicqq6h",
    "ExternalSiteId": 915866001,
    "Version": 1,
    "IsLatestVersion": true,
    "ExternalId": 10090955564
  },
  {
    "SiteId": "916716001",
    "ReportStartDateTime": "2016-12-19T00:50:00+00:00",
    "ReportEndDateTime": "2016-12-19T00:50:00+00:00",
    "ObservationType": 1,
    "CollectionName": 1,
    "WindDirection": 106.0,
    "WindGust_MilePerHour": 4.79,
    "WindGust_MetrePerSecond": 2.1413180505511993,
    "WindSpeed_MilePerHour": 4.36,
    "WindSpeed_MetrePerSecond": 1.9490911691864781,
    "RelativeHumidity": 100.0,
    "DryBulbTemperature_Fahrenheit": 40.64,
    "DryBulbTemperature_Celsius": 4.8,
    "RainfallRate_InchPerHour": 0.0,
    "RainfallRate_MillimetrePerHour": 0.0,
    "IsPublic": true,
    "IsOfficial": true,
    "Longitude": 5.887,
    "Latitude": 52.702,
    "Height": -3,
    "Id": "2016121959xjkysfowe6pfyyyyguicqq6h",
    "ExternalSiteId": 916716001,
    "Version": 1,
    "IsLatestVersion": true,
    "ExternalId": 10090955603
  }
]

Querying Single Observation

To fetch a single observation, you can use this operation.

Endpoint: GetObservation

Sample request code (in C#) to query observation with Id 201612195fz874qfowe6pfyyyyguicqq6h:

private static async Task<dynamic> GetObservationById(string subscriptionKey)
{
    using (var httpClient = new HttpClient())
    {
        httpClient.BaseAddress = new Uri("https://mowowprod.azure-api.net");
        httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);

        using (var response = await httpClient.GetAsync("/api/observations/201612195fz874qfowe6pfyyyyguicqq6h"))
        {
            response.EnsureSuccessStatusCode();
            return JObject.Parse(await response.Content.ReadAsStringAsync());
        }
    }
}

Response:

{
  "SiteId": "915866001",
  "ReportStartDateTime": "2016-12-19T00:50:00+00:00",
  "ReportEndDateTime": "2016-12-19T00:50:00+00:00",
  "ObservationType": 1,
  "CollectionName": 1,
  "WindDirection": 203.0,
  "WindGust_MilePerHour": 5.61,
  "WindGust_MetrePerSecond": 2.5078902429211332,
  "WindSpeed_MilePerHour": 4.42,
  "WindSpeed_MetrePerSecond": 1.9759135247257413,
  "RelativeHumidity": 85.0,
  "DryBulbTemperature_Fahrenheit": 48.02,
  "DryBulbTemperature_Celsius": 8.9000000000000021,
  "MeanSeaLevelPressure_InchOfMercury": 30.452,
  "MeanSeaLevelPressure_Hectopascal": 1031.22317828,
  "IsPublic": true,
  "IsOfficial": true,
  "Longitude": 3.628,
  "Latitude": 53.269,
  "Height": 42,
  "Id": "201612195fz874qfowe6pfyyyyguicqq6h",
  "ExternalSiteId": 915866001,
  "Version": 1,
  "IsLatestVersion": true,
  "ExternalId": 10090955564
}

Querying Latest Observation of a Site

To fetch the latest observation of a site, you can use this operation.

Endpoint: GetLatestBySiteId

Sample request code (in C#) to query observation with site Id 915866001:

private static async Task<dynamic> GetLatestObservationBySiteId(string subscriptionKey)
{
    using (var httpClient = new HttpClient())
    {
        httpClient.BaseAddress = new Uri("https://mowowprod.azure-api.net");
        httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);

        using (var response = await httpClient.GetAsync("/api/observations/latestbysite/915866001"))
        {
            response.EnsureSuccessStatusCode();
            return JObject.Parse(await response.Content.ReadAsStringAsync());
        }
    }
}

Response:

{
  "SiteId": "915866001",
  "ReportStartDateTime": "2016-12-19T00:50:00+00:00",
  "ReportEndDateTime": "2016-12-19T00:50:00+00:00",
  "ObservationType": 1,
  "CollectionName": 1,
  "WindDirection": 203.0,
  "WindGust_MilePerHour": 5.61,
  "WindGust_MetrePerSecond": 2.5078902429211332,
  "WindSpeed_MilePerHour": 4.42,
  "WindSpeed_MetrePerSecond": 1.9759135247257413,
  "RelativeHumidity": 85.0,
  "DryBulbTemperature_Fahrenheit": 48.02,
  "DryBulbTemperature_Celsius": 8.9000000000000021,
  "MeanSeaLevelPressure_InchOfMercury": 30.452,
  "MeanSeaLevelPressure_Hectopascal": 1031.22317828,
  "IsPublic": true,
  "IsOfficial": true,
  "Longitude": 3.628,
  "Latitude": 53.269,
  "Height": 42,
  "Id": "201612195fz874qfowe6pfyyyyguicqq6h",
  "ExternalSiteId": 915866001,
  "Version": 1,
  "IsLatestVersion": true,
  "ExternalId": 10090955564
}

Querying Observations of a Site

This operation will allow you to query a site's observations in a date range.

Endpoint: GetObservationsBySite

Sample request code to query official observations of the site 915866001 at 19/12/2016:

private static async Task<dynamic> GetObservationsBySite(string subscriptionKey)
{
    using (var httpClient = new HttpClient())
    {
        httpClient.BaseAddress = new Uri("https://mowowprod.azure-api.net");
        httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);

        using (var response = await httpClient.GetAsync("/api/observations/bysite?site_id=915866001&start_time=2016-12-19T00:00:00Z&end_time=2016-12-19T23:59:59Z"))
        {
            response.EnsureSuccessStatusCode();
            return JObject.Parse(await response.Content.ReadAsStringAsync());
        }
    }
}

Response:

[
  {
    "SiteId": "916716001",
    "ReportStartDateTime": "2016-12-19T00:50:00+00:00",
    "ReportEndDateTime": "2016-12-19T00:50:00+00:00",
    "ObservationType": 1,
    "CollectionName": 1,
    "WindDirection": 106.0,
    "WindGust_MilePerHour": 4.79,
    "WindGust_MetrePerSecond": 2.1413180505511993,
    "WindSpeed_MilePerHour": 4.36,
    "WindSpeed_MetrePerSecond": 1.9490911691864781,
    "RelativeHumidity": 100.0,
    "DryBulbTemperature_Fahrenheit": 40.64,
    "DryBulbTemperature_Celsius": 4.8,
    "RainfallRate_InchPerHour": 0.0,
    "RainfallRate_MillimetrePerHour": 0.0,
    "IsPublic": true,
    "IsOfficial": true,
    "Longitude": 5.887,
    "Latitude": 52.702,
    "Height": -3,
    "Id": "2016121959xjkysfowe6pfyyyyguicqq6h",
    "ExternalSiteId": 916716001,
    "Version": 1,
    "IsLatestVersion": true,
    "ExternalId": 10090955603
  }
]

Post a New Observation

To submit an observation to a site, you can use this operation. Observations submitted to this endpoint are queued and processed in the background, so this endpoint will not be returning you any value after submission. You can query your site to see if your observation arrived.

Endpoint: PostObservation

Sample request code to submit an observation to our site with 12 Celsius dry bulb temperature at 19/12/2016 13:25:00:

private static async Task<dynamic> PostObservation(string subscriptionKey)
      {
          using (var httpClient = new HttpClient())
          {
              httpClient.BaseAddress = new Uri("https://mowowprod.azure-api.net");
              httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);

              var observation = new
              {
                  SiteId = "a27e78e7-2b39-e611-9cd2-28d244e1ce6c", // Site Id
                  SiteAuthenticationKey = "123123", // When Site Id is present, required.
                  Latitude = 52.702, // Required. Latitude of the observation
                  Longitude = 5.887, // Required. Longitude of the observation
                  ReportStartDateTime = new DateTime(2016, 12, 19, 13, 25, 00), // Required. Start date of this observation.
                  ReportEndDateTime = new DateTime(2016, 12, 19, 13, 25, 00), // Required. End date of this observation.
                  DryBulbTemperature_Celsius = 12 // The dry bulb temperature value
              };

              using (var response = await httpClient.PostAsync("/api/observations", new StringContent(JsonConvert.SerializeObject(observation), Encoding.UTF8, "application/json")))
              {
                  response.EnsureSuccessStatusCode();
                  return JObject.Parse(await response.Content.ReadAsStringAsync());
              }
          }
      }
public static JSONObject postObservation(String subscriptionKey) {
    JSONObject responseObject = null;

    try {
        URL url = new URL("https://mowowprod.azure-api.net/api/Observations");
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        urlConnection.setRequestMethod("POST");
        urlConnection.setRequestProperty("Ocp-Apim-Subscription-Key", subscriptionKey);
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);

        OutputStream outputStream = urlConnection.getOutputStream();

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);

        // Prepare the report's start and end times
        Calendar reportStartAndEndCalendar = GregorianCalendar.getInstance();
        reportStartAndEndCalendar.set(2016, 11, 19, 13, 25, 00); // In the Calendar class, months go from 0 - 11
        Date reportDate = reportStartAndEndCalendar.getTime();
        String reportStartAndEnd = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(reportDate);

        // Create the observation's JSON object with its properties
        JSONObject observationJsonObj = new JSONObject();
        observationJsonObj.put("SiteId", "a27e78e7-2b39-e611-9cd2-28d244e1ce6c"); // Site Id
        observationJsonObj.put("SiteAuthenticationKey", "123123"); // When Site Id is present, required.
        observationJsonObj.put("Latitude", 52.702f); // Required. Latitude of the observation
        observationJsonObj.put("Longitude", 5.887f); // Required. Longitude of the observation
        observationJsonObj.put("ReportStartDateTime", reportStartAndEnd); // Required. Start date of this observation.
        observationJsonObj.put("ReportEndDateTime", reportStartAndEnd); // Required. End date of this observation.
        observationJsonObj.put("DryBulbTemperature_Celsius", 12); // The dry bulb temperature value

        outputStreamWriter.write(observationJsonObj.toString());
        outputStreamWriter.flush();

        int responseCode = urlConnection.getResponseCode();

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
        String responseString = "";
        String line = null;
        while (null != (line = bufferedReader.readLine())) {
            responseString += line;
        }
        responseObject = new JSONObject(responseString);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    }

    return responseObject;
}
      

Successful response is HTTP 200. If an error occurs, it will be different. Check endpoint documentation for more detail.