Skip to content

API Response Formats

Content negotiation

The response format is determined by shouldReturnJSON():

Condition Format
Route starts with /api/ JSON
Accept: application/json header JSON
Otherwise HTML

JSON response formats

Success response

{
  "success": true,
  "data": {
    "key": "value",
    "nested": {
      "more": "data"
    }
  }
}

Error response

{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message"
  }
}

Standard error codes

HTTP Status Error Code Usage
400 INVALID_INPUT Validation errors, malformed request
400 INVALID_ID Invalid ID format (non-numeric, etc.)
401 UNAUTHORIZED Authentication required
401 INVALID_CREDENTIALS Wrong email/password
403 UNAUTHORIZED Authorization failed (insufficient permissions)
404 NOT_FOUND Resource not found
405 METHOD_NOT_ALLOWED Wrong HTTP method
500 SERVER_ERROR Internal server error

Security note: For authorization-protected resources, return 403 (Forbidden) even for non-existent IDs to prevent information leakage about resource existence.

Intranet sync API format

The intranet sync endpoints (/api/intranet/...) use a different response format. See Intranet Sync API for details.

Sync success

{
  "success": true,
  "received": 3,
  "inserted": 2,
  "updated": 1,
  "errors": 0,
  "results": [
    {"identifier": "P001", "status": "inserted"},
    {"identifier": "P002", "status": "updated"},
    {"identifier": "P003", "status": "inserted"}
  ]
}

Sync validation error

{
  "success": false,
  "error": {
    "code": "INVALID_PAYLOAD",
    "message": "Key: 'IntranetPersonBatch.Records[0].ExternalID' Error:..."
  }
}

Authentication error codes (API token)

HTTP Status Code Cause
401 MISSING_AUTH_HEADER No Authorization header
401 INVALID_AUTH_FORMAT Not Bearer scheme
401 EMPTY_TOKEN Empty token value
401 INVALID_TOKEN Token not found or inactive
403 IP_NOT_ALLOWED Client IP not in allowlist