Skip to content

Official Node.js SDK for the Dispatch9 API. Simplify integration with Dispatch9's delivery and logistics platform.

License

Notifications You must be signed in to change notification settings

dispatch9/client-sdk

Repository files navigation

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

npm install @dispatch9/client-sdk

Quick Start

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

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:

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

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

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

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:

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 - Complete order details

Examples:

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

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:

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

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 - Complete client details

Examples:

// 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 - Authentication result with tokens and client data

Examples:

// 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 - Authentication result with tokens

Examples:

// 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 - Verification result with authentication tokens

Examples:

// 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 - Client profile data

Examples:

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

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:

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:

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:

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:

DISPATCH9_API_KEY=your-api-key-here
DISPATCH9_BASE_URL=https://api.dispatch9.com

Then use in your code:

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:

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

License

MIT License. See LICENSE file for details.

About

Official Node.js SDK for the Dispatch9 API. Simplify integration with Dispatch9's delivery and logistics platform.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published