Loading...

Getting Started

Introduction

This public API is built using the light-weight architecture REST. Our API takes advantage of HTTP requests to post any data requests. This API encodes all requests, response bodies, and error codes in JSON.

Users are provided access to exclusive sandbox environment to test the application with live characteristics. The API uses authentication keys to validate every request received and grant further access to the API.

Through our different API endpoints, users can create, update, validate, and transmit the IRS tax returns. The API uses the concept of webhooks to instantly communicate the sender on status of tax forms. It also allows the sender to place a PDF download request through Webhooks.

OAuth 2.0 Authentication

OAuth2.0 is a HTTP authentication scheme that involves security tokens called Access tokens or JSON Web Tokens (JWT). Each request is authenticated with the access token.

The access token is a cryptic string, usually generated by the server in response to a request. The client must send this token in the Authorization header when making requests to protected resources.

Here are the steps on how you can get the JWT from Public API(api.expresstrucktax.com):

Authentication Server URL:

Sandbox: https://testoauth.expressauth.net/v3/ettauth (opens new window)
Live: https://oauth.expressauth.net/v1/ettauth (opens new window)

Step 1: Retrieve the Authentication Keys

Retrieve the below 3 keys in Console site using your credentials. Navigate to Settings >> API Credentials

  • Client ID
  • Client Secret
  • User Token
Note: Do not share the keys with any individual or business.



Step 2: Request the Access Token


To request an Access Token, you need to create a signature (JSON Web Signature) for Authentication. The JWS consists of 3 parts as given below,


  • Header

  • Payload

  • Signature


Header:


    {
      "alg": "HS256", /*Algorithm = HS256*/
      "typ": "JWT" /*Type = JSON Web Token (JWT)*/
    }


Payload:


    {
      "iss": "968a9c78dae29a29", /*Issuer: Client ID retrieved from the console site*/
      "sub": "968a9c78dae29a29", /*Subject: Client ID retrieved from the console site*/
      "aud": "a574b75f18b24fc09f9039ffb5cb08f3", /*Audience: User Token retrieved from the console site*/
      "iat": 1516239022 /*Issued at: Number of seconds from Jan 1 1970 00:00:00 (Unix epoch format)*/
    }

Signature:



    HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    siqHfLy59g3UHxrb5gjxg /*Client Secret retrieved from the console site*/
    )

Combine the Header, payload and signature to create the JWS.



Sample JWS



    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOi
    I5NjhhOWM3OGRhZTI5YTI5Iiwic3ViIjoiOTY4YTljNzhkYWUyOWEyOSIsImF1
    ZCI6ImE1NzRiNzVmMThiMjRmYzA5ZjkwMzlmZmI1Y2IwOGYzIiwiaWF0IjoxN
    TE2MjM5MDIyfQ.HNQznxlPyVt62kyUeVwtk1-uzm1uDWH4NBDLShA6Ac0

Once the JWS is created, then send a request to the Authentication Server for an Access token.



2.1: Generate JWS Key(Client-Side)



index.js
    //Base64 URL encoding
    function base64url(source)
    {
    // Encode in classical base64
    encodedSource = CryptoJS.enc.Base64.stringify(source);
    // Remove padding equal characters
    encodedSource = encodedSource.replace(/=+$/, '');
    // Replace characters according to base64url specifications
    encodedSource = encodedSource.replace(/\+/g, '-');
    encodedSource = encodedSource.replace(/\//g, '_');
    return encodedSource;
    };
    //To generate Header and Payload
    var header = {
    "alg": "HS256",
    "typ": "JWT"
    };
    var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
    var encodedHeader = base64url(stringifiedHeader);
    //Unix epoch time formula
    var time = Math.floor(new Date().getTime()/1000.0);
    var payloaddata = {
      "iss": {Your Client ID},/*Issuer: Client ID retrieved from the console site*/
      "sub": {Your Client ID},/*Subject: Client ID retrieved from the console site*/
      "aud": {User Token},/*Audience: User Token retrieved from the console site*/
      "iat": time /*Current UTC date & time*/
    };
    console.log(time);
    var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(payloaddata));
    var encodedPayloadData = base64url(stringifiedData);
    var headerPayload = encodedHeader + "." + encodedPayloadData;
    // To generate JWS Key
    var secretID = "RmyCGbkn2oeh4kENn4eiVPrCx7w8vsycsoRbOhSlK0y=";
    var signature = CryptoJS.HmacSHA256(headerPayload, secretID);
    signature = base64url(signature);
    var jws = headerPayload + "." + signature; //computed JWS Key


2.2: Generate JWS Key(Server-Side)


This method is used to generate the access token using c#(server side). We have to install necessary library to generate the JWS key.

Generate JWS key and access token

Below is the sample code for generating a JWS key as well as access token by invoking v1/ettauth endpoint using c#.

To work with JWS in C#, we have to install the below library. we can install package through Nuget Package Manager in Visual Studio or by using command line console.

    Install-Package System.IdentityModel.Tokens.Jwt

Example:



Program.cs
    using System;
    using System.IdentityModel.Tokens.Jwt;
    using System.Net.Http.Headers;
    using System.Security.Claims;
    using Microsoft.IdentityModel.Tokens;

    string secretKey = "your-client-secret-key";
    // client secret must have minimum 16 char length,
    // if you are facing any error related to length constraint,
    // please reach out to support for new secret key
    string issuer = "your-client-id";
    string audience = "your-user-token";
    HttpClient httpClient = new HttpClient();
    httpClient.BaseAddress = new Uri("https://sb-oauth.expresstrucktax.com/"); // oauth base URL
    httpClient.DefaultRequestHeaders.Clear();
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    // Generating JWS key
    string jwskey = GenerateJwsKey(secretKey, issuer, audience);

    Console.WriteLine($"JWS key: {jwskey}");

    if (!string.IsNullOrWhiteSpace(jwskey))
    {
        httpClient.DefaultRequestHeaders.Add("Authentication", jwskey); // Computed JWS key has been added in request header
        //retrive access token         string response = await httpClient.GetStringAsync("v1/ettauth"); // v1/ettauth end point invoked by GET method
        Console.WriteLine($"Access token response: {response}"); // This access token should be resued for all other subsequent request to all other endpoint except v1/ettauth.
    }
    else
    {
        Console.WriteLine($" Invalid JWS key");
    }
   
    // Method used to generate JWS key
    string GenerateJwsKey(string secretKey, string issuer, string audience, int expireMinutes = 30)
    {
    var securityKey = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(secretKey));
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
    var token = new JwtSecurityToken(
        claims:[
            new Claim ("sub",issuer),
            new Claim ("iat", ConvertToUnixEpochString(DateTime.UtcNow)) // token issue time should be unix format
        ],
        issuer: issuer,
        audience: audience,
        expires: DateTime.UtcNow.AddMinutes(expireMinutes),
        signingCredentials: credentials
        );
    var tokenHandler = new JwtSecurityTokenHandler();
    return tokenHandler.WriteToken(token);
    }
    //Utility method to datetime to unix format
    string ConvertToUnixEpochString(DateTime dateTime)
    {
        string unixEpoch = string.Empty;
        DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        if (dateTime != null && dateTime != DateTime.MinValue)
        {
            //Unix Epoch time calculation
            TimeSpan diff = dateTime.ToUniversalTime() - origin;
            unixEpoch = Math.Floor(diff.TotalSeconds).ToString();
            }
    return unixEpoch;
}


Note:


After generating JWS key, we have to add the same to the request header and have to invoke v1/ettauth which will provide access token (JWT).

Received Access token(JWT) to be in the following format:

Header:

    {
      "alg": "HS256", /*Algorithm = HS256*/
      "typ": "JWT" /*Type = JSON Web Token (JWT)*/
    }

Payload:


    {
      "iss": "968a9c78dae29a29", /*Issuer: Client ID retrieved from the console site*/
      "sub": "968a9c78dae29a29", /*Subject: Client ID retrieved from the console site*/
      "aud": "a574b75f18b24fc09f9039ffb5cb08f3", /*Audience: User Token retrieved from the console site*/
      "iat": 1516239022 /*Issued at: Number of seconds from Jan 1 1970 00:00:00 (Unix epoch format)*/
    }

Signature:



    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOi
    I5NjhhOWM3OGRhZTI5YTI5Iiwic3ViIjoiOTY4YTljNzhkYWUyOWEyOSIsImF1
    ZCI6ImE1NzRiNzVmMThiMjRmYzA5ZjkwMzlmZmI1Y2IwOGYzIiwiaWF0IjoxN
    TE2MjM5MDIyfQ.HNQznxlPyVt62kyUeVwtk1-uzm1uDWH4NBDLShA6Ac0


Step 3: Use the Access Token to send API Requests



Once you obtain the JWT (Access token), you can determine its expiry by the “ExpiresIn” value in the Response. You will have to use the same JWT along with every API request until the token expires.



Example:



URL: https://api.expresstrucktax.com/v1.7/doc/#api-Form2290-Create (opens new window)


    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3
    MiOiJ0ZXN0YXBpLnRheGJhbmRpdHMuY29tIiwiYXVkI
    joiYTU3NGI3NWYxOGIyNGZjMDlmOTAzOWZmYjVjYjA4ZjMiLCJp
    YXQiOjE1OTU5MjAxMjQsImV4cCI6MTU5NTkyNzMyNH0.BIg8764SOhOai9As
    3uRSidrF1-B9CxL6D5z4OggcVbs
    Content-Type: application/json

Creation of Tax Form

Explore the event sequence below that leads to the creation of a tax form. Once you send a request to the API, its authenticity is verified through a series of validation checks before the actual creation of the form begins.

Request from the sender: The sender sends an API request to the CREATE API Endpoint so as to create a form.

Authentication of the request: The request is validated for authenticity before it is processed further.

Data Validation: Once the request is authenticated, the data across all fields are subjected to validation. The API does basic validation checks for key fields like Business Name and EIN. If these fields pass the validation checks, the form is processed further, if not, the errors are updated through Response JSON.

Business Rule Validation: Records that clear data validation will be subjected to business validation checks. Here, the data are validated against a set of business rules. Records that fail business validation are updated through Response JSON along with the errors observed.

Process the Information: Records that clear business validation are processed further and their respective statuses are communicated in Response JSON through a collection of Success Records.

Create Form: The API will create forms for records that clear the business validation. The response to this create request will have a Submission ID and Record ID unique to a return which needs to be referenced for that particular return across all API calls.

Update Form: To update/change any information, an API request has to be sent to the UPDATE API Endpoint.

Validate Form: To validate a return for business rules, an API request has to be sent to the VALIDATE API Endpoint. Validation is generally done before transmitting the form to the IRS.

Transmit Form: When the return is ready for transmission, an API request has to be sent to the TRANSMIT API Endpoint. And then, the e-filing process is initiated.

Handling Errors in Response: In order to assist the sender to understand the error codes, the unique error codes are made available in Response JSON.

Receive the status of return using Webhooks: The API uses Webhooks to communicate the filing status to the sender. The Webhooks URL has to be configured in the Sandbox account.

Download PDF using Webhooks: An API request has to be sent to the GETPDF API Endpoint to download the PDF form. In turn, the request is processed offline, PDFs are generated and saved in a secure path. The sender is communicated on the secure location path through Webhooks.

Generate Transmittal forms using Webhooks: An API request has to be sent to the GETPDF API Endpoint to generate the transmittal forms like W-3, 1096, etc. In turn, the request is processed offline, PDFs are generated and saved in a secure path. The user is communicated on the secure location path through Webhooks.

Object Fields

The API uses some common object fields across all API Endpoints so as to make referencing easier. As a user, gaining familiarity with these fields will help understand what needs to be sent in the Request and how to interpret the data received in the Response.

Submission ID
Let’s presume that a request is sent to the CREATE API Endpoint. This request can have the data of multiple clients or a single client. Once the request hits the Endpoint, a submission ID is created.

What happens is that the information contained in a single request is tagged to a Submission ID. This is a GUID created at the API end and will be notified back to the sender (you) as part of the Response. From now on, the user must reference this Submission ID in the follow-up requests initiated for Update, Delete, Validate, List, Get and Transmit End Points.

Record ID
A unique GUID is assigned to every form that is created by the API. This ID must be referenced for any follow-up requests.

For example, if a user wants to delete a few forms that were created by the API, a request needs to be sent with the Submission ID and Record ID. Accordingly, the API will delete the forms tagged to that Record ID.

Sequence
It is a unique number that the sender assigns to each record at the time of submission. Since the records are not created at this juncture, record ID would not have been created and thus identifying the list of failed records from a large group becomes difficult. That’s where the object field Sequence comes into play. In case the records are errored out, the 'Sequence' may be used at the receiver end to identify the records. The sender has to pass this as part of the request against each of the form data.

The response will have the Sequence along with the error details so that it’s easier to pull the record and make necessary corrections before submitting it again.

Webhooks

The API uses webhooks to notify users on the status of tax forms filed. Through this, the API gains an advantage to send a notification through an HTTP post as well as to respond to the same request more information.

The user must configure webhooks from the developer control panel. Right now, the scope of this communication is limited to the status of tax forms.

API Webhook

Configure webhook

  1. Log in to the developer control panel. Go to Settings >> Webhooks.

  2. Enter the Callback URL and click on the Submit button. Ensure that the callback URL is valid as the API will post a sample JSON. The callback URL is expected to return HTTP 200 response code in order to remain active. If the API doesn’t return 200 response code, then the callback URL will go to inactive. You can retry posting the sample data to make the callback URL Active.


Receive webhook request from API
The API will issue an HTTP Post to the webhook URL every time when the status gets updated for a tax return. The request’s POST parameter will contain JSON data.

Respond to a webhook request from API
The user must respond to the webhook request by sending an HTTP 200 OK Response. Any other code other than 200 will be treated as an incomplete call. This API does not support 301 redirects, which will be treated as an error.

You are required to initiate a response to our webhook request within 5 seconds, if not, the request will be treated as timeout. If the API doesn’t receive a response during the 5-second time window or in case of an error, it will attempt to retry the connection for a total of 18 times over the next 48 hours.

We recommend users to respond to the webhook request at the earliest before initiating other internal communication processes. For example, if you wish to notify users whose returns were rejected by the IRS, the first thing you should do is to initiate a response to the webhook event by giving HTTP 200 OK response, and then attempt to email the rejected users. In this way, sending emails doesn’t get blocked while responding to webhook.

Security of Webhooks
Before you respond to a webhook request, validate if the request has been sent by the ExpressTruckTax Webhooks. To verify the authenticity, check if the webhook post has the signature on the header. And then, match it with the HMAC digest computed using the algorithm below. If both the components match, you can be assured that the webhook request was sent by ExpressTruckTax.

Below is what you need to do:
Step: 1 Retrieve the Public Key from the user repository. This is the same public key that was provided in the developer control panel.

Step: 2 Read the Timestamp and the Signature from the header.

Step: 3 Use the Public Key and the Timestamp to compute the HMAC hash using SHA 256 algorithm.

Step: 4 The signature generated in the header must match with the hash generated with Step 3.

  • If there is a match, parse the JSON data for further processing.
  • If there is no match, send the Response as 401 and stop processing.