Rate Limits
Per-plan request quotas, response headers, backoff strategy, and how to design integrations that never hit a limit.
Status: planned — not yet available. Tripistic does not currently expose a public API. There is no API-key model, no key-management screen, and no bearer-token authentication path in the application: every route authenticates through a signed session cookie. This page describes the intended design and is published so the direction is visible. It is not a description of shipped functionality, and nothing on it can be called today. It will be replaced with real reference material when the API ships.
Rate limits keep the platform responsive for everyone. Designed well, an integration should rarely see one.
Limits
| Plan | Authenticated requests | Burst |
|---|---|---|
| Solo | 300 / minute | 60 |
| Operator | 600 / minute | 120 |
| Agency | 1,200 / minute | 240 |
| Enterprise | Negotiated | Negotiated |
| Endpoint class | Limit |
|---|---|
Public catalog (/api/public/*, unauthenticated) | 120 / minute per IP |
| Public booking creation | 20 / minute per IP |
| Authentication endpoints | 10 / minute per IP |
| AI generation endpoints | 20 / minute per workspace |
| Bulk export endpoints | 10 / minute per workspace |
Limits apply per credential for authenticated calls and per IP for public ones. Webhook deliveries to you do not consume your quota.
Response headers
Every response carries the current state:
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 583
X-RateLimit-Reset: 1751362500
X-RateLimit-Reset is a Unix timestamp for when the window resets.
When you exceed a limit
HTTP/1.1 429 Too Many Requests
Retry-After: 24
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Retry after 24 seconds."
}
}
Honour Retry-After. Do not retry immediately — it extends the throttle.
Backoff
Exponential backoff with jitter, capped, with a retry ceiling:
async function requestWithBackoff(
url: string,
init: RequestInit,
maxAttempts = 5,
): Promise<Response> {
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
const response = await fetch(url, init);
if (response.status !== 429 && response.status < 500) return response;
if (attempt === maxAttempts - 1) return response;
const retryAfter = Number(response.headers.get("Retry-After"));
const backoff = Number.isFinite(retryAfter) && retryAfter > 0
? retryAfter * 1000
: Math.min(2 ** attempt * 1000, 30_000);
// Jitter prevents synchronised clients from retrying in lockstep.
await new Promise((resolve) => setTimeout(resolve, backoff + Math.random() * 500));
}
throw new Error("Exhausted retries");
}
Retry 429 and 5xx. Never retry 400, 401, 403, 404, or 422 — the same request will fail the same way.
Designing to stay under the limit
Use webhooks instead of polling. A poll every 10 seconds burns 6 requests a minute forever and still lags reality. A webhook fires once, immediately.
Paginate with a sensible page size. limit=100 moves the same data in a quarter of the requests of limit=25.
Filter server-side. ?status=CONFIRMED&from=2026-07-01 beats fetching everything and filtering in your code.
Cache what rarely changes. Tour catalog and workspace settings can be cached for minutes; availability and bookings cannot.
Batch scheduled work. Run a nightly sync as one paginated sweep, not thousands of per-record calls.
Spread scheduled jobs. If every integration fires at exactly 00:00, they collide. Add a random offset.
Concurrency
Keep concurrent in-flight requests per credential modest — 10 or fewer is comfortable for most integrations. High parallelism plus retries is the fastest route to a sustained throttle.
Bulk operations
For migrations and large imports, contact us before you start. We can advise on sequencing and, for enterprise plans, arrange a temporary elevated limit. Running a migration against production limits without warning usually ends in a throttle mid-import.
Monitoring
Track X-RateLimit-Remaining and alert when it drops below 20% of the limit — that gives you time to fix the pattern before it becomes a 429 in production. Log every 429 with its endpoint so you can find the hot path.