# How to Integrate Bolt.new with DHL API

- Tool: Bolt.new
- Difficulty: Intermediate
- Time required: 20 minutes
- Last updated: April 2026

## TL;DR

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.

## Before you start

- 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

### 1. 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.

**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.

### 2. 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.

```
# .env file additions
# DHL API credentials — server-side only, never NEXT_PUBLIC_
DHL_API_KEY=your_sandbox_api_key_here
DHL_TRACKING_API_BASE=https://api-eu.dhl.com
DHL_EXPRESS_API_BASE=https://express.api.dhl.com/mydhlapi
# Use 'test' for sandbox, 'production' for live
DHL_ENVIRONMENT=test
```

**Expected result:** lib/dhl.ts is created with a request helper. Environment variables are set. TypeScript compiles without errors.

### 3. 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.

```
// app/api/dhl/track/route.ts
import { NextResponse } from 'next/server';

async function dhlRequest(url: string) {
  const response = await fetch(url, {
    headers: {
      'DHL-API-Key': process.env.DHL_API_KEY ?? '',
      'Accept': 'application/json',
    },
  });
  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw Object.assign(new Error('DHL API error'), { status: response.status, body: error });
  }
  return response.json();
}

export async function GET(request: Request) {
  const url = new URL(request.url);
  const waybill = url.searchParams.get('waybill')?.trim();

  if (!waybill) {
    return NextResponse.json({ error: 'waybill query parameter is required' }, { status: 400 });
  }

  try {
    const trackingUrl = `${process.env.DHL_TRACKING_API_BASE}/track/shipments?trackingNumber=${encodeURIComponent(waybill)}`;
    const data = await dhlRequest(trackingUrl);

    const shipment = data?.shipments?.[0];
    if (!shipment) {
      return NextResponse.json({ error: 'Shipment not found' }, { status: 404 });
    }

    const normalized = {
      waybill,
      status: shipment.status?.status ?? 'unknown',
      description: shipment.status?.description ?? '',
      estimatedDelivery: shipment.estimatedTimeOfDelivery ?? null,
      origin: {
        name: shipment.origin?.address?.addressLocality ?? '',
        countryCode: shipment.origin?.address?.countryCode ?? '',
      },
      destination: {
        name: shipment.destination?.address?.addressLocality ?? '',
        countryCode: shipment.destination?.address?.countryCode ?? '',
      },
      events: (shipment.events ?? []).map((event: Record<string, unknown>) => ({
        timestamp: event.timestamp,
        location: (event.location as Record<string, unknown>)?.address
          ? `${((event.location as Record<string, unknown>).address as Record<string, unknown>).addressLocality}, ${((event.location as Record<string, unknown>).address as Record<string, unknown>).countryCode}`
          : 'Unknown',
        description: event.description,
        remark: event.remark ?? '',
      })),
    };

    return NextResponse.json(normalized);
  } catch (error: unknown) {
    const err = error as { status?: number };
    if (err.status === 404) {
      return NextResponse.json({ error: 'Shipment not found' }, { status: 404 });
    }
    console.error('DHL tracking error:', error);
    return NextResponse.json({ error: 'Failed to fetch tracking data' }, { status: 500 });
  }
}
```

**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.

### 4. 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.

```
// app/api/dhl/rates/route.ts
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const {
      originCountry, originPostalCode, originCity,
      destinationCountry, destinationPostalCode, destinationCity,
      weightKg, packageDimensions,
    } = body;

    // Shipment date must be today or future, in ISO format
    const plannedDate = new Date();
    plannedDate.setHours(14, 0, 0, 0); // 2pm local time
    const plannedShipmentDateAndTime = plannedDate.toISOString();

    const rateRequest = {
      customerDetails: {
        shipperDetails: {
          postalCode: originPostalCode,
          cityName: originCity,
          countryCode: originCountry,
        },
        receiverDetails: {
          postalCode: destinationPostalCode,
          cityName: destinationCity,
          countryCode: destinationCountry,
        },
      },
      accounts: [{
        typeCode: 'shipper',
        number: process.env.DHL_ACCOUNT_NUMBER ?? 'TEST_ACCOUNT',
      }],
      plannedShipmentDateAndTime,
      unitOfMeasurement: 'metric',
      isCustomsDeclarable: false,
      packages: [{
        weight: Number(weightKg),
        dimensions: {
          length: Number(packageDimensions?.length ?? 20),
          width: Number(packageDimensions?.width ?? 15),
          height: Number(packageDimensions?.height ?? 10),
        },
      }],
    };

    const response = await fetch(`${process.env.DHL_EXPRESS_API_BASE}/rates`, {
      method: 'POST',
      headers: {
        'DHL-API-Key': process.env.DHL_API_KEY ?? '',
        'Content-Type': 'application/json',
        'Accept': 'application/json',
      },
      body: JSON.stringify(rateRequest),
    });

    if (!response.ok) {
      const error = await response.json();
      return NextResponse.json({ error: error?.detail ?? 'Rate request failed' }, { status: response.status });
    }

    const data = await response.json();
    const rates = (data?.products ?? []).map((product: Record<string, unknown>) => ({
      productName: product.productName,
      serviceCode: product.productCode,
      totalCharge: (product.totalPrice as Array<Record<string, unknown>>)?.[0]?.price ?? 0,
      currency: (product.totalPrice as Array<Record<string, unknown>>)?.[0]?.priceCurrency ?? 'USD',
      deliveryDate: (product.deliveryCapabilities as Record<string, unknown>)?.estimatedDeliveryDateAndTime ?? null,
    })).sort((a: Record<string, unknown>, b: Record<string, unknown>) => Number(a.totalCharge) - Number(b.totalCharge));

    return NextResponse.json({ rates });
  } catch (error) {
    console.error('DHL rates error:', error);
    return NextResponse.json({ error: 'Failed to calculate rates' }, { status: 500 });
  }
}
```

**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.

## 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

## 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.

Prompt example:

```
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.
```

### 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.

Prompt example:

```
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.
```

### 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.

Prompt example:

```
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.
```

## 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.

```
headers: {
  'DHL-API-Key': process.env.DHL_API_KEY ?? '', // Exact capitalization required
  'Accept': 'application/json',
}
```

### 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.

```
// Correct: 2-letter ISO country codes
countryCode: '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.

```
// WRONG — client-side call fails with CORS
// const data = await fetch('https://api-eu.dhl.com/track/shipments?...');

// CORRECT — call your own API route which proxies to DHL
const data = await fetch('/api/dhl/track?waybill=' + waybillNumber);
```

## 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.

---

Source: https://www.rapidevelopers.com/bolt-ai-integrations/dhl-api
© RapidDev — https://www.rapidevelopers.com/bolt-ai-integrations/dhl-api
