Welcome to the FreightWaves API Help Page!
This document will serve as your guide as you navigate the various methods available to our clients. Start by getting credentials and you can try the methods directly in the browser or through tools like Postman (we recommend highly!).

The first call will be for the authentication token, found here: /Credential/authenticate

Every subsequent call will use this token. Please be sure to refresh your token daily!

Our global rate limit is 100 requests per minute, but please refer to the response headers for potential individual limits.

If you cannot find the answer you are looking for in this document, please feel free to reach out to us at any time at contact: apisupport@freightwaves.com
Getting Started
Starting Up with the FreightWaves API
  To start using the API, you must first get an Authentication Token from the Credential Section using the Authenticate Method. If you are using the website, you can simply click the area under Body Sample and it will auto fill the userCredentials box with the proper format for you to enter your information. Otherwise, this should be in the format of:

{
"username": "Your Username Here",
"password": "Your Password Here"
}

  Assuming credentials are valid, the method will return an Authentication Token which will be valid for 1 Year. To get a new token, simply authenticate again. This will not invalidate any previously recieved token either, so it may be helpful in certain scenarios. FreightWaves handles the limits on accounts on the backend so the user does not have to worry about any of it, just get the token and you are set. Many of the messages have been designed to help you understand what went wrong. If at any point you are unsure or need more information, please feel free to contact us. There are 3 primary Data calls to retrieve Ticker information and they have been broken down into Item, Level, and Lane (each seperated into by date and by date range respectively). The primary call to retrieve a known valid ticker is the Item calls. It has the URL in the example format of https://api.freightwaves.com/data/OTRI/ATL/2019-02-20 (/2019-02-22 for range)

  To retrieve data from the API, the header must be appended with the token in the format: Authorization: Bearer token-here . For more specific code example information, scroll down to the example code section and utilize some of our example get requests to become more familiar with the API. For more in depth analysis and understanding, Postman is a useful tool to figure out the proper methodology and also provides code samples as well. There are several others as well and again you may reach out to us at anytime for more information or to become better aquainted with the system.

  From here, you can begin to access the API in earnest. Many of the calls use very specific terminology and require a bit of market understanding to properly utilize. In this section, we will describe the various terminology in detail.
List of Terms Used by FreightWaves API
Ticker
  There are many tens of thousands of data sets available in SONAR, and they are organized using a scheme of tickers. Much like a stock market ticker, the SONAR tickers describe the index being evaluated, as well as a qualifier that is used to display the index to the desired level of granularity. The Ticker is simply an index with a qualifier. Example ticker OTRI.ATL (Outbound Tender Reject Index for Atlanta)
Index
  The first portion of a ticker and indicates the data set being queried. Many values are updated daily, but some are updated Weekly or Monthly (checking Frequency will tell you how often we udpate a given Ticker). Check the LookUp call Indexes for more information and a complete list of valid indexes.
Qualifier
  The second and final portion of a ticker and indicates the market, region, city, lane, or general area that the ticker reflects upon. There are a great deal of qualifiers, but not all index and qualifier combinations represent a valid Ticker. For more information on valid tickers, use the LookUp call Qualifiers and Valid Tickers for more information.
Qualifier Level (Qualifier Code)
  This is one of the new additions to the new API. Qualifiers exist in groupings like NATIONAL and XMKT (refered to as Qualifier Code). This query allows you to search for all of the tickers that exist at a particular index and are part of a that Qualifier Level. For instance, OTRI.ATL would be the normal call if interested in Atlanta, but if you wanted more specific information about all of our X-Market data associated with OTRI, you would use the Levels query for OTRI.XMKT (which would return a large list of tickers for even a single day). For more information, use the LookUp call for Levels to determine what levels may be of interest in pulling bulk lists of Tickers. This call is intended to save query time by allowing for a broader return data set.
Qualifier Lane
  This is another new addition to the new API. One of the Qualifier Level types is specifically called Lanes. This is a direct reference to currently active shipping lanes. There are a large number of valid shipping lanes, but this call is specifically used to get ALL inbound and outbound lanes concerning a specific area. For example, the lanes query for OTRI.ATL would return all of our Inbound/Outbound lanes to/from Atlanta. For more information, use the LookUp call for Lanes to determine what lanes specific information you need. This call is intended to help target specific Lane data and save query time with those Lanes specifically.
Dates
  Dates are mainly self explanitory, but we do allow searching based on a specific Date-Time (which is not recommended), a specific Date, a specific Date range, or a specific Date-Time range.
Zip3
  Zip 3 is simply just the first 3 digits in a zipcode. The LookUp call Zip3 and Zip3 specific can give you the full list of Zip3's or the Specific Zip3's location data and how it relates to our markets.
Latest Data
  The LookUp call for Latest Data allows the user to search for a specific ticker's most recent data point. This will allow the user to determine how recent the data is for a given index and determine if they need to pull.
Frequency
  This is the rate which we update the particular Ticker. This value translates like this: A = Annually, Q = Quaterly, W = Weekly, F = Fortnight (Every other week), M = Monthly, D = Daily, I = Intra-Day (updated throughout the day multiple times). These can help you determine at which intervals you need to check for new data to prevent bad queries or duplicate data.
Rate Limits For the FreightWaves API
Rate Limiting
  FreightWaves API implements rate limiting for added security and to ensure the availability of data for all customers. Rate limits may vary by endpoint, so please evaluate the response headers returned from each request to direct your processes to pause or slow down as needed.

We rate limit our customers in 2 ways primarily:

1) We limit the number of RECORDS that can be pulled during a given time frame. This is negotiable with the FreightWaves Customer Success Team. For instance, we may allow a client to pull 10,000 records (rows of data) a day. Note that this does not mean "unique" data, so be sure to have local storage to eliminate duplicate queries.

2) We limit the number of REQUESTS per minute. This is fixed and is non-negotiable. Each endpoint will have its on Requests Per Limit Rate, so make sure to refer to the response headers for more specific rate limit information.

  Please note that many RECORDS can be retrieved per REQUEST. Here is a rough overview of why we've made the decision we have: "Everything You Need to Know About API Rate Limiting"

  In the event of too many requests, we will send back a code 429: Too many requests. This will mean that you have exceeded the current request per minute threshold. To prevent this, simply add a wait into your API query to prevent too many calls from executing at once.

For the most up to date information at any given time, check the various response headers with each call, the x-rate-limit object should provide all the necessary information.
Exceeding Rate Limits
  If you exceed the rate limit, you will receive a 429 (too many requests) status code. Upon receiving this status code, you should immediately halt all requests until the time specified by the x-rate-limit-reset header. You can evaluate the x-rate-limit-remaining and x-rate-limit-limit headers to help determine how many requests can be made before you exceed the limit. If you fail to assess the response headers,this could result in inconsistent data, application errors, or blacklisting.
Lookup Information
  As a general note, we do not charge customers for any lookup API calls. These exist to help the client build out a suitable way to tie everything into their own database.

  There are 2 primary methods for looking up information, Data and Lookup. The Lookup methods allow authenticated users to find what tickers, lanes, and levels are available for searching as outlined above. The Data methods will charge you for use, but allow the users to search specific tickers based on lanes and levels for a single date or date ranges. These should all be determined before using the Data calls. For a more in-depth look at what our data means, start here: FreightWaves Knowledge Center
Rate Limit Blacklist
  FreightWaves API has additional security built-in to prevent abuse via blacklisting. Blacklisting occurs when a process continues to query the API after the rate or record limit has been exceeded. Blacklisting times depend on how many subsequent requests are made after the limit has been exceeded and communicated back to the client. The typical time frame for lock-out is 10 minutes. As long as the process is stopped without continuing to attempt queries during this time frame, their should be no issues after the time frame is up. We are the major source for many organization's critical data infrastructure, so these security measures are to protect us as much as you the customer. Please let our customer success team know at any point if you become inconvenienced in any way.
API Get Request Code Examples
API Get Request Example for: C(LibCurl)
GET /data/OTRI/ATL/02-20-2019 HTTP/1.1
Host: api.freightwaves.com
Authorization: Bearer your token here
API Get Request Example for: HTTP
CURL *hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(hnd, CURLOPT_URL, "https://api.freightwaves.com/data/OTRI/ATL/02-20-2019");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Authorization: Bearer your token here");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "undefined=");
CURLcode ret = curl_easy_perform(hnd);
API Get Request Example for: cURL
curl -X GET \
https://api.freightwaves.com/data/OTRI/ATL/02-20-2019 \
-H 'Authorization: Bearer your token here' \
-d undefined=
API Get Request Example for: C# (RestSharp)
var client = new RestClient("https://api.freightwaves.com/data/OTRI/ATL/02-20-2019");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer your token here");
IRestResponse response = client.Execute(request);
API Get Request Example for: Go
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://api.freightwaves.com/data/OTRI/ATL/02-20-2019"
payload := strings.NewReader("undefined=")
req, _ := http.NewRequest("GET", url, payload)
req.Header.Add("Authorization", "Bearer your token here")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
API Get Request Example for: Java (OK HTTP)
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "undefined=");
Request request = new Request.Builder()
.url("https://api.freightwaves.com/data/OTRI/ATL/02-20-2019")
.get()
.addHeader("Authorization", "Bearer your token here")
.build();
Response response = client.newCall(request).execute();
API Get Request Example for: Javascript (JQuery AJAX)
var settings = {
"async": true,
"crossDomain": true,
"url": "https://api.freightwaves.com/data/OTRI/ATL/02-20-2019",
"method": "GET",
"headers": {
"Authorization": "Bearer your token here",
},
"data": {}
}
$.ajax(settings).done(function (response) {
console.log(response);
});
API Get Request Example for: NodeJS Request
var request = require("request");
var options = { method: 'GET',
url: 'https://api.freightwaves.com/data/OTRI/ATL/02-20-2019',
headers:
{ Authorization: 'Bearer your token here' },
form: { undefined: undefined } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
API Get Request Example for: Objective C (NSURL)
#import Foundation/Foundation.h
NSDictionary *headers = "@{ @"Authorization": @"Bearer your token here" };
NSMutableData *postData = [[NSMutableData alloc] initWithData:[@"undefined=undefined" dataUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.freightwaves.com/data/OTRI/ATL/02-20-2019"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"GET"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume]
API Get Request Example for: OCaml (Cohttp)
open Cohttp_lwt_unix
open Cohttp
open Lwt
let uri = Uri.of_string "https://api.freightwaves.com/data/OTRI/ATL/02-20-2019" in
let headers = Header.init ()
|> fun h -> Header.add h "Authorization" "Bearer your token here"
let body = Cohttp_lwt_body.of_string "undefined=" in
Client.call ~headers ~body `GET uri
>>= fun (res, body_stream) ->
API Get Request Example for: PHP (HttpRequest)
?php
$request = new HttpRequest();
$request->setUrl('https://api.freightwaves.com/data/OTRI/ATL/02-20-2019');
$request->setMethod(HTTP_METH_GET);
$request->setHeaders(array(
'Authorization' => 'Bearer your token here'
));
$request->setContentType('application/x-www-form-urlencoded');
$request->setPostFields(array(
'undefined' => null
));
try {
$response = $request->send();
echo $response->getBody();
} catch (HttpException $ex) {
echo $ex;
}
API Get Request Example for: Python (Requests)
import requests
url = "https://api.freightwaves.com/data/OTRI/ATL/02-20-2019"
payload = ""
headers = { 'Authorization': "Bearer your token here }
response = requests.request("GET", url, data=payload, headers=headers)
print(response.text)
API Get Request Example for: Ruby (NET:http)
require 'uri'
require 'net/http'
url = URI("https://api.freightwaves.com/data/OTRI/ATL/02-20-2019")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer your token here'
request.body = "undefined="
response = http.request(request)
puts response.read_body
API Get Request Example for: Shell cURL
curl --request GET \
--url https://api.freightwaves.com/data/OTRI/ATL/02-20-2019 \
--header 'Authorization: Bearer your token here' \
--data undefined=
API Get Request Example for: Swift (NSURL)
import Foundation
let headers = [ "Authorization": "Bearer your token here" ]
let postData = NSMutableData(data: "undefined=undefined".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "https://api.freightwaves.com/data/OTRI/ATL/02-20-2019")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()