Error Handling

Privé APIs use standard HTTP status codes and structured JSON error responses to help you diagnose issues quickly.

Error Response Format

All errors return a JSON object with this structure:

{
  "errorStatus": 401,
  "errorCode": "INVALID_CREDENTIALS",
  "errorMessage": "The provided username or password is incorrect",
  "timestamp": "2026-01-21T23:37:32.569Z"
}

Fields:

  • errorStatus — Machine-readable error identifier (use for programmatic handling)
  • errorCode — Error type identifier
  • errorMessage — Human-readable error description
  • timestamp — Timestamp of the error message (include when contacting support)

HTTP Status Codes

CodeStatusMeaningCommon Causes
200OKRequest succeeded-
201CreatedResource created successfullyPOST requests
400Bad RequestInvalid request syntax or parametersMissing required fields, invalid JSON
401UnauthorizedAuthentication failedInvalid token, expired token, no token provided
403ForbiddenAuthenticated but not authorizedWrong company credentials, insufficient permissions
404Not FoundResource doesn't existInvalid priveKey, deleted entity
409ConflictResource state conflictDuplicate creation, concurrent modification
422Unprocessable EntityRequest valid but business logic errorGuideline violation, insufficient funds
429Too Many RequestsRate limit exceededToo many requests in short period
500Internal Server ErrorServer-side errorContact Privé support
503Service UnavailableTemporary outageRetry with exponential backoff

Common Error Codes

Authentication Errors

Error CodeHTTP StatusDescriptionSolution
INVALID_CREDENTIALS401Wrong username/passwordVerify credentials with administrator
TOKEN_EXPIRED401JWT token has expiredRe-authenticate to get new token
TOKEN_INVALID401Malformed or tampered tokenEnsure you're using the complete token from login response
TOKEN_MISSING401No Authorization headerInclude Authorization: Bearer {token} header

Authorization Errors

Error CodeHTTP StatusDescriptionSolution
INSUFFICIENT_PERMISSIONS403User lacks required roleVerify you're using correct company credentials
WRONG_TENANT403Accessing resource in different tenantCheck {tenant} parameter matches your company
RESOURCE_ACCESS_DENIED403Can't access this specific resourceEnsure client/account belongs to your company

Validation Errors

Error CodeHTTP StatusDescriptionSolution
MISSING_REQUIRED_FIELD400Required parameter not providedCheck API reference for required fields
INVALID_FORMAT400Parameter in wrong formate.g., date should be YYYY-MM-DD
INVALID_VALUE400Parameter value not allowedCheck allowed values in System Codes
DUPLICATE_KEY409Resource with this ID already existsUse PUT to update instead of POST

Business Logic Errors

Error CodeHTTP StatusDescriptionSolution
GUIDELINE_VIOLATION422Portfolio violates investment guidelinesReview violation details and adjust portfolio
INSUFFICIENT_BALANCE422Not enough cash/assets for transactionCheck account balance before trading
INVALID_STATE_TRANSITION422Operation not allowed in current statee.g., can't approve already-approved transaction
DEPENDENCY_MISSING422Required linked resource doesn't existe.g., risk profile must exist before linking

Resource Errors

Error CodeHTTP StatusDescriptionSolution
RESOURCE_NOT_FOUND404Entity doesn't existVerify priveKey/externalKey is correct
RESOURCE_DELETED410Resource was previously deletedCreate new resource if needed

Rate Limiting

Error CodeHTTP StatusDescriptionSolution
RATE_LIMIT_EXCEEDED429Too many requestsWait before retrying (see Retry-After header)

Error Handling Best Practices

1. Check HTTP Status First

response = requests.post(url, json=payload, headers=headers)

if response.status_code == 200:
    # Success
    data = response.json()
elif response.status_code == 401:
    # Re-authenticate
    refresh_token()
    retry_request()
elif response.status_code >= 500:
    # Server error - retry with backoff
    retry_with_backoff()
else:
    # Client error - log and handle
    error = response.json()
    log_error(error)

2. Use Error Codes for Logic

try:
    response = api_call()
except APIError as e:
    if e.code == "GUIDELINE_VIOLATION":
        # Show violation details to user
        show_violations(e.details)
    elif e.code == "INSUFFICIENT_BALANCE":
        # Suggest reducing order size
        suggest_alternative()
    else:
        # Generic error handling
        log_and_notify(e)

3. Implement Retry Logic

import time
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

def create_session_with_retries():
    session = requests.Session()
    retry_strategy = Retry(
        total=3,
        status_forcelist=[429, 500, 502, 503, 504],
        allowed_methods=["GET", "POST", "PUT", "DELETE"],
        backoff_factor=1  # Wait 1, 2, 4 seconds
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("https://", adapter)
    return session

4. Log Request IDs

Always log the requestId from error responses:

try:
    response = api_call()
except APIError as e:
    logger.error(
        f"API Error: {e.code} - {e.message}",
        extra={"request_id": e.request_id}
    )

When contacting Privé support, include the requestId for faster debugging.


Rate Limiting Details

Limits:

  • 1000 requests per hour per access token
  • Burst limit: 50 requests per minute
  • Resource-intensive endpoints (reports, rebalancing) have lower limits

Response Headers:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1706880000

When Limit Exceeded:

HTTP/1.1 429 Too Many Requests
Retry-After: 3600

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Retry after 3600 seconds",
    "details": {
      "limit": 1000,
      "reset": 1706880000
    }
  }
}

Handling Rate Limits:

import time

def call_with_rate_limit_handling(func):
    try:
        return func()
    except RateLimitError as e:
        retry_after = int(e.response.headers.get('Retry-After', 60))
        print(f"Rate limited. Waiting {retry_after} seconds...")
        time.sleep(retry_after)
        return func()

Troubleshooting Guide

"401 Unauthorized" Even with Valid Token

Possible Causes:

  1. Token expired (check exp field)
  2. Using UAT token in Production (or vice versa)
  3. Token not properly formatted in header

Debug Steps:

import jwt

# Decode token to check expiration and environment
decoded = jwt.decode(token, options={"verify_signature": False})
print(f"Expires at: {decoded['exp']}")
print(f"Environment: {decoded.get('env', 'unknown')}")

# Verify header format
print(f"Header: Authorization: Bearer {token[:20]}...")

"403 Forbidden" with Valid Authentication

Possible Causes:

  1. Using wrong company credentials
  2. Resource belongs to different tenant
  3. User role lacks required permissions

Solution: Verify you're authenticated as the correct company type for this operation.

"404 Not Found" for Existing Resource

Possible Causes:

  1. Incorrect priveKey or externalKey
  2. Wrong {tenant} parameter
  3. Resource was deleted

Debug Steps:

# Try searching by different key types
try:
    # Try by priveKey
    resource = get_by_prive_key(prive_key)
except NotFoundError:
    # Try by externalKey
    resource = get_by_external_key(system_type, external_key)

"422 Unprocessable Entity" on Guideline Check

Cause: Portfolio violates investment guidelines

Solution: Parse details field to see specific violations:

try:
    result = check_guidelines(portfolio)
except GuidelineViolationError as e:
    for violation in e.details['violations']:
        print(f"Rule violated: {violation['rule']}")
        print(f"Current: {violation['current_value']}")
        print(f"Limit: {violation['limit']}")

Getting Help

If you encounter errors not covered here:

  1. Check Request ID: Include in support request
  2. Review API Reference: Verify you're using correct parameters
  3. Search Documentation: Use search bar above
  4. Contact Support: [email protected]

Support Request Template:

Subject: API Error - [Error Code]

Request ID: req_1234567890abcdef
Endpoint: POST /users/3/tenant123
Timestamp: 2024-01-15T10:30:00Z
Environment: UAT / Production

Error Message:
[Paste full error response]

Steps to Reproduce:
1. [Step 1]
2. [Step 2]