Escrow Disbursements API
The Escrow Disbursements API enables merchants to create bulk escrows with customizable terms that recipients must fulfill before receiving funds. Unlike direct disbursements, escrow disbursements create conditional payments that require user interaction and verification.
Overview and Use Cases
Escrow disbursements are ideal for scenarios requiring verification before payment release:
Delivery and Logistics: - Package delivery confirmations - Location-based service verification - Proof of delivery requirements - Last-mile delivery tracking
Services and Gig Economy: - Task completion verification - Service quality confirmation - Photo evidence requirements - Location-based service delivery
Supply Chain and Manufacturing: - Quality control checkpoints - Milestone-based payments - Inspection requirements - Compliance verification
Key Differences from Direct Disbursements:
Feature |
Direct Disburs. |
Escrow Disbursements |
|---|---|---|
Payment Release |
Immediate |
Conditional |
User Interaction |
None Required |
Required |
Verification |
None |
Custom Terms |
Dispute Resolution |
Limited |
Full Support |
Tracking Granularity |
Basic |
Detailed |
Authentication and Security
All escrow disbursement endpoints require merchant API key authentication with enhanced security measures.
Required Headers:
api-key: YOUR_MERCHANT_API_KEY
Content-Type: application/json
X-Piaxis-Client-ID: your_client_id
Security Features: - End-to-end encryption for sensitive data - Multi-factor authentication for high-value disbursements - Audit trail for all operations - Real-time fraud detection
Rate Limits: - Create disbursements: 10 requests per minute - Status checks: 100 requests per minute - Bulk operations: 5 requests per minute
Core API Endpoints
Creating Escrow Disbursements
Create bulk escrows with customizable terms for multiple recipients.
- POST /api/escrow-disbursements
-
Create a new escrow disbursement batch with specified recipients and terms.
- Request Headers:
-
-
api-key – Merchant API key (required)
-
X-Piaxis-Client-ID – Client identifier (required)
-
Content-Type – application/json
-
- Status Codes:
-
-
200 OK – Disbursement created successfully
-
400 Bad Request – Invalid request parameters
-
401 Unauthorized – Authentication failed
-
403 Forbidden – Insufficient permissions
-
422 Unprocessable Entity – Validation errors
-
429 Too Many Requests – Rate limit exceeded
-
Basic Disbursement Example:
POST /api/escrow-disbursements HTTP/1.1
Host: api.gopiaxis.com
api-key: YOUR_API_KEY
X-Piaxis-Client-ID: your_client_id
Content-Type: application/json
{
"recipients": [
{
"recipient_id": "123e4567-e89b-12d3-a456-426614174000",
"email": "[email protected]",
"phone_number": "+256700111000",
"amount": "25000.00",
"reference": "DELIVERY-001",
"terms": [
{
"term_type": "location_verification",
"data": {
"latitude": 0.347596,
"longitude": 32.582520,
"radius": 100,
"description": "Verify delivery at customer location"
}
},
{
"term_type": "photo_upload",
"data": {
"description": "Upload proof of delivery photo",
"required_count": 1,
"accepted_formats": ["jpeg", "png"]
}
}
]
} ],
"currency": "UGX",
"payment_method": "piaxis_external",
"description": "Delivery payments for Route A - June 5, 2025",
"metadata": {
"route_id": "ROUTE_A_20250605",
"batch_number": "BATCH_001",
"delivery_zone": "KAMPALA_CENTRAL"
}
}
Multi-Recipient Disbursement:
POST /api/escrow-disbursements HTTP/1.1
Host: api.gopiaxis.com
api-key: YOUR_API_KEY
X-Piaxis-Client-ID: your_client_id
Content-Type: application/json
{
"recipients": [
{
"email": "[email protected]",
"phone_number": "+256700222000",
"amount": "150000.00",
"reference": "SERVICE-001",
"terms": [
{
"term_type": "photo_upload",
"data": {
"description": "Before and after installation photos",
"required_count": 2,
"accepted_formats": ["jpeg", "png"]
}
},
{
"term_type": "delivery_confirmation",
"data": {
"description": "Customer satisfaction confirmation",
"deadline": "2025-06-10T18:00:00Z"
}
}
]
},
{
"email": "[email protected]",
"phone_number": "+256700333000",
"amount": "120000.00",
"reference": "SERVICE-002",
"terms": [
{
"term_type": "location_verification",
"data": {
"latitude": 0.315789,
"longitude": 32.576543,
"radius": 50,
"description": "Verify service completion at site"
}
}
]
}
],
"currency": "UGX",
"payment_method": "mtn",
"description": "Installation services batch - Phase 2",
"auto_release": {
"enabled": true,
"delay_hours": 24,
"conditions": ["all_terms_fulfilled"]
}
}
Complex Terms Disbursement:
POST /api/escrow-disbursements HTTP/1.1
Host: api.gopiaxis.com
api-key: YOUR_API_KEY
X-Piaxis-Client-ID: your_client_id
Content-Type: application/json
{
"recipients": [
{
"recipient_id": "456e7890-f12b-34c5-6d78-901234567890",
"email": "[email protected]",
"phone_number": "+256700444000",
"amount": "500000.00",
"reference": "QC-INSPECTION-001",
"terms": [
{
"term_type": "custom",
"data": {
"verification_code": "QC-2025-001",
"description": "Complete quality control inspection checklist",
"required_data": {
"inspection_report": true,
"compliance_certificate": true,
"manager_approval": true
}
}
},
{
"term_type": "meeting_delivery",
"data": {
"max_distance_km": 0.05,
"buyer_coordinates": {
"latitude": 0.347596,
"longitude": 32.582520
},
"description": "Meet with site manager for final approval"
}
}
]
}
],
"currency": "UGX",
"payment_method": "piaxis_external",
"description": "Quality control milestone payment",
"notification_settings": {
"email_notifications": true,
"sms_notifications": true,
"webhook_url": "https://your-app.com/webhooks/escrow-updates"
}
}
Successful Response Format:
{
"disbursement_id": "987fcdeb-51a2-43d1-9f4e-123456789abc",
"status": "processing",
"total_amount": "270000.00",
"currency": "UGX",
"payment_method": "mtn",
"recipient_count": 2,
"successful_count": 0,
"failed_count": 0,
"pending_count": 2,
"escrow_items": [
{
"recipient_email": "[email protected]",
"phone_number": "+256700222000",
"amount": "150000.00",
"escrow_id": "escrow_001_abc123",
"status": "pending",
"terms_count": 2,
"reference": "SERVICE-001",
"estimated_completion": "2025-06-08T12:00:00Z"
},
{
"recipient_email": "[email protected]",
"phone_number": "+256700333000",
"amount": "120000.00",
"escrow_id": "escrow_002_def456",
"status": "pending",
"terms_count": 1,
"reference": "SERVICE-002",
"estimated_completion": "2025-06-08T15:00:00Z"
}
],
"description": "Installation services batch - Phase 2",
"created_at": "2025-06-05T10:30:00Z",
"auto_release": {
"enabled": true,
"delay_hours": 24
}
}
Retrieving Disbursement Information
Get detailed information about disbursements and track progress.
- GET /api/escrow-disbursements/{disbursement_id}
-
Retrieve comprehensive details of a specific escrow disbursement.
- Request Headers:
-
-
api-key – Merchant API key (required)
-
- Status Codes:
-
-
200 OK – Disbursement details retrieved successfully
-
401 Unauthorized – Authentication failed
-
404 Not Found – Disbursement not found
-
Request Example:
GET /api/escrow-disbursements/987fcdeb-51a2-43d1-9f4e-123456789abc HTTP/1.1
Host: api.gopiaxis.com
api-key: YOUR_API_KEY
Detailed Response:
{
"disbursement_id": "987fcdeb-51a2-43d1-9f4e-123456789abc",
"status": "partially_completed",
"total_amount": "270000.00",
"currency": "UGX",
"payment_method": "mtn",
"recipient_count": 2,
"successful_count": 1,
"failed_count": 0,
"pending_count": 1,
"progress_summary": {
"completion_rate": 50.0,
"total_terms": 3,
"fulfilled_terms": 2,
"pending_terms": 1,
"average_fulfillment_time": "4.5 hours"
},
"escrow_items": [
{
"recipient_email": "[email protected]",
"phone_number": "+256700222000",
"amount": "150000.00",
"escrow_id": "escrow_001_abc123",
"status": "completed",
"terms_count": 2,
"fulfilled_terms": 2,
"reference": "SERVICE-001",
"completed_at": "2025-06-06T14:30:00Z",
"release_transaction_id": "txn_rel_001234",
"terms_status": [
{
"term_type": "photo_upload",
"status": "fulfilled",
"fulfilled_at": "2025-06-06T12:15:00Z"
},
{
"term_type": "delivery_confirmation",
"status": "fulfilled",
"fulfilled_at": "2025-06-06T14:30:00Z"
}
]
},
{
"recipient_email": "[email protected]",
"phone_number": "+256700333000",
"amount": "120000.00",
"escrow_id": "escrow_002_def456",
"status": "active",
"terms_count": 1,
"fulfilled_terms": 0,
"reference": "SERVICE-002",
"deadline": "2025-06-08T15:00:00Z",
"terms_status": [
{
"term_type": "location_verification",
"status": "pending",
"deadline": "2025-06-08T15:00:00Z"
}
]
}
],
"description": "Installation services batch - Phase 2",
"created_at": "2025-06-05T10:30:00Z",
"last_updated": "2025-06-06T14:30:00Z",
"metadata": {
"route_id": "ROUTE_B_20250605",
"batch_number": "BATCH_002"
}
}
Listing Disbursements
Retrieve paginated list of all disbursements with filtering options.
- GET /api/escrow-disbursements
-
List all escrow disbursements for the authenticated merchant with advanced filtering.
Query Parameters:
-
limit(integer, optional): Results per page (1-100, default: 20) -
offset(integer, optional): Results to skip (default: 0) -
status(string, optional): Filter by status -
payment_method(string, optional): Filter by payment method -
date_from(string, optional): Start date filter (ISO 8601) -
date_to(string, optional): End date filter (ISO 8601) -
min_amount(decimal, optional): Minimum amount filter -
max_amount(decimal, optional): Maximum amount filter -
reference(string, optional): Search by reference
-
Advanced Filtering Example:
GET /api/escrow-disbursements?status=active&payment_method=mtn&date_from=2025-06-01T00:00:00Z&limit=50 HTTP/1.1
Host: api.gopiaxis.com
api-key: YOUR_API_KEY
Response with Analytics:
{
"total": 125,
"offset": 0,
"limit": 20,
"analytics": {
"total_volume": "25000000.00",
"average_completion_rate": 94.2,
"average_fulfillment_time": "6.8 hours",
"payment_method_breakdown": {
"mtn": 45,
"airtel": 32,
"piaxis": 48
},
"status_breakdown": {
"completed": 98,
"active": 15,
"failed": 5,
"cancelled": 7
}
},
"results": [
{
"disbursement_id": "987fcdeb-51a2-43d1-9f4e-123456789abc",
"status": "completed",
"total_amount": "500000.00",
"currency": "UGX",
"recipient_count": 5,
"successful_count": 5,
"failed_count": 0,
"completion_rate": 100.0,
"description": "Delivery batch #001",
"created_at": "2025-06-04T08:00:00Z",
"completed_at": "2025-06-04T16:30:00Z"
}
]
}
Managing Disbursements
Cancel, modify, or perform bulk operations on disbursements.
Cancel Escrow Disbursement:
- POST /api/escrow-disbursements/{disbursement_id}/cancel
-
Cancel a disbursement and all associated pending escrows.
- Request Headers:
-
-
api-key – Merchant API key (required)
-
Content-Type – application/json
-
- Status Codes:
-
-
200 OK – Disbursement cancelled successfully
-
400 Bad Request – Cannot cancel disbursement
-
404 Not Found – Disbursement not found
-
POST /api/escrow-disbursements/987fcdeb-51a2-43d1-9f4e-123456789abc/cancel HTTP/1.1
Host: api.gopiaxis.com
api-key: YOUR_API_KEY
Content-Type: application/json
{
"reason": "Project cancelled due to weather conditions",
"refund_policy": "full_refund",
"notify_recipients": true,
"cancellation_metadata": {
"cancelled_by": "project_manager_001",
"project_id": "PROJ_2025_001"
}
}
Bulk Release Operation:
- POST /api/escrow-disbursements/{disbursement_id}/bulk-release
-
Release all fulfilled escrows in a disbursement batch.
POST /api/escrow-disbursements/987fcdeb-51a2-43d1-9f4e-123456789abc/bulk-release HTTP/1.1
Host: api.gopiaxis.com
api-key: YOUR_API_KEY
Content-Type: application/json
{
"release_criteria": {
"min_terms_fulfilled": 1,
"require_all_terms": false,
"grace_period_hours": 2
},
"notification_settings": {
"notify_recipients": true,
"send_receipt": true
}
}
Term Types and Advanced Configurations
Comprehensive guide to available term types and their configurations.
Location Verification Terms
Basic Location Verification:
{
"term_type": "location_verification",
"data": {
"latitude": 0.347596,
"longitude": 32.582520,
"radius": 100,
"description": "Verify arrival at delivery location",
"verification_window": {
"start_time": "08:00",
"end_time": "18:00"
}
}
}
Multi-Point Location Verification:
{
"term_type": "location_verification",
"data": {
"verification_points": [
{
"name": "Pickup Location",
"latitude": 0.347596,
"longitude": 32.582520,
"radius": 50,
"required": true
},
{
"name": "Delivery Location",
"latitude": 0.315789,
"longitude": 32.576543,
"radius": 100,
"required": true
}
],
"sequence_required": true,
"max_time_between_points": 120
}
}
Photo Upload Terms
Standard Photo Upload:
{
"term_type": "photo_upload",
"data": {
"description": "Upload delivery confirmation photos",
"required_count": 2,
"accepted_formats": ["jpeg", "png", "webp"],
"max_file_size_mb": 10,
"metadata_required": ["timestamp", "location"]
}
}
Structured Photo Requirements:
{
"term_type": "photo_upload",
"data": {
"photo_requirements": [
{
"category": "before_service",
"description": "Before starting work",
"required_count": 1,
"template_url": "https://templates.gopiaxis.com/before-template.jpg"
},
{
"category": "during_service",
"description": "Work in progress",
"required_count": 2,
"min_interval_minutes": 30
},
{
"category": "completion_proof",
"description": "Completed work evidence",
"required_count": 1,
"quality_check": true
}
],
"ai_validation": {
"enabled": true,
"check_quality": true,
"verify_authenticity": true
}
}
}
Meeting and Delivery Terms
Simple Meeting Delivery:
{
"term_type": "meeting_delivery",
"data": {
"max_distance_km": 0.1,
"buyer_coordinates": {
"latitude": 0.347596,
"longitude": 32.582520
},
"description": "Meet customer for product handover",
"meeting_window": {
"start": "2025-06-06T09:00:00Z",
"end": "2025-06-06T17:00:00Z"
}
}
}
Advanced Meeting Requirements:
{
"term_type": "meeting_delivery",
"data": {
"meeting_type": "scheduled_appointment",
"location_tolerance": 0.05,
"required_participants": [
{
"role": "service_provider",
"verification_required": true
},
{
"role": "customer",
"phone_verification": true
}
],
"verification_method": "dual_confirmation",
"photo_evidence_required": true,
"signature_required": true
}
}
Custom Verification Terms
Document Verification:
{
"term_type": "custom",
"data": {
"verification_type": "document_check",
"required_documents": [
{
"type": "completion_certificate",
"format": "pdf",
"max_size_mb": 5,
"verification_authority": "quality_control"
},
{
"type": "inspection_report",
"format": "pdf",
"fields_required": ["inspector_id", "date", "signature"]
}
],
"approval_workflow": {
"requires_manager_approval": true,
"approval_timeout_hours": 48
}
}
}
Time-Based Milestones:
{
"term_type": "custom",
"data": {
"milestone_type": "time_based",
"checkpoints": [
{
"name": "project_start",
"deadline": "2025-06-07T09:00:00Z",
"verification_method": "photo_upload",
"weight": 20
},
{
"name": "50_percent_completion",
"deadline": "2025-06-09T17:00:00Z",
"verification_method": "manager_approval",
"weight": 30
},
{
"name": "final_delivery",
"deadline": "2025-06-12T18:00:00Z",
"verification_method": "customer_signature",
"weight": 50
}
],
"partial_release_enabled": true
}
}
Real-World Integration Examples
Complete implementation examples for common business scenarios.
Delivery Service Integration
Python Implementation for Delivery Company:
import requests
from datetime import datetime, timedelta
from typing import List, Dict
class DeliveryEscrowManager:
def __init__(self, api_key: str, client_id: str):
self.api_key = api_key
self.client_id = client_id
self.base_url = "https://api.gopiaxis.com"
self.headers = {
'api-key': api_key,
'X-Piaxis-Client-ID': client_id,
'Content-Type': 'application/json'
}
def create_daily_delivery_batch(self, delivery_routes: List[Dict]) -> Dict:
"""Create escrow disbursement for daily delivery routes"""
recipients = []
for route in delivery_routes:
recipient = {
"email": route["driver_email"],
"phone_number": route["driver_phone"],
"amount": str(route["payment_amount"]),
"reference": f"ROUTE_{route['route_id']}_{datetime.now().strftime('%Y%m%d')}",
"terms": [
{
"term_type": "location_verification",
"data": {
"verification_points": [
{
"name": f"Stop_{i+1}",
"latitude": stop["lat"],
"longitude": stop["lng"],
"radius": 100,
"required": True
}
for i, stop in enumerate(route["delivery_stops"])
],
"sequence_required": True,
"max_time_between_points": 60
}
},
{
"term_type": "photo_upload",
"data": {
"description": f"Delivery confirmation for {len(route['delivery_stops'])} packages",
"required_count": len(route["delivery_stops"]),
"metadata_required": ["timestamp", "location"],
"ai_validation": {
"enabled": True,
"check_quality": True
}
}
}
]
}
recipients.append(recipient)
disbursement_data = {
"recipients": recipients,
"currency": "UGX",
"payment_method": "mtn",
"description": f"Daily delivery payments - {datetime.now().strftime('%Y-%m-%d')}",
"auto_release": {
"enabled": True,
"delay_hours": 2,
"conditions": ["all_terms_fulfilled"]
},
"notification_settings": {
"email_notifications": True,
"sms_notifications": True,
"webhook_url": "https://delivery-company.com/webhooks/escrow-updates"
}
}
response = requests.post(
f"{self.base_url}/api/escrow-disbursements",
headers=self.headers,
json=disbursement_data
)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Failed to create disbursement: {response.json()}")
def monitor_delivery_progress(self, disbursement_id: str) -> Dict:
"""Monitor real-time progress of delivery disbursement"""
response = requests.get(
f"{self.base_url}/api/escrow-disbursements/{disbursement_id}",
headers=self.headers
)
if response.status_code == 200:
data = response.json()
# Calculate delivery metrics
metrics = {
"total_routes": data["recipient_count"],
"completed_routes": data["successful_count"],
"active_routes": data["pending_count"],
"completion_rate": (data["successful_count"] / data["recipient_count"]) * 100,
"estimated_completion": self._calculate_eta(data["escrow_items"])
}
return {
"disbursement_data": data,
"delivery_metrics": metrics
}
else:
raise Exception(f"Failed to get disbursement status: {response.json()}")
def _calculate_eta(self, escrow_items: List[Dict]) -> str:
"""Calculate estimated completion time based on current progress"""
active_items = [item for item in escrow_items if item["status"] == "active"]
if not active_items:
return "All deliveries completed"
# Simple ETA calculation based on average completion time
avg_time_per_delivery = 45 # minutes
remaining_deliveries = len(active_items)
eta_minutes = remaining_deliveries * avg_time_per_delivery
eta = datetime.now() + timedelta(minutes=eta_minutes)
return eta.strftime("%Y-%m-%d %H:%M:%S")
# Usage example
def main():
delivery_manager = DeliveryEscrowManager(
api_key="your_api_key",
client_id="your_client_id"
)
# Sample delivery routes
routes = [
{
"route_id": "R001",
"driver_email": "[email protected]",
"driver_phone": "+256700111000",
"payment_amount": 25000,
"delivery_stops": [
{"lat": 0.347596, "lng": 32.582520},
{"lat": 0.315789, "lng": 32.576543}
]
}
]
# Create disbursement
disbursement = delivery_manager.create_daily_delivery_batch(routes)
print(f"Created disbursement: {disbursement['disbursement_id']}")
# Monitor progress
progress = delivery_manager.monitor_delivery_progress(disbursement['disbursement_id'])
print(f"Completion rate: {progress['delivery_metrics']['completion_rate']:.1f}%")
Service Provider Integration
Node.js Implementation for Service Marketplace:
const axios = require('axios');
class ServiceEscrowManager {
constructor(apiKey, clientId) {
this.apiKey = apiKey;
this.clientId = clientId;
this.baseUrl = 'https://api.gopiaxis.com';
this.client = axios.create({
baseURL: this.baseUrl,
headers: {
'api-key': apiKey,
'X-Piaxis-Client-ID': clientId,
'Content-Type': 'application/json'
}
});
}
async createServiceBatch(serviceBookings) {
const recipients = serviceBookings.map(booking => ({
email: booking.provider_email,
phone_number: booking.provider_phone,
amount: booking.service_fee.toString(),
reference: `SERVICE_${booking.booking_id}`,
terms: this.buildServiceTerms(booking)
}));
const disbursementData = {
recipients,
currency: 'UGX',
payment_method: 'piaxis_external',
description: `Service payments batch - ${new Date().toISOString().split('T')[0]}`,
auto_release: {
enabled: true,
delay_hours: 4,
conditions: ['all_terms_fulfilled', 'customer_satisfaction']
}
};
try {
const response = await this.client.post('/api/escrow-disbursements', disbursementData);
return response.data;
} catch (error) {
console.error('Failed to create service disbursement:', error.response?.data);
throw error;
}
}
buildServiceTerms(booking) {
const terms = [];
// Add location verification for on-site services
if (booking.service_type === 'on_site') {
terms.push({
term_type: 'location_verification',
data: {
latitude: booking.service_location.lat,
longitude: booking.service_location.lng,
radius: 50,
description: `Verify arrival at ${booking.customer_address}`,
verification_window: {
start_time: booking.appointment_start,
end_time: booking.appointment_end
}
}
});
}
// Add photo requirements based on service type
if (booking.requires_photo_proof) {
terms.push({
term_type: 'photo_upload',
data: {
description: `Upload ${booking.service_type} completion photos`,
required_count: booking.min_photos || 2,
accepted_formats: ['jpeg', 'png'],
metadata_required: ['timestamp', 'location'],
ai_validation: {
enabled: true,
check_quality: true,
verify_authenticity: true
}
}
});
}
// Add customer confirmation
terms.push({
term_type: 'delivery_confirmation',
data: {
description: 'Customer satisfaction confirmation',
deadline: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
require_rating: true,
min_rating: 3
}
});
return terms;
}
async trackServiceProgress(disbursementId) {
try {
const response = await this.client.get(`/api/escrow-disbursements/${disbursementId}`);
const data = response.data;
// Generate service analytics
const analytics = {
total_services: data.recipient_count,
completed_services: data.successful_count,
in_progress: data.pending_count,
completion_rate: (data.successful_count / data.recipient_count) * 100,
average_service_time: this.calculateAverageServiceTime(data.escrow_items),
provider_performance: this.analyzeProviderPerformance(data.escrow_items)
};
return {
disbursement: data,
analytics
};
} catch (error) {
console.error('Failed to track service progress:', error.response?.data);
throw error;
}
}
calculateAverageServiceTime(escrowItems) {
const completedItems = escrowItems.filter(item => item.status === 'completed');
if (completedItems.length === 0) return null;
const totalTime = completedItems.reduce((sum, item) => {
const startTime = new Date(item.created_at);
const endTime = new Date(item.completed_at);
return sum + (endTime - startTime);
}, 0);
const avgTimeMs = totalTime / completedItems.length;
return Math.round(avgTimeMs / (1000 * 60 * 60 * 100)) / 100; // Hours with 2 decimal places
}
analyzeProviderPerformance(escrowItems) {
const providers = {};
escrowItems.forEach(item => {
const email = item.recipient_email;
if (!providers[email]) {
providers[email] = {
total_jobs: 0,
completed_jobs: 0,
completion_rate: 0,
avg_completion_time: 0
};
}
providers[email].total_jobs++;
if (item.status === 'completed') {
providers[email].completed_jobs++;
}
providers[email].completion_rate =
(providers[email].completed_jobs / providers[email].total_jobs) * 100;
});
return providers;
}
}
// Usage example
async function processServiceBookings() {
const serviceManager = new ServiceEscrowManager(
'your_api_key',
'your_client_id'
);
const bookings = [
{
booking_id: 'BK001',
provider_email: '[email protected]',
provider_phone: '+256700555000',
service_fee: 75000,
service_type: 'on_site',
service_location: { lat: 0.347596, lng: 32.582520 },
customer_address: 'Kampala Central',
appointment_start: '09:00',
appointment_end: '12:00',
requires_photo_proof: true,
min_photos: 2
}
];
try {
const disbursement = await serviceManager.createServiceBatch(bookings);
console.log('Service disbursement created:', disbursement.disbursement_id);
// Track progress periodically
const progress = await serviceManager.trackServiceProgress(disbursement.disbursement_id);
console.log('Service completion rate:', progress.analytics.completion_rate.toFixed(1) + '%');
} catch (error) {
console.error('Service processing failed:', error.message);
}
}
module.exports = { ServiceEscrowManager };
Advanced Features and Configuration
Auto-Release Configuration
Configure automatic fund release based on conditions and time delays.
Simple Auto-Release:
{
"auto_release": {
"enabled": true,
"delay_hours": 24,
"conditions": ["all_terms_fulfilled"]
}
}
Advanced Auto-Release with Conditions:
{
"auto_release": {
"enabled": true,
"delay_hours": 4,
"conditions": [
"all_terms_fulfilled",
"customer_satisfaction",
"photo_quality_approved"
],
"business_hours_only": true,
"exclude_weekends": false,
"timezone": "Africa/Kampala",
"fallback_strategy": {
"max_wait_hours": 72,
"action": "manual_review"
}
}
}
Notification and Webhook Configuration
Set up comprehensive notification systems for disbursement tracking.
Notification Settings:
{
"notification_settings": {
"email_notifications": true,
"sms_notifications": true,
"push_notifications": true,
"webhook_url": "https://your-app.com/webhooks/escrow-updates",
"webhook_events": [
"disbursement_created",
"escrow_term_fulfilled",
"escrow_completed",
"disbursement_completed",
"escrow_expired"
],
"notification_templates": {
"email_template_id": "custom_template_001",
"sms_template_id": "sms_template_001"
},
"notification_schedule": {
"immediate": ["escrow_completed", "term_fulfilled"],
"hourly_digest": ["progress_updates"],
"daily_summary": ["completion_statistics"]
}
}
}
Webhook Payload Examples:
{
"event_type": "escrow_term_fulfilled",
"timestamp": "2025-06-05T14:30:00Z",
"disbursement_id": "987fcdeb-51a2-43d1-9f4e-123456789abc",
"escrow_id": "escrow_001_abc123",
"data": {
"term_id": "term_456_def789",
"term_type": "location_verification",
"fulfilled_by": "[email protected]",
"fulfillment_timestamp": "2025-06-05T14:30:00Z",
"fulfillment_data": {
"location": {
"latitude": 0.347596,
"longitude": 32.582520,
"accuracy": 5.2
}
},
"recipient_info": {
"email": "[email protected]",
"reference": "DELIVERY-001"
}
}
}
Metadata and Custom Fields
Add custom data to disbursements for enhanced tracking and integration.
Comprehensive Metadata Example:
{
"metadata": {
"business_context": {
"department": "logistics",
"cost_center": "DELIVERY_OPS",
"project_id": "PROJ_2025_Q2_001",
"campaign_id": "SUMMER_DELIVERY_2025"
},
"operational_data": {
"batch_type": "daily_routes",
"priority_level": "standard",
"estimated_duration_hours": 8,
"weather_conditions": "clear",
"vehicle_type": "motorcycle"
},
"tracking_info": {
"external_reference": "EXT_REF_789123",
"erp_integration_id": "ERP_INT_456",
"analytics_tags": ["delivery", "urban", "same_day"]
},
"compliance": {
"regulatory_requirements": ["local_permit", "insurance_valid"],
"audit_trail_required": true,
"data_retention_days": 2555
}
}
}
Error Handling and Troubleshooting
Comprehensive error handling guide for escrow disbursements.
Common Error Scenarios
Validation Errors:
{
"detail": "Disbursement validation failed",
"error_code": "VALIDATION_ERROR",
"errors": {
"recipients[0].amount": ["Amount must be greater than 1000 UGX"],
"recipients[1].terms": ["At least one term is required"],
"payment_method": ["MTN payment method not available for this merchant"]
},
"request_id": "req_disb_001"
}
Business Logic Errors:
{
"detail": "Insufficient merchant balance",
"error_code": "INSUFFICIENT_BALANCE",
"context": {
"required_amount": "500000.00",
"available_balance": "250000.00",
"currency": "UGX",
"merchant_id": "merchant_123"
},
"suggested_actions": [
"Add funds to merchant account",
"Reduce disbursement amount",
"Split into smaller batches"
],
"request_id": "req_disb_002"
}
Rate Limiting:
{
"detail": "Rate limit exceeded",
"error_code": "RATE_LIMIT_EXCEEDED",
"context": {
"limit": 10,
"window": "60 seconds",
"reset_time": "2025-06-05T15:01:00Z",
"current_usage": 10
},
"retry_after": 45,
"request_id": "req_disb_003"
}
Error Recovery Strategies
Python Error Recovery Example:
import time
import requests
from typing import Dict, List
import logging
class RobustEscrowDisbursement:
def __init__(self, api_key: str, client_id: str):
self.api_key = api_key
self.client_id = client_id
self.base_url = "https://api.gopiaxis.com"
self.logger = logging.getLogger(__name__)
def create_disbursement_with_retry(self, disbursement_data: Dict, max_retries: int = 3) -> Dict:
"""Create disbursement with automatic retry logic"""
headers = {
'api-key': self.api_key,
'X-Piaxis-Client-ID': self.client_id,
'Content-Type': 'application/json'
}
for attempt in range(max_retries + 1):
try:
response = requests.post(
f"{self.base_url}/api/escrow-disbursements",
headers=headers,
json=disbursement_data,
timeout=30
)
if response.status_code == 200:
return response.json()
elif response.status_code == 429: # Rate limited
error_data = response.json()
retry_after = error_data.get('retry_after', 60)
self.logger.warning(f"Rate limited, waiting {retry_after} seconds")
time.sleep(retry_after)
continue
elif response.status_code == 400: # Validation error
error_data = response.json()
if error_data.get('error_code') == 'INSUFFICIENT_BALANCE':
# Handle insufficient balance
return self._handle_insufficient_balance(disbursement_data, error_data)
else:
# Other validation errors - don't retry
raise Exception(f"Validation error: {error_data}")
elif 500 <= response.status_code < 600: # Server error
if attempt < max_retries:
wait_time = (2 ** attempt) * 5 # Exponential backoff
self.logger.warning(f"Server error, retrying in {wait_time} seconds")
time.sleep(wait_time)
continue
else:
raise Exception(f"Server error after {max_retries} retries: {response.json()}")
else:
raise Exception(f"Unexpected error: {response.status_code} {response.json()}")
except requests.exceptions.Timeout:
if attempt < max_retries:
wait_time = (2 ** attempt) * 10
self.logger.warning(f"Request timeout, retrying in {wait_time} seconds")
time.sleep(wait_time)
continue
else:
raise Exception("Request timeout after maximum retries")
except requests.exceptions.ConnectionError:
if attempt < max_retries:
wait_time = (2 ** attempt) * 15
self.logger.warning(f"Connection error, retrying in {wait_time} seconds")
time.sleep(wait_time)
continue
else:
raise Exception("Connection error after maximum retries")
raise Exception("Maximum retry attempts exceeded")
def _handle_insufficient_balance(self, disbursement_data: Dict, error_data: Dict) -> Dict:
"""Handle insufficient balance by splitting disbursement"""
required_amount = float(error_data['context']['required_amount'])
available_balance = float(error_data['context']['available_balance'])
if available_balance < required_amount * 0.1: # Less than 10% available
raise Exception("Insufficient balance - manual intervention required")
# Split recipients into smaller batches
recipients = disbursement_data['recipients']
batch_size = max(1, int(len(recipients) * (available_balance / required_amount)))
self.logger.info(f"Splitting {len(recipients)} recipients into batches of {batch_size}")
results = []
for i in range(0, len(recipients), batch_size):
batch_recipients = recipients[i:i + batch_size]
batch_data = disbursement_data.copy()
batch_data['recipients'] = batch_recipients
batch_data['description'] += f" (Batch {i//batch_size + 1})"
# Retry with smaller batch
batch_result = self.create_disbursement_with_retry(batch_data, max_retries=2)
results.append(batch_result)
# Small delay between batches
time.sleep(1)
return {
"batch_results": results,
"total_batches": len(results),
"split_due_to_balance": True
}
Best Practices and Optimization
Performance Optimization
-
Batch Size Optimization: - Recommended batch size: 25-50 recipients - Monitor processing time vs batch size - Consider payment method limitations - Balance between efficiency and error handling
-
Request Optimization: - Use compression for large payloads - Implement request deduplication - Cache frequently used data - Use appropriate timeouts
-
Monitoring and Alerting: - Track disbursement success rates - Monitor fulfillment completion times - Set up alerts for high failure rates - Analyze performance trends
Business Logic Best Practices
-
Term Design: - Make terms clear and achievable - Set realistic deadlines - Provide clear instructions - Consider local constraints (network, location accuracy)
-
User Experience: - Send clear notifications to recipients - Provide progress tracking - Offer support channels - Handle edge cases gracefully
-
Risk Management: - Implement fraud detection - Monitor unusual patterns - Set appropriate limits - Plan for dispute resolution
Security Considerations
-
Data Protection: - Encrypt sensitive data in transit and at rest - Implement proper access controls - Audit all operations - Follow PCI DSS guidelines for payment data
-
API Security: - Rotate API keys regularly - Use HTTPS for all communications - Implement proper authentication - Monitor for suspicious activity
-
Compliance: - Follow local financial regulations - Implement KYC/AML procedures - Maintain audit trails - Handle data retention requirements
Production Deployment Checklist
Pre-Deployment: - [ ] Load testing completed - [ ] Error handling tested - [ ] Webhook endpoints secured - [ ] Monitoring systems configured - [ ] API keys properly managed - [ ] Documentation updated
Deployment: - [ ] Blue-green deployment strategy - [ ] Database migrations tested - [ ] Rollback plan prepared - [ ] Health checks configured - [ ] Logging properly configured
Post-Deployment: - [ ] Monitor success rates - [ ] Check performance metrics - [ ] Verify webhook delivery - [ ] Test notification systems - [ ] Review error logs
Support and Troubleshooting
Common Issues and Solutions
Issue: High disbursement failure rates
Symptoms: Many disbursements failing to create or complete Possible Causes: - Insufficient merchant balance - Invalid recipient information - Network connectivity issues - Payment method restrictions
Solutions: 1. Check merchant balance before creating disbursements 2. Validate recipient data before submission 3. Implement retry logic with exponential backoff 4. Monitor payment method availability
Issue: Slow term fulfillment
Symptoms: Recipients taking too long to fulfill terms Possible Causes: - Terms too complex or unclear - Poor mobile network coverage - Inadequate user education - Technical difficulties
Solutions: 1. Simplify term requirements 2. Provide clearer instructions 3. Offer multiple fulfillment methods 4. Implement user support systems
Issue: Webhook delivery failures
Symptoms: Not receiving webhook notifications Possible Causes: - Incorrect webhook URL - Server downtime - SSL certificate issues - Request timeout
Solutions: 1. Verify webhook URL accessibility 2. Implement proper SSL certificates 3. Use webhook testing tools 4. Implement retry logic for webhook processing
Emergency Procedures
Production Issues: - Contact: support@piaxis.com (mark as URGENT) - Include: disbursement_id, error details, timestamp - Escalation: Available 24/7 for critical issues
Data Issues: - Document all data discrepancies - Provide request_id for investigation - Do not retry failed operations without investigation
Security Issues: - Immediately report suspected security breaches - Rotate API keys if compromise suspected - Monitor for unusual transaction patterns
Resources and Support
Documentation: - API Reference: https://docs.gopiaxis.com/api/disbursements - Integration Guides: https://docs.gopiaxis.com/guides - Best Practices: https://docs.gopiaxis.com/best-practices
Development Tools: - Postman Collection: Available for API testing - SDK Libraries: Python, Node.js, PHP available - Webhook Testing: Use ngrok or webhook.site for development
Community and Support: - Developer Forum: https://community.gopiaxis.com - Technical Support: developers@piaxis.com - Status Page: https://status.gopiaxis.com - Changelog: https://docs.gopiaxis.com/changelog
Training and Certification: - API Integration Training: Available monthly - Best Practices Workshops: Quarterly sessions - Certification Program: For enterprise clients