Skip to main content

Error Handling and Troubleshooting

This guide explains how Terminal49’s API reports errors and provides strategies for troubleshooting and handling them effectively in your applications.

Understanding Error Responses

Terminal49’s API follows the JSON:API specification for error responses. When an error occurs, the API returns:
  1. An appropriate HTTP status code
  2. A JSON response with detailed error information
{
  "errors": [
    {
      "status": "422",
      "title": "Invalid attribute",
      "detail": "The SCAC 'UNKNOWN' is not supported.",
      "source": {
        "pointer": "/data/attributes/scac"
      },
      "code": "unsupported_scac"
    }
  ]
}

Error Object Properties

Each error object in the errors array includes:
status
string
The HTTP status code for this particular error (as a string).
title
string
A short, human-readable summary of the problem.
detail
string
A human-readable explanation with specific details about the error.
source
object
Information about the source of the error:
  • pointer: A JSON Pointer to the specific field that caused the error (e.g., “/data/attributes/scac”)
code
string
A machine-readable error code that can be used for programmatic handling (not always present).

Common HTTP Status Codes

Status CodeMeaningTypical Causes
400 Bad RequestThe request was malformed or invalidInvalid JSON, missing required fields
401 UnauthorizedAuthentication failedInvalid or missing API key
403 ForbiddenPermission deniedYour API key doesn’t have access to the requested resource
404 Not FoundResource not foundThe requested ID doesn’t exist
422 Unprocessable EntityValidation errorsInput validation failed
429 Too Many RequestsRate limit exceededYou’ve made too many requests in a short period
500, 502, 503Server errorsProblem on Terminal49’s side

Common Error Types and Solutions

Example:
{
  "errors": [
    {
      "status": "401",
      "title": "Unauthorized",
      "detail": "Invalid API key provided"
    }
  ]
}
Solutions:
  1. Check that you’re including the Authorization header with the correct format: Token YOUR_API_KEY
  2. Verify your API key is active in the Developer Settings
  3. Make sure the API key hasn’t been disabled
Example:
{
  "errors": [
    {
      "status": "422",
      "source": {
        "pointer": "/data/attributes/request_number"
      },
      "title": "Unprocessable Entity",
      "detail": "Request number 'ABCD1234567' with scac 'MAEU' already exists in a tracking_request with a pending or created status",
      "code": "duplicate"
    }
  ]
}
Solutions:
  1. Check the pointer field to identify which attribute caused the error
  2. Review the detail message for specific information about the validation failure
  3. For duplicate tracking requests, check if the shipment is already being tracked
  4. Verify SCAC codes against the supported carriers list
Example:
{
  "errors": [
    {
      "status": "404",
      "title": "Not Found",
      "detail": "Couldn't find Shipment with ID=123e4567-e89b-12d3-a456-426614174000"
    }
  ]
}
Solutions:
  1. Verify the ID you’re using exists and is correctly formatted
  2. Check if the resource might have been deleted
  3. Confirm you’re using the correct endpoint for the resource type
Example:
{
  "errors": [
    {
      "status": "429",
      "title": "Too Many Requests",
      "detail": "Rate limit exceeded. Please wait and try again later."
    }
  ]
}
Solutions:
  1. Implement retry logic with exponential backoff
  2. Spread requests over a longer period
  3. Contact Terminal49 support if you need a higher rate limit for your use case

Common Error Scenarios

Duplicate Tracking Requests

Error:
{
  "errors": [
    {
      "status": "422",
      "source": {
        "pointer": "/data/attributes/request_number"
      },
      "title": "Unprocessable Entity",
      "detail": "Request number 'MAEU1234567' with scac 'MAEU' already exists in a tracking_request with a pending or created status",
      "code": "duplicate"
    }
  ]
}
Solution: When you receive a duplicate error, you should:
  1. Look up the existing tracking request using the GET /tracking_requests endpoint with appropriate filters
  2. Use the ID of the existing request to fetch its current status
  3. If needed, you can update the existing tracking request rather than creating a new one

Unsupported Carrier

Error:
{
  "errors": [
    {
      "status": "422",
      "source": {
        "pointer": "/data/attributes/scac"
      },
      "title": "Unprocessable Entity",
      "detail": "Scac 'ABCD' is not supported",
      "code": "unsupported_scac"
    }
  ]
}
Solution:
  1. Reference the Carrier Data Matrix for a list of supported carriers
  2. Double-check the SCAC code format (usually 4 uppercase letters)
  3. If you need support for a specific carrier, contact Terminal49

Implementing Effective Error Handling

JavaScript Example

async function makeApiRequest(endpoint, method = 'GET', data = null) {
  try {
    const options = {
      method,
      headers: {
        'Authorization': `Token ${API_KEY}`,
        'Content-Type': 'application/vnd.api+json'
      }
    };

    if (data && (method === 'POST' || method === 'PATCH')) {
      options.body = JSON.stringify(data);
    }

    const response = await fetch(`https://api.terminal49.com/v2/${endpoint}`, options);
    const responseData = await response.json();

    // Check if the response contains errors
    if (!response.ok) {
      // Process errors
      if (responseData.errors) {
        const error = responseData.errors[0];

        switch (response.status) {
          case 401:
            throw new Error(`Authentication error: ${error.detail}`);
          case 404:
            throw new Error(`Resource not found: ${error.detail}`);
          case 422:
            const field = error.source?.pointer?.split('/').pop() || 'unknown field';
            throw new Error(`Validation error in ${field}: ${error.detail}`);
          case 429:
            // Implement retry with exponential backoff
            throw new Error(`Rate limit exceeded: ${error.detail}`);
          default:
            throw new Error(`API error ${response.status}: ${error.detail}`);
        }
      }

      throw new Error(`API request failed with status ${response.status}`);
    }

    return responseData;
  } catch (error) {
    console.error('API request failed:', error);
    throw error;
  }
}

Retry Strategy

When dealing with rate limiting or transient errors, implementing a retry strategy with exponential backoff is essential:
async function makeRequestWithRetry(endpoint, method = 'GET', data = null, maxRetries = 3) {
  let retries = 0;

  while (retries < maxRetries) {
    try {
      return await makeApiRequest(endpoint, method, data);
    } catch (error) {
      retries++;

      // If it's not a retriable error or we've used all retries, throw
      if (
        !error.message.includes('Rate limit exceeded') ||
        retries >= maxRetries
      ) {
        throw error;
      }

      // Exponential backoff with jitter
      const delay = Math.min(1000 * 2 ** retries + Math.random() * 1000, 60000);
      console.log(`Retrying after ${delay}ms (attempt ${retries} of ${maxRetries})...`);
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

Best Practices for Error Handling

  1. Always check for error responses
    • Parse the response body to look for the errors array
    • Handle both HTTP errors and JSON:API formatted errors
  2. Log detailed error information
    • Include the status code, error title, error detail, and any source information
    • Add context from your application (e.g., what operation was being attempted)
  3. Implement appropriate retry logic
    • Use exponential backoff for rate limiting (429) errors
    • Don’t retry for validation (422) or authentication (401) errors
  4. Present user-friendly error messages
    • Translate technical API errors to understandable messages for end-users
    • Provide actionable guidance when possible
  5. Monitor error rates
    • Set up alerts for unusual error patterns
    • Keep track of error frequency to identify potential issues with your integration

Getting Help

If you encounter persistent errors that you can’t resolve:
  1. Check the API Documentation for endpoint-specific requirements
  2. Ensure you’re using the latest version of the API
  3. Contact Terminal49 support at support@terminal49.com with:
    • The full error response (with headers if possible)
    • A description of what you were trying to do
    • Any relevant request IDs or resource IDs

Next Steps