Errors, limits, and rate limiting
Pro
Error responses
Errors are deliberately generic. They never include configuration, SQL, file paths or internal details.
| Status | Body |
|---|---|
| Most errors | { "code": "…", "message": "…" } |
| 422 validation | the error, plus a list of { path, message } for each field (see Writing values) |
| 429 throttled | { "code": "too_many_requests", "message": "…" }, with a Retry-After header when set |
Limits
- Collections return at most 100 items per page.
- A relation includes at most 100 linked entries, and linked entries' own fields go 2 levels deep.
- Responses are cached per access tier for up to 5 minutes, and cleared as soon as content or exposure settings change.
Rate limiting
WordPress has no built-in rate limiting, and VX doesn't add one, because doing it properly needs a shared store (such as Redis) or your host's edge. Limit REST traffic at the layer your hosting provides:
CDN or firewall (for example Cloudflare): a rate-limiting rule on paths containing
/wp-json/. This is usually the simplest and sturdiest option.nginx:
nginxlimit_req_zone $binary_remote_addr zone=wp_rest:10m rate=10r/s; location /wp-json/ { limit_req zone=wp_rest burst=20 nodelay; try_files $uri $uri/ /index.php?$args; }Apache:
mod_ratelimit,mod_qos, or ModSecurity rules scoped to/wp-json/.
To make the decision in PHP instead, for example with per-user budgets stored in Redis, use the vxframework/rest/throttle filter. It runs before any REST route, so a refusal short-circuits the request:
php
add_filter( 'vxframework/rest/throttle', function ( $decision, array $context ) {
if ( my_limiter_is_over_budget( $context['ip'], $context['route'] ) ) {
return 60; // 429 with Retry-After: 60
}
return $decision;
}, 10, 2 );Warning
$context['ip'] is the connecting address (REMOTE_ADDR). Behind a proxy or CDN, that's the proxy. Headers like X-Forwarded-For can be forged by clients, so resolve the real address inside your limiter only if you trust the proxy.
Technical details for LLMs
vxframework/rest/throttle( $decision, array $context )onrest_pre_dispatch; context keysroute,method,viewer_id,is_logged_in,ip. Returnnull(allow),true(429),int > 0(429 +Retry-After), or aWP_Error/WP_REST_Responsereturned verbatim.- Caps:
vxframework/rest/max_per_page(default 100); relation depth 2, 100 refs (fixed). Cache TTL 300 s.