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:

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:

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:
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

  1. 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

  2. Request Optimization: - Use compression for large payloads - Implement request deduplication - Cache frequently used data - Use appropriate timeouts

  3. 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

  1. Term Design: - Make terms clear and achievable - Set realistic deadlines - Provide clear instructions - Consider local constraints (network, location accuracy)

  2. User Experience: - Send clear notifications to recipients - Provide progress tracking - Offer support channels - Handle edge cases gracefully

  3. Risk Management: - Implement fraud detection - Monitor unusual patterns - Set appropriate limits - Plan for dispute resolution

Security Considerations

  1. Data Protection: - Encrypt sensitive data in transit and at rest - Implement proper access controls - Audit all operations - Follow PCI DSS guidelines for payment data

  2. API Security: - Rotate API keys regularly - Use HTTPS for all communications - Implement proper authentication - Monitor for suspicious activity

  3. 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