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
| Resource | Limit | Window |
|---|---|---|
POST /listings (create) | 200 | 1 minute |
| All other listing reads | 500 | 1 minute |
| All listing writes | 200 | 1 minute |
POST /media/upload | 100 | 1 minute |
GET /scheduling/availability | 300 | 1 minute |
GET /users | 200 | 1 minute |
GET /webhooks/events (catalog) | 60 | 1 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:
| Operation | Limit | Window |
|---|---|---|
| Test console runs | 60 | 1 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
| Operation | Limit | Window |
|---|---|---|
| Inbound deliveries per endpoint | 1000 | 1 hour |
| Replay | 10 | 1 minute per endpoint |
| Test fire (verifier) | 5 | 1 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 resetsX-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.