Skip to main content

Rate limits

The Valara API applies per-agency rate limits to protect platform stability. Sandbox and live traffic have completely separate limits - a runaway sandbox test cannot consume your production budget.

Public API limits

ResourceLimitWindow
POST /listings (create)2001 minute
All other listing reads5001 minute
All listing writes2001 minute
POST /media/upload1001 minute
GET /scheduling/availability3001 minute
GET /users2001 minute
GET /webhooks/events (catalog)601 minute

These limits apply per agency (not per key). Multiple keys from the same agency share the same budget.

Sandbox vs live limits

Sandbox requests (sk_test_* keys) use a completely separate Redis rate-limit bucket from live requests (sk_live_* keys):

  • Sandbox: 500 requests/minute total (shared across all sandbox keys for the agency)
  • Live: limits as listed in the table above

You cannot "burn" your live production budget from sandbox keys, and vice versa.

Test console limits

The in-app test console proxy has a separate budget:

OperationLimitWindow
Test console runs601 minute

This is separate from the public API limits - a console run consumes both the console budget and the underlying API endpoint budget.

Webhook limits

OperationLimitWindow
Inbound deliveries per endpoint10001 hour
Replay101 minute per endpoint
Test fire (verifier)51 minute per endpoint

429 response format

When you exceed a rate limit, you receive:

HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1748476812
Content-Type: application/json

{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded for POST /api/v1/listings. Retry after 12 seconds.",
"retry_after_seconds": 12,
"request_id": "req_01HXREQUESTID"
}
}
  • Retry-After - seconds until the window resets (honor this header)
  • X-RateLimit-Reset - Unix timestamp when the window resets
  • X-RateLimit-Remaining - remaining requests in the current window

Handling 429 in your integration

Implement exponential backoff when you receive a 429:

import time
import httpx

def request_with_retry(client, method, url, **kwargs):
"""
Make an API request with automatic 429 backoff.
Honors the Retry-After header when present.
"""
max_retries = 5
for attempt in range(max_retries):
response = client.request(method, url, **kwargs)
if response.status_code != 429:
return response
retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
time.sleep(retry_after)
return response # Return the last 429 if all retries exhausted

Monitoring your usage

/manage/developer/analytics shows:

  • Request volume - requests per minute over the selected time window, split by endpoint group
  • Error rate - 4xx and 5xx counts, including 429s specifically

Set up a webhook subscription to listing.status_changed events rather than polling GET /listings if you need near-real-time listing updates - push beats poll for both your rate budget and latency.

Increasing limits

If your integration legitimately needs higher limits (e.g. bulk historical import, high-frequency sync), contact support@valara.cloud with:

  • Your agency ID (visible in the dashboard URL after login)
  • The specific endpoint(s) you need higher limits on
  • Your expected request volume and usage pattern

We evaluate limit increases case by case and will not approve limits that could affect platform stability for other agencies.