Skip to Content

Centermark Developer Portal

Welcome to Centermark’s internal developer portal. This hub explains how to integrate with the EFE Leads API
using clear technical references, working examples, and practical guidance for production use.

This documentation is intended for authenticated Centermark users only. It is not public and should not be shared
outside approved partner and client development teams.

What You Can Do Here

Use this portal to:

  • Understand authentication requirements and how credentials are used
  • Learn how to call the Leads endpoint correctly (request parameters, expected outputs)
  • Implement FMA ID logic consistently across environments
  • Copy/paste real integration examples (Node.js, C#, PHP, etc.)
  • Troubleshoot common errors and edge cases with known fixes

Start Here

  1. Read Getting Started for prerequisites and environment
    basics.
  2. Configure Authentication (required before any endpoint
    calls).
  3. Implement the Leads Endpoint using the parameter and payload
    reference.
  4. Review Code Examples to ensure you’re pulling and scoping data correctly.
  5. Validate against Errors & Troubleshooting before
    promoting to production.

Getting Started

The Enspire Leads API provides programmatic access to your lead feed data, allowing you to retrieve and integrate
lead information directly into your systems. This RESTful API delivers call, web form, and offer leads in real-time,
enabling automated workflows for lead distribution, tracking, and reporting.

What You Need

Before integrating with the API, ensure you have:

  • API Credentials – A username and password provided by Centermark
  • FMA ID – Your unique franchise/location identifier in the Centermark system
  • Base URLhttps://api.yodle.com
  • HTTPS Support – All requests must be made over secure connections
Integration Flow

A typical integration follows these steps:

  1. Authenticate using HTTP Basic Authentication with your provided credentials
  2. Call the Leads endpoint with your FMA ID and desired date range
  3. Process the returned lead data (calls, web forms, offers)
  4. Handle pagination if retrieving more than 1,000 leads
  5. Implement appropriate error handling and retry logic

The API returns structured JSON data containing lead details, contact information, attribution data, and timestamps.
Lead types include CALL (phone inquiries), WEB (form submissions), and OFFER (promotional engagements).


Authentication

The EFE Leads API uses HTTP Basic Authentication to secure all endpoint calls. Every request must include a
properly formatted Authorization header containing your credentials encoded in Base64.

How Authentication Works

Before making any API requests, you must authenticate using credentials provided by Centermark. Authentication
follows the standard HTTP Basic Authentication scheme:

  1. Combine your username and password with a colon separator: username:password
  2. Encode the combined string using Base64 encoding
  3. Prefix the encoded string with Basic (note the space after “Basic”)
  4. Include this value in the Authorization header of every API request
Required Header
Header Required Format Example
Authorization Yes Basic <base64_credentials> Basic dGVzdDp0ZXN0
Constructing the Authorization Header

Example credentials:

  • Username: your_username
  • Password: your_password

Step-by-step construction:

1. Combine: "your_username:your_password"
2. Base64 encode: "eW91cl91c2VybmFtZTp5b3VyX3Bhc3N3b3Jk"
3. Add prefix: "Basic eW91cl91c2VybmFtZTp5b3VyX3Bhc3N3b3Jk"
4. Set header: Authorization: Basic eW91cl91c2VybmFtZTp5b3VyX3Bhc3N3b3Jk
Code Examples

const axios = require('axios');

const username = 'your_username';
const password = 'your_password';
const fmaId = '123456';

// Create Base64 encoded credentials
const credentials = Buffer.from(`${username}:${password}`).toString('base64');
const authHeader = `Basic ${credentials}`;

const config = {
    headers: {
        'Authorization': authHeader
    }
};

axios.get(`https://api.yodle.com/api/v2/fma/${fmaId}/leads`, config)
    .then(response => console.log(response.data))
    .catch(error => console.error(error));

using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

public class LeadsApiClient
{
    private readonly HttpClient _httpClient;
    private readonly string _username = "your_username";
    private readonly string _password = "your_password";
    
    public LeadsApiClient()
    {
        _httpClient = new HttpClient();
        _httpClient.BaseAddress = new Uri("https://api.yodle.com");
        
        // Create Base64 encoded credentials
        var credentials = Convert.ToBase64String(
            Encoding.ASCII.GetBytes($"{_username}:{_password}")
        );
        
        _httpClient.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Basic", credentials);
    }
    
    public async Task GetLeads(int fmaId, DateTime startDate, DateTime endDate)
    {
        var url = $"/api/v2/fma/{fmaId}/leads?startDate={startDate:yyyy-MM-ddTHH:mm:ss}&endDate={endDate:yyyy-MM-ddTHH:mm:ss}";
        var response = await _httpClient.GetAsync(url);
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}

curl -X GET \
  'https://api.yodle.com/api/v2/fma/123456/leads?startDate=2024-01-01T00:00:00&endDate=2024-12-31T23:59:59' \
  -H 'Authorization: Basic eW91cl91c2VybmFtZTp5b3VyX3Bhc3N3b3Jk'

import requests
import base64

username = 'your_username'
password = 'your_password'
fma_id = '123456'

# Create Base64 encoded credentials
credentials = base64.b64encode(f'{username}:{password}'.encode()).decode()
headers = {
    'Authorization': f'Basic {credentials}'
}

url = f'https://api.yodle.com/api/v2/fma/{fma_id}/leads'
params = {
    'startDate': '2024-01-01T00:00:00',
    'endDate': '2024-12-31T23:59:59'
}

response = requests.get(url, headers=headers, params=params)
print(response.json())
Security Best Practices

Important: Base64 encoding is NOT encryption. It’s a reversible encoding scheme, meaning anyone
with access to your Authorization header can decode your credentials. Treat the encoded value with the same
security as you would treat a plaintext password.

  • Never hardcode credentials in source code or commit them to version control
  • Store credentials in environment variables or secure credential management systems (e.g., Azure Key Vault,
    AWS Secrets Manager, HashiCorp Vault)
  • Use configuration files that are excluded from version control (add to .gitignore)
  • Apply least-privilege principles: use credentials with minimum required permissions

Transmission Security:

  • All API calls must use HTTPS (enforced by the API endpoint)
  • Never send credentials over unencrypted HTTP connections
  • Do not log or display full authorization headers in application logs or error messages
Troubleshooting Authentication

If you receive authentication errors (401 Unauthorized), verify:

  • The Authorization header is present and correctly formatted
  • The header value starts with “Basic ” (with a space after Basic)
  • The Base64 encoding is correct (test by decoding to verify username:password format)

Testing Your Authentication:

# Quick test to verify your credentials work
curl -X GET \
  'https://api.yodle.com/api/v2/fma/YOUR_FMA_ID/leads?startDate=2024-01-01T00:00:00&endDate=2024-01-02T00:00:00&page=0' \
  -H 'Authorization: Basic YOUR_BASE64_CREDENTIALS' \
  -v

# A successful response returns HTTP 200 with lead data
# A failed authentication returns HTTP 401 Unauthorized

Leads Endpoint Reference

The Leads endpoint retrieves lead data for a specific FMA (franchise/location) within a specified date range. It returns call leads, web form submissions, and offer engagements with full contact details and attribution information.

Endpoint

Method: GET

URL: https://api.yodle.com/api/v2/fma/{fma_id}/leads

Path Parameters
Parameter Required Type Description Example
fma_id Yes Integer Your unique franchise/location identifier in the Centermark system 123456
Query Parameters
Parameter Required Type Default Description Example
startDate Yes ISO 8601 DateTime Start of date range to query 2014-02-16T13:01:06
endDate Yes ISO 8601 DateTime End of date range to query 2015-01-04T01:23:45
page No Integer 0 Which page to retrieve (0-indexed). Page size is 1,000 leads 1
filtered No Boolean true Whether to return filtered leads (true) or unfiltered leads (false) false
Response Structure

The API returns a JSON object with the following top-level fields:

Field Type Description
fmaLeadResources Array Array of lead objects (see Field and Payload Reference below)
lastPage Boolean Indicates whether this is the last page of results
Pagination Behavior
  • Results are returned in pages of up to 1,000 leads per request
  • Pages are zero-indexed (first page is page=0)
  • Use the lastPage field in the response to determine if more pages are available
  • If lastPage is false, increment the page parameter to retrieve the next page
  • Continue requesting pages until lastPage returns true
Filtering

By default (filtered=true), the API returns only filtered/validated leads that meet quality criteria. Set filtered=false to retrieve all leads including those that may not meet standard quality thresholds.

Example Request
GET https://api.yodle.com/api/v2/fma/123456/leads?startDate=2024-01-01T00:00:00&endDate=2024-01-31T23:59:59&page=0
Authorization: Basic dGVzdDp0ZXN0

Field and Payload Reference

The API returns a JSON response containing an array of lead objects. Each lead contains common fields plus type-specific data depending on whether it’s a CALL, WEB, or OFFER lead.

Lead Resource (FmaLeadResource)

Each lead in the fmaLeadResources array contains the following fields:

Field Type Description
id Integer Unique identifier for the lead in the system
clientId Integer Unique identifier for your location in the system
leadType Enum Type of lead: CALL, WEB, or OFFER
referral String Primary referral source
subReferral String Secondary referral classification
franchiseNumber String Franchise or location identifier
createdDate ISO 8601 DateTime Timestamp when the lead was created
attribution Object Attribution data (see Attribution table below)
callLeadData Object or null Only populated for CALL leads (see CallLeadData table below)
webLeadData Object or null Only populated for WEB leads (see WebLeadData table below)
offerLeadData Object or null Only populated for OFFER leads (see OfferLeadData table below)
Attribution
Field Type Description
primaryAttribution String or null Primary attribution category
secondaryAttribution String or null Secondary attribution details
CallLeadData (for CALL leads only)
Field Type Description
name String Name of the lead
sourceNumber String Phone number the lead called from
trackingNumber String Tracking number the lead called
destinationNumber String Number that was ultimately contacted
duration String Call duration
callStatus String Indicates if the call was answered
address Object Address information for the lead (see Address table below)
Address (within CallLeadData)
Field Type Description
street1 String Primary street address
street2 String Secondary address line (apartment, suite, etc.)
city String City name
state String State or province code
zipcode String Postal/ZIP code
country String Country code
WebLeadData (for WEB leads only)
Field Type Description
emailAddress String Email address of the lead
formData Object Dynamic key-value pairs containing all form fields submitted by the lead (e.g., firstName, lastName, phone, comments)
OfferLeadData (for OFFER leads only)
Field Type Description
offerId String Unique identifier for the offer
emailAddress String Email address of the lead
Example Response
{
  "fmaLeadResources": [
    {
      "id": 6343159740,
      "clientId": 100001,
      "leadType": "CALL",
      "referral": "Yodle",
      "subReferral": "Organic",
      "franchiseNumber": "D1",
      "createdDate": "2015-11-16T17:18:37.000",
      "attribution": {
        "primaryAttribution": "unpaid",
        "secondaryAttribution": null
      },
      "callLeadData": {
        "name": "Steveson Steve H",
        "sourceNumber": "9045551234",
        "trackingNumber": "8045551234",
        "destinationNumber": "7045551234",
        "duration": "00:00:27",
        "callStatus": "Answered",
        "address": {
          "street1": "33 Fake St",
          "street2": "",
          "city": "New York",
          "state": "NY",
          "zipcode": "11111",
          "country": "US"
        }
      },
      "webLeadData": null,
      "offerLeadData": null
    },
    {
      "id": 6345686398,
      "clientId": 100002,
      "leadType": "WEB",
      "referral": "Yodle",
      "subReferral": "Organic",
      "franchiseNumber": "DS199",
      "createdDate": "2015-11-17T17:10:28.386",
      "attribution": {
        "primaryAttribution": null,
        "secondaryAttribution": null
      },
      "callLeadData": null,
      "webLeadData": {
        "emailAddress": "test.lead@enspireforenterprise.com",
        "formData": {
          "firstName": "Matt",
          "lastName": "Wong",
          "phone": "19045551234",
          "Comments": "Hi I have a question",
          "email": "test.lead@enspireforenterprise.com",
          "reasonInquiry": "General Inquiry"
        }
      },
      "offerLeadData": null
    }
  ],
  "lastPage": true
}

Code Examples

Production-oriented integration examples demonstrating how to retrieve leads, handle pagination, and process data.

const axios = require('axios');

// Load credentials from environment variables (never hardcode)
const API_USERNAME = process.env.ENSPIRE_API_USERNAME;
const API_PASSWORD = process.env.ENSPIRE_API_PASSWORD;
const FMA_ID = process.env.FMA_ID;

class LeadsApiClient {
    constructor(username, password, fmaId) {
        this.baseUrl = 'https://api.yodle.com';
        this.fmaId = fmaId;
        this.authHeader = 'Basic ' + Buffer.from(`${username}:${password}`).toString('base64');
    }

    async getLeads(startDate, endDate, filtered = true) {
        const allLeads = [];
        let page = 0;
        let lastPage = false;

        while (!lastPage) {
            try {
                const response = await axios.get(
                    `${this.baseUrl}/api/v2/fma/${this.fmaId}/leads`,
                    {
                        headers: { 'Authorization': this.authHeader },
                        params: { startDate, endDate, page, filtered }
                    }
                );

                const { fmaLeadResources, lastPage: isLastPage } = response.data;
                allLeads.push(...fmaLeadResources);
                lastPage = isLastPage;
                page++;

                console.log(`Retrieved page ${page}, leads count: ${fmaLeadResources.length}`);

            } catch (error) {
                if (error.response?.status === 401) {
                    throw new Error('Authentication failed. Check credentials.');
                }
                throw error;
            }
        }

        return allLeads;
    }
}

// Usage
(async () => {
    const client = new LeadsApiClient(API_USERNAME, API_PASSWORD, FMA_ID);
    
    const startDate = '2024-01-01T00:00:00';
    const endDate = '2024-01-31T23:59:59';
    
    try {
        const leads = await client.getLeads(startDate, endDate);
        console.log(`Total leads retrieved: ${leads.length}`);
        
        // Process leads by type
        leads.forEach(lead => {
            switch(lead.leadType) {
                case 'CALL':
                    console.log(`Call from ${lead.callLeadData.sourceNumber}`);
                    break;
                case 'WEB':
                    console.log(`Web lead: ${lead.webLeadData.emailAddress}`);
                    break;
                case 'OFFER':
                    console.log(`Offer lead: ${lead.offerLeadData.offerId}`);
                    break;
            }
        });
    } catch (error) {
        console.error('Failed to retrieve leads:', error.message);
        process.exit(1);
    }
})();

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

public class LeadsApiClient : IDisposable
{
    private readonly HttpClient _httpClient;
    private readonly string _fmaId;

    public LeadsApiClient(string username, string password, string fmaId)
    {
        _httpClient = new HttpClient
        {
            BaseAddress = new Uri("https://api.yodle.com")
        };

        var credentials = Convert.ToBase64String(
            Encoding.ASCII.GetBytes($"{username}:{password}")
        );
        _httpClient.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Basic", credentials);
        
        _fmaId = fmaId;
    }

    public async Task> GetAllLeadsAsync(
        DateTime startDate, 
        DateTime endDate, 
        bool filtered = true)
    {
        var allLeads = new List();
        int page = 0;
        bool lastPage = false;

        while (!lastPage)
        {
            var startDateStr = startDate.ToString("yyyy-MM-ddTHH:mm:ss");
            var endDateStr = endDate.ToString("yyyy-MM-ddTHH:mm:ss");
            var url = $"/api/v2/fma/{_fmaId}/leads?" +
                      $"startDate={startDateStr}&" +
                      $"endDate={endDateStr}&" +
                      $"page={page}&" +
                      $"filtered={filtered.ToString().ToLower()}";

            var response = await _httpClient.GetAsync(url);
            
            if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
            {
                throw new UnauthorizedAccessException("Authentication failed.");
            }
            
            response.EnsureSuccessStatusCode();

            var json = await response.Content.ReadAsStringAsync();
            var result = JsonSerializer.Deserialize(json);

            allLeads.AddRange(result.FmaLeadResources);
            lastPage = result.LastPage;
            page++;

            Console.WriteLine($"Retrieved page {page}, leads: {result.FmaLeadResources.Count}");
        }

        return allLeads;
    }

    public void Dispose() => _httpClient?.Dispose();
}

public class LeadsResponse
{
    public List FmaLeadResources { get; set; }
    public bool LastPage { get; set; }
}

public class Lead
{
    public long Id { get; set; }
    public int ClientId { get; set; }
    public string LeadType { get; set; }
    public string Referral { get; set; }
    public string SubReferral { get; set; }
    public string FranchiseNumber { get; set; }
    public DateTime CreatedDate { get; set; }
    public Attribution Attribution { get; set; }
    public CallLeadData CallLeadData { get; set; }
    public WebLeadData WebLeadData { get; set; }
    public OfferLeadData OfferLeadData { get; set; }
}

// Usage
class Program
{
    static async Task Main(string[] args)
    {
        // Load from configuration (appsettings.json, environment variables, etc.)
        var username = Environment.GetEnvironmentVariable("ENSPIRE_API_USERNAME");
        var password = Environment.GetEnvironmentVariable("ENSPIRE_API_PASSWORD");
        var fmaId = Environment.GetEnvironmentVariable("FMA_ID");

        using var client = new LeadsApiClient(username, password, fmaId);
        
        try
        {
            var leads = await client.GetAllLeadsAsync(
                new DateTime(2024, 1, 1),
                new DateTime(2024, 1, 31, 23, 59, 59)
            );

            Console.WriteLine($"Total leads retrieved: {leads.Count}");
            
            // Process by type
            var callLeads = leads.Where(l => l.LeadType == "CALL").ToList();
            var webLeads = leads.Where(l => l.LeadType == "WEB").ToList();
            var offerLeads = leads.Where(l => l.LeadType == "OFFER").ToList();
            
            Console.WriteLine($"Calls: {callLeads.Count}, Web: {webLeads.Count}, Offers: {offerLeads.Count}");
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error: {ex.Message}");
            Environment.Exit(1);
        }
    }
}

<?php

class LeadsApiClient {
    private $baseUrl = 'https://api.yodle.com';
    private $fmaId;
    private $authHeader;
    
    public function __construct($username, $password, $fmaId) {
        $this->fmaId = $fmaId;
        // Create Base64 encoded credentials
        $credentials = base64_encode("$username:$password");
        $this->authHeader = "Authorization: Basic $credentials";
    }
    
    public function getAllLeads($startDate, $endDate, $filtered = true) {
        $allLeads = [];
        $page = 0;
        $lastPage = false;
        
        while (!$lastPage) {
            $url = sprintf(
                '%s/api/v2/fma/%s/leads?startDate=%s&endDate=%s&page=%d&filtered=%s',
                $this->baseUrl,
                $this->fmaId,
                urlencode($startDate),
                urlencode($endDate),
                $page,
                $filtered ? 'true' : 'false'
            );
            
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [$this->authHeader]);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
            
            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            
            if (curl_errno($ch)) {
                $error = curl_error($ch);
                curl_close($ch);
                throw new Exception("cURL error: $error");
            }
            
            curl_close($ch);
            
            if ($httpCode === 401) {
                throw new Exception('Authentication failed. Check credentials.');
            }
            
            if ($httpCode !== 200) {
                throw new Exception("HTTP error $httpCode: $response");
            }
            
            $data = json_decode($response, true);
            
            if (json_last_error() !== JSON_ERROR_NONE) {
                throw new Exception('Failed to parse JSON response');
            }
            
            $allLeads = array_merge($allLeads, $data['fmaLeadResources']);
            $lastPage = $data['lastPage'];
            $page++;
            
            echo "Retrieved page $page, leads count: " . count($data['fmaLeadResources']) . "\n";
        }
        
        return $allLeads;
    }
    
    public function processLeads($leads) {
        $stats = [
            'CALL' => 0,
            'WEB' => 0,
            'OFFER' => 0
        ];
        
        foreach ($leads as $lead) {
            $stats[$lead['leadType']]++;
            
            switch ($lead['leadType']) {
                case 'CALL':
                    if (isset($lead['callLeadData'])) {
                        echo "Call from {$lead['callLeadData']['sourceNumber']}\n";
                    }
                    break;
                case 'WEB':
                    if (isset($lead['webLeadData'])) {
                        echo "Web lead: {$lead['webLeadData']['emailAddress']}\n";
                    }
                    break;
                case 'OFFER':
                    if (isset($lead['offerLeadData'])) {
                        echo "Offer lead: {$lead['offerLeadData']['offerId']}\n";
                    }
                    break;
            }
        }
        
        return $stats;
    }
}

// Usage
try {
    // Load credentials from environment variables (never hardcode)
    $username = getenv('ENSPIRE_API_USERNAME');
    $password = getenv('ENSPIRE_API_PASSWORD');
    $fmaId = getenv('FMA_ID');
    
    if (!$username || !$password || !$fmaId) {
        throw new Exception('Required environment variables not set');
    }
    
    $client = new LeadsApiClient($username, $password, $fmaId);
    
    $startDate = '2024-01-01T00:00:00';
    $endDate = '2024-01-31T23:59:59';
    
    echo "Retrieving leads...\n";
    $leads = $client->getAllLeads($startDate, $endDate);
    
    echo "Total leads retrieved: " . count($leads) . "\n";
    
    $stats = $client->processLeads($leads);
    echo "\nBreakdown:\n";
    echo "Calls: {$stats['CALL']}\n";
    echo "Web: {$stats['WEB']}\n";
    echo "Offers: {$stats['OFFER']}\n";
    
} catch (Exception $e) {
    error_log("Failed to retrieve leads: " . $e->getMessage());
    exit(1);
}

?>

Error Handling and Troubleshooting

The API returns structured JSON error responses for invalid requests. Understanding these error codes and their causes will help you quickly diagnose and resolve integration issues.

Error Response Format

When an error occurs, the API returns an appropriate HTTP status code along with a JSON response body containing error details:

{
    "timestamp": 1777652067436,
    "status": 401,
    "error": "Unauthorized",
    "message": "Bad Credentials",
    "path": "/api/v2/fma/123456/leads"
}

Common Error Codes

HTTP Status: 401 Unauthorized
Cause: The provided username/password credentials are incorrect or invalid.
Example Response:

{
    "timestamp": 1777652067436,
    "status": 401,
    "error": "Unauthorized",
    "message": "Bad Credentials",
    "path": "/api/v2/fma/123456/leads"
}

Resolution:

  • Verify your username and password are correct
  • Ensure the Base64 encoding of username:password is accurate
  • Check that the Authorization header format is Basic <base64_credentials> with a space after “Basic”
  • Confirm your credentials haven’t expired or been revoked
  • Contact Centermark support if credentials need to be reset

HTTP Status: 400 Bad Request
Cause: The FMA ID in the URL path contains non-numeric characters or is malformed.
Example Request: GET /api/v2/fma/1234S6/leads
Example Response:

{
    "exception": "org.springframework.beans.TypeMismatchException",
    "path": "/api/v2/fma/1234S6/leads",
    "error": "Bad Request",
    "message": "Failed to convert value of type 'java.lang.String' to required type 'long'; nested exception is java.lang.NumberFormatException: For input string: \"1234S6\"",
    "timestamp": "2026-05-01T12:15:41.774-04:00",
    "status": 400
}

Resolution:

  • Ensure the FMA ID contains only numeric digits
  • Verify you’re using the correct FMA ID provided by Centermark
  • Check for typos or extra characters in the URL path
  • FMA ID should be an integer (e.g., 123456, not 1234S6)

HTTP Status: 403 Forbidden
Cause: Your credentials are valid, but you don’t have permission to access the specified FMA ID.
Example Response:

{
    "exception": "org.springframework.security.access.AccessDeniedException",
    "path": "/api/v2/fma/123456/leads",
    "error": "Forbidden",
    "message": "Not authorized",
    "timestamp": "2026-05-01T12:16:13.402-04:00",
    "status": 403
}

Resolution:

  • Verify the FMA ID belongs to your organization
  • Confirm your credentials have been granted access to this specific FMA
  • Contact Centermark support to request access to additional FMA IDs
  • Double-check you’re not using a test or staging FMA ID in production (or vice versa)

HTTP Status: 400 Bad Request
Cause: The request URL contains syntax errors, such as multiple query string delimiters.
Example Request: GET /api/v2/fma/123456/leads?startDate=2026-10-13T00:00:00&endDate=2026-01-14T23:00:00?test
Response: 400 Bad Request with no response body
Resolution:

  • Check for duplicate ? characters in the URL (only one ? should appear before the first parameter)
  • Use & to separate query parameters, not ?
  • Ensure parameter names and values are properly URL-encoded
  • Validate date formats are ISO 8601: YYYY-MM-DDTHH:mm:ss
  • Example correct URL: /api/v2/fma/123456/leads?startDate=2026-01-13T00:00:00&endDate=2026-01-14T23:00:00

Additional Error Scenarios

Invalid Date Format

If date parameters don’t match the expected ISO 8601 format, the API may return a 400 Bad Request.

Resolution:

  • Use the format YYYY-MM-DDTHH:mm:ss (e.g., 2024-01-15T00:00:00)
  • Ensure the date separator is T between date and time components
  • Verify startDate is before or equal to endDate
Missing Required Parameters

Omitting required parameters (startDate or endDate) will result in a 400 Bad Request.

Resolution:

  • Always include both startDate and endDate query parameters
  • Optional parameters (page, filtered) can be omitted to use defaults

Retry Logic and Best Practices

Implement appropriate retry strategies:

  • Don’t retry: 400 (Bad Request), 401 (Unauthorized), 403 (Forbidden) – these require fixing the request or credentials
  • Retry with backoff: 500 (Internal Server Error), 503 (Service Unavailable), network timeouts
  • Use exponential backoff (e.g., 1s, 2s, 4s, 8s delays between retries)
  • Set a maximum retry count (typically 3-5 attempts)
  • Log all errors with request details for debugging

Debugging Checklist

When encountering errors, systematically verify:

  1. URL Structure: Correct base URL, FMA ID in path, proper query string format
  2. Authentication: Valid credentials, correct Base64 encoding, proper Authorization header
  3. Parameters: Required parameters present, correct date format, valid page numbers
  4. Permissions: Credentials authorized for the specific FMA ID
  5. Network: Firewall rules allow HTTPS outbound
Getting Help

If you encounter an error not documented here or need assistance:

  • Contact Centermark support through your designated channel
  • Include the full error response (redact credentials)
  • Provide the exact request URL and parameters used (redact sensitive data)
  • Note the timestamp when the error occurred
  • Describe the expected behavior vs. what you observed

Changelog

Version 1.0 – May 2026

  • Initial documentation release covering authentication, endpoint reference, field definitions, and error handling
  • Added production-ready code examples for Node.js, C#, and SQL integrations
Who this is for
  • Client developers integrating Centermark lead delivery into their systems
  • Partner teams building middleware or connectors
  • Internal EFE and Centermark support teams validating expected behavior
Support and feedback

If you spot an issue (incorrect field name, outdated behavior, unclear example), send feedback to the
Centermark/AFE support channel or your EFE project contact. Include:

  • The page name you were viewing
  • What you expected vs. what you observed
  • Sample request/response (redact credentials)

Security note

This portal contains implementation guidance that may include sensitive integration details. Keep credentials
private, follow least-privilege principles, and do not paste secrets into tickets or shared docs.