Degree Days
Weather Data for Energy Saving
The XML API is carefully designed and well tested. But it's not particularly easy to use. The wide range of options and data that can be specified and returned in XML means there's a lot of XML creation and parsing involved. There's also a strict HMAC-signature-based security scheme to negotiate.
We have robust client libraries for Java, .NET, and Python; we recommend you use them if you are using Java (or Kotlin, Scala, Groovy etc.), .NET (e.g. C# or VB.NET), or Python. All 3 client libraries use the XML API internally, but they make all the request options immediately available, and use fast XML-stream parsing to convert the XML responses into a simple object model. With the client libraries you can be up and running fetching data in a couple of minutes.
For dynamic object-oriented languages with good JSON support, the JSON API is typically easier to use than the XML API, as the JSON maps naturally and automatically to objects. We have code samples for JavaScript, Node.js, Office/Excel, PHP, PowerShell, R, Ruby, and VBA. But there is no other significant difference between the XML API and the JSON API. Both let you do exactly the same things, both have the same security scheme, both are served by the same backend system, and you can use either or both through the same API account. We suggest you choose whichever best suits your platform and experience.
If you do choose the XML API, the XML API test tool should be useful for testing different XML requests and seeing the XML responses that come back.
base64url
encoding, and send the encoded data as HTTP request parameters to http://apiv1.degreedays.net/xml
or https://apiv1.degreedays.net/xml
Each of these steps is explained below:
There are currently three main types of request:
LocationDataRequest
– for fetching data from a specified Location
(which can be a station ID, a longitude/latitude position, or a postal/zip code).LocationInfoRequest
– typically used to get information about the station that would be used to generate data for a given Location
, without actually getting that data back. It's basically LocationDataRequest
but without any data in the response.RegressionRequest
– used to send energy data to the API so it can test thousands of regressions and send back a regression model with the HDD and/or CDD base temperature(s) that give the best statistical fit.All three types of request are highly configurable. The request formats of LocationDataRequest
and LocationInfoRequest
differ only in the name of the request (i.e. "LocationDataRequest"
or "LocationInfoRequest"
). The docs on the API's regression functionality explain how to configure an XML RegressionRequest
. All XML requests are sent to the API in the same way explained further down on this page.
Below is an example XML request (a LocationDataRequest
) that shows a few of the main options. You can copy/paste it into the XML API test tool to try it out. Below that are more details of the various options you can use within the XML.
If you have a specific data-fetching pattern in mind, and you're struggling to figure out what XML you'll need, please feel free to email us for help at info@degreedays.net.
<?xml version="1.0" encoding="UTF-8" ?> <RequestEnvelope> <SecurityInfo> <!-- "Endpoint" is the URL you send your request to. You can send it to http://apiv1.degreedays.net/xml (to call the API over HTTP) or https://apiv1.degreedays.net/xml (to call it over HTTPS); just make sure the Endpoint you specify here is exactly the same as the URL you actually send your request to. --> <Endpoint>http://apiv1.degreedays.net/xml</Endpoint> <!-- "AccountKey" comes with your API account. --> <AccountKey>test-test-test</AccountKey> <!-- "Timestamp" should be the time of the request, in ISO format. You should update this for each request you make. --> <Timestamp>2024-11-11T11:23:59Z</Timestamp> <!-- "Random" should be a random string, generated afresh for each request. It can be a random number or a UUID or similar. --> <Random>6731e94f65f26</Random> </SecurityInfo> <LocationDataRequest> <!-- Specify the "Location" you want data for (more options further below): --> <PostalCodeLocation> <PostalCode>02532</PostalCode> <CountryCode>US</CountryCode> </PostalCodeLocation> <!-- Now specify what data you want. You can specify up to 120 "DataSpec" items in a single request (e.g. HDD and CDD in 60 base temperatures each). Give each "DataSpec" a "key" attribute so you can identify the corresponding "DataSet" in the response. --> <DataSpecs> <!-- The following specifies HDD with a base temperature of 65 F, broken down daily (a value for each day), and covering the last 7 days. --> <DatedDataSpec key="dailyHDD"> <!-- The "Calculation" defines the type of degree days (e.g. heating or cooling) and the base temperature. --> <HeatingDegreeDaysCalculation> <FahrenheitBaseTemperature>65</FahrenheitBaseTemperature> </HeatingDegreeDaysCalculation> <!-- There are different types of "Breakdown" (see further below). --> <DailyBreakdown> <!-- A Breakdown has a "Period" to specify the dates that the data should cover. There's more on specifying the Period further down this page. --> <LatestValuesPeriod> <NumberOfValues>7</NumberOfValues> </LatestValuesPeriod> </DailyBreakdown> </DatedDataSpec> <!-- The following specifies CDD with a base temperature of 21.5 C, broken down monthly, and covering June, July, and August of 2024. --> <DatedDataSpec key="monthlyCDD"> <CoolingDegreeDaysCalculation> <CelsiusBaseTemperature>21.5</CelsiusBaseTemperature> </CoolingDegreeDaysCalculation> <MonthlyBreakdown> <DayRangePeriod> <DayRange first="2024-06-01" last="2024-08-31"/> </DayRangePeriod> </MonthlyBreakdown> </DatedDataSpec> <!-- The following specifies 5-year-average HDD with a base temperature of 15.5 C. If you made this request today you could expect to get an average of data from 2019, 2020, 2021, 2022, and 2023. NB as this covers 5 years it will use more request units than the much-shorter items defined above. For repeated testing you might want to remove it or temporarily reduce its "numberOfValues" to 1 if your API account does not have a high rate limit. --> <AverageDataSpec key="averageHDD"> <HeatingDegreeDaysCalculation> <CelsiusBaseTemperature>15.5</CelsiusBaseTemperature> </HeatingDegreeDaysCalculation> <FullYearsAverageBreakdown> <LatestValuesPeriod> <NumberOfValues>5</NumberOfValues> </LatestValuesPeriod> </FullYearsAverageBreakdown> </AverageDataSpec> <!-- The following specifies hourly temperatures for just the most recent full day. You can fetch hourly temperatures covering much longer periods, but here we specify just one day to keep the example response short. NB fetching hourly temperatures uses extra request units and requires at least an API Standard account. So we suggest you remove this TimeSeriesDataSpec from your code if you don't need it. --> <TimeSeriesDataSpec key="hourlyTemperatures"> <TemperatureTimeSeriesCalculation> <Interval>Hourly</Interval> <TemperatureUnit>Celsius</TemperatureUnit> </TemperatureTimeSeriesCalculation> <!-- Hourly data is always broken down hourly, but TimeSeriesDataSpec takes a DatedBreakdown (like DailyBreakdown) to enable you to get hourly data that matches your degree days exactly, and so you can easily specify hourly data covering e.g. the last x days, weeks, or months. It is a little confusing at first, but it is useful too! NB If you want figures for the current day so far, add an allowPartialLatest="true" attribute to the DailyBreakdown element below: --> <DailyBreakdown> <LatestValuesPeriod> <NumberOfValues>1</NumberOfValues> </LatestValuesPeriod> </DailyBreakdown> </TimeSeriesDataSpec> </DataSpecs> </LocationDataRequest> </RequestEnvelope>
LocationDataRequest
The above XML is just an example, you can easily configure your own LocationDataRequest
to specify exactly the data you want. The XML API test tool can be useful here: you can copy/paste in the example XML request above and then modify it to try out the options described below:
The Location
can be a station ID, or a "geographic location" for which the API will select the best weather station to use automatically:
<StationIdLocation> <!-- the StationId must match [-_0-9a-zA-Z]{1,60} --> <StationId>EGLL</StationId> </StationIdLocation> <LongLatLocation> <LongLat longitude="-135.23127" latitude="43.92135"/> </LongLatLocation> <PostalCodeLocation> <!-- the PostalCode is the postal/zip code of the location and must match [- 0-9a-zA-Z]{1,16} --> <PostalCode>WC2N 5DN</PostalCode> <!-- the CountryCode should be the 2-letter ISO country code of the location, in upper case e.g. US for United States, GB for Great Britain --> <CountryCode>GB</CountryCode> </PostalCodeLocation>
A DataSpec
can be either a DatedDataSpec
(for daily/weekly/monthly/yearly degree days), an AverageDataSpec
, or a TimeSeriesDataSpec
(for hourly temperature data). All three are shown in the example request XML further above.
A Calculation
(which goes inside a DatedDataSpec
or AverageDataSpec
) can specify heating or cooling degree days:
<HeatingDegreeDaysCalculation> <CelsiusBaseTemperature>15.5</CelsiusBaseTemperature> </HeatingDegreeDaysCalculation> <CoolingDegreeDaysCalculation> <FahrenheitBaseTemperature>65</FahrenheitBaseTemperature> </CoolingDegreeDaysCalculation>
All temperatures must be specified as whole numbers or with one digit after the decimal point.
A TimeSeriesCalculation
(which goes inside a TimeSeriesDataSpec
) can specify hourly temperature data in Celsius or Fahrenheit:
<TemperatureTimeSeriesCalculation> <Interval>Hourly</Interval> <TemperatureUnit>Celsius</TemperatureUnit> </TemperatureTimeSeriesCalculation> <TemperatureTimeSeriesCalculation> <Interval>Hourly</Interval> <TemperatureUnit>Fahrenheit</TemperatureUnit> </TemperatureTimeSeriesCalculation>
A DatedDataSpec
(and a TimeSeriesDataSpec
*) can have the following kinds of breakdown:
<DailyBreakdown> <!-- Period goes here. --> </DailyBreakdown> <WeeklyBreakdown firstDayOfWeek="Monday"> <!-- Period goes here. --> </WeeklyBreakdown> <!-- startOfMonth is optional, the default being ---01 for regular calendar months starting on the first day of each month. The ---DD format is XML Schema's gDay format for days that recur each month, based on ISO 8601. --> <MonthlyBreakdown startOfMonth="---01"> <!-- Period goes here. --> </MonthlyBreakdown> <!-- startOfYear is optional, the default being --01-01 for regular calendar years starting on Jan 1st each year. The --MM-DD format is XML Schema's gMonthDay format for days that recur each year, based on ISO 8601. The example below specifies years starting on May 21st: --> <YearlyBreakdown startOfYear="--05-21"> <!-- Period goes here. --> </YearlyBreakdown> <CustomBreakdown> <DayRanges> <DayRange first="2023-10-16" last="2023-11-14"/> <!-- Typically one range would start the day after the last day of the previous range (i.e. no gap). But you can have gaps between ranges if you like (e.g. if your energy data has gaps), as in this example which leaves a gap between 2023-11-15 and 2023-11-20. --> <DayRange first="2023-11-21" last="2023-12-17"/> </DayRanges> </CustomBreakdown>
*As mentioned in the example XML above, it might seem strange that a TimeSeriesDataSpec
(for hourly temperature data) would take these breakdowns in the same way that a DatedDataSpec
(for degree days) does, but it works this way to give you flexibility in how you specify the time-period that the hourly data should cover, and to make it easy for you to get hourly data that lines up perfectly with your degree days.
All the breakdown types above can also have an allowPartialLatest
attribute that you can specify as true
(as opposed to the default value of false
) to enable you to fetch time-series data that includes figures for the current day/week/month/year so far. For example:
<DailyBreakdown allowPartialLatest="true"> <!-- Period goes here. --> </DailyBreakdown>
Please note that the most recent time-series data can be a little volatile, as weather stations sometimes send multiple reports for the same time, some delayed, and some marked as corrections for reports they sent earlier. Our system generates time-series data using all the relevant reports that each weather station has sent, but the generated figures may change if delayed or corrected reports come through later. If you are storing partial-latest time-series data we suggest you overwrite it later with figures generated after the day has completed and any delayed/corrected reports have had time to filter through.
An AverageDataSpec
can currently only have one type of breakdown:
<!-- This specifies that data should be averaged from the full calendar years specified by the period. --> <FullYearsAverageBreakdown> <!-- Period goes here. Typically you'd use a LatestValuesPeriod to specify that the average should come from the most recent x full calendar years. --> </FullYearsAverageBreakdown>
A Period
can be specified in two ways:
<!-- Get the most recent available data: --> <LatestValuesPeriod> <NumberOfValues>12</NumberOfValues> <!-- MinimumNumberOfValues is optional - you can specify it if you would rather have a failure than a partial set of data with less than your specified minimum number of values. (Otherwise you may get back less data than you asked for if there aren't enough temperature-data records to generate a full set for your specified location.) --> <MinimumNumberOfValues>12</MinimumNumberOfValues> </LatestValuesPeriod> <!-- Get data covering your specified dates: --> <DayRangePeriod> <DayRange first="2019-01-01" last="2023-12-31"/> <!-- MinimumDayRange is optional - you can specify it if you would rather have a failure than a partial set of data covering less than your specified minimum range (like for MinimumNumberOfValues above). --> <MinimumDayRange first="2021-01-01" last="2023-12-31"/> </DayRangePeriod>
LocationInfoRequest
and two-stage data fetchingExcept in name, LocationInfoRequest
looks exactly the same as LocationDataRequest
. Take the example LocationDataRequest
XML above, change "<LocationDataRequest>
" to "<LocationInfoRequest>
" and "</LocationDataRequest>
" to "</LocationInfoRequest>
", and you will have a valid LocationInfoRequest
.
Each API request you make uses request units that count against your hourly rate limit. A big LocationDataRequest
can use a lot of request units, but a LocationInfoRequest
will only ever use one. See the sign-up page for more on request units and rate limits.
If you try this out in the XML API test tool, you will see that LocationInfoResponse
does not contain any data (it has no <DataSets>
element)... It's typically used for two-stage data fetching, which can be useful if you are dealing with geographic locations (postal/zip codes, or longitude/latitude positions), but storing data by station ID (returned in every successful response). For this use-case, two-stage data fetching can help you save request units (see right) and improve the efficiency of your system by avoiding re-fetching data that you already have stored.
When you want to add a new location into your system (e.g. if a new user signs up with a new address), you can do the following:
LocationInfoRequest
with the geographic location and the specification of the data that you want. This will only take one request unit. You won't get any data back, but you will get the station ID that the system would use for an equivalent LocationDataRequest
. If you already have data stored for that station ID, use it; if not, progress to stage 2.LocationDataRequest
with the station ID from stage 1. This will take more request units (more the more data you fetch), but using the station ID will save a request unit, such that your two-stage fetch will use the same number of request units in total as you would have used if you had made a LocationDataRequest
with the geographic location in the first place.Two-stage fetching will only improve efficiency and save request units if/when you have enough geographic locations in your system that some of them end up sharing weather stations. But, if that is the case, two-stage fetching can really help your system to scale well as more and more geographic locations are added in.
RegressionRequest
for advanced regression functionalityWith RegressionRequest
you can send energy data to the API so it can test thousands of regressions and find the HDD and/or CDD base temperatures that give the best statistical fit. Our docs on the API's regression functionality cover all the RegressionRequest
configuration options and the data you can expect in the RegressionResponse
. They do not, however, cover how to send a RegressionRequest
to the API and get a response back. This process is the same for all request types, so we suggest you follow the instructions on this page to get your code sending LocationDataRequest
to the API and getting a response back, then get it sending RegressionRequest
as well.
You can also test a RegressionRequest
quickly with the API regression docs and the XML API test tool.
You need to send five parameters to the endpoint URL (http://apiv1.degreedays.net/xml
or https://apiv1.degreedays.net/xml
):
request_encoding=base64url
signature_method=HmacSHA256
(or alternative)signature_encoding=base64url
encoded_request
(the XML string, base64url
encoded)encoded_signature
(the signature, base64url
encoded)HTTP POST
is ideal, but, if that's difficult for you, a GET
should be OK too.
The signature and base64url
encoding are both explained below:
The signature has two purposes:
The signature_method
will ideally be HmacSHA256
. If you can't do that for whatever reason (it might not be supported by your programming language), HmacSHA1
should work instead. Of course the method you use to make the signature has to correspond with the signature_method
parameter that you send with your request.
Your XML string should be fed into the HMAC function, with the key being your security key (one of the access keys that comes with your API account). If the HMAC function requires a byte array, convert the XML string into bytes first using UTF-8
encoding. The HMAC function should return the signature as a byte array. Encode that using base64url
(as described below), and use the resulting string as the encoded_signature
parameter.
base64url
encoding is required to:
encoded_request
parameter); andencoded_signature
parameter).base64url
encoding is like regular base 64, but with a few differences:
+
characters are -
(minus) instead;/
characters are _
(underscore) instead;=
characters as padding, and no line breaks.Many libraries can do base64url encoding automatically, but if not, then hopefully you can generate a regular base-64 string and convert it using the simple rules above. Note that you might find it works OK with the =
characters and line breaks left in, but to ensure future compatibility it's best to remove them.
If your base-64 function takes a byte array instead of a string, to encode the request XML you should encode the XML string into bytes first (using UTF-8
encoding) and then feed the bytes into your base-64 function.
If, in your programming language, you're struggling to generate anything base 64, email us at info@degreedays.net as we should be able to set up an alternative like hex.
As mentioned above, an HTTP POST is the best way, but, if that's difficult in your programming language, a GET should work too.
If you can handle a compressed response, you can set the Accept-Encoding
header to gzip
or deflate
. Then the XML response will come back in compressed format. This won't make much of a difference if you're only fetching a small amount of data with each request, but it's well worth using compression to reduce bandwidth if you're fetching daily data covering long periods or in lots of base temperatures.
The XML API test tool can be useful for debugging your HTTP requests, as it generates and shows all the HTTP request parameters for any XML request you give it. Usually the test tool's "Auto-prepare request" option is helpful, but you should switch it off if you are checking your encoded_request
or encoded_signature
against the ones generated by the test tool, as you don't want it modifying your XML request before generating the HTTP parameters.
Below is an annotated example XML response to the example XML LocationDataRequest
above. It shows all the elements and attributes that you should see, apart from Failure
elements (covered later), but, when writing your parsing code, please do bear in mind that we may add extra new elements or attributes in the future.
<Response> <!-- The following Metadata is included with every response. --> <Metadata> <RateLimit> <!-- RequestUnitsAvailable shows how many request units your account has left in the current period. --> <RequestUnitsAvailable>2116</RequestUnitsAvailable> <!-- MinutesToReset is the number of minutes until your available request units are reset to their full allowance. --> <MinutesToReset>33</MinutesToReset> </RateLimit> </Metadata> <!-- The LocationDataResponse element is what you get in response to a LocationDataRequest (from your XML request). --> <LocationDataResponse> <Head> <!-- There will always be a StationId, assuming your request could be satisfied. --> <StationId>KFMH</StationId> <!-- The TargetLocation will always have the same format, however you specified the Location in your XML request. If you specified a StationIdLocation it will give the location of that station; if you specified a LongLatLocation it will repeat those coordinates back to you; if you specified a PostalCodeLocation (as in the example XML request) it will give you the coordinates that the API used to represent that postal code. --> <TargetLocation> <LongLat longitude="-70.59047" latitude="42.7455"/> </TargetLocation> <!-- The Sources represent the stations that were used to generate your data. There will always be at least one, and at present there will only be one (we've allowed for the future possibility of combining data from multiple stations without breaking compatibility). --> <Sources> <Source> <Station> <Id>KFMH</Id> <LongLat longitude="-70.5215" latitude="41.6585"/> <ElevationMetres>40</ElevationMetres> <DisplayName>Otis Air National Guard Base, MA, US</DisplayName> </Station> <!-- How far is this Station from the TargetLocation? (It will be 0 if you specified a StationIdLocation in your request.) --> <MetresFromTarget>11242</MetresFromTarget> </Source> </Sources> </Head> <DataSets> <!-- Every DataSet has a key that matches the corresponding DataSpec from the XML request. The following examples show the formats you can expect for the different types of DataSet: --> <DatedDataSet key="dailyHDD"> <Head> <PercentageEstimated>1</PercentageEstimated> </Head> <Values> <!-- d is the first day of the period that the value V covers. The ld (last day) property isn't included for daily data as it's always the same as d. We don't like cryptic abbreviations or attributes that are only sometimes present, but big responses can easily have hundreds of thousands of values, so we keep them small to minimize bandwidth and memory footprint. --> <V d="2024-11-04">3.8</V> <!-- pe is short for "percentage estimated". If it's missing, it's the default value of 0. --> <V d="2024-11-05" pe="0.6">2.6</V> <V d="2024-11-06">1.4</V> <V d="2024-11-07">0.3</V> <V d="2024-11-08">2.9</V> <V d="2024-11-09" pe="1">3.9</V> <V d="2024-11-10">1.4</V> </Values> </DatedDataSet> <DatedDataSet key="monthlyCDD"> <Head> <PercentageEstimated>0.6</PercentageEstimated> </Head> <Values> <!-- ld is short for "last date". It's only included if it's different to d (the first date) i.e. if the data is weekly or monthly or yearly instead of daily. --> <V d="2024-06-01" ld="2024-06-30" pe="2">17.4</V> <V d="2024-07-01" ld="2024-07-31">73.6</V> <V d="2024-08-01" ld="2024-08-31">24.1</V> </Values> </DatedDataSet> <AverageDataSet key="averageHDD"> <Head> <PercentageEstimated>0.2</PercentageEstimated> <FirstYear>2019</FirstYear> <LastYear>2023</LastYear> </Head> <Values> <!-- Annual has the average-annual total. --> <Annual pe="0.2">2478.3</Annual> <Monthly> <!-- M (Month) no 1 has the average value for January; 2 has the average value for February; etc. --> <M no="1" pe="0.01">523.9</M> <M no="2" pe="0.3">435</M> <M no="3" pe="0.06">363.1</M> <M no="4" pe="0.007">203.5</M> <M no="5" pe="0.4">85.9</M> <M no="6" pe="1">21.1</M> <M no="7" pe="0.2">1.9</M> <M no="8" pe="0.01">4.2</M> <M no="9" pe="0.1">35.8</M> <M no="10" pe="0.08">125.4</M> <M no="11" pe="0.007">257.3</M> <M no="12" pe="0.03">421.2</M> </Monthly> </Values> </AverageDataSet> <TimeSeriesDataSet key="hourlyTemperatures"> <Head> <PercentageEstimated>0.4</PercentageEstimated> </Head> <Values> <!-- "dt" is short for "date-time". They are in ISO format, so you can easily parse out the local time (from the first 16 characters), and the time-zone offset is there too if you want it or the time in UTC. --> <V dt="2024-11-10T00:00-05:00">4</V> <V dt="2024-11-10T01:00-05:00">3.8</V> <V dt="2024-11-10T02:00-05:00">2.5</V> <V dt="2024-11-10T03:00-05:00">1</V> <V dt="2024-11-10T04:00-05:00">0.8</V> <V dt="2024-11-10T05:00-05:00">0.2</V> <V dt="2024-11-10T06:00-05:00">1.2</V> <V dt="2024-11-10T07:00-05:00" pe="1">3.2</V> <V dt="2024-11-10T08:00-05:00" pe="1">7.5</V> <V dt="2024-11-10T09:00-05:00">10</V> <V dt="2024-11-10T10:00-05:00">10.5</V> <V dt="2024-11-10T11:00-05:00">11.8</V> <V dt="2024-11-10T12:00-05:00">11</V> <V dt="2024-11-10T13:00-05:00">11.2</V> <V dt="2024-11-10T14:00-05:00" pe="1">11.6</V> <V dt="2024-11-10T15:00-05:00" pe="2">10</V> <V dt="2024-11-10T16:00-05:00" pe="2">9.5</V> <V dt="2024-11-10T17:00-05:00">8.9</V> <V dt="2024-11-10T18:00-05:00">6.9</V> <V dt="2024-11-10T19:00-05:00" pe="1">6.2</V> <V dt="2024-11-10T20:00-05:00">5.9</V> <V dt="2024-11-10T21:00-05:00">5.9</V> <V dt="2024-11-10T22:00-05:00">5.4</V> <V dt="2024-11-10T23:00-05:00">5</V> </Values> </TimeSeriesDataSet> </DataSets> </LocationDataResponse> </Response>
You can generate a similar response yourself by running the example XML request further above through the XML API test tool. But please note that the annotated response above is just an example to show the response structure; the figures you get in your live response will be different.
If something goes wrong, the XML response will contain a Failure
.
Every Failure
has a Code
that indicates the cause of the failure.
These codes are named in a hierarchical way. For example, if a failure is caused by an invalid request, its code will begin with "InvalidRequest". The idea is that you can quickly test for broader types of failure code without having to know or itemize all the sub-types (like "InvalidRequestAccount" and "InvalidRequestSignature").
New codes may be added into the API at any time. New codes might be sub-types of existing types (like if "InvalidRequestSomeNewCode" was added as a sub-type of "InvalidRequest"), or they might be completely new (like "SomeCompletelyNewCode"). If you're writing logic that checks for different failure codes, make sure that it won't blow up if it comes across a code that it doesn't recognize.
Any request can fail completely for a variety of reasons. Here's an example of the sort of XML response you should expect if it does:
<Response> <!-- Note how the Metadata comes through as usual even though the request failed. This is expected, you can rely on the Metadata being there. --> <Metadata> <RateLimit> <RequestUnitsAvailable>1954</RequestUnitsAvailable> <MinutesToReset>11</MinutesToReset> </RateLimit> </Metadata> <!-- Note how there's a Failure instead of the LocationDataResponse or LocationInfoResponse you'd usually expect. --> <Failure> <Code>LocationNotRecognized</Code> <Message>Sorry, we do not recognize the location that you specified. Our postal-code database did not recognize the specified PostalCodeLocation, and was consequently unable to find its longitude/latitude position.</Message> </Failure> </Response>
Here are some failure codes you might see:
Location
failures (all codes starting with "Location"):
LocationNotRecognized
– if you request data from a location that the API does not recognize as a weather station or real-world geographic location. This type of failure will occur if you specify a StationIdLocation
with an unrecognized ID, or a PostalCodeLocation
with an unrecognized postal code (or with the wrong country code).LocationNotSupported
– if you request data from a location that is recognized but not currently supported by the API. This can happen if you request data from a LongLatLocation
or PostalCodeLocation
for which the API is unable to find a good weather station, or if you request data from a StationIdLocation
specifying a weather station that has stopped working. For more information on this failure, see here.RateLimit
failures (all codes starting with "RateLimit"):
RateLimit
– if you've hit your rate limit. You can check the Metadata
to see how many minutes you will have to wait until it resets. If this happens a lot, you might want to upgrade your account (just email us at info@degreedays.net
if so).RateLimitOnLocationChanges
– rate limit on the number of times a low-end location-limited account can change the location(s) that they access data from. You probably won't need to special-case this – it starts with "RateLimit" and that is probably all that matters. But there's more information here if you want it.InvalidRequest
failures (all codes starting with "InvalidRequest"):
InvalidRequestDeliveryFormat
– this means there's something wrong with the way you sent the request. Typically it means you've not included all the request parameters mentioned above, or their values aren't in the expected format.InvalidRequestXml
– this means your XML (encoded within the encoded_request
parameter) does not match the expected format. If it helps, feel free to email us at info@degreedays.net to ask for the XML schema – it's not very well documented but our API servers use it for validation and you are welcome to do the same.InvalidRequestAccount
– if a request is sent with an unrecognized account key.InvalidRequestForAccountPlan
– if you request hourly temperature data through one of the lower-level API account plans that doesn't support it.InvalidRequestSignature
– if a request is sent with an invalid signature, either because of an error in the security key or an error in the code that uses that key to generate the signature.InvalidRequestTimestamp
– if a request is sent with an invalid timestamp, typically caused by an out-of-sync clock on the client machine.Service
failures (all codes starting with "Service"):
ServiceTemporarilyDown
– a temporary problem preventing the API service from functioning properly (sorry!).ServiceUnexpectedError
– a unexpected error in the API service (sorry again!).The list above is not complete, and more failure codes may be added at any time. Instead of trying to get your system to handle them all, we suggest you just watch out for the codes you want to do something specific with. Always test for codes with e.g. code.startsWith("LocationNotRecognized")
so that your system will be able to handle us adding new sub-types of the codes you're watching out for.
DataSet
failure (a partial failure)A LocationDataRequest
can succeed partially, but some or all of its keyed DataSpec
/DataSet
items can fail. For example, you might specify that you want data from 100 years ago from a specific PostalCodeLocation
. The API might find a good weather station to match the postal code (partial success), but not one with coverage going that far back in time (partial failure).
In such instances, you can expect to receive a Failure
element in place of the DataSet
that you would usually receive if everything had worked. The Failure
will have a key
attribute matching the key of the corresponding DataSpec
from your request.
<Response> <Metadata> <!-- details omitted for clarity --> </Metadata> <LocationDataResponse> <Head> <!-- details omitted for clarity --> </Head> <DataSets> <!-- successful DataSet items omitted for clarity --> <Failure key="keyOfCorrespondingDataSpecFromRequest"> <Code>SourceDataCoverage</Code> <Message>Sorry, the source does not have enough recorded temperature readings for us to be able to generate data covering enough time to satisfy your specification.</Message> </Failure> <!-- successful DataSet items omitted for clarity --> </DataSets> </LocationDataResponse> </Response>
LocationInfoResponse
If you submit a LocationInfoRequest
you'll get a LocationInfoResponse
back. LocationInfoResponse
is basically just LocationDataResponse
without the <DataSets>
element. It contains the <Head>
element only. And of course the XML says "<LocationInfoResponse>
" instead of "<LocationDataResponse>
".
Beyond these differences, LocationInfoResponse
is identical to LocationDataResponse
(including the same request-failure possibilities), and you should be able to re-use most of your parsing code.
You can try this out with the XML API test tool by copy/pasting in the example LocationDataRequest
further above, changing "<LocationDataRequest>
" to "<LocationInfoRequest>
" and "</LocationDataRequest>
" to "</LocationInfoRequest>
", and sending it to the API to get a LocationInfoResponse
back.
This page focuses on the technical details, but is also worth reading the higher-level integration guide for tips on the various approaches to integrating with the API. We have helped a lot of businesses integrate their software with our API so we are very familiar with the patterns that work well for common use cases.
© 2008–2024 BizEE Software – About | Contact | Privacy | Free Website | API | Integration Guide | API FAQ | API Sign-Up