DHL's REST APIs let your Bolt.new app track shipments, calculate shipping rates, and generate labels. Authentication is simple: an API key in the request header. The free developer sandbox includes test credentials for all three core APIs. Build your tracking dashboard and rate calculator in Bolt's WebContainer preview, then switch to production credentials when deploying.
DHL API in Bolt.new: Tracking, Rates, and Labels for Shipping Apps
DHL offers REST APIs for tracking, rate calculation, and label creation covering their global express network. Authentication is a single API key in a header — no OAuth complexity. The free developer sandbox at developer.dhl.com provides instant test credentials, making this one of the simpler logistics integrations to build.
The three core APIs are: Shipment Tracking (query status by waybill number), Express Rate Finding (get quotes for origin/destination/weight), and Shipment API (create shipments and generate PDF labels). All use the same DHL-API-Key header authentication and the same base URL structure.
DHL tracking uses polling rather than webhooks — you query the API to get the latest status rather than receiving push notifications. This means the full integration works in Bolt's WebContainer preview without deployment.
Integration method
DHL APIs use simple API key authentication — pass your key in the DHL-API-Key header on every request. Build Next.js API routes that proxy calls to DHL's endpoints, keeping your API key server-side. Outbound API calls (tracking, rate quotes) work in Bolt's WebContainer preview. DHL doesn't use webhooks for tracking updates, so there are no incoming connection requirements.
Prerequisites
- A Bolt.new account with a Next.js project created
- A DHL developer account at developer.dhl.com (free registration)
- A DHL sandbox application created in the developer portal to get test API credentials
- For label generation: a DHL Express business account (separate from the developer account)
- Basic understanding of shipping terminology (waybill, service level, dimensions)
Step-by-step guide
Register on DHL Developer Portal and Create a Sandbox Application
Register on DHL Developer Portal and Create a Sandbox Application
Go to developer.dhl.com and click Sign Up. Registration requires a name and email address — there's no approval process for sandbox access, so credentials are available immediately after confirming your email. After logging in, click 'Create App' in the My Apps section. Name your application and select which APIs you want to enable: start with 'DHL Express - MyDHL API' for rate finding and shipment creation, and 'Shipment Tracking' for the tracking API. Each API has both a Sandbox and Production environment. After creating your app, the dashboard shows your API key for each environment. The sandbox and production API keys are different strings. Copy your sandbox API key — you'll use this for all development and testing. Switch to your production key only when you've tested everything and are ready to go live. For the Shipment Tracking API, you'll also see a sandbox test waybill number in the documentation — use this to test tracking responses without needing a real shipment. The number returns a realistic tracking history with multiple scan events.
Pro tip: The DHL developer portal has separate API keys for each API product (Tracking, Express). If your app needs both, note that you may have different keys per product. Check the API reference for each API to confirm the correct authentication header name.
Expected result: You have a DHL developer account, a sandbox application created, and your sandbox API key. You've noted a test waybill number from the documentation for testing.
Configure Environment Variables and Install HTTP Client
Configure Environment Variables and Install HTTP Client
DHL's APIs are straightforward to call with standard fetch() — no SDK required. The authentication is a single header: 'DHL-API-Key: your_api_key'. Add your sandbox API key to your Bolt.new project's .env file. The API key must be server-side only (no NEXT_PUBLIC_ prefix). While DHL's API key is simpler than OAuth credentials, it still grants API quota access and should not be exposed in client-side code where it could be scraped and abused by others. For the DHL API base URLs: the Shipment Tracking API uses api-eu.dhl.com, and the Express (MyDHL) API for rate finding and label creation uses express.api.dhl.com. These are the production URLs — the sandbox uses the same base URLs but with sandbox API keys that automatically route requests to test environments.
Create a lib/dhl.ts file that exports a dhlRequest(endpoint, options) helper function. The function should prepend the DHL API base URL (from DHL_API_BASE_URL env var), add the 'DHL-API-Key' header using DHL_API_KEY env var, handle response errors (including parsing DHL's error response format), and return the parsed JSON. Use TypeScript.
Paste this in Bolt.new chat
1# .env file additions2# DHL API credentials — server-side only, never NEXT_PUBLIC_3DHL_API_KEY=your_sandbox_api_key_here4DHL_TRACKING_API_BASE=https://api-eu.dhl.com5DHL_EXPRESS_API_BASE=https://express.api.dhl.com/mydhlapi6# Use 'test' for sandbox, 'production' for live7DHL_ENVIRONMENT=testPro tip: DHL's sandbox API key automatically routes to test data when ENVIRONMENT=test — you don't need separate base URLs. Switch to your production API key and set DHL_ENVIRONMENT=production when going live.
Expected result: lib/dhl.ts is created with a request helper. Environment variables are set. TypeScript compiles without errors.
Build the Shipment Tracking API Route
Build the Shipment Tracking API Route
The DHL Shipment Tracking API accepts a waybill number (tracking number) and returns the current status plus a full event history of every scan the package has received. The endpoint is: GET /track/shipments?trackingNumber={waybillNumber}. The response includes: the shipment's current status (transit, in-transit, delivered, failure), the estimated delivery date, the origin and destination, and an events array where each event has a timestamp, location, description, and service area code. For a tracking dashboard, normalize the response to extract the most useful fields: current status, latest event location and description, estimated delivery date, and the full event timeline sorted newest-first. Multiple tracking numbers can be queried in a single request by comma-separating them: ?trackingNumber=1234,5678.
Create a /api/dhl/track route that accepts a 'waybill' query parameter, calls the DHL Shipment Tracking API (GET /track/shipments), and returns: currentStatus, estimatedDelivery, originLocation, destinationLocation, and an events array with timestamp, location, description, and remark for each event. Handle the case where the tracking number is not found. Use the dhlRequest helper from lib/dhl.ts.
Paste this in Bolt.new chat
1// app/api/dhl/track/route.ts2import { NextResponse } from 'next/server';34async function dhlRequest(url: string) {5 const response = await fetch(url, {6 headers: {7 'DHL-API-Key': process.env.DHL_API_KEY ?? '',8 'Accept': 'application/json',9 },10 });11 if (!response.ok) {12 const error = await response.json().catch(() => ({}));13 throw Object.assign(new Error('DHL API error'), { status: response.status, body: error });14 }15 return response.json();16}1718export async function GET(request: Request) {19 const url = new URL(request.url);20 const waybill = url.searchParams.get('waybill')?.trim();2122 if (!waybill) {23 return NextResponse.json({ error: 'waybill query parameter is required' }, { status: 400 });24 }2526 try {27 const trackingUrl = `${process.env.DHL_TRACKING_API_BASE}/track/shipments?trackingNumber=${encodeURIComponent(waybill)}`;28 const data = await dhlRequest(trackingUrl);2930 const shipment = data?.shipments?.[0];31 if (!shipment) {32 return NextResponse.json({ error: 'Shipment not found' }, { status: 404 });33 }3435 const normalized = {36 waybill,37 status: shipment.status?.status ?? 'unknown',38 description: shipment.status?.description ?? '',39 estimatedDelivery: shipment.estimatedTimeOfDelivery ?? null,40 origin: {41 name: shipment.origin?.address?.addressLocality ?? '',42 countryCode: shipment.origin?.address?.countryCode ?? '',43 },44 destination: {45 name: shipment.destination?.address?.addressLocality ?? '',46 countryCode: shipment.destination?.address?.countryCode ?? '',47 },48 events: (shipment.events ?? []).map((event: Record<string, unknown>) => ({49 timestamp: event.timestamp,50 location: (event.location as Record<string, unknown>)?.address51 ? `${((event.location as Record<string, unknown>).address as Record<string, unknown>).addressLocality}, ${((event.location as Record<string, unknown>).address as Record<string, unknown>).countryCode}`52 : 'Unknown',53 description: event.description,54 remark: event.remark ?? '',55 })),56 };5758 return NextResponse.json(normalized);59 } catch (error: unknown) {60 const err = error as { status?: number };61 if (err.status === 404) {62 return NextResponse.json({ error: 'Shipment not found' }, { status: 404 });63 }64 console.error('DHL tracking error:', error);65 return NextResponse.json({ error: 'Failed to fetch tracking data' }, { status: 500 });66 }67}Pro tip: Test with DHL's sandbox test waybill numbers from their documentation page. These return realistic tracking events without needing an actual shipment. Common test numbers include numbers like 1234567890 — check the current sandbox documentation for valid test values.
Expected result: The /api/dhl/track?waybill=[number] endpoint returns normalized tracking data. Test in Bolt's WebContainer preview using a sandbox test waybill number.
Build the Rate Calculator API Route
Build the Rate Calculator API Route
The DHL Express Rate Finding API (part of MyDHL API) returns available shipping services, their prices, and estimated delivery dates for a given origin/destination/package combination. The endpoint is: POST /rates to the express.api.dhl.com base URL. The request body requires: an account number (your DHL Express account, or a sandbox account number from the developer portal), the planned shipment date, origin and destination address details (country code, postal code, city), and package details (weight in kg, dimensions in cm). The response lists available service products (EXPRESS_WORLDWIDE, EXPRESS_9_00, EXPRESS_12_00, EXPRESS_9_00_DOC) with total charge, currency, and commitment date for each. Present these as a comparison table so users can choose based on price vs. delivery speed.
Create a /api/dhl/rates route (POST) that accepts originCountry, originPostalCode, originCity, destinationCountry, destinationPostalCode, destinationCity, weightKg, and packageDimensions (length, width, height in cm). Call the DHL Express Rate Finding API and return an array of available services with: productName, serviceCode, totalCharge, currency, and deliveryDate. Sort by total charge ascending.
Paste this in Bolt.new chat
1// app/api/dhl/rates/route.ts2import { NextResponse } from 'next/server';34export async function POST(request: Request) {5 try {6 const body = await request.json();7 const {8 originCountry, originPostalCode, originCity,9 destinationCountry, destinationPostalCode, destinationCity,10 weightKg, packageDimensions,11 } = body;1213 // Shipment date must be today or future, in ISO format14 const plannedDate = new Date();15 plannedDate.setHours(14, 0, 0, 0); // 2pm local time16 const plannedShipmentDateAndTime = plannedDate.toISOString();1718 const rateRequest = {19 customerDetails: {20 shipperDetails: {21 postalCode: originPostalCode,22 cityName: originCity,23 countryCode: originCountry,24 },25 receiverDetails: {26 postalCode: destinationPostalCode,27 cityName: destinationCity,28 countryCode: destinationCountry,29 },30 },31 accounts: [{32 typeCode: 'shipper',33 number: process.env.DHL_ACCOUNT_NUMBER ?? 'TEST_ACCOUNT',34 }],35 plannedShipmentDateAndTime,36 unitOfMeasurement: 'metric',37 isCustomsDeclarable: false,38 packages: [{39 weight: Number(weightKg),40 dimensions: {41 length: Number(packageDimensions?.length ?? 20),42 width: Number(packageDimensions?.width ?? 15),43 height: Number(packageDimensions?.height ?? 10),44 },45 }],46 };4748 const response = await fetch(`${process.env.DHL_EXPRESS_API_BASE}/rates`, {49 method: 'POST',50 headers: {51 'DHL-API-Key': process.env.DHL_API_KEY ?? '',52 'Content-Type': 'application/json',53 'Accept': 'application/json',54 },55 body: JSON.stringify(rateRequest),56 });5758 if (!response.ok) {59 const error = await response.json();60 return NextResponse.json({ error: error?.detail ?? 'Rate request failed' }, { status: response.status });61 }6263 const data = await response.json();64 const rates = (data?.products ?? []).map((product: Record<string, unknown>) => ({65 productName: product.productName,66 serviceCode: product.productCode,67 totalCharge: (product.totalPrice as Array<Record<string, unknown>>)?.[0]?.price ?? 0,68 currency: (product.totalPrice as Array<Record<string, unknown>>)?.[0]?.priceCurrency ?? 'USD',69 deliveryDate: (product.deliveryCapabilities as Record<string, unknown>)?.estimatedDeliveryDateAndTime ?? null,70 })).sort((a: Record<string, unknown>, b: Record<string, unknown>) => Number(a.totalCharge) - Number(b.totalCharge));7172 return NextResponse.json({ rates });73 } catch (error) {74 console.error('DHL rates error:', error);75 return NextResponse.json({ error: 'Failed to calculate rates' }, { status: 500 });76 }77}Pro tip: The DHL Express API requires an account number in the rates request. For sandbox testing, DHL provides a test account number in the documentation (or use any number — the sandbox accepts placeholder values). For production, use your actual DHL Express account number.
Expected result: The /api/dhl/rates endpoint returns available DHL Express services with prices and delivery dates. Test with real country codes and postal codes in the sandbox environment.
Common use cases
Shipment Tracking Dashboard
Build a customer-facing portal where users can enter their DHL waybill number to get real-time tracking status. Show the full event history, estimated delivery date, and current location. For businesses shipping large volumes, display all active shipments in a table with bulk tracking.
Create a DHL shipment tracking page. Add a search input where users enter a DHL waybill number. On submit, call /api/dhl/track?waybill=[number] which fetches the tracking status from the DHL Shipment Tracking API. Display the shipment status, current location, estimated delivery, and full event timeline sorted by date. Handle 'shipment not found' errors gracefully.
Copy this prompt to try it in Bolt.new
Shipping Rate Calculator
Integrate a real-time shipping rate calculator into a checkout flow or order management system. Users enter the origin, destination, weight, and dimensions, and your app returns DHL Express rate options with transit time and price for each service level.
Build a shipping rate calculator using the DHL Express Rate Finding API. Create a form with origin country/postal code, destination country/postal code, weight (kg), and package dimensions (cm). Call /api/dhl/rates with these values and display available service levels (EXPRESS_WORLDWIDE, EXPRESS_9, EXPRESS_12) with price and delivery date. Show prices in USD.
Copy this prompt to try it in Bolt.new
E-Commerce Fulfillment with Label Generation
Automate label generation for an e-commerce store. When an order is ready to ship, call the DHL Shipment API to create a shipment record and receive a base64-encoded PDF label. Display or download the label, and store the waybill number with the order for tracking.
Build a shipment creation flow for my order management system. Create an API route that accepts shipper details, recipient address, package weight/dimensions, and calls the DHL Shipment API to create a shipment and return a PDF label as base64. Build a UI form pre-filled from order data, with a 'Create Shipment' button that generates the label and shows a download link.
Copy this prompt to try it in Bolt.new
Troubleshooting
'Authentication Failed' or 401 error on API calls despite correct API key
Cause: The API key is for the wrong environment (using a production key for sandbox endpoints or vice versa), or the DHL-API-Key header name is not capitalized exactly correctly.
Solution: Verify the exact header name is 'DHL-API-Key' (not 'dhl-api-key' or 'X-API-Key'). Confirm you're using the sandbox API key from your developer portal app, not the production key. Check that the key was copied without trailing spaces.
1headers: {2 'DHL-API-Key': process.env.DHL_API_KEY ?? '', // Exact capitalization required3 'Accept': 'application/json',4}Tracking returns 404 'Shipment not found' for real DHL tracking numbers
Cause: Sandbox API keys only return data for DHL's designated test tracking numbers. Real tracking numbers from actual shipments only work with production API keys.
Solution: Use sandbox test waybill numbers from DHL's documentation during development. Switch to production API key (update DHL_API_KEY in your environment variables) to track real shipments.
Rate API returns 'Error: Invalid account' or rates come back empty
Cause: The account number in the rates request doesn't match a valid DHL Express account, or the origin/destination country codes are not in ISO 3166-1 alpha-2 format.
Solution: Use 2-letter country codes (US, GB, DE) not country names. For sandbox testing, check DHL documentation for the correct test account number. For production, use your actual DHL Express contract account number.
1// Correct: 2-letter ISO country codes2countryCode: 'US' // NOT 'United States' or 'USA'CORS error when calling DHL API from the Bolt preview
Cause: DHL API endpoints do not include CORS headers allowing browser-origin requests, so direct calls from client-side React code fail.
Solution: All DHL API calls must go through Next.js API routes (server-side), never from client-side code. Your React components should call /api/dhl/track, not api-eu.dhl.com directly.
1// WRONG — client-side call fails with CORS2// const data = await fetch('https://api-eu.dhl.com/track/shipments?...');34// CORRECT — call your own API route which proxies to DHL5const data = await fetch('/api/dhl/track?waybill=' + waybillNumber);Best practices
- Store DHL_API_KEY server-side only — never use NEXT_PUBLIC_ prefix, as the API key grants quota access and should not be exposed in browser network requests
- All DHL API calls must go through Next.js API routes to avoid CORS errors — DHL's APIs don't include browser-origin CORS headers
- Use sandbox test waybill numbers from DHL documentation during development, and switch to production keys only when deploying to a live environment
- Cache tracking responses for 5-10 minutes — tracking status doesn't change minute-by-minute, and caching reduces API calls and improves page load speed
- Normalize DHL's response format in your API route rather than in the frontend — keep the frontend components independent of DHL's specific field names
- Handle 404 responses gracefully with a user-friendly 'Shipment not found — please check the tracking number' message rather than a generic error
- For label generation, store the returned waybill number in your database immediately — it's your reference for tracking the shipment after creation
Alternatives
FedEx offers similar tracking, rating, and label APIs — better choice for US-domestic focused shipping apps where FedEx has stronger coverage than DHL Express.
UPS APIs cover domestic US shipping as well as international — useful when you need to support multiple carriers in one app, as UPS and DHL have complementary coverage.
AfterShip aggregates tracking across 700+ carriers including DHL, FedEx, and UPS in a single API — better for multi-carrier tracking apps that need to support various shipping providers.
ShipStation manages multi-carrier shipping (including DHL) with batch label generation and order management — better for e-commerce fulfillment than DHL's direct API.
Frequently asked questions
How do I connect Bolt.new to DHL?
Register at developer.dhl.com, create a sandbox application, and copy your sandbox API key. Add DHL_API_KEY to your .env file (server-side only). Create Next.js API routes that pass the DHL-API-Key header to DHL's endpoints. The Shipment Tracking API (api-eu.dhl.com) and Express API (express.api.dhl.com) are the two base URLs you'll use most. Test with DHL's sandbox test waybill numbers.
Is the DHL API free to use?
The DHL developer sandbox is free with no usage limits for testing. Production API access is included with a DHL Express business account — there are no per-call API charges, but you must have an active shipping contract with DHL Express. The Shipment Tracking API is generally available without a contract for tracking existing shipments.
Can I use DHL tracking in Bolt's WebContainer preview?
Yes. DHL's tracking API is an outbound HTTP call from your server — exactly the kind of request that works in Bolt's WebContainer. Your Next.js API route calls DHL's servers, and those results are returned to your React component. There are no incoming webhooks or special networking requirements for tracking.
What's the difference between DHL Express, DHL Parcel, and DHL eCommerce?
DHL operates multiple business units with different APIs. DHL Express (international express delivery) uses the MyDHL API (express.api.dhl.com). DHL Parcel (domestic parcel delivery in Europe) has its own API. DHL eCommerce (economy international shipping) has a separate API. The APIs, credentials, and endpoints are different between divisions — verify which DHL service your business uses before choosing the API.
How do I track multiple shipments at once?
The DHL Shipment Tracking API supports tracking multiple waybill numbers in a single request by comma-separating them in the trackingNumber query parameter: /track/shipments?trackingNumber=1234,5678,9012. The response includes a shipments array with one entry per waybill. This is more efficient than making separate requests for each shipment.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation