npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jazzdev/dpd-local-sdk

v1.0.12

Published

TypeScript SDK for DPD Local shipping API integration - database-agnostic and framework-independent

Downloads

1,184

Readme

DPD Local SDK

TypeScript SDK for integrating DPD Local shipping services into your application. Database-agnostic, framework-independent, and production-ready.

npm version TypeScript License: MIT

Features

Complete DPD Integration

  • Create shipments and generate labels
  • Address validation (UK postcodes)
  • Real-time tracking
  • Multi-parcel support
  • Service selection (Next Day, By 12 PM)

Database-Agnostic

  • Works with any database (Firestore, MongoDB, PostgreSQL, etc.)
  • Adapter pattern for easy integration
  • TypeScript-first design

Production-Ready

  • Battle-tested in production
  • Comprehensive error handling
  • Automatic token management
  • Request retry logic
  • Detailed logging

Developer-Friendly

  • Full TypeScript support
  • Comprehensive JSDoc comments
  • Example implementations included
  • Zero runtime dependencies (peer deps only)

Installation

npm install @jazzdev/dpd-local-sdk
# or
yarn add @jazzdev/dpd-local-sdk
# or
pnpm add @jazzdev/dpd-local-sdk

Quick Start

1. Create Configuration

import { createDPDConfig } from '@jazzdev/dpd-local-sdk';

const config = createDPDConfig({
  credentials: {
    accountNumber: process.env.DPD_ACCOUNT_NUMBER!,
    username: process.env.DPD_USERNAME!,
    password: process.env.DPD_PASSWORD!,
  },
  business: {
    name: 'Your Business Name',
    collectionAddress: {
      organisation: 'Your Company Ltd',
      property: 'Unit 1',
      street: '123 Main Street',
      locality: '',
      town: 'London',
      county: 'Greater London',
      postcode: 'SW1A 1AA',
      countryCode: 'GB',
    },
    contactName: 'Your Name',
    contactPhone: '+441234567890',
    contactEmail: '[email protected]',
  },
});

2. Implement Adapters

The SDK requires two adapters to work with your database and storage:

Database Adapter

import { DatabaseAdapter } from '@jazzdev/dpd-local-sdk';

const myDatabaseAdapter: DatabaseAdapter = {
  async getOrder(orderId: string) {
    // Your implementation
    return await db.orders.findById(orderId);
  },

  async updateOrder(orderId: string, data: any) {
    // Your implementation
    await db.orders.update(orderId, data);
  },

  async getSavedAddresses(userId: string) {
    // Your implementation
    return await db.addresses.find({ userId });
  },

  async getSavedAddress(addressId: string) {
    // Your implementation
    return await db.addresses.findById(addressId);
  },

  async createSavedAddress(address) {
    // Your implementation
    const result = await db.addresses.create(address);
    return result.id;
  },

  async updateSavedAddress(addressId: string, data) {
    // Your implementation
    await db.addresses.update(addressId, data);
  },

  async deleteSavedAddress(addressId: string) {
    // Your implementation
    await db.addresses.delete(addressId);
  },

  async createDPDLog(log) {
    // Your implementation
    const result = await db.dpdLogs.create(log);
    return result.id;
  },

  async getDPDLogs(filters) {
    // Your implementation
    return await db.dpdLogs.find(filters);
  },
};

Storage Adapter

import { StorageAdapter } from '@jazzdev/dpd-local-sdk';

const myStorageAdapter: StorageAdapter = {
  async uploadLabel(labelData: string, fileName: string) {
    // Upload to your storage (S3, Firebase Storage, etc.)
    const url = await storage.upload(labelData, `labels/${fileName}`);
    return url;
  },

  async getLabel(fileName: string) {
    // Get label URL from storage
    return await storage.getUrl(`labels/${fileName}`);
  },

  async deleteLabel(fileName: string) {
    // Delete label from storage
    await storage.delete(`labels/${fileName}`);
  },
};

3. Create a Shipment

import { createCompleteShipment } from '@jazzdev/dpd-local-sdk';

const result = await createCompleteShipment(
  'ORDER123', // Your order ID
  {
    orderRef: 'ORDER123',
    service: '12', // Next Day Delivery
    deliveryAddress: {
      id: 'addr_123',
      userId: 'user_123',
      isDefault: true,
      property: '10',
      street: 'Downing Street',
      town: 'London',
      postcode: 'SW1A 2AA',
      countryCode: 'GB',
      contactName: 'John Doe',
      contactPhone: '+441234567890',
      validated: true,
      createdAt: new Date(),
      updatedAt: new Date(),
    },
    totalWeight: 2.5, // kg
    numberOfParcels: 1,
    customerEmail: '[email protected]',
    customerPhone: '+441234567890',
    deliveryInstructions: 'Leave with neighbor if not home',
    collectionDate: '2024-01-15',
  },
  config,
  myDatabaseAdapter,
  myStorageAdapter
);

if (result.success) {
  console.log('Shipment created!');
  console.log('Shipment ID:', result.shipmentId); // Save this for label regeneration
  console.log('Consignment Number:', result.consignmentNumber); // 10-digit reference
  console.log('Parcel Number:', result.parcelNumber); // 14-digit tracking number
  console.log('Tracking URL:', result.trackingUrl);
  console.log('Label URL:', result.labelUrl);
} else {
  console.error('Failed:', result.error);
}

Understanding DPD Identifiers

When you create a shipment with DPD, you receive three different identifiers:

  1. shipmentId - DPD's internal shipment identifier (numeric)

    • Required for label regeneration
    • Save this in your database!
  2. consignmentNumber - 10-digit reference number (e.g., 6504286395)

    • Used for internal tracking
  3. parcelNumber - 14-digit tracking number (e.g., 15976504286395)

    • What customers use to track their delivery
    • Used in the tracking URL
// When creating a shipment, save ALL identifiers:
const result = await createCompleteShipment(...);

if (result.success) {
  await saveToDatabase({
    shipmentId: result.shipmentId,           // Save for label regeneration
    consignmentNumber: result.consignmentNumber,
    parcelNumber: result.parcelNumber,       // Give to customer for tracking
    trackingUrl: result.trackingUrl,
  });
}

Regenerating Labels

If you need to regenerate a label (e.g., printer jam), use the shipmentId:

import { generateLabel } from '@jazzdev/dpd-local-sdk';

const result = await generateLabel(credentials, {
  shipmentId: '12345678',  // Use the shipmentId, not consignment/parcel number
  labelFormat: 'zpl'       // or 'clp', 'html'
});

Testing Label Generation

A test script is included to verify label generation:

# Using npm script
npm run test:label <shipmentId> [format]

# Or directly with tsx
npx tsx test-label-generation.ts <shipmentId> [format]

# Examples
npm run test:label 12345678
npm run test:label 12345678 html
npm run test:label 12345678 zpl

The script will:

  • Validate your DPD credentials
  • Generate the label in the specified format
  • Save it to a file (label-<shipmentId>.<format>)
  • Display a preview of the label content

API Reference

Configuration

createDPDConfig(options)

Creates a complete DPD module configuration.

Parameters:

  • options.credentials - DPD API credentials
  • options.business - Your business information
  • options.pricing (optional) - Custom pricing configuration
  • options.services (optional) - Service configuration
  • options.labels (optional) - Label printer configuration
  • options.notifications (optional) - Email/SMS configuration
  • options.testMode (optional) - Enable test mode

Returns: DPDModuleConfig

Core Functions

createCompleteShipment(orderId, params, config, dbAdapter, storageAdapter)

Create a complete shipment including label generation and database update.

Parameters:

  • orderId - Your internal order ID
  • params - Shipment parameters (address, weight, service, etc.)
  • config - DPD configuration
  • dbAdapter - Database adapter
  • storageAdapter - Storage adapter

Returns: Promise<CreateShipmentResult>

validateDeliveryAddress(params, credentials)

Validate a UK delivery address using postcodes.io API.

Parameters:

  • params.postcode - UK postcode
  • params.town - Town/city name
  • credentials - DPD credentials

Returns: Promise<ValidateAddressResult>

testDPDConnection(credentials)

Test connection to DPD API.

Parameters:

  • credentials - DPD credentials

Returns: Promise<{ success: boolean; message: string }>

Utility Functions

calculateDeliveryFee(subtotal, service, config)

Calculate customer-facing delivery fee.

calculateDPDCost(weight, service, config)

Calculate DPD shipping cost (what DPD charges you).

getNextCollectionDate()

Get next available collection date (excludes Sundays).

getEstimatedDeliveryDate(service, collectionDate?)

Calculate estimated delivery date.

getTrackingUrl(parcelNumber)

Generate DPD tracking URL.

Integration Examples

Next.js App Router

// app/api/shipping/create/route.ts
import { createCompleteShipment } from '@jazzdev/dpd-local-sdk';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  const { orderId, deliveryAddress, weight } = await req.json();

  const result = await createCompleteShipment(
    orderId,
    {
      orderRef: orderId,
      service: '12',
      deliveryAddress,
      totalWeight: weight,
      numberOfParcels: 1,
      customerEmail: deliveryAddress.contactEmail,
      collectionDate: new Date().toISOString().split('T')[0],
    },
    dpdConfig,
    databaseAdapter,
    storageAdapter
  );

  return NextResponse.json(result);
}

Express.js

import express from 'express';
import { createCompleteShipment } from '@jazzdev/dpd-local-sdk';

const app = express();

app.post('/api/shipping/create', async (req, res) => {
  const { orderId, deliveryAddress, weight } = req.body;

  const result = await createCompleteShipment(
    orderId,
    {
      orderRef: orderId,
      service: '12',
      deliveryAddress,
      totalWeight: weight,
      numberOfParcels: 1,
      customerEmail: deliveryAddress.contactEmail,
      collectionDate: new Date().toISOString().split('T')[0],
    },
    dpdConfig,
    databaseAdapter,
    storageAdapter
  );

  res.json(result);
});

Environment Variables

# DPD Credentials (Required)
DPD_ACCOUNT_NUMBER=your_account_number
DPD_USERNAME=your_username
DPD_PASSWORD=your_password

# Encryption (Required in production)
DPD_ENCRYPTION_KEY=your_32_byte_hex_key

# Optional
NODE_ENV=production

Generating Encryption Key

import { generateEncryptionKey } from '@jazzdev/dpd-local-sdk';

const key = generateEncryptionKey();
console.log('DPD_ENCRYPTION_KEY=' + key);

Adapter Examples

Complete adapter examples are available in the examples/ directory:

  • examples/basic-usage.ts - Complete workflow example
  • examples/regenerate-label.ts - Label regeneration example
  • examples/firestore-adapter.ts - Firestore database adapter
  • examples/firebase-storage-adapter.ts - Firebase Storage adapter

For other databases (MongoDB, PostgreSQL, etc.), implement the DatabaseAdapter interface following the Firestore example as a reference. The adapter pattern is database-agnostic by design.

Error Handling

const result = await createCompleteShipment(...);

if (!result.success) {
  console.error("Error Code:", result.errorCode);
  console.error("Error Message:", result.error);

  // Handle specific errors
  switch (result.errorCode) {
    case "AUTH_FAILED":
      // Invalid credentials
      break;
    case "INVALID_ADDRESS":
      // Address validation failed
      break;
    case "NETWORK_ERROR":
      // Connection issues
      break;
    default:
      // Generic error
  }
}

TypeScript Support

This SDK is written in TypeScript and provides complete type definitions:

import type {
  DPDModuleConfig,
  CreateShipmentParams,
  CreateShipmentResult,
  SavedAddress,
  ShippingData,
  DatabaseAdapter,
  StorageAdapter,
} from '@jazzdev/dpd-local-sdk';

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for details.

License

MIT © Taiow Babarinde

Support

Changelog

See CHANGELOG.md for release history.