Skip to main content
RapidDev - Software Development Agency
replit-integrationsStandard API Integration

How to Integrate Replit with FedEx API

To integrate Replit with the FedEx API, register a FedEx developer account, generate OAuth 2.0 client credentials, store them in Replit Secrets (lock icon πŸ”’), and call the FedEx REST API from Python or Node.js to get shipping rates, track packages, and create labels. FedEx's REST API uses client credentials OAuth β€” your backend exchanges credentials for a Bearer token before each API session.

What you'll learn

  • How to create a FedEx developer application and obtain OAuth 2.0 client credentials
  • How to store FedEx credentials in Replit Secrets and implement token refresh
  • How to get FedEx shipping rates for domestic and international packages using Python and Node.js
  • How to track FedEx packages and parse delivery events in real time
  • How to deploy your Replit shipping integration for production use
Book a free consultation
4.9Clutch rating ⭐
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read35 minutesOtherMarch 2026RapidDev Engineering Team
TL;DR

To integrate Replit with the FedEx API, register a FedEx developer account, generate OAuth 2.0 client credentials, store them in Replit Secrets (lock icon πŸ”’), and call the FedEx REST API from Python or Node.js to get shipping rates, track packages, and create labels. FedEx's REST API uses client credentials OAuth β€” your backend exchanges credentials for a Bearer token before each API session.

Why Connect Replit to FedEx?

FedEx is the dominant carrier for US domestic express shipping, offering next-day, two-day, and ground services with real-time tracking across millions of packages daily. The FedEx REST API (launched 2022, replacing the older SOAP Web Services API) gives Replit developers access to rate quotes, package tracking, label generation, address validation, and pickup scheduling through a modern JSON-based interface.

For e-commerce applications and order management systems built on Replit, integrating FedEx enables live shipping rate calculation at checkout, automated label generation after order confirmation, proactive delivery status notifications to customers, and exception handling for delayed or lost packages. The FedEx API is particularly valuable for businesses shipping high volumes of domestic parcels where FedEx Express and Ground services provide the best coverage and reliability.

The FedEx REST API uses OAuth 2.0 client credentials authentication β€” your backend exchanges a client ID and secret for a Bearer token that is valid for one hour. This token-based approach is more secure than static API keys because tokens expire automatically and can be revoked individually. Store your client ID and client secret in Replit Secrets (lock icon πŸ”’) and implement token caching to avoid requesting a new token on every API call.

Integration method

Standard API Integration

You connect Replit to FedEx by creating a FedEx developer account, registering an application to get client credentials (client ID and client secret), storing them in Replit Secrets, and authenticating via OAuth 2.0 client credentials flow before calling FedEx REST API endpoints. The access token expires after 3600 seconds, so your backend must refresh it periodically. All FedEx API calls must originate from your server-side code to protect credentials.

Prerequisites

  • A Replit account with a Python or Node.js project created
  • A FedEx developer account registered at developer.fedex.com
  • A FedEx business account number (required for label creation β€” tracking and rates work with the sandbox account)
  • Basic familiarity with OAuth 2.0 client credentials flow
  • Node.js 18+ or Python 3.10+ (both available on Replit by default)

Step-by-step guide

1

Create a FedEx Developer App and Get Client Credentials

Navigate to developer.fedex.com and sign in with your FedEx account credentials (or create a developer account if you do not have one). Click on 'My Projects' in the top navigation and then 'Create a Project'. Select the APIs you want to use β€” for a typical shipping integration, select 'Rate' (for rate quotes), 'Ship' (for label creation), and 'Track' (for package tracking). Give your project a name and complete the creation wizard. Once the project is created, you will see your project dashboard with a Client ID and Client Secret. Copy both values immediately β€” the client secret may not be shown again after you navigate away. These are your OAuth 2.0 credentials. FedEx provides a sandbox testing environment by default for new projects. Test your integration against the sandbox (with test tracking numbers and sandbox addresses) before switching to production. To enable production access, you will need to go through FedEx's certification process, which involves testing specific scenarios and submitting them for FedEx review. Note your FedEx account number from your FedEx billing account β€” you will need this for creating shipments (though not for tracking or rate queries in sandbox mode).

Pro tip: FedEx sandbox credentials and production credentials are different. Store them separately in Replit Secrets with prefixes like FEDEX_SANDBOX_CLIENT_ID vs FEDEX_PROD_CLIENT_ID, and use an environment variable to toggle between them.

Expected result: You have a FedEx developer project with a Client ID, Client Secret, and the base URLs for sandbox API testing.

2

Store FedEx Credentials in Replit Secrets

Open your Replit project and click the lock icon πŸ”’ in the left sidebar to open the Secrets pane. Add the following secrets: - Key: FEDEX_CLIENT_ID β€” Value: your FedEx project client ID - Key: FEDEX_CLIENT_SECRET β€” Value: your FedEx project client secret - Key: FEDEX_ACCOUNT_NUMBER β€” Value: your FedEx billing account number (for label creation) For toggling between sandbox and production: - Key: FEDEX_ENV β€” Value: 'sandbox' or 'production' (your code reads this to select the base URL) In Python, access these with os.environ['FEDEX_CLIENT_ID']. In Node.js, use process.env.FEDEX_CLIENT_ID. The FedEx client secret is sensitive β€” if exposed, an attacker could generate shipping labels or access your account data. Replit's Secret Scanner will alert you if credentials are accidentally written to code files.

Pro tip: FedEx access tokens expire after 3600 seconds (1 hour). Cache the token and its expiry time in a module-level variable to avoid requesting a new token on every API call β€” the token endpoint itself has rate limits.

Expected result: FEDEX_CLIENT_ID, FEDEX_CLIENT_SECRET, and FEDEX_ACCOUNT_NUMBER appear in Replit Secrets with masked values.

3

Authenticate and Query Shipping Rates with Python

The FedEx REST API requires an OAuth 2.0 Bearer token obtained by POST-ing your client ID and secret to the token endpoint. The token is valid for 3600 seconds. Cache it in a module-level dictionary with the expiry timestamp to avoid requesting a new token on every API call. The Rate API requires a detailed request body including shipper and recipient addresses, package weight and dimensions, and the requested service types. The response lists available services with base rates and estimated delivery dates. The code below implements a full FedEx client with token management, rate queries, and package tracking. Install the requests library (pre-installed on Replit) and you are ready to run.

fedex_client.py
1import os
2import time
3import requests
4from typing import Optional
5
6CLIENT_ID = os.environ["FEDEX_CLIENT_ID"]
7CLIENT_SECRET = os.environ["FEDEX_CLIENT_SECRET"]
8ACCOUNT_NUMBER = os.environ.get("FEDEX_ACCOUNT_NUMBER", "")
9ENV = os.environ.get("FEDEX_ENV", "sandbox")
10
11BASE_URL = (
12 "https://apis-sandbox.fedex.com" if ENV == "sandbox"
13 else "https://apis.fedex.com"
14)
15
16# Token cache: stores {'token': str, 'expires_at': float}
17_token_cache = {}
18
19def get_access_token() -> str:
20 """Get a valid FedEx OAuth access token, refreshing if expired."""
21 now = time.time()
22 if _token_cache.get('token') and _token_cache.get('expires_at', 0) > now + 60:
23 return _token_cache['token']
24
25 response = requests.post(
26 f"{BASE_URL}/oauth/token",
27 data={
28 "grant_type": "client_credentials",
29 "client_id": CLIENT_ID,
30 "client_secret": CLIENT_SECRET
31 },
32 headers={"Content-Type": "application/x-www-form-urlencoded"}
33 )
34 response.raise_for_status()
35 data = response.json()
36 _token_cache['token'] = data['access_token']
37 _token_cache['expires_at'] = now + data.get('expires_in', 3600)
38 return _token_cache['token']
39
40def get_rates(shipper_zip: str, recipient_zip: str, weight_lb: float,
41 length: int = 12, width: int = 10, height: int = 8) -> list:
42 """Get FedEx shipping rates between two US zip codes."""
43 token = get_access_token()
44 payload = {
45 "accountNumber": {"value": ACCOUNT_NUMBER or "510087240"}, # Test account for sandbox
46 "requestedShipment": {
47 "shipper": {"address": {"postalCode": shipper_zip, "countryCode": "US"}},
48 "recipient": {"address": {"postalCode": recipient_zip, "countryCode": "US"}},
49 "pickupType": "DROPOFF_AT_FEDEX_LOCATION",
50 "rateRequestType": ["LIST", "ACCOUNT"],
51 "requestedPackageLineItems": [{
52 "weight": {"units": "LB", "value": weight_lb},
53 "dimensions": {"length": length, "width": width, "height": height, "units": "IN"}
54 }]
55 }
56 }
57 response = requests.post(
58 f"{BASE_URL}/rate/v1/rates/quotes",
59 json=payload,
60 headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json", "X-locale": "en_US"}
61 )
62 response.raise_for_status()
63 data = response.json()
64 rates = []
65 for rate_reply in data.get('output', {}).get('rateReplyDetails', []):
66 for rated_shipment in rate_reply.get('ratedShipmentDetails', []):
67 total = rated_shipment.get('totalNetCharge')
68 if total:
69 rates.append({
70 'service': rate_reply.get('serviceType'),
71 'transit_days': rate_reply.get('commit', {}).get('dateDetail', {}).get('dayOfWeek'),
72 'total_charge': total,
73 'currency': rated_shipment.get('currency', 'USD')
74 })
75 return rates
76
77def track_package(tracking_number: str) -> Optional[dict]:
78 """Track a FedEx package by tracking number."""
79 token = get_access_token()
80 payload = {
81 "includeDetailedScans": True,
82 "trackingInfo": [{"trackingNumberInfo": {"trackingNumber": tracking_number}}]
83 }
84 response = requests.post(
85 f"{BASE_URL}/track/v1/trackingnumbers",
86 json=payload,
87 headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json", "X-locale": "en_US"}
88 )
89 response.raise_for_status()
90 output = response.json().get('output', {})
91 complete_track = output.get('completeTrackResults', [])
92 if not complete_track:
93 return None
94 track_results = complete_track[0].get('trackResults', [])
95 if not track_results:
96 return None
97 result = track_results[0]
98 return {
99 'tracking_number': tracking_number,
100 'status': result.get('latestStatusDetail', {}).get('code'),
101 'description': result.get('latestStatusDetail', {}).get('description'),
102 'estimated_delivery': result.get('estimatedDeliveryTimeWindow', {}).get('window', {}).get('ends'),
103 'actual_delivery': result.get('actualDeliveryTime'),
104 'events': result.get('scanEvents', [])
105 }
106
107if __name__ == "__main__":
108 print("Getting FedEx rates from 10001 to 90210 for 5lb package...")
109 rates = get_rates("10001", "90210", 5.0)
110 for r in rates:
111 print(f" {r['service']}: ${r['total_charge']} ({r['currency']})")

Pro tip: Use FedEx sandbox tracking number '123456789012' for testing the track endpoint. The sandbox environment returns mock tracking data for this number so you can test your parsing logic before using real tracking numbers.

Expected result: Running the script prints available FedEx shipping services with rates for a 5lb package between the two zip codes.

4

Build a Node.js FedEx Proxy with Express

The Node.js server below implements the same OAuth token caching pattern and exposes clean REST endpoints for your frontend or downstream services. Token caching is critical β€” FedEx's OAuth endpoint has rate limits, and requesting a new token for every API call will quickly hit those limits in production. Install dependencies with npm install express axios in the Replit Shell. The server implements endpoints for rates, tracking, and a webhook receiver stub. Bind to 0.0.0.0:3000 for Replit port routing. For production deployments handling checkout rate requests, deploy with Autoscale to handle traffic spikes during promotional periods when many customers reach checkout simultaneously.

server.js
1const express = require('express');
2const axios = require('axios');
3
4const app = express();
5app.use(express.json());
6
7const CLIENT_ID = process.env.FEDEX_CLIENT_ID;
8const CLIENT_SECRET = process.env.FEDEX_CLIENT_SECRET;
9const ACCOUNT_NUMBER = process.env.FEDEX_ACCOUNT_NUMBER || '510087240';
10const ENV = process.env.FEDEX_ENV || 'sandbox';
11const BASE_URL = ENV === 'production' ? 'https://apis.fedex.com' : 'https://apis-sandbox.fedex.com';
12
13// Token cache
14let tokenCache = { token: null, expiresAt: 0 };
15
16async function getAccessToken() {
17 if (tokenCache.token && tokenCache.expiresAt > Date.now() + 60000) {
18 return tokenCache.token;
19 }
20 const params = new URLSearchParams();
21 params.append('grant_type', 'client_credentials');
22 params.append('client_id', CLIENT_ID);
23 params.append('client_secret', CLIENT_SECRET);
24
25 const response = await axios.post(`${BASE_URL}/oauth/token`, params, {
26 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
27 });
28 tokenCache.token = response.data.access_token;
29 tokenCache.expiresAt = Date.now() + (response.data.expires_in || 3600) * 1000;
30 return tokenCache.token;
31}
32
33// POST /rates β€” get shipping rates
34app.post('/rates', async (req, res) => {
35 const { shipperZip, recipientZip, weightLb, length = 12, width = 10, height = 8 } = req.body;
36 if (!shipperZip || !recipientZip || !weightLb) {
37 return res.status(400).json({ error: 'shipperZip, recipientZip, and weightLb are required' });
38 }
39 try {
40 const token = await getAccessToken();
41 const payload = {
42 accountNumber: { value: ACCOUNT_NUMBER },
43 requestedShipment: {
44 shipper: { address: { postalCode: shipperZip, countryCode: 'US' } },
45 recipient: { address: { postalCode: recipientZip, countryCode: 'US' } },
46 pickupType: 'DROPOFF_AT_FEDEX_LOCATION',
47 rateRequestType: ['LIST'],
48 requestedPackageLineItems: [{
49 weight: { units: 'LB', value: weightLb },
50 dimensions: { length, width, height, units: 'IN' }
51 }]
52 }
53 };
54 const response = await axios.post(`${BASE_URL}/rate/v1/rates/quotes`, payload, {
55 headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', 'X-locale': 'en_US' }
56 });
57 const rateDetails = response.data?.output?.rateReplyDetails || [];
58 const rates = rateDetails.map(r => ({
59 service: r.serviceType,
60 charge: r.ratedShipmentDetails?.[0]?.totalNetCharge
61 }));
62 res.json(rates);
63 } catch (err) {
64 console.error('FedEx rates error:', err.response?.data);
65 res.status(500).json({ error: err.message });
66 }
67});
68
69// GET /track/:number β€” track a package
70app.get('/track/:number', async (req, res) => {
71 try {
72 const token = await getAccessToken();
73 const payload = {
74 includeDetailedScans: true,
75 trackingInfo: [{ trackingNumberInfo: { trackingNumber: req.params.number } }]
76 };
77 const response = await axios.post(`${BASE_URL}/track/v1/trackingnumbers`, payload, {
78 headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', 'X-locale': 'en_US' }
79 });
80 const result = response.data?.output?.completeTrackResults?.[0]?.trackResults?.[0];
81 if (!result) return res.status(404).json({ error: 'Tracking number not found' });
82 res.json({
83 status: result.latestStatusDetail?.code,
84 description: result.latestStatusDetail?.description,
85 estimatedDelivery: result.estimatedDeliveryTimeWindow?.window?.ends,
86 events: result.scanEvents?.slice(0, 10)
87 });
88 } catch (err) {
89 res.status(500).json({ error: err.message });
90 }
91});
92
93app.listen(3000, '0.0.0.0', () => {
94 console.log(`FedEx proxy running on port 3000 (${ENV})`)
95});

Pro tip: Add a /health endpoint that checks if your cached token is valid and returns the environment (sandbox/production). This makes it easy to verify your deployment is connected to the right FedEx environment without making a real API call.

Expected result: The server starts on port 3000. A POST to /rates with origin and destination zip codes returns available FedEx services with pricing.

Common use cases

Live Shipping Rate Calculator at Checkout

Build a Replit backend that calculates real-time FedEx shipping rates when customers reach your checkout page. Pass package dimensions, weight, origin zip code, and destination zip code to the FedEx Rate API and return available service options β€” Ground, Express, Overnight β€” with prices and estimated delivery dates.

Replit Prompt

Create a Flask server with a POST /shipping-rates endpoint that accepts origin zip, destination zip, weight in pounds, and package dimensions, calls the FedEx Rate API with FEDEX_CLIENT_ID and FEDEX_CLIENT_SECRET from Replit Secrets, and returns available service options with prices.

Copy this prompt to try it in Replit

Automated Shipping Label Generation

After an order is placed, automatically create a FedEx shipping label from your Replit backend. Send the sender and recipient addresses, package weight, and service type to the FedEx Ship API, receive a PDF label back, and store it or email it to your fulfilment team. This eliminates manual label creation for high-volume shippers.

Replit Prompt

Write a Node.js function that accepts order data (sender address, recipient address, package weight, service type), authenticates with FedEx OAuth, creates a shipment via the FedEx Ship API, and returns the tracking number and a Base64-encoded PDF label.

Copy this prompt to try it in Replit

Customer Delivery Status Notification System

Build a Replit service that tracks FedEx shipments on a schedule and sends proactive SMS or email notifications to customers when their package status changes. Pull tracking events, detect status transitions (in transit β†’ out for delivery β†’ delivered), and trigger SendGrid or Twilio notifications without requiring customers to check manually.

Replit Prompt

Create a Python script that reads open FedEx tracking numbers from a database, queries the FedEx Tracking API for status updates, compares to the last known status stored in the database, and sends an email notification via SendGrid when the status changes to 'OUT_FOR_DELIVERY' or 'DELIVERED'.

Copy this prompt to try it in Replit

Troubleshooting

OAuth token request returns 401 with 'AuthenticationFailure'

Cause: The client ID or client secret in Replit Secrets is incorrect, or you are using sandbox credentials against the production endpoint (or vice versa).

Solution: Verify your FEDEX_CLIENT_ID and FEDEX_CLIENT_SECRET in the FedEx Developer Portal under My Projects. Make sure your FEDEX_ENV matches the credentials β€” sandbox credentials only work against apis-sandbox.fedex.com and production credentials against apis.fedex.com. Re-copy the secret from the portal to avoid transcription errors.

typescript
1# Python: test token endpoint directly
2import requests
3response = requests.post(
4 'https://apis-sandbox.fedex.com/oauth/token',
5 data={'grant_type': 'client_credentials', 'client_id': CLIENT_ID, 'client_secret': CLIENT_SECRET},
6 headers={'Content-Type': 'application/x-www-form-urlencoded'}
7)
8print(response.status_code, response.json())

Rate API returns 'BUSINESS.RULE.VALIDATION.FAILURE' for valid addresses

Cause: The FedEx Rate API requires an account number even in sandbox mode for some service types. The sandbox test account number may differ from your real account number.

Solution: Use FedEx's sandbox test account number '510087240' when testing in the sandbox environment. Switch to your real account number in FEDEX_ACCOUNT_NUMBER for production. For international rates, ensure the countryCode fields are ISO 3166-1 alpha-2 codes (e.g., 'US', 'GB', 'DE').

typescript
1# Python: use sandbox test account number
2ACCOUNT_NUMBER = os.environ.get('FEDEX_ACCOUNT_NUMBER') or '510087240' # Sandbox fallback

Tracking returns empty results for a valid FedEx tracking number

Cause: The package may be too new (not yet in the FedEx system), the tracking number format is incorrect, or you are querying sandbox tracking numbers against the production API.

Solution: Verify the tracking number format β€” FedEx tracking numbers are 12, 15, 20, or 22 digits depending on the service. New labels take 1-2 hours to appear in the tracking system. In sandbox, only specific test tracking numbers return mock data.

typescript
1# Python: print full tracking API response for debugging
2response = requests.post(url, json=payload, headers=headers)
3print('Status:', response.status_code)
4print('Response:', response.json())

Token refresh causes API errors during concurrent requests

Cause: Multiple concurrent requests detect an expired token and simultaneously try to refresh it, causing race conditions with the token cache.

Solution: Add a threading lock around the token refresh logic in Python, or use a queue/mutex in Node.js for concurrent requests. Alternatively, use a token with a generous buffer (refresh when less than 5 minutes remain) to reduce the window for race conditions.

typescript
1import threading
2_lock = threading.Lock()
3
4def get_access_token() -> str:
5 with _lock:
6 if _token_cache.get('token') and _token_cache.get('expires_at', 0) > time.time() + 300:
7 return _token_cache['token']
8 # ... refresh token ...

Best practices

  • Store FEDEX_CLIENT_ID and FEDEX_CLIENT_SECRET in Replit Secrets (lock icon πŸ”’) β€” never hardcode them or expose them to frontend clients.
  • Cache the OAuth access token in a module-level variable with its expiry time to avoid requesting a new token on every API call β€” the token is valid for 3600 seconds.
  • Use separate credentials for sandbox and production environments, toggled via a FEDEX_ENV Replit Secret, to prevent accidental production API calls during testing.
  • Always validate addresses using the FedEx Address Validation API before creating shipments β€” invalid addresses cause label creation to fail at the worst possible time.
  • Handle the BUSINESS.RULE.VALIDATION.FAILURE error gracefully in your UI β€” it often means a required field is missing or formatted incorrectly, not a credentials problem.
  • For label creation, store the generated PDF (Base64-decoded) in your storage system immediately β€” FedEx does not store labels and they cannot be regenerated if lost.
  • Deploy with Autoscale for checkout rate endpoints handling variable customer traffic; use Reserved VM if your backend processes continuous background label creation.
  • Test against the FedEx sandbox environment using test account number 510087240 and sandbox-specific test tracking numbers before requesting production API access.

Alternatives

Frequently asked questions

How do I store FedEx API credentials in Replit?

Click the lock icon πŸ”’ in the Replit sidebar to open Secrets. Add FEDEX_CLIENT_ID and FEDEX_CLIENT_SECRET with values from your FedEx developer project. Add FEDEX_ACCOUNT_NUMBER with your billing account number and FEDEX_ENV set to 'sandbox' or 'production'. Access them in Python with os.environ['FEDEX_CLIENT_ID'] and in Node.js with process.env.FEDEX_CLIENT_ID.

Does the FedEx API require a paid FedEx account?

Tracking and rate queries are available on a free FedEx developer account with sandbox access. To generate real shipping labels and make production API calls, you need an active FedEx business account. The transition from sandbox to production also requires FedEx's certification process where you demonstrate correct API usage before production credentials are issued.

How does FedEx OAuth 2.0 work in Replit?

Your Replit backend posts your client ID and client secret to the FedEx OAuth token endpoint to receive a Bearer token valid for one hour. You include this token in the Authorization header for all subsequent API calls. Cache the token with its expiry time and only request a new one when the cached token is about to expire β€” do not request a new token on every API call.

Can I track FedEx packages from Replit for free?

Yes. The FedEx Track API is available on the free developer plan and can track any FedEx shipment using a tracking number. You need to implement OAuth token acquisition, but there are no per-query fees for tracking. Register at developer.fedex.com, create a project with the Track API, and you can start tracking packages in the sandbox environment immediately.

Why does the FedEx rate calculation return different prices than the FedEx website?

The FedEx Rate API returns rates based on your account number, which may have negotiated discounts different from standard retail rates shown on the FedEx website. In sandbox mode, rates are mock values for testing and do not reflect real prices. Use rateRequestType: ['LIST'] for list rates and ['ACCOUNT'] for your account's negotiated rates β€” both can be requested in the same call.

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.