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/sdk2. 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
NPM/Yarn (Recommended)
bash
# NPM
npm install @dedot/sdk
# Yarn
yarn add @dedot/sdk
# PNPM
pnpm add @dedot/sdkCDN (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=productionLoad 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].priceAfter (De. Utilities):
typescript
const result = await client.realm.utilities.delivery.calculate({
origin: from,
destination: to,
serviceLevel: 'STANDARD',
weight
})
return result.totalFeeBest 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
}
}
}
