Skip to main content
RapidDev - Software Development Agency
lovable-integrationsEdge Function Integration

How to Integrate Lovable with AfterShip

To integrate AfterShip with Lovable, create a Supabase Edge Function that proxies AfterShip Tracking API v4 calls using your AfterShip API key stored in Cloud Secrets. This lets you build multi-carrier shipment tracking pages, delivery status dashboards, and order status tools covering 1,100+ carriers — without exposing your API key in frontend code. Setup takes about 30 minutes.

What you'll learn

  • How to obtain an AfterShip API key and understand the Tracking API v4 structure
  • How to store the AfterShip API key securely in Lovable Cloud Secrets
  • How to write a Supabase Edge Function that creates trackings, fetches delivery status, and handles AfterShip webhooks on Deno
  • How to build a multi-carrier order status dashboard in React that shows live delivery information for all customer orders
  • How to set up AfterShip webhooks to automatically update delivery status in your Supabase database when packages move
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read30 minutesE-commerceMarch 2026RapidDev Engineering Team
TL;DR

To integrate AfterShip with Lovable, create a Supabase Edge Function that proxies AfterShip Tracking API v4 calls using your AfterShip API key stored in Cloud Secrets. This lets you build multi-carrier shipment tracking pages, delivery status dashboards, and order status tools covering 1,100+ carriers — without exposing your API key in frontend code. Setup takes about 30 minutes.

Build a Multi-Carrier Tracking Dashboard in Lovable with AfterShip

Post-purchase tracking is one of the most viewed pages in any e-commerce experience — customers check their order status repeatedly between purchase and delivery. AfterShip solves the fragmented carrier tracking problem: instead of building separate tracking integrations for USPS, UPS, FedEx, DHL, Canada Post, and dozens of regional carriers, you connect to AfterShip once and get unified tracking data from 1,100+ carriers worldwide. Add a tracking number and carrier to AfterShip, and it handles polling the carrier, normalizing the event data, and delivering updates via webhook.

Integrating AfterShip with Lovable lets you build branded tracking pages, order status dashboards, and proactive delivery notification systems. Because AfterShip abstracts carrier differences, a single React component can display tracking timelines for packages shipped via any carrier — the data structure is always the same. AfterShip also provides a tag system (Pending, InTransit, OutForDelivery, Delivered, Exception) that makes it easy to build status-based filtering and alerting in your app.

AfterShip differs from ShipStation in its scope: AfterShip is a tracking-only platform. It doesn't create shipments, generate labels, or manage orders — it exclusively handles the post-shipment tracking experience. If you need both label generation and tracking, consider Shippo (which includes basic tracking) or pair AfterShip with a label generation tool. If your primary goal is giving customers excellent post-purchase tracking visibility across whatever carriers you're already using, AfterShip is the purpose-built solution.

Integration method

Edge Function Integration

AfterShip integration in Lovable works by routing all Tracking API calls through Supabase Edge Functions running on Deno. Your AfterShip API key is stored as an encrypted secret in Cloud → Secrets and accessed via Deno.env.get() — never exposed to the browser. The React frontend calls the Edge Function to create trackings, fetch delivery status, and receive webhook events from AfterShip's 1,100+ carrier network.

Prerequisites

  • An AfterShip account — sign up free at aftership.com (free plan includes 50 trackings/month; paid plans for higher volume)
  • Your AfterShip API key from the AfterShip dashboard under Settings → API
  • A Lovable project with Lovable Cloud enabled (the default for all new projects)
  • An existing order or shipment system in your app with tracking numbers and carrier information — AfterShip enriches this data, it doesn't create shipments
  • Understanding of AfterShip's carrier slug format — each carrier has a slug (e.g., 'usps', 'ups', 'fedex', 'dhl') used when creating trackings

Step-by-step guide

1

Get your AfterShip API key

Log in to your AfterShip account at app.aftership.com. In the left navigation, go to Settings → API. You'll see an API Keys section with your organization's API keys listed. Click Create API Key, give it a name (e.g., 'Lovable App'), and click Create. The new API key is displayed once — copy it immediately, as AfterShip doesn't show the full key again after this screen. AfterShip's API uses API key authentication via the 'as-api-key' request header. The current API version is v4 with base URL https://api.aftership.com/v4. AfterShip's API includes endpoints for: POST /trackings (add a new shipment to track), GET /trackings/{slug}/{tracking_number} (get tracking details for a specific shipment), GET /trackings (list all trackings with filtering), DELETE /trackings (remove a tracking), and POST /notifications/.../{tracking_number} (manage customer notifications). AfterShip also provides a Webhook feature where AfterShip sends POST requests to your Edge Function URL whenever a tracking status changes — this is the preferred approach for real-time updates instead of polling. You'll configure the webhook URL in a later step after deploying your Edge Function.

Pro tip: AfterShip auto-detects the carrier from the tracking number format in many cases — you don't always need to specify the carrier slug when creating a tracking. However, providing the carrier slug speeds up tracking activation and prevents misidentification of ambiguous tracking numbers.

Expected result: You have an AfterShip API key copied from Settings → API → Create API Key.

2

Store the AfterShip API key in Cloud Secrets

In your Lovable project, click the '+' icon next to the Preview panel to open the Cloud tab. Click Secrets in the left sidebar. Click Add Secret. Set the name to AFTERSHIP_API_KEY and paste your AfterShip API key as the value. Click Save. The key is now encrypted and stored, accessible only from Edge Functions via Deno.env.get('AFTERSHIP_API_KEY'). AfterShip API keys grant full access to your AfterShip account — they can create, read, update, and delete all your trackings. Never expose this key in frontend React code, and never paste it into Lovable's chat prompt. On Lovable's free tier, chat history is publicly visible and API keys pasted there are recoverable from Git commit history. The Cloud Secrets panel is the only secure location for credentials in a Lovable project. Lovable's security system blocks approximately 1,200 hardcoded API keys daily across all projects — the Secrets panel is how you stay protected. If you accidentally expose your API key, rotate it immediately in AfterShip's Settings → API by deleting the old key and creating a new one.

Pro tip: AfterShip also supports a Webhook Secret for verifying incoming webhook payloads — store it as AFTERSHIP_WEBHOOK_SECRET in Cloud Secrets when you set up the webhook Edge Function.

Expected result: Cloud → Secrets shows AFTERSHIP_API_KEY as an encrypted entry.

3

Create the AfterShip Edge Function proxy

Create the Edge Function that proxies AfterShip API calls and receives AfterShip webhooks. Type the prompt below into Lovable's chat. Lovable will generate the TypeScript at supabase/functions/aftership-proxy/index.ts and deploy it to Cloud. The Edge Function handles four operations based on the 'action' query parameter: 'create' (POST to AfterShip to register a new tracking), 'get' (GET a specific tracking by slug and tracking number), 'list' (GET all trackings with optional filters), and 'webhook' (receive AfterShip webhook POST events and update Supabase). The webhook handler verifies the request is from AfterShip using the webhook secret and updates the relevant order's delivery status in the database. AfterShip sends webhook events as POST requests with a JSON body containing the updated tracking object, including the new tag (Delivered, InTransit, etc.), last event message, and estimated delivery date. The webhook handler extracts these values and updates the corresponding order record in Supabase using the tracking number as the lookup key.

Lovable Prompt

Create a Supabase Edge Function at supabase/functions/aftership-proxy/index.ts for the AfterShip Tracking API v4. Use Deno.env.get('AFTERSHIP_API_KEY') as the 'as-api-key' header for authentication. Base URL: https://api.aftership.com/v4. Support four actions via query parameter: 'create' (POST /trackings with tracking_number, slug, and optional customer_name/emails in body), 'get' (GET /trackings/{slug}/{tracking_number} using slug and trackingNumber query params), 'list' (GET /trackings with optional tag, page, and limit query params passed through), and 'webhook' (POST — receive AfterShip webhook, extract tracking data, and update the delivery_status and last_tracking_event columns on the orders table in Supabase where tracking_number matches). Include CORS headers.

Paste this in Lovable chat

supabase/functions/aftership-proxy/index.ts
1import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
2import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
3
4const AFTERSHIP_BASE = 'https://api.aftership.com/v4'
5
6const corsHeaders = {
7 'Access-Control-Allow-Origin': '*',
8 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
9}
10
11serve(async (req) => {
12 if (req.method === 'OPTIONS') {
13 return new Response('ok', { headers: corsHeaders })
14 }
15
16 const url = new URL(req.url)
17 const action = url.searchParams.get('action')
18
19 const apiKey = Deno.env.get('AFTERSHIP_API_KEY')
20 if (!apiKey) {
21 return new Response(
22 JSON.stringify({ error: 'AFTERSHIP_API_KEY not configured' }),
23 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
24 )
25 }
26
27 const aftershipHeaders = {
28 'as-api-key': apiKey,
29 'Content-Type': 'application/json',
30 }
31
32 try {
33 if (action === 'webhook') {
34 const supabase = createClient(
35 Deno.env.get('SUPABASE_URL') ?? '',
36 Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
37 )
38 const body = await req.json()
39 const tracking = body?.msg
40
41 if (tracking?.tracking_number) {
42 await supabase
43 .from('orders')
44 .update({
45 delivery_status: tracking.tag,
46 last_tracking_event: tracking.last_event_time_at,
47 estimated_delivery: tracking.estimated_delivery,
48 })
49 .eq('tracking_number', tracking.tracking_number)
50 }
51
52 return new Response(JSON.stringify({ ok: true }), {
53 headers: { ...corsHeaders, 'Content-Type': 'application/json' },
54 })
55 }
56
57 if (action === 'create') {
58 const body = await req.text()
59 const res = await fetch(`${AFTERSHIP_BASE}/trackings`, {
60 method: 'POST',
61 headers: aftershipHeaders,
62 body,
63 })
64 const data = await res.json()
65 return new Response(JSON.stringify(data), {
66 status: res.status,
67 headers: { ...corsHeaders, 'Content-Type': 'application/json' },
68 })
69 }
70
71 if (action === 'get') {
72 const slug = url.searchParams.get('slug')
73 const trackingNumber = url.searchParams.get('trackingNumber')
74 const res = await fetch(`${AFTERSHIP_BASE}/trackings/${slug}/${trackingNumber}`, {
75 headers: aftershipHeaders,
76 })
77 const data = await res.json()
78 return new Response(JSON.stringify(data), {
79 status: res.status,
80 headers: { ...corsHeaders, 'Content-Type': 'application/json' },
81 })
82 }
83
84 if (action === 'list') {
85 const tag = url.searchParams.get('tag') || ''
86 const page = url.searchParams.get('page') || '1'
87 const limit = url.searchParams.get('limit') || '25'
88 const queryStr = new URLSearchParams({ tag, page, limit }).toString()
89 const res = await fetch(`${AFTERSHIP_BASE}/trackings?${queryStr}`, {
90 headers: aftershipHeaders,
91 })
92 const data = await res.json()
93 return new Response(JSON.stringify(data), {
94 status: res.status,
95 headers: { ...corsHeaders, 'Content-Type': 'application/json' },
96 })
97 }
98
99 return new Response(
100 JSON.stringify({ error: 'Invalid action. Use: create, get, list, or webhook' }),
101 { status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
102 )
103 } catch (error) {
104 return new Response(
105 JSON.stringify({ error: error.message }),
106 { status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
107 )
108 }
109})

Pro tip: AfterShip's webhook payload wraps the tracking object inside a 'msg' property. The tag field inside msg is AfterShip's normalized status: 'Pending', 'InTransit', 'OutForDelivery', 'AttemptFail', 'Delivered', 'AvailableForPickup', or 'Exception'.

Expected result: Lovable deploys the aftership-proxy Edge Function to Cloud. The function handles tracking creation, retrieval, listing, and webhook processing.

4

Configure AfterShip webhooks and build the tracking UI

With the Edge Function deployed, copy its URL from Cloud → Edge Functions in your Lovable project. Navigate to your AfterShip dashboard at app.aftership.com → Integrations → Webhooks. Click Add Webhook URL and paste your Edge Function URL with '?action=webhook' appended, then click Save. AfterShip will now send POST requests to your Edge Function whenever any tracking status changes. Next, ask Lovable to build the order status dashboard. The tracking timeline displays AfterShip's checkpoints array from the tracking object — each checkpoint has a tag, message, city, state, country, zip, created_at, and subtag_message. The most recent checkpoint is at the top. AfterShip's tag system maps to user-friendly status labels: 'InTransit' → 'In Transit', 'OutForDelivery' → 'Out for Delivery', 'Delivered' → 'Delivered', 'Exception' → 'Delivery Issue'. Color-code these tags for quick visual scanning — green for Delivered, blue for InTransit, orange for OutForDelivery, red for Exception. Test the webhook by creating a tracking for a real shipment and confirming that when AfterShip sends an update, your orders table in Supabase updates accordingly. For complex setups involving multi-carrier workflows or large tracking volumes, RapidDev's team can help design the right database schema and webhook architecture.

Lovable Prompt

Build an order tracking page using the aftership-proxy Edge Function. Call action=list to fetch all trackings and display them as a dashboard. Each tracking card shows: carrier name, tracking number, current status tag (color-coded: green=Delivered, blue=InTransit, orange=OutForDelivery, red=Exception), last event message, and estimated delivery date. When clicking a tracking, show a detail panel with the full checkpoint timeline — each event showing date/time, location, and event description. Add a search bar to filter by tracking number. Show the total count of In Transit vs Delivered vs Exception shipments at the top as stat cards.

Paste this in Lovable chat

Pro tip: Register AfterShip webhook URL in AfterShip → Settings → Webhooks. After adding the URL, use the 'Test Webhook' button in AfterShip to send a sample payload to your Edge Function and verify the Supabase update logic works before relying on real carrier events.

Expected result: The order tracking dashboard displays AfterShip tracking data. The webhook URL is registered in AfterShip, and test webhook payloads successfully update order records in Supabase.

Common use cases

Order status dashboard for customers

Build a customer-facing order tracking page where customers see the delivery status of all their orders in one view. Each order card shows the current AfterShip tag (In Transit, Out for Delivery, Delivered), last event description, and days since shipment. Clicking an order shows the full tracking timeline.

Lovable Prompt

Create an order status page that shows a customer's recent orders with their shipping status from AfterShip. Fetch tracking data for each order's tracking number via the aftership-proxy Edge Function using the AfterShip Tracking API v4 GET /trackings endpoint. Display each order as a card with product name, order date, current status tag (In Transit/Delivered/etc), last update message, and estimated delivery date. Clicking a card shows a full tracking event timeline. Store my AfterShip API key in Cloud Secrets as AFTERSHIP_API_KEY.

Copy this prompt to try it in Lovable

Add shipment to AfterShip tracking on order fulfillment

Automatically register new shipments with AfterShip when an order is marked as shipped. The Edge Function calls AfterShip's POST /trackings endpoint to create a tracking entry, which AfterShip then monitors and updates via webhook.

Lovable Prompt

When an order status is changed to 'Shipped' in my Supabase orders table, call the aftership-proxy Edge Function to create a new AfterShip tracking using POST /trackings with the tracking number, carrier slug, and customer email. Save the returned AfterShip tracking_id to the order record. Set up an AfterShip webhook pointing to a separate Edge Function that updates the order's delivery_status in Supabase when AfterShip sends status updates.

Copy this prompt to try it in Lovable

Delivery exception alert system

Build a delivery exceptions dashboard that shows all orders with failed delivery attempts, address issues, or delayed shipments. AfterShip's 'Exception' tag and webhook events make it easy to surface problem shipments that need attention before customers complain.

Lovable Prompt

Create a delivery exceptions dashboard that shows all shipments with AfterShip status tag 'Exception' or 'AttemptFail'. Query the AfterShip Tracking API via the aftership-proxy Edge Function with tag=Exception to get all problem shipments. Display each exception with the tracking number, carrier, last event message, and customer order number (joined from Supabase). Add a Resolved button that marks the issue as handled in Supabase. Set up an AfterShip webhook Edge Function that automatically flags new exceptions in real time.

Copy this prompt to try it in Lovable

Troubleshooting

AfterShip API returns 'Invalid API Key' or 401 error

Cause: The AFTERSHIP_API_KEY value in Cloud Secrets is incorrect, contains extra whitespace, or the API key was deleted from AfterShip's Settings → API panel after being stored.

Solution: Log in to AfterShip → Settings → API and verify the API key still exists. Copy the key name (shown in the list) and confirm it matches the one stored in Cloud Secrets. If the key was deleted or you're unsure of the full key value, delete the existing AFTERSHIP_API_KEY secret, generate a new API key in AfterShip, and re-add it to Cloud Secrets.

Tracking returns 'Tracking not found' (404) for a valid tracking number

Cause: The tracking hasn't been added to AfterShip yet, or the carrier slug is wrong causing AfterShip to look in the wrong carrier namespace.

Solution: Ensure you call action=create first to register the tracking with AfterShip before calling action=get. Verify the carrier slug is correct — AfterShip's carrier slug list is available at aftership.com/couriers. If unsure of the carrier, create the tracking without specifying a slug and AfterShip will attempt to auto-detect it. Auto-detection may take a few minutes.

AfterShip webhooks are not updating Supabase

Cause: The webhook Edge Function URL is not registered in AfterShip, or the Supabase update logic uses a column name that doesn't match the actual orders table schema.

Solution: Verify the webhook URL is registered in AfterShip → Settings → Webhooks and shows a green 'Active' status. Use AfterShip's 'Test Webhook' button to send a sample payload and check Cloud → Logs for the Edge Function response. If the function runs but Supabase doesn't update, verify the column names (delivery_status, last_tracking_event, estimated_delivery) match your orders table schema exactly.

Tracking shows 'Pending' status indefinitely after creation

Cause: AfterShip hasn't been able to find the tracking number at the carrier yet — this happens for very new shipments (carrier hasn't scanned the label yet) or if the carrier slug is wrong.

Solution: Wait 2-4 hours for a newly generated label to be scanned into the carrier's system before expecting tracking events. If the status stays Pending for more than 24 hours, verify the carrier slug is correct by looking up the tracking number directly on the carrier's website. If the carrier website shows events but AfterShip shows Pending, update the carrier slug on the tracking via AfterShip's dashboard.

Best practices

  • Create AfterShip trackings immediately when an order is fulfilled — don't wait until a customer asks for tracking status. Proactive tracking registration ensures AfterShip starts collecting events as soon as the carrier scans the package.
  • Store AfterShip's tracking_id (returned when creating a tracking) in your Supabase orders table alongside the tracking number — use tracking_id for future AfterShip API operations since it's more reliable than carrier slug + tracking number combinations.
  • Use AfterShip webhooks for real-time status updates instead of polling the GET tracking endpoint — webhooks are event-driven and more efficient than polling, especially for orders at scale.
  • Display AfterShip's estimated_delivery date prominently on tracking pages — AfterShip calculates this from historical carrier data and customers find it more useful than raw event timestamps.
  • Map AfterShip's subtag codes (e.g., 'InTransit_002' for 'Departure Scan') to human-friendly messages in your UI — subtags provide more specific status information than the top-level tag.
  • Rotate your AfterShip API key every 90 days as a security practice — update the AFTERSHIP_API_KEY secret in Cloud Secrets and delete the old key from AfterShip's API settings.
  • For high tracking volumes (thousands of shipments), use AfterShip's batch operations and pagination when listing trackings rather than fetching all trackings at once — the list endpoint returns a maximum of 200 trackings per request.

Alternatives

Frequently asked questions

How many carriers does AfterShip support?

AfterShip supports 1,100+ carriers worldwide, including all major global carriers (USPS, UPS, FedEx, DHL, Canada Post, Royal Mail, Australia Post, China Post) and hundreds of regional carriers across Asia-Pacific, Europe, and Latin America. The carrier list is available at aftership.com/couriers with each carrier's slug identifier. If your carrier isn't listed, AfterShip has a process for requesting new carrier additions.

What is the difference between AfterShip and ShipStation?

AfterShip is a tracking-only platform — it monitors shipments across 1,100+ carriers and provides unified tracking data, webhooks, and branded tracking pages. ShipStation is a full shipping management platform where you import orders, create shipments, print labels, and track packages. Use AfterShip when you already generate labels through other means and need excellent cross-carrier tracking; use ShipStation when you want a complete shipping operations workflow.

Does AfterShip have a free plan?

AfterShip's free plan includes 50 trackings per month, which is enough for testing your integration. Paid plans start at around $11/month for 100 trackings and scale up by tracking volume. If you have an e-commerce store shipping more than 50 orders per month, you'll need a paid AfterShip plan. The API key and all core API features are available on the free plan during development.

Can AfterShip automatically detect the carrier from a tracking number?

Yes. When you create a tracking without specifying a carrier slug, AfterShip applies pattern matching to identify the carrier from the tracking number format. Auto-detection works for most major carriers. However, providing the carrier slug is recommended when you know it — auto-detection adds 5-15 minutes before tracking starts, and some tracking number formats (e.g., generic barcodes) can be ambiguous across carriers.

How do AfterShip webhooks work in Lovable?

AfterShip sends a POST request to your Edge Function URL every time a tracked shipment's status changes. The payload contains the full updated tracking object including the new tag (Delivered, InTransit, Exception, etc.), the latest checkpoint event, and the estimated delivery date. Your Edge Function receives this data and updates the corresponding order record in Supabase — no polling required. Register your Edge Function URL in AfterShip → Settings → Webhooks to activate this flow.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.