Skip to content

Rate Limits

The Project Expedition API enforces rate limits to ensure fair usage and system stability.

Daily Limits

EnvironmentDaily LimitNotes
Production5,000 calls/dayCan be increased upon request
Staging2,000 calls/dayFor development only

Rate Limit Response

When you exceed the daily limit, the API returns:

{
"error": "Rate limit exceeded. Please try again tomorrow or contact support."
}

HTTP Status: 429 Too Many Requests

Caching Best Practices

Implement caching to minimize API calls and improve performance:

Tour Catalog (/return_tours)

Cache Duration: 1 week

Tour catalog data (product descriptions, images, logistics) changes infrequently.

// Example caching strategy
const CACHE_TTL = 7 * 24 * 60 * 60 * 1000; // 1 week in ms
const getCachedTours = async function(country) {
const cacheKey = `tours_${country}`;
const cached = cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data;
}
const response = await fetch(`${BASE_URL}/return_tours?country=${country}`, {
headers: { 'access-token': TOKEN }
});
const data = await response.json();
cache.set(cacheKey, { data, timestamp: Date.now() });
return data;
};

Availability (/return_availability)

Cache Duration: Do NOT cache

Availability and pricing can change in real-time. Always call this endpoint fresh.

Locations (/return_countries)

Cache Duration: 1 month

Geographic data (countries, regions, towns, hubs) rarely changes.

const LOCATIONS_CACHE_TTL = 30 * 24 * 60 * 60 * 1000; // 30 days

Handling Rate Limits

Implement exponential backoff when approaching limits:

const callWithRetry = async function(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status === 429) {
// Rate limited - wait and retry
const waitTime = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
return response;
}
throw new Error('Rate limit exceeded after retries');
};

Bulk Operations

For bulk operations (syncing catalogs, etc.):

  1. Add delays - Wait 100-200ms between requests
  2. Use pagination - Process in smaller batches
  3. Schedule off-peak - Run during low-traffic hours (UTC nighttime)
const syncAllTours = async function(countries) {
for (const country of countries) {
const tours = await fetchTours(country);
await processAndStore(tours);
// Wait 200ms before next request
await new Promise(resolve => setTimeout(resolve, 200));
}
};

Monitoring Usage

Track your API usage to avoid hitting limits:

let dailyCallCount = 0;
const trackApiCall = function() {
dailyCallCount++;
if (dailyCallCount >= 4500) {
console.warn('Approaching daily rate limit:', dailyCallCount);
}
};
Data TypeFetch StrategyCache Duration
Tour catalogWeekly sync7 days
LocationsMonthly sync30 days
AvailabilityReal-timeNever
BookingsAs neededN/A
CruisesWeekly sync7 days

Need Higher Limits?

If your integration requires higher rate limits:

  1. Describe your use case and expected volume
  2. Explain your caching strategy
  3. Contact partners@projectexpedition.com

Most limit increases are approved for partners with proper caching implementations.