Total Access Docs
API Reference

Error Codes

Complete reference for all API error codes and their resolution

Error Response Format

All API errors follow a standardized envelope:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request body failed validation",
    "details": [
      { "field": "email", "issue": "Invalid email format" },
      { "field": "start_date", "issue": "Date cannot be in the future" }
    ],
    "request_id": "req_abc123",
    "documentation_url": "https://dev-developer.totalaccess.co.za/docs/api-reference/errors#validation_error"
  }
}

The request_id field is included in all error responses. Include this ID when contacting support for faster resolution.

Error Code Catalog

400 — Bad Request

CodeDescriptionCommon CausesResolution
BAD_REQUESTMalformed request body or missing required fieldsMissing action field, invalid JSON, wrong parameter typesCheck request body against the action's schema
VALIDATION_ERRORRequest body failed field validationInvalid email format, date out of range, negative values where positive expectedReview details array for field-specific errors
INVALID_ACTIONUnknown action specifiedTypo in action name, action not available for this clientCheck available actions via GET /api/v1/public/data

401 — Unauthorized

CodeDescriptionCommon CausesResolution
UNAUTHORIZEDMissing, invalid, or expired API keyKey revoked, key expired, wrong headerGenerate a new API key, check X-API-Key header
TOKEN_EXPIREDJWT access token has expiredToken TTL exceeded (15 min)Refresh using the refresh token
INVALID_API_KEYAPI key format is invalidMalformed key, wrong prefixEnsure key starts with ta_sk_

403 — Forbidden

CodeDescriptionCommon CausesResolution
FORBIDDENValid auth but insufficient permissionsMissing required scope, IP not in allowlistAdd required scope to API key, add IP to allowlist
IP_NOT_ALLOWEDRequest from non-allowlisted IPIP allowlist configured but request IP not listedAdd the IP to the key's allowlist
SCOPE_REQUIREDAPI key lacks a specific scopeKey created without the needed scopeEdit the key to add the scope, or create a new key
TIER_RESTRICTEDFinance document type not allowed by subscription tierClient's Total Finance tier does not include the requested document typeUpgrade the Total Finance subscription tier to include the document type

404 — Not Found

CodeDescriptionCommon CausesResolution
NOT_FOUNDRequested resource not foundWrong ID, resource deleted, resource belongs to different clientVerify the ID and client context

405 — Method Not Allowed

CodeDescriptionCommon CausesResolution
METHOD_NOT_ALLOWEDHTTP method not supported for this endpointGET on a POST-only endpointCheck the endpoint's allowed methods

409 — Conflict

CodeDescriptionCommon CausesResolution
CONFLICTRequest conflicts with current stateDuplicate unique constraint violationUse a new idempotency key or resolve the conflict
IDEMPOTENCY_CONFLICTSame idempotency key with different request bodyKey reused with different payloadUse a unique key per unique request

422 — Unprocessable Entity

CodeDescriptionCommon CausesResolution
UNPROCESSABLE_ENTITYRequest is valid but cannot be processedBusiness rule violation (e.g., clock out before clock in)Review the message field for the specific rule

429 — Rate Limited

CodeDescriptionCommon CausesResolution
RATE_LIMITEDRate limit exceededToo many requests in the time windowWait for X-RateLimit-Reset, upgrade tier

5xx — Server Errors

CodeDescriptionCommon CausesResolution
INTERNAL_ERRORUnexpected server errorBug, database timeout, infrastructure issueRetry with exponential backoff, contact support if persistent
BAD_GATEWAYUpstream service unavailableWebSocket server, email server, or FreeSWITCH unreachableRetry, check status page
SERVICE_UNAVAILABLEService temporarily unavailableMaintenance mode, capacity exceededRetry after a delay, check status page
GATEWAY_TIMEOUTUpstream service timed outDatabase query timeout, external API timeoutRetry with longer timeout

Rate Limit Headers

When rate limited, check these headers to understand your limits:

HeaderDescription
X-RateLimit-LimitMaximum requests per minute
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetISO 8601 timestamp when the window resets

Handling Errors

try {
  const response = await fetch('https://totalaccess.co.za/api/v1/public/data', {
    method: 'POST',
    headers: {
      'X-API-Key': apiKey,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ action: 'list-work-items' }),
  });

  const data = await response.json();

  if (!response.ok) {
    console.error(`Error ${data.error.code}: ${data.error.message}`);
    console.error(`Request ID: ${data.error.request_id}`);
    // Retry with exponential backoff for 5xx errors
    if (response.status >= 500) {
      await retryWithBackoff();
    }
  }
} catch (err) {
  console.error('Network error:', err);
}
import requests
import time

def call_api(action, params, api_key, max_retries=3):
    for attempt in range(max_retries):
        response = requests.post(
            'https://totalaccess.co.za/api/v1/public/data',
            headers={'X-API-Key': api_key, 'Content-Type': 'application/json'},
            json={'action': action, **params}
        )

        if response.status_code == 429:
            reset = response.headers.get('X-RateLimit-Reset')
            wait_time = 60  # Default wait
            print(f"Rate limited. Reset at: {reset}")
            time.sleep(wait_time)
            continue

        data = response.json()
        if not response.ok:
            error = data.get('error', {})
            print(f"Error {error.get('code')}: {error.get('message')}")
            print(f"Request ID: {error.get('request_id')}")
            if response.status_code >= 500:
                time.sleep(2 ** attempt)
                continue
            return None

        return data

    return None

On this page