Skip to content

Integration Guide

Get started with De. Utilities in 5 minutes.

Quick Start

1. Install the SDK

bash
npm install @dedot/sdk
# or
yarn add @dedot/sdk

2. Initialize Client

typescript
import { DeClient } from '@dedot/sdk'

const client = new DeClient({
  apiKey: process.env.DE_API_KEY,
  workspace: 'your-workspace-id'
})

3. Calculate Your First Fare

typescript
// Calculate delivery fee
const deliveryFee = await client.realm.utilities.delivery.calculate({
  origin: { country: 'NG', city: 'Lagos' },
  destination: { country: 'NG', city: 'Abuja' },
  serviceLevel: 'NEXT_DAY',
  weight: { value: 5, unit: 'kg' }
})

console.log(`Shipping Cost: ${deliveryFee.totalFee} ${deliveryFee.currency}`)

That's it! You're now calculating fares with LSP integration.


Installation Options

bash
# NPM
npm install @dedot/sdk

# Yarn
yarn add @dedot/sdk

# PNPM
pnpm add @dedot/sdk

CDN (Browser)

html
<script src="https://cdn.dedot.app/sdk/latest/dedot.min.js"></script>
<script>
  const client = new De.Client({
    apiKey: 'your-api-key',
    workspace: 'your-workspace'
  })
</script>

REST API (Any Language)

bash
curl -X POST https://api.dedot.app/realm/utilities/fares/delivery \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"origin": {...}, "destination": {...}}'

Configuration

Basic Configuration

typescript
import { DeClient } from '@dedot/sdk'

const client = new DeClient({
  // Required
  apiKey: process.env.DE_API_KEY,
  workspace: 'your-workspace-id',
  
  // Optional
  environment: 'production', // or 'sandbox'
  timeout: 30000, // Request timeout in ms
  retries: 3, // Number of retries on failure
  cache: true // Enable response caching
})

Environment Variables

Create a .env file:

bash
DE_API_KEY=your_api_key_here
DE_WORKSPACE=your_workspace_id
DE_ENVIRONMENT=production

Load in your app:

typescript
import dotenv from 'dotenv'
dotenv.config()

const client = new DeClient({
  apiKey: process.env.DE_API_KEY,
  workspace: process.env.DE_WORKSPACE,
  environment: process.env.DE_ENVIRONMENT
})

TypeScript Configuration

Add types to tsconfig.json:

json
{
  "compilerOptions": {
    "types": ["@dedot/sdk"]
  }
}

Authentication

API Key Authentication

Get your API key from the De. Dashboard.

typescript
const client = new DeClient({
  apiKey: 'de_live_xxxxxxxxxxxx', // Production key
  workspace: 'ws_xxxxxxxxxxxx'
})

Security Best Practices:

  • ✅ Store API keys in environment variables
  • ✅ Use different keys for development and production
  • ✅ Rotate keys regularly
  • ✅ Never commit keys to version control
  • ❌ Don't expose keys in client-side code

Sandbox vs Production

typescript
// Sandbox - for testing
const sandboxClient = new DeClient({
  apiKey: 'de_test_xxxxxxxxxxxx',
  workspace: 'ws_xxxxxxxxxxxx',
  environment: 'sandbox'
})

// Production - for live traffic
const productionClient = new DeClient({
  apiKey: 'de_live_xxxxxxxxxxxx',
  workspace: 'ws_xxxxxxxxxxxx',
  environment: 'production'
})

Usage Patterns

1. Internal Functions (Direct Access)

Use utilities as internal functions with full LSP access:

typescript
import { calculateDeliveryFees } from '@dedot/sdk/utilities'
import { FastifyInstance } from 'fastify'

// In your Fastify app
async function handler(request, reply) {
  const App: FastifyInstance = request.server
  
  // Direct function call with LSP access
  const result = await calculateDeliveryFees({
    origin: request.body.origin,
    destination: request.body.destination,
    serviceLevel: 'NEXT_DAY',
    weight: request.body.weight
  }, App) // Pass Fastify instance for LSP database queries
  
  return { shippingCost: result.totalFee }
}

Benefits:

  • Full LSP integration
  • No network overhead
  • Real-time pricing data
  • Better performance

2. REST API (External Access)

Consume utilities via REST endpoints:

typescript
// Via SDK
const result = await client.realm.utilities.delivery.calculate({
  origin: { country: 'NG', city: 'Lagos' },
  destination: { country: 'NG', city: 'Abuja' },
  serviceLevel: 'NEXT_DAY',
  weight: { value: 5, unit: 'kg' }
})

// Or via HTTP
const response = await fetch('https://api.dedot.app/realm/utilities/fares/delivery', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ origin, destination, serviceLevel, weight })
})

Benefits:

  • Language-agnostic
  • Webhook-compatible
  • Cached responses
  • Easy integration

Common Use Cases

E-commerce Checkout

typescript
async function getShippingEstimate(cart, destination) {
  // Calculate total weight
  const totalWeight = cart.items.reduce((sum, item) => 
    sum + (item.weight * item.quantity), 0
  )
  
  // Get shipping options
  const [sameDayFee, nextDayFee, standardFee] = await Promise.all([
    client.realm.utilities.delivery.calculate({
      origin: { country: 'NG', city: 'Lagos' },
      destination,
      serviceLevel: 'SAME_DAY',
      weight: { value: totalWeight, unit: 'kg' }
    }),
    client.realm.utilities.delivery.calculate({
      origin: { country: 'NG', city: 'Lagos' },
      destination,
      serviceLevel: 'NEXT_DAY',
      weight: { value: totalWeight, unit: 'kg' }
    }),
    client.realm.utilities.delivery.calculate({
      origin: { country: 'NG', city: 'Lagos' },
      destination,
      serviceLevel: 'STANDARD',
      weight: { value: totalWeight, unit: 'kg' }
    })
  ])
  
  return {
    options: [
      { service: 'Same Day', cost: sameDayFee.totalFee, time: '6-8 hours' },
      { service: 'Next Day', cost: nextDayFee.totalFee, time: '24 hours' },
      { service: 'Standard', cost: standardFee.totalFee, time: '3-5 days' }
    ],
    currency: sameDayFee.currency
  }
}

Ride-Hailing App

typescript
async function estimateRide(pickup, dropoff, vehicleClass) {
  const fare = await client.realm.utilities.ride.calculate({
    pickup,
    dropoff,
    vehicleClass,
    includeNearbyDrivers: true
  })
  
  return {
    price: fare.estimatedFare.totalAfterSurge,
    currency: fare.estimatedFare.currency,
    surge: fare.surgeInfo.multiplier,
    eta: fare.pickupEstimate.eta.minute,
    driversNearby: fare.pickupEstimate.nearbyDrivers,
    tripDuration: fare.tripEstimate.duration.minute
  }
}

Freight Quotes

typescript
async function generateQuote(shipment) {
  const fare = await client.realm.utilities.transport.calculate({
    origin: shipment.origin,
    destination: shipment.destination,
    transportMode: 'ROAD',
    vehicleType: 'CONTAINER_TRUCK',
    cargo: shipment.cargo
  })
  
  return {
    quote: {
      total: fare.totalFare,
      currency: fare.currency,
      breakdown: {
        base: fare.baseFare,
        distance: fare.distanceFare,
        fuel: fare.fuelSurcharge
      }
    },
    distance: fare.distance.kilometer,
    estimatedDuration: fare.estimatedDuration?.day,
    confidence: fare.metadata.confidence
  }
}

Import Cost Calculator

typescript
async function calculateImportCost(product, destination) {
  const crossBorder = await client.realm.utilities.crossborder.calculate({
    origin: product.origin,
    destination,
    shipment: {
      weight: product.weight,
      declaredValue: product.value,
      hsCode: product.hsCode,
      description: product.description,
      quantity: product.quantity
    },
    transportMode: 'AIR',
    incoterms: 'DDP'
  })
  
  return {
    landedCost: crossBorder.totalCost.amount,
    breakdown: {
      shipping: crossBorder.breakdown.transportFee.amount,
      duties: crossBorder.breakdown.customsDuty?.amount || 0,
      vat: crossBorder.breakdown.vat?.amount || 0,
      fees: crossBorder.breakdown.brokerageFee.amount
    },
    clearanceTime: crossBorder.estimatedClearanceTime,
    documents: crossBorder.requiredDocuments
  }
}

Error Handling

Try-Catch Pattern

typescript
async function calculateShipping(request) {
  try {
    const result = await client.realm.utilities.delivery.calculate(request)
    return result
  } catch (error) {
    if (error.code === 'UTILITY::VALIDATION_FAILED') {
      console.error('Invalid request:', error.message)
      // Handle validation error
    } else if (error.code === 'UTILITY::CALCULATION_FAILED') {
      console.error('Calculation failed:', error.message)
      // Use fallback estimate
    } else {
      console.error('Unexpected error:', error)
      // Generic error handling
    }
    throw error
  }
}

Graceful Degradation

typescript
async function getShippingCostWithFallback(request) {
  try {
    // Try full calculation with LSP
    const result = await client.realm.utilities.delivery.calculate(request)
    
    // Check confidence
    if (result.metadata.confidence < 0.70) {
      console.warn('Low confidence estimate')
    }
    
    return result
    
  } catch (error) {
    console.error('Primary calculation failed, using fallback')
    
    // Fallback to simple estimate
    const distance = await client.realm.utilities.distance.calculate({
      origin: request.origin,
      destination: request.destination,
      mode: 'ROAD'
    })
    
    return {
      totalFee: distance.distance.value * 2, // $2 per km
      currency: 'USD',
      metadata: {
        accuracy: 'ESTIMATE',
        confidence: 0.50,
        dataSource: 'FALLBACK'
      }
    }
  }
}

Retry Logic

typescript
async function calculateWithRetry(request, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await client.realm.utilities.delivery.calculate(request)
    } catch (error) {
      if (attempt === maxRetries) throw error
      
      // Exponential backoff
      const delay = Math.pow(2, attempt) * 1000
      console.log(`Retry ${attempt}/${maxRetries} in ${delay}ms`)
      await new Promise(resolve => setTimeout(resolve, delay))
    }
  }
}

Performance Optimization

Parallel Requests

typescript
// ❌ Sequential (slow)
const delivery = await client.realm.utilities.delivery.calculate(req1)
const transport = await client.realm.utilities.transport.calculate(req2)
const ride = await client.realm.utilities.ride.calculate(req3)

// ✅ Parallel (fast)
const [delivery, transport, ride] = await Promise.all([
  client.realm.utilities.delivery.calculate(req1),
  client.realm.utilities.transport.calculate(req2),
  client.realm.utilities.ride.calculate(req3)
])

Response Caching

typescript
import NodeCache from 'node-cache'

const cache = new NodeCache({ stdTTL: 3600 }) // 1 hour TTL

async function getCachedFare(cacheKey, request) {
  // Check cache
  const cached = cache.get(cacheKey)
  if (cached) return cached
  
  // Calculate
  const result = await client.realm.utilities.delivery.calculate(request)
  
  // Store in cache
  cache.set(cacheKey, result)
  
  return result
}

// Usage
const cacheKey = `delivery:${origin.city}:${dest.city}:${weight}`
const fare = await getCachedFare(cacheKey, request)

Request Batching

typescript
async function calculateBulkShipping(orders) {
  // Batch calculate in parallel
  const results = await Promise.all(
    orders.map(order => 
      client.realm.utilities.delivery.calculate({
        origin: order.warehouse,
        destination: order.destination,
        serviceLevel: order.serviceLevel,
        weight: order.weight
      })
    )
  )
  
  return results
}

Testing

Unit Tests with Mocks

typescript
import { jest } from '@jest/globals'
import { DeClient } from '@dedot/sdk'

// Mock the SDK
jest.mock('@dedot/sdk')

describe('Shipping Calculator', () => {
  beforeEach(() => {
    DeClient.mockImplementation(() => ({
      realm: {
        utilities: {
          delivery: {
            calculate: jest.fn().mockResolvedValue({
              totalFee: 8500,
              currency: 'NGN',
              metadata: { confidence: 0.92, dataSource: 'LSP' }
            })
          }
        }
      }
    }))
  })
  
  it('should calculate delivery fee', async () => {
    const client = new DeClient({ apiKey: 'test', workspace: 'test' })
    const result = await client.realm.utilities.delivery.calculate({
      origin: { country: 'NG', city: 'Lagos' },
      destination: { country: 'NG', city: 'Abuja' },
      serviceLevel: 'NEXT_DAY',
      weight: { value: 5, unit: 'kg' }
    })
    
    expect(result.totalFee).toBe(8500)
    expect(result.currency).toBe('NGN')
  })
})

Integration Tests

typescript
import { DeClient } from '@dedot/sdk'

describe('Utilities Integration', () => {
  const client = new DeClient({
    apiKey: process.env.DE_TEST_API_KEY,
    workspace: process.env.DE_TEST_WORKSPACE,
    environment: 'sandbox'
  })
  
  it('should calculate real delivery fee', async () => {
    const result = await client.realm.utilities.delivery.calculate({
      origin: { country: 'NG', city: 'Lagos' },
      destination: { country: 'NG', city: 'Abuja' },
      serviceLevel: 'NEXT_DAY',
      weight: { value: 5, unit: 'kg' }
    })
    
    expect(result).toHaveProperty('totalFee')
    expect(result).toHaveProperty('currency')
    expect(result.metadata.confidence).toBeGreaterThan(0.5)
  }, 10000) // 10s timeout
})

Monitoring & Debugging

Request Logging

typescript
const client = new DeClient({
  apiKey: process.env.DE_API_KEY,
  workspace: process.env.DE_WORKSPACE,
  onRequest: (config) => {
    console.log('Request:', config.method, config.url)
  },
  onResponse: (response) => {
    console.log('Response:', response.status, response.data.status)
  },
  onError: (error) => {
    console.error('Error:', error.message)
  }
})

Confidence Monitoring

typescript
async function calculateWithMonitoring(request) {
  const result = await client.realm.utilities.delivery.calculate(request)
  
  // Log low confidence results
  if (result.metadata.confidence < 0.70) {
    console.warn('Low confidence calculation:', {
      confidence: result.metadata.confidence,
      dataSource: result.metadata.dataSource,
      request
    })
  }
  
  // Track metrics
  trackMetric('utility.delivery.confidence', result.metadata.confidence)
  trackMetric('utility.delivery.dataSource', result.metadata.dataSource)
  
  return result
}

Performance Tracking

typescript
async function calculateWithTiming(request) {
  const start = Date.now()
  
  try {
    const result = await client.realm.utilities.delivery.calculate(request)
    const duration = Date.now() - start
    
    console.log(`Calculation took ${duration}ms`)
    trackMetric('utility.delivery.duration', duration)
    
    return result
  } catch (error) {
    const duration = Date.now() - start
    console.error(`Failed after ${duration}ms:`, error)
    throw error
  }
}

Framework Integration

Express.js

typescript
import express from 'express'
import { DeClient } from '@dedot/sdk'

const app = express()
const client = new DeClient({
  apiKey: process.env.DE_API_KEY,
  workspace: process.env.DE_WORKSPACE
})

app.post('/api/shipping/estimate', async (req, res) => {
  try {
    const result = await client.realm.utilities.delivery.calculate({
      origin: req.body.origin,
      destination: req.body.destination,
      serviceLevel: req.body.serviceLevel,
      weight: req.body.weight
    })
    
    res.json({
      success: true,
      shippingCost: result.totalFee,
      currency: result.currency
    })
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    })
  }
})

Next.js API Route

typescript
// pages/api/shipping/estimate.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { DeClient } from '@dedot/sdk'

const client = new DeClient({
  apiKey: process.env.DE_API_KEY!,
  workspace: process.env.DE_WORKSPACE!
})

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' })
  }
  
  try {
    const result = await client.realm.utilities.delivery.calculate(req.body)
    
    res.status(200).json({
      success: true,
      data: result
    })
  } catch (error) {
    res.status(500).json({
      success: false,
      error: error.message
    })
  }
}

Fastify

typescript
import Fastify from 'fastify'
import { DeClient } from '@dedot/sdk'

const fastify = Fastify()
const client = new DeClient({
  apiKey: process.env.DE_API_KEY,
  workspace: process.env.DE_WORKSPACE
})

fastify.post('/api/shipping/estimate', async (request, reply) => {
  const result = await client.realm.utilities.delivery.calculate(request.body)
  
  return {
    success: true,
    shippingCost: result.totalFee,
    currency: result.currency
  }
})

Migration Guide

From Hardcoded Logic

Before:

typescript
function calculateShipping(origin, destination, weight) {
  const distance = calculateDistance(origin, destination)
  const baseFee = 5.00
  const distanceFee = distance * 2.00
  const weightFee = weight * 1.50
  
  return baseFee + distanceFee + weightFee
}

After:

typescript
async function calculateShipping(origin, destination, weight) {
  const result = await client.realm.utilities.delivery.calculate({
    origin,
    destination,
    serviceLevel: 'STANDARD',
    weight: { value: weight, unit: 'kg' }
  })
  
  return result.totalFee
}

From Other APIs

Before (Hypothetical Shipping API):

typescript
const response = await fetch('https://api.shipping-service.com/v1/rates', {
  method: 'POST',
  body: JSON.stringify({ from, to, weight })
})
const data = await response.json()
return data.rates[0].price

After (De. Utilities):

typescript
const result = await client.realm.utilities.delivery.calculate({
  origin: from,
  destination: to,
  serviceLevel: 'STANDARD',
  weight
})
return result.totalFee

Best Practices

✅ Do's

  • Use environment variables for API keys
  • Cache results when appropriate (1-hour TTL)
  • Handle errors gracefully with fallback logic
  • Monitor confidence scores and log low-confidence results
  • Batch requests when processing multiple calculations
  • Use TypeScript for better type safety
  • Test with sandbox environment before production
  • Track performance metrics and response times

❌ Don'ts

  • Don't hardcode API keys in your code
  • Don't ignore confidence scores - they indicate reliability
  • Don't make sequential requests when parallel is possible
  • Don't cache forever - prices change, use appropriate TTLs
  • Don't expose API keys in client-side code
  • Don't skip error handling - always handle failures
  • Don't use production keys in development/testing
  • Don't make unnecessary requests - cache when possible

Troubleshooting

Common Issues

Issue: "Invalid API Key"

typescript
// ❌ Wrong
const client = new DeClient({ apiKey: 'my-key' })

// ✅ Correct
const client = new DeClient({ 
  apiKey: 'de_live_xxxxxxxxxxxx',
  workspace: 'ws_xxxxxxxxxxxx'
})

Issue: "Low Confidence Results"

typescript
const result = await client.realm.utilities.delivery.calculate(request)

if (result.metadata.confidence < 0.70) {
  // Possible causes:
  // - Missing LSP pricing data
  // - Incomplete request data (no coordinates)
  // - Using fallback calculations
  
  console.log('Data source:', result.metadata.dataSource)
  // Show disclaimer to user about estimate accuracy
}

Issue: "Request Timeout"

typescript
// Increase timeout
const client = new DeClient({
  apiKey: process.env.DE_API_KEY,
  workspace: process.env.DE_WORKSPACE,
  timeout: 60000 // 60 seconds
})

Issue: "Rate Limit Exceeded"

typescript
// Implement exponential backoff
async function calculateWithBackoff(request, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      return await client.realm.utilities.delivery.calculate(request)
    } catch (error) {
      if (error.code === 'RATE_LIMIT_EXCEEDED' && i < retries - 1) {
        await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000))
        continue
      }
      throw error
    }
  }
}

Next Steps