Skip to main content

Overview

The Forerunner API uses conventional HTTP status codes to indicate the success or failure of requests. This guide helps you understand error responses and resolve common issues.

HTTP Status Codes

Success Codes

CodeMeaningDescription
200OKRequest succeeded
201CreatedResource created successfully
204No ContentRequest succeeded with no response body

Client Error Codes

CodeMeaningDescription
400Bad RequestInvalid request syntax or parameters
401UnauthorizedMissing or invalid API key
403ForbiddenValid credentials but insufficient permissions
404Not FoundRequested resource does not exist
409ConflictResource already exists (duplicate externalSystemId)
422Unprocessable EntityRequest syntax is valid but contains semantic errors
429Too Many RequestsRate limit exceeded

Server Error Codes

CodeMeaningDescription
500Internal Server ErrorUnexpected server error occurred
502Bad GatewayTemporary server issue, retry with backoff
503Service UnavailableServer is temporarily unavailable
504Gateway TimeoutRequest timed out, retry with backoff

Error Response Format

All error responses follow a consistent JSON structure with an errors array:
{
  "errors": [
    {
      "message": "Human-readable error description",
      "field": "fieldName or path.to.field"
    }
  ],
  "file": null
}
Error responses also include endpoint-specific fields (like file, sisd, property, properties) set to null or empty arrays.

Example Error Responses

{
  "errors": [
    {
      "field": "fileType",
      "message": "Could not find AccountDocumentType with name invalidType for account abc123. Must be one of elevation_certificate, flood_map"
    }
  ],
  "file": null
}

Common Errors

Authentication Errors

Cause: API key is malformed, missing, or invalidSolution:
  • Verify API key is correctly formatted
  • Ensure Bearer prefix is included in Authorization header
  • Check for extra whitespace in API key value
  • Add Authorization header to all requests
  • Contact your Customer Success Manager for a new API key if expired
// Correct format
headers: {
  'Authorization': 'Bearer YOUR_API_KEY'
}
# Example with cURL
curl https://app.withforerunner.com/api/v1/properties \
  -H "Authorization: Bearer YOUR_API_KEY"

Validation Errors

Cause: Required parameter not provided in requestError example:
{
  "errors": [
    {
      "field": "value",
      "message": "Required field 'value' is missing"
    }
  ]
}
Solution:
  • Check API documentation for required fields
  • Ensure all required fields are included in request body
// Missing required field
{
  "type": "damage"
  // Missing: value, date
}

// Correct
{
  "type": "damage",
  "value": 125000,
  "date": "03/15/2024"
}
Cause: Date provided in incorrect formatError example:
{
  "errors": [
    {
      "field": "date",
      "message": "Date must be in MM/DD/YYYY format"
    }
  ]
}
Solution:
  • Use MM/DD/YYYY format for date fields
  • Ensure leading zeros for single-digit months/days
// Incorrect
{ "date": "2024-03-15" }

// Correct
{ "date": "03/15/2024" }
Cause: Unsupported or incorrect file type specifiedError example:
{
  "errors": [
    {
      "field": "fileType",
      "message": "Could not find AccountDocumentType with name invalidType"
    }
  ]
}
Solution:
  • Use valid file types provided by your account configuration
  • Check for typos in fileType parameter
  • Common types include: elevation_certificate, permit, map, photo, letter
// Incorrect
{ "fileType": "elevation-certificate" }

// Correct
{ "fileType": "elevation_certificate" }
Cause: Malformed GeoJSON coordinates or geometrySolution:
  • Ensure GeoJSON follows standard format
  • Verify longitude comes before latitude: [longitude, latitude]
  • Validate GeoJSON structure with type and coordinates
// Incorrect
{
  "coordinates": {
    "lat": 39.78,
    "lng": -89.65
  }
}

// Correct
{
  "type": "Point",
  "coordinates": [-89.65, 39.78]
}
Cause: Resource ID is not a valid UUIDError example:
{
  "errors": [
    {
      "field": "id",
      "message": "Invalid UUID format for id parameter"
    }
  ]
}
Solution:
  • Ensure resource IDs are valid UUIDs
  • Verify you’re using the correct ID from previous API responses

Resource Errors

Cause: Requested resource does not existSolution:
  • Verify resource ID is correct
  • Ensure resource hasn’t been deleted
  • Check you’re querying the correct environment (staging vs production)
Cause: Could not match address or parcel to a propertyError example:
{
  "errors": [
    {
      "field": "address",
      "message": "Could not find property matching the provided address"
    }
  ]
}
Solution:
  • Verify address format and spelling
  • Ensure property exists in your organization’s database
  • Try using parcel ID or coordinates if address matching fails
  • Provide multiple identifiers for better matching
// Provide multiple identifiers for better matching
{
  "address": "123 Main St, Springfield, IL",
  "parcelId": "12-34-567-890",
  "coordinates": {
    "type": "Point",
    "coordinates": [-89.65, 39.78]
  }
}
Cause: Attempted to modify address, parcelId, or coordinates on existing recordSolution:
  • Geospatial information cannot be changed after record creation
  • Delete the record and create a new one with correct location
  • Or keep existing record and update only non-geospatial fields
Cause: Resource with the same external system ID already existsError example:
{
  "errors": [
    {
      "field": "externalSystemId",
      "message": "Document upload already exists with external system id 12345"
    }
  ]
}
Solution:
  • Use a unique external system ID for each resource
  • Update the existing resource instead of creating a new one
  • Or omit the externalSystemId if not needed

File Upload Errors

Cause: Uploaded file exceeds size limitSolution:
  • Compress or resize files before upload
  • Split large documents into smaller files
  • Contact support if you need higher limits
Cause: File format is not supported for the specified document typeError example:
{
  "errors": [
    {
      "field": "mimeType",
      "message": "MIME type \"image/jpeg\" is not allowed for document type \"elevation_certificate\""
    }
  ]
}
Solution:
  • Convert to supported format (PDF for elevation certificates, etc.)
  • Check file extension matches actual file type
  • Verify MIME type is allowed for your document type
Cause: File upload not sent as multipart/form-dataSolution:
  • Set Content-Type header to multipart/form-data
  • Use proper file upload mechanism with FormData
const formData = new FormData();
formData.append('fileUpload', file);

fetch('https://app.withforerunner.com/api/v1/files', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
    // Do NOT set Content-Type, let browser set it with boundary
  },
  body: formData
});

Implementing Error Handling

Basic Error Handling

async function makeApiRequest(url, options) {
  try {
    const response = await fetch(url, {
      ...options,
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json',
        ...options.headers
      }
    });

    const data = await response.json();

    // Check for errors in response
    if (data.errors && data.errors.length > 0) {
      console.error('API Errors:', data.errors);

      // Format error messages
      const errorMessages = data.errors
        .map(err => `${err.field}: ${err.message}`)
        .join(', ');

      switch (response.status) {
        case 400:
          throw new Error(`Bad Request: ${errorMessages}`);
        case 401:
          throw new Error('Authentication failed. Check your API key.');
        case 404:
          throw new Error(`Resource not found: ${errorMessages}`);
        case 409:
          throw new Error(`Conflict: ${errorMessages}`);
        case 422:
          throw new Error(`Validation error: ${errorMessages}`);
        case 429:
          throw new Error('Rate limit exceeded. Retry after delay.');
        case 500:
          throw new Error('Server error. Please try again later.');
        default:
          throw new Error(`API error: ${errorMessages}`);
      }
    }

    return data;
  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  }
}

Exponential Backoff for Retries

Implement exponential backoff for transient errors (500, 502, 503, 504):
async function makeRequestWithRetry(url, options, maxRetries = 3) {
  let lastError;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      const data = await response.json();

      // Don't retry client errors (4xx)
      if (response.status >= 400 && response.status < 500) {
        if (data.errors && data.errors.length > 0) {
          const errorMessages = data.errors
            .map(err => `${err.field}: ${err.message}`)
            .join(', ');
          throw new Error(errorMessages);
        }
        throw new Error('Client error occurred');
      }

      // Retry server errors (5xx)
      if (response.status >= 500) {
        throw new Error(`Server error: ${response.status}`);
      }

      // Check for errors even with 200 status
      if (data.errors && data.errors.length > 0) {
        const errorMessages = data.errors
          .map(err => `${err.field}: ${err.message}`)
          .join(', ');
        throw new Error(errorMessages);
      }

      return data;

    } catch (error) {
      lastError = error;

      // Only retry on server errors (5xx)
      if (error.message.includes('Server error') && attempt < maxRetries - 1) {
        // Exponential backoff: 1s, 2s, 4s
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Retry attempt ${attempt + 1} after ${delay}ms`);
        await new Promise(resolve => setTimeout(resolve, delay));
      } else {
        break;
      }
    }
  }

  throw new Error(`Request failed after ${maxRetries} attempts: ${lastError.message}`);
}

Best Practices

Don’t just handle successful responses. Plan for and gracefully handle all possible error scenarios.
For 5xx errors and timeouts, use exponential backoff with jitter to avoid overwhelming the server.
Include timestamps, request details, and full error responses in your logs for easier debugging.
4xx errors indicate issues with your request. Retrying won’t help - fix the request instead.
Track error rates and response times to detect issues early.
Validate data client-side before making API requests to catch issues early and reduce unnecessary requests.

Debugging

Log all requests and responses to diagnose issues:
console.log('Request:', url, options);
console.log('Response:', response);

Getting Help

If you’re experiencing issues not covered in this guide:
1

Check API status

Verify there are no ongoing incidents or maintenance
2

Review your request

  • Confirm all required parameters are included
  • Verify data types and formats match documentation
  • Check authentication header is correct
3

Gather debugging information

  • Request ID from error response
  • Full error message and status code
  • Example request that reproduces the issue
  • Timestamp when error occurred
4

Contact support

Email engineering@withforerunner.com with your debugging information