Skip to content

Authentication

In order to access the core functionality of the OtterTax API, you must be authenticated. The API performs authentication by checking the HTTP headers for three values: access-token, client, and uid. These three values must be present in every call you make to the API or the call will fail.

To get a credential which includes these three values, send a request to the endpoint v2/auth/sign_in with a JSON payload as follows:

"email":    "<YOUR LOGIN EMAIL>",
"password": "<YOUR PASSWORD>"
The relevant values are returned in as header values.

The code snippets below illustrate how to get your credential in several different languages.

# Terminate lines with \ character to allow command to span multiple lines.
# Escape quotation marks in data stream with single backslashes.
# Tested using the bash interpreter on Linux.
curl 'https://sandbox.ottertax.com/v2/auth/sign_in' \
  -i \
  -X POST \
  -H 'content-type:  application/json' \
  -d "{ \"email\": \"YOUR LOGIN EMAIL\", \"password\": \"YOUR PASSWORD\" }"
# Output contains values for access-token, client, and uid
:: Terminate lines with ^ character to allow command to span multiple lines.
:: Escape quotation marks in data stream with single backslashes.
:: Tested using a command prompt on Windows 10.
curl "https://sandbox.ottertax.com/v2/auth/sign_in" ^
  -i ^
  -X POST ^
  -H "content-type: application/json" ^
  -d "{ \"email\": \"YOUR LOGIN EMAIL\", \"password\": \"YOUR PASSWORD\" }"
:: Output contains values for access-token, client, and uid
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.apache.http.entity.StringEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import com.ottertax.support.Credential;

public class CredentialFetcher {
  private String loginData = "{ \"email\": \"YOUR LOGIN EMAIL\",\n" +
                             "\"password\": \"YOUR PASSWORD\" }\n";
  private String endpoint = "https://sandbox.ottertax.com/v2/auth/sign_in";

  private void getCredential() {
    CloseableHttpClient httpClient = HttpClients.createDefault();
    Credential credential = new Credential();

    try {
      HttpPost httpPost = new HttpPost(endpoint);
      httpPost.addHeader("Content-Type", "application/json");

      StringEntity stringEntity = new StringEntity(loginData);
      httpPost.setEntity(stringEntity);
      CloseableHttpResponse httpResponse = httpClient.execute(httpPost);

      int responseCode = httpResponse.getStatusLine().getStatusCode();
      boolean headersPresent = (httpResponse.containsHeader("access-token") &&
                                httpResponse.containsHeader("client") &&
                                httpResponse.containsHeader("uid"));
      if( responseCode == 200 && headersPresent ) {
        String accessToken = httpResponse.getFirstHeader("access-token").getValue();
        String client = httpResponse.getFirstHeader("client").getValue();
        String uid = httpResponse.getFirstHeader("uid").getValue();
        credential = new Credential(accessToken, client, uid);
      } else {
        BufferedReader reader = new BufferedReader(new InputStreamReader(
            httpResponse.getEntity().getContent()));
        StringBuffer responseBuffer = new StringBuffer();
        String inputLine;
        while ((inputLine = reader.readLine()) != null) {
          responseBuffer.append(inputLine);
        }
        reader.close();
        System.out.println("Error retrieving credential.  Status code was " + String.valueOf(responseCode) + "." );
        System.out.println(responseBuffer.toString());
        System.out.println("Exiting.");
        System.exit(1);
      }
      httpResponse.close();
      httpClient.close();
    } catch(IOException e) {
      System.out.println("Error retrieving credential.\nExiting");
      System.exit(1);
    }
    // Print a JSON format version of the credential.
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    System.out.println(gson.toJson(credential));
  }

  public static void main(String[] args) {
    CredentialFetcher credentialFetcher = new CredentialFetcher();
    credentialFetcher.getCredential();
  }
}
// If using node, be sure to install and require node-fetch.
// Example tested with node version 14.16.0
const fetch = require("node-fetch");

const data = { email:    "YOUR LOGIN EMAIL",
               password: "YOUR PASSWORD" };
fetch( "https://sandbox.ottertax.com/v2/auth/sign_in",
      { method: "POST",
        headers: {"content-type": "application/json"},
        body: JSON.stringify(data) })
.then(response => {
  const accessToken = response.headers.get('access-token');
  const client = response.headers.get('client');
  const uid = response.headers.get('uid');
  console.log( 'access-token: ', accessToken );
  console.log( 'client:       ', client );
  console.log( 'uid:          ', uid );
})
.catch(err => console.log(err));
<?php
// Tested with php-cli version 8.0.5.
$data = array( 'email'    => 'YOUR LOGIN EMAIL',
               'password' => 'YOUR PASSWORD' );
$options = array(
  'http' => array(
    'method'  => 'POST',
    'content' => json_encode( $data ),
    'header'=>  "Content-Type: application/json\r\n"
    )
);

$context  = stream_context_create( $options );
$response = get_headers( 'https://sandbox.ottertax.com/v2/auth/sign_in',
                         1, $context );
if( $response === FALSE ) {
  print "Call to server failed.\n";
} else {
  print "access-token: ${response['access-token']}\n";
  print "client:       ${response['client']}\n";
  print "uid:          ${response['uid']}\n";
}
?>
# Tested using python version 3.8.8
import urllib.request
import json

url = "https://sandbox.ottertax.com/v2/auth/sign_in"
data = {
    "email":    "YOUR LOGIN EMAIL",
    "password": "YOUR PASSWORD"  
}
headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
}
body = json.dumps(data).encode("utf-8")

try:
    req = urllib.request.Request(url, body, headers)
    with urllib.request.urlopen(req) as f:
        info = f.info()
    print(f"access-token: {info['access-token']}")
    print(f"client:       {info['client']}")
    print(f"uid:          {info['uid']}")
except Exception as e:
    print(e)
# Tested using ruby 2.7.2.
require( 'net/http' )
require( 'uri' )
require( 'json' )

uri = URI( "https://sandbox.ottertax.com/v2/auth/sign_in" )
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Post.new( uri.request_uri,
                               { 'Content-Type': 'application/json' } )
request.body = JSON.generate( {'email' =>   'YOUR LOGIN EMAIL',
                              'password' => 'YOUR PASSWORD'} )
response = http.request(request)
if( response.code == '200' )
  STDOUT.puts( "\nCredential:" )
  STDOUT.puts( "  access-token:  #{response['access-token']}" )
  STDOUT.puts( "  client:        #{response['client']}" )
  STDOUT.puts( "  uid:           #{response['uid']}" )
else
  STDOUT.puts( "Response code was #{response.code}:\n#{response.inspect}" )
end

Before moving on, you may wish to test your authentication by accessing a protected query.