Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.lms.bsa.ai/llms.txt

Use this file to discover all available pages before exploring further.

The API returns structured errors with stable codes. Branch on the code field, not the human-readable message.

Error envelope

Any non-2xx response has the following body:
{
  "code": "not_found",
  "message": "lms: status=404: Customer with id 9999 does not exist"
}
The message is a human-readable string scoped to the partner contract — internal LMS vocabulary (Client, globalisation codes like error.msg.*) is rewritten or stripped before it reaches the wire. For validation failures (invalid_argument), the body wraps a list of field errors:
{
  "code": "invalid_argument",
  "message": "[{\"field\":\"officeId\",\"error\":\"required\"},{\"field\":\"activationDate\",\"error\":\"required when active=true\"}]"
}
The message is a JSON-encoded array of {field, error} pairs.

Status code mapping

HTTPCodeWhen
400invalid_argumentMalformed body, missing required field, invalid path/query param
401unauthenticatedMissing/invalid/expired token, or non-admin subject
403permission_deniedToken recognized but caller lacks permission for this resource
404not_foundResource does not exist
409abortedState conflict — e.g. attempting an action the resource’s current state does not allow
500internalUnexpected upstream failure
503unavailableService is temporarily unavailable

Retrying

CodeRetry?
unavailableYes, with backoff
internalYes once, then surface to caller
abortedNo — fix the request or the resource state
invalid_argument, not_found, unauthenticated, permission_deniedNo — client-side fix

Example: branching on errors

import requests

resp = requests.post(f"{BASE}/v1/customers", json=payload, headers={"Authorization": f"Bearer {token}"})

if resp.ok:
    customer = resp.json()
elif resp.status_code == 400:
    fields = json.loads(resp.json()["message"])
    for fe in fields:
        print(f"  {fe['field']}: {fe['error']}")
elif resp.status_code == 401:
    refresh_token_and_retry()
else:
    raise RuntimeError(resp.json()["message"])