PERS API uses structured error responses for consistent error handling across all endpoints. All errors follow the same format with security-filtered messages and correlation IDs for support.
- Consistency: All errors follow a uniform structure and categorization
- Security: Sensitive system details are filtered out; only safe messages are returned
- Traceability: Every error includes a correlation ID for support and debugging
- Programmatic Handling: Structured format enables reliable error processing
All PERS API errors return structured JSON responses following RFC 7807 (Problem Details for HTTP APIs):
{
"status": 404,
"title": "Resource Not Found",
"detail": "User with ID 12345 could not be found",
"message": "The requested user could not be found",
"code": "USER_NOT_FOUND",
"category": "DOMAIN_RULE",
"timestamp": "2026-01-15T10:30:00.000Z",
"correlationId": "req-abc-123",
"retryable": false,
"domain": "user"
}| Field | Type | Description |
|---|---|---|
status | number | HTTP status code |
title | string | Human-readable error summary |
detail | string | Specific error explanation |
message | string | Error message (usually same as detail) |
code | string | Error code for programmatic handling |
category | string | Error classification (VALIDATION, SECURITY, etc.) |
timestamp | string | ISO timestamp when error occurred |
correlationId | string | Request correlation ID for distributed tracing and support |
retryable | boolean | Whether operation can be retried |
domain | string | Domain that generated the error (user, campaign, transaction, etc.) |
details | object | Additional structured error context (optional) |
target | string | Target property/parameter for validation errors (optional) |
For TypeScript applications, import error types from the shared library:
import type { StructuredError, ErrorCategory } from '@explorins/pers-shared';| Category | HTTP Status | Description | Retryable |
|---|---|---|---|
| VALIDATION | 400 | Invalid request data or format | No |
| SECURITY | 401/403 | Authentication/authorization failures | No |
| DOMAIN_RULE | 422 | Business logic validation errors | No |
| TECHNICAL | 422 | Application/configuration issues | Maybe |
| RATE_LIMIT | 429 | API rate limit exceeded | Yes |
| TIMEOUT | 504 | Request timeout | Yes |
| INFRASTRUCTURE | 503 | External service failures | Yes |
| UNKNOWN | 500 | Unclassified errors | Maybe |
Authentication Error (401)
{
"status": 401,
"title": "Authentication Required",
"detail": "Valid authentication credentials are required",
"message": "Please log in to access this resource",
"code": "AUTHENTICATION_REQUIRED",
"category": "SECURITY",
"timestamp": "2026-01-15T10:30:00.000Z",
"correlationId": "req-abc-123",
"retryable": false
}Validation Error (400)
{
"status": 400,
"title": "Validation Error",
"detail": "The email field is required",
"message": "The email field is required",
"code": "REQUIRED_FIELD",
"category": "VALIDATION",
"timestamp": "2026-01-15T10:30:00.000Z",
"correlationId": "req-def-456",
"details": {
"field": "email",
"rejectedValue": null
},
"retryable": false
}// Example: Handling API errors in JavaScript/TypeScript
async function callAPI() {
try {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Authorization': 'Bearer your-token',
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John' })
});
if (!response.ok) {
const error = await response.json();
// Handle different error categories
if (error.category === 'SECURITY') {
// Redirect to login
window.location.href = '/login';
} else if (error.category === 'VALIDATION') {
// Show validation errors to user
showValidationError(error.details);
} else {
// Show generic error message
showErrorMessage(error.message);
}
return;
}
const data = await response.json();
// Handle success response
} catch (networkError) {
// Handle network errors
showErrorMessage('Network error. Please try again.');
}
}Every request and error response includes a unique correlation ID for distributed tracing:
- Automatically generated for each request
- Included in response headers:
X-Correlation-ID - Persisted across service boundaries for end-to-end tracing
- Essential for debugging issues across distributed systems
The API implements intelligent message safety filtering:
- System internals (stack traces, database errors) are never exposed
- Sensitive data (secrets, keys, credentials) is automatically filtered
- Business-friendly error messages are preserved
- Technical errors are sanitized for user consumption
For enhanced type safety in TypeScript applications:
import type {
ValidationStructuredError,
DomainRuleStructuredError,
SecurityStructuredError,
RateLimitStructuredError
} from '@explorins/pers-shared';
// Validation errors include field violations
interface ValidationStructuredError {
category: 'VALIDATION';
details: {
violations: Array<{
field: string;
code: string;
message: string;
rejectedValue?: any;
}>;
};
target: string; // Required field
retryable: false;
}
// Rate limit errors include quota information
interface RateLimitStructuredError {
category: 'RATE_LIMIT';
details: {
limit: number;
remaining: number;
resetTime: string; // ISO 8601
window: string; // e.g., "1h", "1d"
};
retryable: true;
}Error responses include correlation tracking headers:
X-Correlation-ID: Unique request identifier (set for all responses)X-Response-Time: ISO timestamp of response generationAccess-Control-Expose-Headers: Exposes correlation ID for CORS requests
Note: Additional error metadata (category, retryable, etc.) is available in the response body, not as separate headers.
- System error details are never exposed to API consumers
- Sensitive data automatically filtered using pattern matching
- Every error includes a correlation ID for traceability
- All errors are logged with full context for debugging
- Consistent error categorization across all domains
- Message safety filtering prevents information leakage
For further details, see the Authentication Guide and Developer Resources.