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.
{
"detail": "Error message describing what went wrong."
}
{
"detail": "Authentication credentials were not provided."
}
{
"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.
{
"field_name": ["Error message for this field."],
"another_field": ["First error.", "Second error."],
"non_field_errors": ["Error that applies to the whole request."]
}
{
"caller_id": [
"Enter a valid phone number in E.164 format (e.g. +27831234567)."
]
}
{
"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.
{
"error": "Detailed error message with context."
}
{
"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)
| Status | Condition | Resolution |
|---|---|---|
| 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
| Status | Condition | Resolution |
|---|---|---|
| 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
| Status | Condition | Resolution |
|---|---|---|
| 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
| Status | Condition | Resolution |
|---|---|---|
| 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.