Prompt
I'm building a Next.js app and need an API plus delivery visibility.
Latest observation
Building a full-stack Next.js app with an internal/external API layer and real-time delivery tracking requires two core parts: Route Handlers (to power your API) and a Data Pipeline / Webhook Architecture (for status visibility).
1. Architecture Overview
[ Client / Front-End ]
│
▼
[ Next.js App Router API (`app/api/delivery/route.ts`) ]
│
┌─────┴────────────────────────┐
▼ ▼
[ Database ] [ Logistics Partner ]
(PostgreSQL / Supabase) (FedEx, EasyPost, Shippo, etc.)
▲ │
└───── [ Webhook Handler ] ◄──┘
2. Setting Up the API with Route Handlers
Using Next.js App Router, endpoints are defined using route.ts files inside app/api/....
Fetch / Search Delivery Status
app/api/delivery/route.ts
TypeScript
import { NextRequest, NextResponse } from 'next/server';
// Mock DB call / API integration
async function getDeliveryStatus(trackingNumber: string) {
// Query your DB or logistics vendor here
return {
trackingNumber,
status: 'IN_TRANSIT',
estimatedDelivery: '2026-10-05T18:00:00Z',
location: 'Distribution Center - Chicago, IL',
updates: [
{ timestamp: '2026-10-01T08:00:00Z', status: 'Package Dispatched', location: 'Origin Facility' },
{ timestamp: '2026-10-01T14:30:00Z', status: 'In Transit', location: 'Chicago Hub' },
]
};
}
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const trackingNumber = searchParams.get('trackingNumber');
if (!trackingNumber) {
return NextResponse.json({ error: 'Tracking number is required' }, { status: 400 });
}
try {
const data = await getDeliveryStatus(trackingNumber);
return NextResponse.json({ success: true, data }, { status: 200 });
} catch (error) {
return NextResponse.json({ error: 'Failed to fetch tracking information' }, { status: 500 });
}
}
3. Real-Time Delivery Visibility (Webhook Endpoint)
To get live visibility when a carrier updates a package status, expose a webhook endpoint for carriers (e.g., EasyPost, Shippo, or custom carriers) to ping.
app/api/webhooks/delivery/route.ts
TypeScript
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
try {
const body = await request.json();
// 1. Verify webhook signature for security
const signature = request.headers.get('x-carrier-signature');
if (!signature) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// 2. Extract delivery details
const { tracking_number, status, current_location } = body;
// 3. Update your database record
console.log(`Updated tracking #${tracking_number} to ${status} at ${current_location}`);
// 4. Return a 200 OK fast so the carrier doesn't retry
return NextResponse.json({ received: true }, { status: 200 });
} catch (err) {
return NextResponse.json({ error: 'Webhook processing failed' }, { status: 500 });
}
}
4. Frontend Component for Delivery Tracking
You can consume this API cleanly on the client or in a Server Component.
TypeScript
'use client';
import { useState } from 'react';
export default function DeliveryTracker() {
const [trackingNumber, setTrackingNumber] = useState('');
const [delivery, setDelivery] = useState<any>(null);
const [loading, setLoading] = useState(false);
const fetchTracking = async () => {
if (!trackingNumber) return;
setLoading(true);
try {
const res = await fetch(`/api/delivery?trackingNumber=${trackingNumber}`);
const result = await res.json();
if (result.success) setDelivery(result.data);
} catch (e) {
console.error(e);
} finally {
setLoading(false);
}
};
return (
<div style={{ padding: '2rem', maxWidth: '600px', margin: '0 auto' }}>
<h2>Track Your Delivery</h2>
<div style={{ display: 'flex', gap: '10px', marginBottom: '1rem' }}>
<input
type="text"
placeholder="Enter tracking number"
value={trackingNumber}
onChange={(e) => setTrackingNumber(e.target.value)}
style={{ flex: 1, padding: '8px' }}
/>
<button onClick={fetchTracking} disabled={loading} style={{ padding: '8px 16px' }}>
{loading ? 'Searching...' : 'Track'}
</button>
</div>
{delivery && (
<div style={{ border: '1px solid #ccc', padding: '16px', borderRadius: '8px' }}>
<h3>Status: {delivery.status}</h3>
<p><strong>Location:</strong> {delivery.location}</p>
<p><strong>Est. Delivery:</strong> {new Date(delivery.estimatedDelivery).toLocaleDateString()}</p>
<h4>Updates:</h4>
<ul>
{delivery.updates.map((item: any, idx: number) => (
<li key={idx}>
{new Date(item.timestamp).toLocaleString()} - <strong>{item.status}</strong> ({item.location})
</li>
))}
</ul>
</div>
)}
</div>
);
}
Recommended Logistics API Tools
If you are connecting to real-world carriers, consider using a aggregator API instead of writing direct integrations for every carrier:
- EasyPost / Shippo: Unified API for USPS, FedEx, UPS, and DHL with built-in webhook status events.
- Supabase / PostgreSQL + Server-Sent Events (SSE): Push live status updates directly to your Next.js UI when a webhook updates the DB.