UNPKG

@dispatch9/client-sdk

Version:

Official Node.js SDK for Dispatch9 API - Complete solution with email/phone client creation, order management, client management, and dual-method authentication

1,050 lines (884 loc) 35 kB
# Dispatch9 Node.js SDK Official Node.js SDK for the Dispatch9 API. Simplify integration with Dispatch9's delivery and logistics platform. ## Core Operations This SDK focuses on the 4 essential operations: -**Create Orders** - Create delivery and service orders -**Update Orders** - Modify existing orders -**Create Clients** - Add new clients to your system -**Update Clients** - Modify existing client information ## Installation ```bash npm install @dispatch9/client-sdk ``` ## Quick Start ```javascript const Dispatch9Client = require('@dispatch9/client-sdk'); // Initialize the client const dispatch9 = new Dispatch9Client({ apiKey: 'your-api-key-here', baseURL: 'https://api.dispatch9.com' // or your server URL }); // Create a client const client = await dispatch9.createClient({ name: 'Acme Corporation', email: 'contact@acmecorp.com', businessType: 'retail' }); // Create an order (addresses must be created separately first) const order = await dispatch9.createOrder({ orderTotal: 49.99, client: client.id, hasGoods: true, items: [ { SKU: 'ITEM001', itemName: 'Sample Product', price: 49.99, quantity: 1 } ], pickupLocation: 'pickup-address-id', // Use ID from previously created address deliveryLocation: 'delivery-address-id' // Use ID from previously created address }); // Update the order const updatedOrder = await dispatch9.updateOrder(order.id, { status: 'confirmed', priority: 5, specialInstructions: 'Handle with care' }); console.log('Order updated:', updatedOrder.status); ``` ## Configuration ### Constructor Options ```javascript const dispatch9 = new Dispatch9Client({ apiKey: 'your-api-key-here', // Required: Your API key baseURL: 'https://api.dispatch9.com', // Optional: API base URL timeout: 30000, // Optional: Request timeout (ms) debug: false, // Optional: Enable debug logging headers: {} // Optional: Additional headers }); ``` ## API Reference ### Important: Address Management **⚠️ Note**: This SDK focuses on the 4 core operations listed above. Address management is handled separately through the Dispatch9 API. **Address Workflow:** 1. **Create addresses first** using the address API endpoints (not included in this SDK) 2. **Save the returned address IDs** from the address creation responses 3. **Use those address IDs** in your order creation calls **Address Creation Schema (POST /v1/addresses):** **Required Fields:** - `street` (string) - Street address (1-255 characters) - `city` (string) - City name (1-100 characters) - `state` (string) - State/province (1-100 characters) - `country` (string) - Country name (1-100 characters) **Optional Fields:** - `building` (string) - Building number/name (max 100 characters) - `apartment` (string) - Apartment/unit number (max 50 characters) - `postalCode` (string) - Postal/ZIP code (max 20 characters) - `country_code` (string) - 2-letter country code (uppercase) - `instructions` (string) - Delivery instructions (max 500 characters) - `contactName` (string) - Contact person name (max 100 characters) - `contactPhone` (string) - Contact phone number (valid international format) - `contactEmail` (string) - Contact email address (valid email) - `timeWindow` (object) - Delivery time window - `start` (Date) - Start time - `end` (Date) - End time - `timezone` (string) - Timezone identifier (e.g., "America/New_York") - `days` (Array) - Available days ["monday", "tuesday", etc.] - `notes` (string) - Additional schedule notes (max 500 characters) **Google Geocoding Fields (Optional):** - `formatted_address` (string) - Google formatted address - `place_id` (string) - Google Place ID - `geometry` (object) - Geographic coordinates - `location` (object) - Point coordinates `{type: "Point", coordinates: [lng, lat]}` **Example Address Creation Flow:** ```javascript // 1. Create pickup address using Dispatch9 API (separate HTTP call) const pickupResponse = await fetch('https://api.dispatch9.com/v1/addresses', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'your-api-key' }, body: JSON.stringify({ street: '123 Warehouse Street', city: 'San Francisco', state: 'California', country: 'United States', postalCode: '94105', contactName: 'Warehouse Manager', contactPhone: '+1-555-0123', instructions: 'Loading dock entrance' }) }); const pickupAddress = await pickupResponse.json(); // Returns: { id: '507f1f77bcf86cd799439012', street: '123 Warehouse Street', ... } // 2. Create delivery address using Dispatch9 API (separate HTTP call) const deliveryResponse = await fetch('https://api.dispatch9.com/v1/addresses', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Key': 'your-api-key' }, body: JSON.stringify({ street: '456 Customer Avenue, Apt 3B', city: 'San Francisco', state: 'California', country: 'United States', postalCode: '94107', contactName: 'John Customer', contactPhone: '+1-555-0456', instructions: 'Ring apartment 3B' }) }); const deliveryAddress = await deliveryResponse.json(); // Returns: { id: '507f1f77bcf86cd799439013', street: '456 Customer Avenue, Apt 3B', ... } // 3. Use the address IDs in your order (using this SDK) const order = await dispatch9.createOrder({ orderTotal: 49.99, client: 'client-id', pickupLocation: pickupAddress.id, // '507f1f77bcf86cd799439012' deliveryLocation: deliveryAddress.id, // '507f1f77bcf86cd799439013' hasGoods: true, items: [/* ... */] }); ``` ### Order Management #### `createOrder(orderData)` Create a new order. **Required Fields:** - `orderTotal` (number) - Total order amount (min: 0) - `client` (string) - Client ID (ObjectId) **Optional Fields:** - `orderNumber` (string) - Custom order number - `orderCurrency` (string) - Order currency (default: 'USD') - `isPaid` (boolean) - Payment status (default: false) - `hasGoods` (boolean) - Contains goods/items (default: false) - `hasServices` (boolean) - Contains services (default: false) - `hasWorkers` (boolean) - Requires worker transport (default: false) - `priority` (number) - Priority 0-10 (default: 0) - `autoAssign` (boolean) - Auto-assign workers (default: false) - `manualAssignWorker` (string) - Worker ID for manual assignment - `status` (string) - Order status (default: 'created') - `completeAfter` (number) - Earliest completion timestamp - `completeBefore` (number) - Latest completion timestamp - `pickupLocation` (string) - Pickup address ID (ObjectId - create address first, then use the returned ID) - `deliveryLocation` (string) - Delivery address ID (ObjectId - create address first, then use the returned ID) - `serviceLocation` (string) - Service address ID (ObjectId - create address first, then use the returned ID, required if `hasServices=true`) - `specialInstructions` (string) - Special delivery instructions - `customerNotes` (string) - Customer notes - `metadata` (Object) - Additional metadata - `isRecurring` (boolean) - Is recurring order (default: false) - `recurringSettings` (Object) - Recurring settings (required if `isRecurring=true`) - `requiredProof` (Object) - Proof of delivery requirements - `signature` (boolean) - Require signature (default: false) - `photo` (boolean) - Require photo (default: false) **Conditional Required Fields:** - `items` (Array) - Items array (required if `hasGoods=true`) - `services` (Array) - Services array (required if `hasServices=true`) - `workers` (Array) - Workers array (required if `hasWorkers=true`) **Item Schema** (when `hasGoods=true`): - `SKU` (string, required) - Item SKU - `itemName` (string, required) - Item name - `price` (number, required) - Item price (min: 0) - `quantity` (number, required) - Quantity (min: 1) - `category` (string) - Item category - `description` (string) - Item description - `currency` (string) - Item currency (default: 'USD') - `weight` (number) - Item weight - `weightUnit` (string) - Weight unit: `kg`, `lb`, `g`, `oz` (default: 'kg') - `dimensionH` (number) - Height - `dimensionW` (number) - Width - `dimensionL` (number) - Length - `dimensionUnit` (string) - Dimension unit: `cm`, `in` (default: 'cm') - `packaging` (string) - Packaging requirements - `handling` (string) - Handling instructions - `notes` (string) - Item notes **Service Schema** (when `hasServices=true`): - `serviceCode` (string, required) - Service code/identifier - `serviceName` (string, required) - Service name - `category` (string, required) - Service category (any string value for flexible categorization) - `description` (string) - Service description - `estimatedDuration` (number) - Estimated duration in minutes (default: 60) - `price` (number, required) - Service price (min: 0) - `currency` (string) - Service currency (default: 'USD') - `requirements` (Array) - Service requirements - can be strings or structured objects: - String requirements: `'Tools'`, `'Safety equipment'`, etc. - Object requirements for workers: `{ type: 'workers', count: 2, description: 'Technicians required' }` - Object requirements for other resources: `{ type: 'tools'|'qualifications'|'equipment', description: 'Details', mandatory: true }` - `notes` (string) - Service notes or special instructions **Example:** ```javascript // Note: Addresses must be created first using the address API endpoints // Then use the returned address IDs in the order const order = await dispatch9.createOrder({ orderTotal: 99.99, client: '507f1f77bcf86cd799439011', hasGoods: true, items: [ { SKU: 'PROD001', itemName: 'Premium Widget', price: 99.99, quantity: 1, category: 'Electronics', weight: 2.5, weightUnit: 'kg' } ], pickupLocation: '507f1f77bcf86cd799439012', // ID from created address deliveryLocation: '507f1f77bcf86cd799439013', // ID from created address specialInstructions: 'Handle with care', priority: 5 }); ``` **Service Order Example:** ```javascript // Service order example with multiple workers required const serviceOrder = await dispatch9.createOrder({ orderTotal: 299.99, client: '507f1f77bcf86cd799439011', hasServices: true, services: [ { serviceCode: 'INSTALL001', serviceName: 'Appliance Installation', category: 'installation', description: 'Install washing machine and dryer', estimatedDuration: 120, price: 199.99, requirements: [ { type: 'workers', count: 2, description: '2 installers required' }, 'Tools', { type: 'qualifications', description: 'Electrical knowledge', mandatory: true } ], notes: 'Customer will be home between 2-4 PM' }, { serviceCode: 'CLEAN001', serviceName: 'Post-Installation Cleanup', category: 'housekeeping', // Custom category example description: 'Clean up installation area', estimatedDuration: 30, price: 100.00, requirements: [ { type: 'workers', count: 1, description: 'Single cleaner' }, 'Cleaning supplies' ] } ], serviceLocation: '507f1f77bcf86cd799439014', // ID from created address specialInstructions: 'Call customer 30 minutes before arrival', priority: 7 }); ``` ### 🔧 **Service Requirements & Multiple Jobs** The new `requirements` array supports both simple string requirements and structured object requirements. When a service specifies multiple workers, the system automatically creates separate jobs for each worker, enabling individual assignment and tracking. **Requirements Format:** ```javascript requirements: [ // String requirements (tools, materials, etc.) 'Cleaning supplies', 'Safety equipment', // Structured worker requirements { type: 'workers', count: 3, // Creates 3 separate jobs description: 'Experienced cleaners', mandatory: true }, // Other structured requirements { type: 'qualifications', description: 'OSHA certification', mandatory: true }, { type: 'tools', description: 'Industrial vacuum cleaners' }, { type: 'equipment', description: 'Scaffolding for high areas' } ] ``` **Multiple Job Creation:** - Service with `{ type: 'workers', count: 3 }` → Creates 3 separate jobs - Service with `{ type: 'workers', count: 1 }` → Creates 1 job - Service with no worker requirement → Creates 1 job (default) **Benefits:** - ✅ Individual job assignment to different workers - ✅ Independent tracking and status updates - ✅ Flexible resource management - ✅ Better scheduling and coordination #### `updateOrder(orderId, updateData)` Update an existing order. **Parameters:** - `orderId` (string, required) - Order ID (ObjectId) - `updateData` (Object, required) - Data to update (at least one field required) **All fields are optional** (but at least one must be provided): - `orderNumber` (string) - Custom order number - `hasGoods` (boolean) - Order contains goods/items - `hasServices` (boolean) - Order contains services - `hasWorkers` (boolean) - Order requires worker transport - `priority` (number) - Order priority (0-10) - `autoAssign` (boolean) - Auto-assign to workers - `status` (string) - Order status: `created`, `confirmed`, `in_progress`, `completed`, `cancelled`, `partially_completed` - `items` (Array) - Items array (follows same schema as createOrder) - `services` (Array) - Services array (follows same schema as createOrder) - `workers` (Array) - Workers array - `pickupLocation` (string) - Pickup address ID (ObjectId - must be created first) - `deliveryLocation` (string) - Delivery address ID (ObjectId - must be created first) - `serviceLocation` (string) - Service address ID (ObjectId - must be created first) - `specialInstructions` (string) - Special delivery instructions - `customerNotes` (string) - Customer notes - `statusNotes` (string) - Status notes - `metadata` (Object) - Additional metadata - `isRecurring` (boolean) - Is this a recurring order - `recurringSettings` (Object) - Recurring settings **Item Schema** (when updating items): Same as `createOrder` - all item fields follow the same validation rules. **Service Schema** (when updating services): Same as `createOrder` - all service fields follow the same validation rules. **Example:** ```javascript const updatedOrder = await dispatch9.updateOrder('507f1f77bcf86cd799439014', { status: 'confirmed', priority: 8, specialInstructions: 'Urgent delivery - customer called', items: [ { SKU: 'PROD001', itemName: 'Premium Widget (Updated)', price: 109.99, quantity: 2, category: 'Electronics' } ] }); ``` #### `getOrderById(orderId, options)` Get a specific order by its ID with optional population of related fields. **Parameters:** - `orderId` (string, required) - Order ID (must be valid ObjectId) - `options` (Object, optional) - Query options - `populate` (string) - Comma-separated list of fields to populate - Available fields: `client`, `pickupLocation`, `deliveryLocation`, `serviceLocation`, `workers.worker` - `includeJobs` (boolean) - Include associated jobs in response **Returns:** Promise<Order> - Complete order details **Examples:** ```javascript // Get basic order details const order = await dispatch9.getOrderById('507f1f77bcf86cd799439011'); console.log(`Order Status: ${order.status}`); console.log(`Order Total: $${order.orderTotal}`); // Get order with populated client and location details const orderWithDetails = await dispatch9.getOrderById('507f1f77bcf86cd799439011', { populate: 'client,pickupLocation,deliveryLocation,serviceLocation' }); console.log(`Client: ${orderWithDetails.client.name}`); console.log(`Pickup: ${orderWithDetails.pickupLocation.street}`); // Get order with associated jobs for tracking const orderWithJobs = await dispatch9.getOrderById('507f1f77bcf86cd799439011', { includeJobs: true }); console.log(`Jobs: ${orderWithJobs.jobs.length}`); orderWithJobs.jobs.forEach(job => { console.log(`Job ${job.jobId}: ${job.status}`); }); // Check order status for tracking/monitoring const checkOrderStatus = async (orderId) => { try { const order = await dispatch9.getOrderById(orderId); return { id: order.id, status: order.status, progress: order.completionPercentage || 0, estimatedDelivery: order.estimatedDeliveryTime, isCompleted: order.status === 'completed' }; } catch (error) { if (error.message.includes('404')) { return { error: 'Order not found' }; } throw error; } }; ``` ### Client Management #### `getClients(options)` Retrieve clients with filtering and pagination. **Parameters:** - `options` (Object, optional) - Query options - `name` (string) - Filter by client name - `status` (string) - Filter by status: `active`, `inactive`, `suspended` - `businessType` (string) - Filter by business type: `restaurant`, `retail`, `grocery`, `pharmacy`, `other` - `sortBy` (string) - Sort field - `limit` (number) - Items per page - `page` (number) - Page number **Example:** ```javascript const clients = await dispatch9.getClients({ businessType: 'retail', status: 'active', limit: 20 }); ``` #### `createClient(clientData)` Create a new client with email or phone number. **Required Fields:** - `name` (string) - Client/business name (min: 1 character) **Contact Information (at least one required):** - `email` (string, optional) - Client email (must be valid email if provided) - `phone` (string, optional) - Client phone number (must be valid phone if provided) **Note:** At least one of `email` OR `phone` is required for client creation. **Optional Fields:** - `websiteURL` (string) - Website URL (must be valid URI) - `logoURL` (string) - Logo URL (must be valid URI) - `businessType` (string) - Business type: `restaurant`, `retail`, `grocery`, `pharmacy`, `other` - `taxId` (string) - Tax identification number - `address` (string) - Address ID (ObjectId) - `webhookURL` (string) - Webhook URL for notifications (must be valid URI) **Optional Objects:** - `apiConfig` (Object) - API configuration - `enabled` (boolean) - Enable API access (default: true) - `rateLimit` (number) - API rate limit (default: 1000, min: 1) - `integrations` (Array) - Third-party integrations - `platform` (string, required) - Platform name - `enabled` (boolean) - Integration enabled (default: false) - `config` (Object) - Integration configuration (default: {}) - `webhookSecret` (string) - Webhook secret - `syncOrders` (boolean) - Sync orders (default: true) - `orderSettings` (Object) - Order settings - `autoAccept` (boolean) - Auto-accept orders (default: false) - `autoAssign` (boolean) - Auto-assign workers (default: false) - `maxOrdersPerHour` (number) - Max orders per hour (default: 50, min: 1) - `preparationTime` (number) - Preparation time in minutes (default: 15, min: 1) - `deliveryRadius` (number) - Delivery radius (default: 10, min: 0) - `permissions` (Object) - Client permissions - `modify` (boolean) - Can modify settings (default: false) - `delete` (boolean) - Can delete data (default: false) - `createOrders` (boolean) - Can create orders (default: true) - `viewOrders` (boolean) - Can view orders (default: true) - `authentication` (Object) - Authentication settings - `enablePortalAccess` (boolean, required) - Enable portal access - `phone` (string) - Phone number - `password` (string) - Password - `firstName` (string) - First name - `lastName` (string) - Last name - `businessName` (string) - Business name **Examples:** ```javascript // Create client with email const clientWithEmail = await dispatch9.createClient({ name: 'Acme Corporation', email: 'contact@acmecorp.com', businessType: 'retail', websiteURL: 'https://www.acmecorp.com', taxId: '12-3456789', orderSettings: { autoAccept: true, maxOrdersPerHour: 25, deliveryRadius: 15 }, permissions: { createOrders: true, viewOrders: true } }); // Create client with phone number only const clientWithPhone = await dispatch9.createClient({ name: 'Mobile Business', phone: '+1234567890', businessType: 'restaurant' }); // Create client with both email and phone const clientWithBoth = await dispatch9.createClient({ name: 'Full Contact Business', email: 'info@business.com', phone: '+1 (234) 567-8900', businessType: 'grocery', authentication: { enablePortalAccess: true, password: 'securePassword123', firstName: 'John', lastName: 'Doe' } }); ``` #### `updateClient(clientId, updateData)` Update an existing client. **Parameters:** - `clientId` (string, required) - Client ID (ObjectId) - `updateData` (Object, required) - Data to update (at least one field required) **All fields are optional** (but at least one must be provided): - `name` (string) - Client name (min: 1 character) - `email` (string) - Client email (must be valid email) - `phone` (string) - Client phone number (must be valid phone) - `websiteURL` (string) - Website URL (must be valid URI) - `logoURL` (string) - Logo URL (must be valid URI) - `status` (string) - Status: `active`, `inactive`, `suspended` - `businessType` (string) - Business type: `restaurant`, `retail`, `grocery`, `pharmacy`, `other` - `taxId` (string) - Tax ID - `address` (string) - Address ID (ObjectId) - `contactName` (string) - Contact name (min: 1 character) - `contactPhone` (string) - Contact phone (min: 10 characters) - `timeWindow` (Object) - Time window - `start` (Date) - Start time - `end` (Date) - End time - `webhookURL` (string) - Webhook URL (must be valid URI) - `apiConfig` (Object) - API configuration - `enabled` (boolean) - Enable API access - `rateLimit` (number) - API rate limit (min: 1) - `permissions` (Object) - Client permissions - `modify` (boolean) - Can modify settings - `delete` (boolean) - Can delete data - `createOrders` (boolean) - Can create orders - `viewOrders` (boolean) - Can view orders - `orderSettings` (Object) - Order settings - `autoAccept` (boolean) - Auto-accept orders - `autoAssign` (boolean) - Auto-assign workers - `maxOrdersPerHour` (number) - Max orders per hour (min: 1) - `preparationTime` (number) - Preparation time (min: 1) - `deliveryRadius` (number) - Delivery radius (min: 0) **Example:** ```javascript const updatedClient = await dispatch9.updateClient('507f1f77bcf86cd799439011', { name: 'Acme Corp (Updated)', websiteURL: 'https://www.newacmecorp.com', orderSettings: { maxOrdersPerHour: 30, deliveryRadius: 20 } }); ``` #### `getClientById(clientId, options)` Get a specific client by its ID with optional population of related fields and statistics. **Parameters:** - `clientId` (string, required) - Client ID (must be valid ObjectId) - `options` (Object, optional) - Query options - `populate` (string) - Comma-separated list of fields to populate - Available fields: `addresses`, `primaryAddress`, `billingAddress` - `includeStats` (boolean) - Include client statistics (order count, total revenue, etc.) **Returns:** Promise<Client> - Complete client details **Examples:** ```javascript // Get basic client details const client = await dispatch9.getClientById('507f1f77bcf86cd799439011'); console.log(`Client: ${client.name}`); console.log(`Status: ${client.status}`); console.log(`Business Type: ${client.businessType}`); // Get client with populated address details const clientWithAddresses = await dispatch9.getClientById('507f1f77bcf86cd799439011', { populate: 'addresses,primaryAddress,billingAddress' }); console.log(`Primary Address: ${clientWithAddresses.primaryAddress.street}`); console.log(`Total Addresses: ${clientWithAddresses.addresses.length}`); // Get client with statistics for analytics const clientWithStats = await dispatch9.getClientById('507f1f77bcf86cd799439011', { includeStats: true }); console.log(`Total Orders: ${clientWithStats.stats.totalOrders}`); console.log(`Total Revenue: $${clientWithStats.stats.totalRevenue}`); console.log(`Average Order Value: $${clientWithStats.stats.averageOrderValue}`); // Verify client registration and status const verifyClient = async (clientId) => { try { const client = await dispatch9.getClientById(clientId); return { exists: true, id: client.id, name: client.name, email: client.email, status: client.status, isActive: client.status === 'active', businessType: client.businessType, registrationDate: client.createdAt }; } catch (error) { if (error.message.includes('404')) { return { exists: false, error: 'Client not found or not registered' }; } throw error; } }; // Usage for client verification const clientStatus = await verifyClient('507f1f77bcf86cd799439011'); if (clientStatus.exists) { console.log(`✅ Client ${clientStatus.name} is registered and ${clientStatus.status}`); } else { console.log('❌ Client not found - please register first'); } ``` ### Client Authentication The SDK now supports comprehensive client authentication with both email and phone number login capabilities. #### `loginClient(credentials)` Authenticate a client using email address or phone number with password. **Parameters:** - `credentials` (Object, required) - Login credentials - `identifier` (string, required) - Email address or phone number - `password` (string, required) - Client password - `providerId` (string, optional) - Provider ID for multi-provider clients **Returns:** Promise<Object> - Authentication result with tokens and client data **Examples:** ```javascript // Login with email address const emailLogin = await dispatch9.loginClient({ identifier: 'client@example.com', password: 'securePassword123' }); if (emailLogin.success) { console.log('✅ Email login successful'); console.log(`Welcome ${emailLogin.client.name}`); } else { console.log('❌ Login failed:', emailLogin.message); } // Login with phone number const phoneLogin = await dispatch9.loginClient({ identifier: '+1234567890', password: 'securePassword123' }); // Login with formatted phone number const formattedPhoneLogin = await dispatch9.loginClient({ identifier: '+1 (234) 567-8900', password: 'securePassword123' }); // Handle multi-provider client login const result = await dispatch9.loginClient({ identifier: 'client@example.com', password: 'securePassword123' }); if (result.requiresProviderSelection) { console.log('Multiple providers available:'); result.providers.forEach((provider, index) => { console.log(`${index + 1}. ${provider.database} (ID: ${provider.providerId})`); }); // Select a provider (see selectClientProvider method) } // Handle first-time login OTP requirement if (result.requiresOTP) { console.log('First-time login requires OTP verification'); console.log(`OTP sent to: ${result.client.email}`); // User enters OTP, then verify (see verifyClientLoginOTP method) } ``` #### `selectClientProvider(selection)` Select a provider for clients with multiple provider access. **Parameters:** - `selection` (Object, required) - Provider selection data - `clientId` (string, required) - Client ID (ObjectId format) - `providerId` (string, required) - Provider ID to select (ObjectId format) **Returns:** Promise<Object> - Authentication result with tokens **Examples:** ```javascript // Select provider after multi-provider login const providerSelection = await dispatch9.selectClientProvider({ clientId: '507f1f77bcf86cd799439011', providerId: '507f1f77bcf86cd799439012' }); if (providerSelection.success) { console.log('✅ Provider selected successfully'); console.log(`Connected to: ${providerSelection.client.selectedProvider.database}`); // Client is now authenticated and ready to use the API } ``` #### `verifyClientLoginOTP(verification)` Verify OTP for first-time client login security. **Parameters:** - `verification` (Object, required) - OTP verification data - `clientId` (string, required) - Client ID (ObjectId format) - `otp` (string, required) - 6-digit OTP code **Returns:** Promise<Object> - Verification result with authentication tokens **Examples:** ```javascript // Verify OTP for first-time login const otpVerification = await dispatch9.verifyClientLoginOTP({ clientId: '507f1f77bcf86cd799439011', otp: '123456' }); if (otpVerification.success) { console.log('✅ OTP verified successfully'); console.log(`Welcome ${otpVerification.client.name}`); // Client is now authenticated } ``` #### `getClientProfile()` Get the current authenticated client's profile information. **Returns:** Promise<Object> - Client profile data **Examples:** ```javascript // Get current client profile (requires authentication) try { const profile = await dispatch9.getClientProfile(); console.log('📋 Client Profile:'); console.log(`Name: ${profile.name}`); console.log(`Email: ${profile.email}`); console.log(`Phone: ${profile.phone || 'Not provided'}`); console.log(`Status: ${profile.status}`); console.log(`Registration: ${profile.registrationStatus}`); console.log(`First Login: ${profile.isFirstLogin ? 'Yes' : 'No'}`); console.log(`Last Login: ${profile.lastLogin || 'Never'}`); console.log('\n🏢 Available Providers:'); profile.providers.forEach((provider, index) => { console.log(`${index + 1}. ${provider.database} (${provider.status})`); }); } catch (error) { console.log('❌ Authentication required or profile access failed'); } ``` ### Complete Authentication Flow Examples **Basic Email/Phone Login:** ```javascript const authenticateClient = async (identifier, password) => { try { const result = await dispatch9.loginClient({ identifier, password }); if (result.success && result.tokens) { // Direct login success console.log('✅ Authentication successful'); return { success: true, client: result.client }; } else if (result.requiresProviderSelection) { // Handle provider selection console.log('🔄 Multiple providers available'); return { success: false, requiresProviderSelection: true, clientId: result.clientId, providers: result.providers }; } else if (result.requiresOTP) { // Handle OTP verification console.log('📧 OTP verification required'); return { success: false, requiresOTP: true, clientId: result.clientId }; } return { success: false, message: result.message }; } catch (error) { return { success: false, message: error.message }; } }; // Usage examples const emailAuth = await authenticateClient('client@example.com', 'password123'); const phoneAuth = await authenticateClient('+1234567890', 'password123'); const formattedPhoneAuth = await authenticateClient('+1 (234) 567-8900', 'password123'); ``` **Multi-Provider Authentication:** ```javascript const handleMultiProviderAuth = async (identifier, password) => { // Step 1: Initial login const loginResult = await dispatch9.loginClient({ identifier, password }); if (loginResult.requiresProviderSelection) { console.log('Available providers:'); loginResult.providers.forEach((provider, index) => { console.log(`${index + 1}. ${provider.database}`); }); // Step 2: Select provider (in real app, user would choose) const selectedProvider = loginResult.providers[0]; // Example: select first const providerResult = await dispatch9.selectClientProvider({ clientId: loginResult.clientId, providerId: selectedProvider.providerId }); if (providerResult.success) { console.log('✅ Multi-provider authentication complete'); return providerResult.client; } } return null; }; ``` **First-Time Login with OTP:** ```javascript const handleFirstTimeLogin = async (identifier, password, otpCode) => { // Step 1: Initial login const loginResult = await dispatch9.loginClient({ identifier, password }); if (loginResult.requiresOTP) { console.log('📧 First-time login detected, OTP sent to email'); // Step 2: Verify OTP (otpCode would come from user input) const otpResult = await dispatch9.verifyClientLoginOTP({ clientId: loginResult.clientId, otp: otpCode }); if (otpResult.success) { console.log('✅ First-time login complete'); return otpResult.client; } } return null; }; // Usage const newClient = await handleFirstTimeLogin('new@client.com', 'password', '123456'); ``` ## Error Handling The SDK provides detailed error messages for validation and API errors: ```javascript try { const client = await dispatch9.createClient({ // Missing required fields }); } catch (error) { console.error('Error:', error.message); // Output: "name is required and must be at least 1 character" } ``` ### Common Error Types - **Validation Errors**: Field requirements, format validation, constraints - **Authentication Errors**: Invalid API key, expired tokens - **Permission Errors**: Insufficient permissions for operation - **Rate Limit Errors**: Too many requests - **Network Errors**: Connection issues, timeouts ## Environment Variables Create a `.env` file in your project root: ```env DISPATCH9_API_KEY=your-api-key-here DISPATCH9_BASE_URL=https://api.dispatch9.com ``` Then use in your code: ```javascript require('dotenv').config(); const dispatch9 = new Dispatch9Client({ apiKey: process.env.DISPATCH9_API_KEY, baseURL: process.env.DISPATCH9_BASE_URL }); ``` ## Examples See the `examples/` directory for complete working examples: - `basic-usage.js` - Basic SDK usage with all 4 core operations - `order-management.js` - Order creation and management - `client-management.js` - Client operations and settings - `complete-workflow.js` - End-to-end business workflow - `address-creation-example.js` - Complete address creation workflow (shows how to create addresses before orders) ## Testing Run the test suite: ```bash npm test ``` ## API Key Requirements Your API key must have the following permissions: - `orders.create` - Create orders - `orders.update` - Update orders - `clients.create` - Create clients (may require elevated permissions) - `clients.read` - View clients - `clients.update` - Update clients (may require elevated permissions) ## Support - **Documentation**: [https://docs.dispatch9.com](https://docs.dispatch9.com) - **API Reference**: [https://api.dispatch9.com/docs](https://api.dispatch9.com/docs) - **Issues**: [GitHub Issues](https://github.com/dispatch9/client-sdk/issues) - **Support**: support@dispatch9.com ## License MIT License. See [LICENSE](LICENSE) file for details.