Skip to main content

Error Response Format

All VoicePact API errors follow a consistent JSON format:
{
  "detail": "Error message describing what went wrong"
}
In debug mode, additional error information may be included:
{
  "detail": "Internal server error",
  "error": "Detailed exception message"
}
Detailed error messages are only shown when DEBUG=true. In production, generic messages are returned for security.

HTTP Status Codes

The VoicePact API uses standard HTTP status codes:

Success Codes

CodeMeaningUsage
200OKSuccessful GET, PUT requests
201CreatedSuccessful POST creating a resource

Client Error Codes

CodeMeaningCommon Causes
400Bad RequestInvalid input data, malformed JSON
404Not FoundContract, payment, or recording not found
422Unprocessable EntityValidation error in request body
503Service UnavailableExternal service (SMS, payment) unavailable

Server Error Codes

CodeMeaningDescription
500Internal Server ErrorUnexpected server error

Common Error Scenarios

1. Contract Not Found

Status Code: 404
{
  "detail": "Contract not found"
}
Causes:
  • Invalid contract ID
  • Contract was deleted
  • Contract hasn’t been created yet
Example:
curl http://localhost:8000/api/v1/contracts/INVALID-ID
Solution:
# List available contracts
curl http://localhost:8000/api/v1/contracts/

2. Validation Error

Status Code: 422
{
  "detail": [
    {
      "loc": ["body", "total_amount"],
      "msg": "ensure this value is greater than 0",
      "type": "value_error.number.not_gt"
    }
  ]
}
Causes:
  • Missing required fields
  • Invalid data types
  • Values outside allowed ranges
Example:
curl -X POST http://localhost:8000/api/v1/contracts/create/manual \
  -H "Content-Type: application/json" \
  -d '{
    "product": "Maize",
    "total_amount": -100
  }'
Solution:
curl -X POST http://localhost:8000/api/v1/contracts/create/manual \
  -H "Content-Type: application/json" \
  -d '{
    "product": "Maize",
    "quantity": "100",
    "unit": "bags",
    "total_amount": 50000,
    "currency": "KES",
    "parties": [
      {"phone": "+254712345678", "role": "seller", "name": "John"},
      {"phone": "+254723456789", "role": "buyer", "name": "Jane"}
    ]
  }'

3. Voice Processing Failed

Status Code: 400
{
  "detail": "Voice processing failed: Unsupported audio format"
}
Causes:
  • Unsupported audio file format
  • Audio file too large (>50MB)
  • Audio duration too long (>1200 seconds)
  • Corrupted audio file
  • Audio URL not accessible
Supported Formats:
  • WAV
  • MP3
  • M4A
  • OGG
  • FLAC
Example Error:
curl -X POST http://localhost:8000/api/v1/voice/upload \
  -F "[email protected]"
Solution:
curl -X POST http://localhost:8000/api/v1/voice/upload \
  -F "[email protected]" \
  -F "contract_type=agricultural_supply"

4. Payment Service Unavailable

Status Code: 503
{
  "detail": "SMS service unavailable. Check AT_API_KEY."
}
Causes:
  • Africa’s Talking API key not configured
  • Africa’s Talking service down
  • Network connectivity issues
  • Invalid API credentials
Configuration Check:
# Check SMS service status
curl http://localhost:8000/api/v1/sms/status
Response:
{
  "service": "SMS",
  "username": "sandbox",
  "api_key_set": true,
  "service_available": true,
  "message": "SMS service ready"
}
Solution:
# Set environment variable
export AT_API_KEY=your-api-key-here

# Restart application
systemctl restart voicepact

5. Contract Creation Failed

Status Code: 500
{
  "detail": "Contract creation failed: Database error"
}
Causes:
  • Database connection lost
  • Invalid party phone numbers
  • Duplicate contract ID
  • Terms validation failed
Example Error:
curl -X POST http://localhost:8000/api/v1/contracts/create \
  -H "Content-Type: application/json" \
  -d '{
    "transcript": "Test contract",
    "parties": [{"phone": "invalid"}],
    "terms": {}
  }'
Solution:
curl -X POST http://localhost:8000/api/v1/contracts/create \
  -H "Content-Type: application/json" \
  -d '{
    "transcript": "Agreement to supply 100 bags of maize",
    "parties": [
      {"phone": "+254712345678", "role": "seller"},
      {"phone": "+254723456789", "role": "buyer"}
    ],
    "contract_type": "agricultural_supply",
    "terms": {
      "product": "Maize",
      "quantity": "100",
      "unit": "bags",
      "total_amount": 50000,
      "currency": "KES"
    }
  }'

6. Mobile Checkout Failed

Status Code: 500
{
  "detail": "Mobile checkout failed: Insufficient balance"
}
Causes:
  • Payer has insufficient funds
  • Invalid phone number format
  • Payment amount exceeds limits
  • Africa’s Talking payment service error
Payment Amount Limits:
  • Minimum: KES 100 (1.00 KES)
  • Maximum: KES 1,000,000 (10,000.00 KES)
Example:
curl -X POST http://localhost:8000/api/v1/payments/checkout \
  -H "Content-Type: application/json" \
  -d '{
    "contract_id": "AG-2024-001",
    "amount": 50000,
    "currency": "KES",
    "phone_number": "+254712345678",
    "payment_type": "escrow"
  }'

7. Signature Not Found

Status Code: 404
{
  "detail": "Signature record not found"
}
Causes:
  • Phone number not a contract party
  • Contract doesn’t exist
  • Signature already confirmed
Check Contract Parties:
curl http://localhost:8000/api/v1/contracts/AG-2024-001
Confirm with Correct Phone:
curl -X POST http://localhost:8000/api/v1/contracts/AG-2024-001/confirm \
  -H "Content-Type: application/json" \
  -d '{"phone_number": "+254712345678"}'

Error Handling Best Practices

1. Always Check Status Codes

import requests

response = requests.post(
    "http://localhost:8000/api/v1/contracts/create",
    json=contract_data
)

if response.status_code == 200:
    contract = response.json()
    print(f"Contract created: {contract['contract_id']}")
elif response.status_code == 404:
    print("Resource not found")
elif response.status_code == 422:
    errors = response.json()['detail']
    print(f"Validation errors: {errors}")
else:
    print(f"Error: {response.json()['detail']}")

2. Implement Retry Logic

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

session = requests.Session()
retry = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry)
session.mount('http://', adapter)
session.mount('https://', adapter)

response = session.post(url, json=data)

3. Validate Input Before Sending

def validate_phone_number(phone: str) -> bool:
    """Validate Kenyan phone number format"""
    import re
    pattern = r'^\+254\d{9}$'
    return bool(re.match(pattern, phone))

def validate_contract_data(data: dict) -> tuple:
    """Validate contract data before API call"""
    errors = []
    
    if data.get('total_amount', 0) <= 0:
        errors.append("Total amount must be greater than 0")
    
    if not data.get('parties') or len(data['parties']) < 2:
        errors.append("At least 2 parties required")
    
    for party in data.get('parties', []):
        if not validate_phone_number(party.get('phone', '')):
            errors.append(f"Invalid phone: {party.get('phone')}")
    
    return len(errors) == 0, errors

4. Log Errors for Debugging

import logging

logger = logging.getLogger(__name__)

try:
    response = requests.post(url, json=data)
    response.raise_for_status()
except requests.HTTPError as e:
    logger.error(f"API Error: {e.response.status_code}")
    logger.error(f"Response: {e.response.json()}")
    raise
except requests.RequestException as e:
    logger.error(f"Request failed: {e}")
    raise

Global Exception Handler

The VoicePact API includes a global exception handler (main.py:73-88):
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    """Global exception handler"""
    logger.error(f"Unhandled exception in {request.method} {request.url}: {exc}")
    
    if settings.debug:
        import traceback
        logger.error(f"Traceback: {traceback.format_exc()}")
    
    return JSONResponse(
        status_code=500,
        content={
            "detail": "Internal server error",
            "error": str(exc) if settings.debug else "An error occurred"
        }
    )
Enable debug mode to see detailed error messages during development: DEBUG=true

Debugging Tips

Set environment variable for detailed errors:
export DEBUG=true
export LOG_LEVEL=DEBUG
Check logs:
tail -f voicepact.log
Test SMS service:
curl http://localhost:8000/api/v1/sms/status
Test payment service:
curl http://localhost:8000/api/v1/payments/wallet/balance
Test database:
curl http://localhost:8000/health
Use the interactive API docs to validate requests:
http://localhost:8000/docs
The Swagger UI shows required fields, data types, and validation rules.
View application logs:
# If using systemd
journalctl -u voicepact -f

# If using Docker
docker logs -f voicepact

# If running directly
tail -f logs/voicepact.log

Health Check Endpoint

Monitor system health:
curl http://localhost:8000/health
Healthy Response:
{
  "status": "healthy",
  "services": {
    "database": "connected",
    "redis": "connected"
  },
  "timestamp": 1710505800.123
}
Unhealthy Response:
{
  "status": "unhealthy",
  "services": {
    "database": {
      "error": "Connection timeout"
    },
    "redis": "connected"
  },
  "timestamp": 1710505800.123
}

Support and Resources

API Introduction

Back to API overview and quick start

GitHub Issues

Report bugs and request features

Need Help?

If you encounter an error not covered here:
  1. Check the application logs
  2. Verify your configuration settings
  3. Test with the interactive API docs at /docs
  4. Review the source code at the referenced file locations
  5. Open an issue on GitHub with error details

Build docs developers (and LLMs) love