Getting Started Errors & Status Codes

Errors & Status Codes

The Logimeter API uses standard HTTP status codes to signal the outcome of every request. Error responses always return a JSON body so your integration can parse and handle them programmatically.

Overview

Successful requests return 2xx status codes. Client errors return 4xx codes. Server errors return 5xx codes. In all error cases the response body is a JSON object describing what went wrong.

Always check the HTTP status code first, then parse the JSON body for the specific error detail. Never rely on error message text being stable — the status code is the contract.

Error Response Format

Logimeter uses Django REST Framework (DRF) as its API layer. Three distinct error body shapes are used depending on the type of error:

Standard detail error

Used for authentication failures, permission denials, and general errors where a single human-readable message is appropriate.

Format
{
  "detail": "Error message describing what went wrong."
}
Example — 401 Unauthorized
{
  "detail": "Authentication credentials were not provided."
}
Example — 404 Not Found
{
  "detail": "Not found."
}

Validation error

Used for 400 Bad Request responses when one or more submitted fields fail validation. The response object maps each failing field name to a list of error messages. Non-field errors (those that apply to the request as a whole rather than a single field) are keyed under non_field_errors.

Format
{
  "field_name": ["Error message for this field."],
  "another_field": ["First error.", "Second error."],
  "non_field_errors": ["Error that applies to the whole request."]
}
Example — phone number validation failure
{
  "caller_id": [
    "Enter a valid phone number in E.164 format (e.g. +27831234567)."
  ]
}
Example — missing required fields
{
  "username": ["This field is required."],
  "password": ["This field is required."]
}

Blocklist error

Certain endpoints — particularly the Blocklist API — return a flat error key with a longer descriptive message that includes context such as entity identifiers.

Format
{
  "error": "Detailed error message with context."
}
Example — blocklist entity ownership error
{
  "error": "Entity 'example-entity-uuid' is not owned by the authenticated partner and cannot be modified."
}

HTTP Status Code Reference

Code Name When it occurs
200 OK The request succeeded. Returned for successful GET and PATCH (and sometimes POST) requests.
201 Created A new resource was created successfully. Returned for successful POST requests that create a resource.
204 No Content The request succeeded but there is no response body to return. Returned for successful DELETE requests.
400 Bad Request The request was malformed or failed validation. Missing required fields, invalid field values, or constraint violations. Check the JSON body for per-field error messages.
401 Unauthorized The Authorization header is missing, malformed, or contains an invalid token. Request a valid token via Integration and include it in your request.
403 Forbidden The token is valid but the authenticated user does not have permission for this resource or action. This typically means a required feature is not enabled for the partner, or the requested resource belongs to a different partner.
404 Not Found The requested resource does not exist, or is not accessible to the authenticated user. For DNA endpoints, also returned when no tracking number is available for the requested prefix.
405 Method Not Allowed The HTTP method used (e.g. DELETE, PUT) is not supported on this endpoint. Check the API reference for the allowed methods.
500 Internal Server Error An unexpected server-side error occurred. These are not caused by your request. If you consistently receive 500 errors, contact support@logimeter.com with the full request and response details.

Common Errors by Product

Certain products have specific error conditions worth noting when building your integration:

Dynamic Number Allocation (DNA)

StatusConditionResolution
404 No tracking number available for the requested dialling prefix. The number pool for that prefix is exhausted. Contact support to expand the pool or try a different prefix.

Connect

StatusConditionResolution
403 The CanLeadConnect permission is not enabled for the authenticated partner. Contact Logimeter support to enable the Connect product for your partner account.

Call Manager

StatusConditionResolution
403 The company referenced in the request does not belong to the authenticated partner. Verify that you are using the correct company identifier and that your partner account owns or manages that company.
401 The authenticated user does not have the call2lead permission required by the endpoint. Contact Logimeter support to have the call2lead permission granted to your user account.

Blocklist

StatusConditionResolution
403 The blocklist entity being modified is not owned by the authenticated partner. You can only manage blocklist entries that were created by your own partner account. Check the entity identifier and ensure you are authenticating with the correct token.

Validation Error Example

The following example shows a real validation error response returned when a phone number is submitted in an incorrect format. The caller_id field expects E.164 format (e.g. +27831234567).

curl -X POST https://next.logimeter.com/v1/connect/ \
  -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" \
  -H "Content-Type: application/json" \
  -d '{
    "caller_id": "0831234567",
    "reference": "lead-001"
  }'
HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "caller_id": [
    "Enter a valid phone number in E.164 format (e.g. +27831234567)."
  ]
}

Always submit phone numbers in E.164 format — a leading + followed by the country code and subscriber number with no spaces, dashes, or parentheses (e.g. +27831234567 for South Africa).

Handling Errors in Code

The pattern below shows a robust approach to catching and classifying API errors in both JavaScript and Python.

async function callApi(url, options = {}) {
  const response = await fetch(url, {
    ...options,
    headers: {
      'Authorization': `Token ${process.env.LOGIMETER_API_TOKEN}`,
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });

  if (response.ok) {
    // 204 No Content has no body
    return response.status === 204 ? null : response.json();
  }

  let errorBody;
  try {
    errorBody = await response.json();
  } catch {
    errorBody = { detail: response.statusText };
  }

  switch (response.status) {
    case 400:
      // Validation errors — errorBody may contain per-field messages
      console.error('Validation error:', errorBody);
      throw new Error(`Bad request: ${JSON.stringify(errorBody)}`);
    case 401:
      console.error('Authentication failed — check your API token.');
      throw new Error(errorBody.detail);
    case 403:
      console.error('Permission denied:', errorBody.detail);
      throw new Error(errorBody.detail);
    case 404:
      console.error('Resource not found:', errorBody.detail);
      throw new Error(errorBody.detail);
    default:
      throw new Error(`API error ${response.status}: ${JSON.stringify(errorBody)}`);
  }
}
import os
import requests

session = requests.Session()
session.headers['Authorization'] = f'Token {os.environ["LOGIMETER_API_TOKEN"]}'

def call_api(method, path, **kwargs):
    url = f'https://next.logimeter.com{path}'
    response = session.request(method, url, **kwargs)

    if response.ok:
        # 204 No Content has no body
        return None if response.status_code == 204 else response.json()

    try:
        error_body = response.json()
    except ValueError:
        error_body = {'detail': response.text}

    if response.status_code == 400:
        # Validation errors — error_body may contain per-field messages
        raise ValueError(f'Validation error: {error_body}')
    elif response.status_code == 401:
        raise PermissionError(f'Authentication failed: {error_body.get("detail")}')
    elif response.status_code == 403:
        raise PermissionError(f'Permission denied: {error_body.get("detail")}')
    elif response.status_code == 404:
        raise LookupError(f'Resource not found: {error_body.get("detail")}')
    else:
        response.raise_for_status()

For integration and token prerequisites, see Integration. For pagination behaviour on list endpoints, see Pagination.