To integrate AfterShip with V0 by Vercel, create a Next.js API route that calls the AfterShip REST API using your API key stored in Vercel environment variables. V0 generates the tracking UI and API route code; you add the real AfterShip API key in Vercel Dashboard → Settings → Environment Variables, then deploy for live shipment tracking across 1,100+ carriers.
Add Multi-Carrier Shipment Tracking to Your V0 App
AfterShip aggregates tracking data from more than 1,100 carriers — including FedEx, UPS, DHL, USPS, and regional last-mile couriers — into a single unified API. Instead of integrating dozens of carrier APIs individually, your V0-generated Next.js app can query one endpoint and display a consistent tracking timeline regardless of which carrier is handling a shipment. This makes AfterShip the go-to choice for e-commerce apps, order management dashboards, and customer-facing order status pages.
V0 generates the React tracking UI and the API route scaffold. You supply the AfterShip API key and the tracking numbers from your order system. The integration uses AfterShip's Tracking API v2 (REST/JSON), which supports creating trackings, fetching tracking status, and listing all trackings for an account. AfterShip also offers a Webhook feature that pushes status updates to your app in real time — useful for sending shipping notification emails without polling.
Unlike integrating a single carrier such as FedEx or UPS, AfterShip's value is normalization: every carrier's status codes are mapped to AfterShip's universal tag system (InfoReceived, InTransit, OutForDelivery, Delivered, Exception). Your UI code only needs to handle these normalized tags, making the frontend much simpler.
Integration method
AfterShip connects to V0-generated Next.js apps through a server-side API route that securely proxies requests to the AfterShip Tracking API. The API key lives in Vercel environment variables and never reaches the browser. The V0-generated UI component fetches tracking data from your own API route, which in turn calls AfterShip.
Prerequisites
- A V0 account at v0.dev with a Next.js project created
- An AfterShip account at aftership.com (free tier available)
- An AfterShip API key from the AfterShip Dashboard → Settings → API Keys
- A Vercel account connected to your V0 project for deployment
- At least one tracking number and carrier name to test with
Step-by-step guide
Generate the Tracking UI with V0
Generate the Tracking UI with V0
Open your V0 project and use the chat panel to generate the shipment tracking interface. Be specific about what data you want to display — AfterShip returns a rich tracking object including the current status tag, estimated delivery date, a list of checkpoints with timestamps and locations, carrier name, origin and destination countries, and any exception messages. Describe the layout you want: a search input at the top, a status banner showing the normalized tag (InTransit, Delivered, Exception), and a vertical timeline of checkpoint events. V0 will generate a React component that expects tracking data as props or fetches it from an API endpoint. Make sure to specify /api/aftership/track as the endpoint so the generated code already wires up to the route you will create in the next step. If you want real-time updates, ask V0 to add polling with a 30-second interval using useEffect and setInterval. After V0 generates the component, review it in the preview panel. The UI will use placeholder/mock data since the API route does not exist yet — that is expected. Focus on whether the layout matches your requirements before moving to the backend setup.
Create a shipment tracking page with a search form at the top (tracking number input + carrier dropdown), a status banner showing current shipment status with a color-coded badge, and a vertical timeline of tracking events below. Each timeline item shows timestamp, location, and event description. Fetch data from /api/aftership/track?trackingNumber=X&carrier=Y. Show a skeleton loader while fetching. Use Tailwind CSS and shadcn/ui components.
Paste this in V0 chat
Pro tip: Ask V0 to handle the AfterShip normalized status tags by name: InfoReceived, InTransit, OutForDelivery, AttemptFail, Delivered, Exception, Expired. Map each to a specific color and icon for a polished UI.
Expected result: V0 generates a tracking page component with a search form and timeline layout using mock data. The component calls /api/aftership/track which does not exist yet.
Create the AfterShip API Route
Create the AfterShip API Route
Create a new file at app/api/aftership/route.ts in your project. This server-side route receives tracking requests from your frontend, adds your AfterShip API key from the environment, and calls the AfterShip Tracking API. Using a server-side proxy instead of calling AfterShip directly from the browser is essential — it keeps your API key secret and avoids CORS errors since AfterShip's API does not allow direct browser requests. The AfterShip Tracking API v2 endpoint for fetching a single tracking is GET https://api.aftership.com/v4/trackings/{slug}/{tracking_number} where slug is the carrier slug (e.g., fedex, ups, dhl). The API requires an as-api-key header with your secret key. You can also use the newer v2 endpoint at https://api.aftership.com/tracking/2024-10/trackings/{id} — check the AfterShip developer docs for the latest version. The route handler reads the tracking number and carrier from query parameters, constructs the AfterShip API URL, makes an authenticated fetch call, and returns the normalized tracking data to the frontend. Always include error handling for cases where the tracking number is not found (404 from AfterShip) or the API key is invalid (401).
1import { NextRequest, NextResponse } from 'next/server';23export async function GET(request: NextRequest) {4 const { searchParams } = new URL(request.url);5 const trackingNumber = searchParams.get('trackingNumber');6 const carrier = searchParams.get('carrier');78 if (!trackingNumber || !carrier) {9 return NextResponse.json(10 { error: 'trackingNumber and carrier are required' },11 { status: 400 }12 );13 }1415 const apiKey = process.env.AFTERSHIP_API_KEY;16 if (!apiKey) {17 return NextResponse.json(18 { error: 'AfterShip API key not configured' },19 { status: 500 }20 );21 }2223 try {24 const response = await fetch(25 `https://api.aftership.com/v4/trackings/${encodeURIComponent(carrier)}/${encodeURIComponent(trackingNumber)}`,26 {27 headers: {28 'as-api-key': apiKey,29 'Content-Type': 'application/json',30 },31 }32 );3334 if (!response.ok) {35 const error = await response.json();36 return NextResponse.json(37 { error: error.meta?.message || 'AfterShip API error' },38 { status: response.status }39 );40 }4142 const data = await response.json();43 return NextResponse.json(data.data.tracking);44 } catch (error) {45 console.error('AfterShip API error:', error);46 return NextResponse.json(47 { error: 'Failed to fetch tracking data' },48 { status: 500 }49 );50 }51}Pro tip: AfterShip uses carrier slugs (not names) in the URL — e.g., 'fedex' not 'FedEx'. Use the AfterShip carrier list at aftership.com/couriers to find the correct slug for each carrier.
Expected result: The API route file is created. Calling /api/aftership/track?trackingNumber=123&carrier=fedex in your browser returns an error about the missing API key (expected at this stage).
Add the AfterShip API Key to Vercel Environment Variables
Add the AfterShip API Key to Vercel Environment Variables
Your AfterShip API key must be stored in Vercel's environment variable system — never hardcoded in your source code or committed to GitHub. To add it, go to your Vercel Dashboard, select your project, navigate to Settings → Environment Variables, and add a new variable. Set the name to AFTERSHIP_API_KEY and paste your AfterShip API key as the value. In the Environment selector, choose All Environments (Production, Preview, Development) so the key works across all deployment contexts. If you want to use different AfterShip accounts for testing versus production, you can set separate values per environment — for example, a test account key for Preview and your main account key for Production. To find your AfterShip API key: log in to the AfterShip Dashboard at app.aftership.com, go to Settings → API Keys (or the API section in the left sidebar), and copy your existing key or generate a new one. AfterShip API keys on the free tier support up to 50 trackings and 100 API calls per month, which is enough for testing. After adding the variable, you must redeploy your Vercel project for the new environment variable to take effect. In V0, click the Deploy button or push a commit to trigger a redeployment.
Pro tip: If you are testing locally, create a .env.local file in your project root and add AFTERSHIP_API_KEY=your_key_here. This file is automatically excluded from git and Next.js loads it automatically during local development.
Expected result: The AFTERSHIP_API_KEY environment variable appears in Vercel Dashboard. After redeployment, calling /api/aftership/route.ts with a valid tracking number returns real tracking data from AfterShip.
Add a Webhook Endpoint for Real-Time Updates (Optional)
Add a Webhook Endpoint for Real-Time Updates (Optional)
AfterShip can push tracking status updates to your app via webhooks instead of requiring your app to poll the API. This is useful for triggering shipping notification emails, updating order status in your database, or refreshing a cached tracking page. To receive webhooks, you need a POST endpoint in your Next.js app. Create a webhook route at app/api/aftership/webhook/route.ts. AfterShip sends a POST request to your URL whenever a tracking status changes. The request body is a JSON object containing the tracking details, the new status tag, and the checkpoint event that triggered the update. AfterShip also sends a Hmac-Sha256 signature header (aftership-hmac-sha256) that you should verify to confirm the webhook originated from AfterShip and not from a third party. To configure the webhook in AfterShip: go to the AfterShip Dashboard → Notifications → Webhooks, click Add Webhook, enter your Vercel deployment URL plus /api/aftership/webhook (e.g., https://your-app.vercel.app/api/aftership/webhook), and select which status events to trigger on. AfterShip will send a test payload when you save — check your Vercel Function logs to confirm receipt. For complex webhook processing logic or integrating AfterShip webhooks with downstream systems like email providers or databases, RapidDev's team can help design the full notification pipeline.
Create a webhook handler display component that shows a feed of the last 10 shipment status updates received from our webhook. Each entry shows tracking number, carrier, new status badge, and timestamp. Fetch from /api/aftership/updates. Use shadcn/ui Card components.
Paste this in V0 chat
1import { NextRequest, NextResponse } from 'next/server';2import crypto from 'crypto';34export async function POST(request: NextRequest) {5 const body = await request.text();6 const signature = request.headers.get('aftership-hmac-sha256');7 const secret = process.env.AFTERSHIP_WEBHOOK_SECRET;89 // Verify webhook signature if secret is configured10 if (secret && signature) {11 const expectedSig = crypto12 .createHmac('sha256', secret)13 .update(body)14 .digest('hex');15 if (expectedSig !== signature) {16 return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });17 }18 }1920 const payload = JSON.parse(body);21 const tracking = payload.msg;2223 console.log('AfterShip webhook received:', {24 trackingNumber: tracking.tracking_number,25 carrier: tracking.slug,26 tag: tracking.tag,27 estimatedDelivery: tracking.expected_delivery,28 });2930 // Add your business logic here:31 // - Update order status in database32 // - Send email notification33 // - Trigger other workflows3435 return NextResponse.json({ received: true });36}Pro tip: AfterShip retries failed webhook deliveries up to 5 times with exponential backoff. Always return a 200 response quickly and process the event asynchronously to avoid timeouts.
Expected result: The webhook endpoint is live. Shipment status changes in AfterShip trigger POST requests to your Vercel app, which logs the event and can update your database or trigger notifications.
Deploy and Test the Full Integration
Deploy and Test the Full Integration
With the UI component, API route, and environment variable all in place, deploy your app to Vercel. In V0, click the Deploy button in the top-right corner of the interface. V0 pushes the code to GitHub and Vercel triggers an automatic build and deployment. The process typically completes in 60-90 seconds. Once deployed, open your live app URL and test the tracking flow with a real tracking number. Use a recent shipment you have the tracking number for — enter the tracking number, select the carrier, and submit the form. The frontend calls /api/aftership/track, which calls the AfterShip API and returns the tracking timeline. You should see the shipment's checkpoint history displayed in the timeline component. If tracking data does not appear, check the Vercel Function Logs: go to your Vercel project → Functions tab → select the aftership route → view recent invocations. Look for error messages about the API key, network errors, or AfterShip API error responses. Common issues include using the wrong carrier slug or an API key from the wrong AfterShip account. AfterShip's free plan allows 50 trackings per month. Each time you call the API with a new tracking number, AfterShip creates a tracking record that counts toward this limit. For production e-commerce apps, you will likely need a paid AfterShip plan.
Add error handling to the tracking page so that when /api/aftership/track returns an error, we show a friendly error message with the specific issue (tracking not found, invalid carrier, API error). Also add a 'Try again' button that retries the fetch.
Paste this in V0 chat
Pro tip: Test with carriers AfterShip officially supports — find the full list at aftership.com/couriers. Using an unsupported carrier slug returns a 404 from AfterShip.
Expected result: The live app displays real shipment tracking data from AfterShip. Entering a valid tracking number and carrier shows the full checkpoint timeline with timestamps, locations, and status badges.
Common use cases
Customer Order Tracking Page
Build a self-service tracking page where customers enter their order number or tracking number and see a timeline of shipment events. AfterShip normalizes carrier data so the same component works for FedEx, DHL, and 1,100 other carriers.
Create a shipment tracking page with a text input for a tracking number, a carrier selector dropdown, and a timeline component that displays tracking events fetched from /api/aftership/track. Show each event with a status badge, location, and timestamp. Use Tailwind CSS.
Copy this prompt to try it in V0
Admin Order Fulfillment Dashboard
Display all active shipments in an admin dashboard with their current status, estimated delivery date, and exception alerts. The AfterShip API returns all trackings for your account, making it easy to build a real-time fulfillment overview.
Build an admin dashboard table showing all shipments fetched from /api/aftership/trackings. Columns: tracking number, carrier, status badge (color-coded), estimated delivery, last update time. Add a filter for status (In Transit, Delivered, Exception). Use shadcn/ui Table component.
Copy this prompt to try it in V0
Post-Purchase Shipping Notification Widget
Embed a compact tracking widget on a post-purchase confirmation page that automatically polls for the latest status and updates without a page refresh. Customers see live shipping progress immediately after checkout.
Create a compact shipping status widget that takes a trackingNumber prop and polls /api/aftership/track every 30 seconds. Display the carrier logo placeholder, current status, and last event description. Show a loading skeleton while fetching. Handle error states with a retry button.
Copy this prompt to try it in V0
Troubleshooting
API returns 401 Unauthorized — 'Invalid API key'
Cause: The AFTERSHIP_API_KEY environment variable is missing, empty, or the key was regenerated in the AfterShip Dashboard after being added to Vercel.
Solution: Go to AfterShip Dashboard → Settings → API Keys to confirm your key is active. Then verify the variable name in Vercel Dashboard → Settings → Environment Variables is exactly AFTERSHIP_API_KEY (case-sensitive). After updating the variable, redeploy your project — Vercel injects environment variables at build/deploy time, so existing deployments do not pick up new values automatically.
Tracking returns empty checkpoints array — no timeline events shown
Cause: The tracking number exists in AfterShip but no carrier checkpoints have been received yet. This happens when a shipment label is created but the package has not been picked up, or when the carrier has not yet scanned the package into their system.
Solution: Check the 'tag' field in the AfterShip response. If it is 'InfoReceived', the label was created but transit has not started. Display a message like 'Label created — waiting for carrier pickup' instead of an empty timeline. Checkpoints populate once the carrier scans the package.
CORS error — 'Access to fetch at aftership.com has been blocked by CORS policy'
Cause: The frontend component is calling the AfterShip API directly from the browser instead of going through the Next.js API route. AfterShip's API does not allow direct browser requests (no CORS headers).
Solution: Ensure all AfterShip API calls in your React components use your own API route (/api/aftership/track) and never call api.aftership.com directly from client-side code. V0 may have generated a direct fetch to AfterShip — update it to call your proxy route instead.
1// Wrong — do not call AfterShip from the browser2const res = await fetch('https://api.aftership.com/v4/trackings/...');34// Correct — call your Next.js API route5const res = await fetch(`/api/aftership/track?trackingNumber=${num}&carrier=${carrier}`);404 from AfterShip — 'Tracking not found'
Cause: The carrier slug in the URL does not match AfterShip's internal slug for that carrier, or the tracking number format is incorrect. AfterShip uses lowercase hyphenated slugs (e.g., 'dhl-express' not 'DHL Express').
Solution: Look up the correct carrier slug at aftership.com/couriers — search for the carrier name and copy the slug shown. Common examples: 'fedex' for FedEx, 'ups' for UPS, 'usps' for USPS, 'dhl' for DHL, 'dhl-express' for DHL Express (different from standard DHL). Pass the exact slug from this list.
Best practices
- Always proxy AfterShip API calls through a Next.js API route — never call api.aftership.com from client-side code to keep your API key secret and avoid CORS issues.
- Cache tracking responses for 5-10 minutes using Vercel's fetch cache or a simple in-memory cache to reduce AfterShip API calls and stay within rate limits on free plans.
- Use AfterShip's normalized status tags (InfoReceived, InTransit, OutForDelivery, Delivered, Exception) for UI logic rather than carrier-specific status strings, which vary widely between carriers.
- Implement webhook-based updates for production apps instead of polling — this reduces API usage, provides faster updates, and scales better than scheduled fetch calls.
- Validate the AfterShip webhook signature using HMAC-SHA256 before processing any webhook payload to prevent malicious actors from spoofing tracking updates.
- Display the estimated delivery date from AfterShip when available — customers care most about when a package will arrive, not just where it is now.
- Handle the 'Exception' status tag explicitly in your UI with a clear message and a link to the AfterShip tracking page for the full carrier details.
- Use AfterShip's auto-detect feature (omit the carrier slug) for cases where you do not know the carrier — AfterShip will identify the carrier from the tracking number format.
Alternatives
FedEx API is the right choice if you only ship with FedEx and want direct integration with FedEx-specific features like dangerous goods tracking and FedEx Office services.
ShipStation is better if you need end-to-end order fulfillment including label creation and multi-carrier rate shopping, not just tracking aggregation.
Shippo combines rate comparison, label creation, and tracking across carriers, making it a good alternative if you need shipping label generation alongside tracking.
Frequently asked questions
Does AfterShip have a free tier?
Yes, AfterShip offers a free plan that includes 50 trackings per month and 100 API calls. This is sufficient for testing and small apps. Paid plans start at higher tracking volumes and add features like branded tracking pages, email notifications, and analytics.
How many carriers does AfterShip support?
AfterShip supports over 1,100 carriers worldwide as of 2026, including all major global carriers (FedEx, UPS, DHL, USPS, TNT) and hundreds of regional and last-mile couriers. The full list is available at aftership.com/couriers.
Can I use AfterShip without knowing the carrier?
Yes, AfterShip's API supports auto-detection. When creating a tracking without specifying a carrier slug, AfterShip will attempt to identify the carrier based on the tracking number format. This works well for major carriers but may require a carrier slug for regional couriers with ambiguous number formats.
How do AfterShip's status tags work?
AfterShip normalizes all carrier-specific status messages into a set of universal tags: InfoReceived (label created), InTransit (in transit), OutForDelivery (out for delivery), AttemptFail (delivery attempted but failed), Delivered, Exception (issue with delivery), and Expired (tracking not updated for 30 days). Build your UI logic around these tags rather than carrier-specific messages.
What is the difference between AfterShip and ShipStation?
AfterShip focuses on post-shipment tracking and customer notifications — it aggregates tracking data from 1,100+ carriers but does not create shipping labels. ShipStation is a full order fulfillment platform that includes label creation, rate shopping, and tracking. Use AfterShip if you already have a shipping solution and just need unified tracking visibility.
How quickly does AfterShip update tracking status?
AfterShip polls carriers on a schedule that varies by carrier and plan — typically every 1-6 hours for standard carriers on free plans. Paid plans get more frequent polling. For real-time updates, use AfterShip's webhook feature which pushes status changes to your app as soon as AfterShip detects them.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation