Skip to main content

Errors & Rate Limits

Error envelope

All HTTP error responses use a single canonical JSON envelope:

{
"code": "ERROR_CODE",
"message": "Human-readable description safe to display to clients."
}
FieldTypeDescription
codestringMachine-readable error identifier (SCREAMING_SNAKE_CASE). Stable across releases — safe for client switch/case logic.
messagestringHuman-readable description. May change between releases; do not match on this field programmatically.

Some validation failures additionally include a fields object mapping field names to per-field messages.

Standard codes

CodeHTTP statusMeaning
BAD_REQUEST400Malformed request that cannot be understood.
UNAUTHORIZED401Authentication is required or credentials are invalid.
FORBIDDEN403Authenticated but not permitted to perform this action.
NOT_FOUND404The requested resource does not exist.
CONFLICT409The resource already exists or is in a conflicting state.
VALIDATION_ERROR422Request body or parameters failed validation.
INTERNAL_ERROR500An unexpected server-side error occurred.
SERVICE_UNAVAILABLE503A downstream dependency is unavailable.

Domain-specific codes

CodeHTTP statusMeaning
PAYMENT_REQUIRED402The plan quota for this billing period is exhausted.
SEND_CAP_REACHED402Your own configured monthly send cap has been reached — raise the cap in Billing rather than upgrading the plan.
TENANT_SUSPENDED403The workspace account has been suspended.
TENANT_DELETED403The workspace account has been closed.
FEATURE_NOT_AVAILABLE403The feature is not available on your current plan.
READ_ONLY_TOKEN403The token is read-only and cannot authorize write operations.
FILE_TOO_LARGE413An uploaded file exceeds the maximum allowed size.
TEMPLATE_NOT_FOUND422The template_id referenced in the request does not exist in this workspace.
QUOTA_EXCEEDED429The workspace has exceeded a plan quota.
RATE_LIMITED429Too many attempts on a rate-limited surface (currently account registration).

Rate limits

Per-workspace request limit

Requests authenticated with a dashboard session token are rate limited per workspace over a fixed one-minute window. The limit depends on your plan:

PlanRequests per minute
Free60
Starter300
Pro1,000
Enterprise10,000

When the limit is exceeded, the API responds 429 with a Retry-After header giving the number of seconds until the window resets. Retry-After is the only rate-limit header — there are no X-RateLimit-* headers. Note that this particular response uses a different body shape from the standard envelope:

{ "error": "rate limit exceeded", "retry_after": 42 }

Requests authenticated with a client SDK key or server key are not counted against this per-minute limit; the event ingestion endpoint instead enforces per-tier payload caps, below.

Event ingestion caps

POST /v1/events applies fixed caps that depend on the credential tier:

Client (X-SDK-Key)Server (Bearer hober_srv_…)
Events per request501,000
Request body500 KB (413 beyond)
Single event32 KB
occurred_at backdating window48 hours90 days

Cap violations return 422 with code VALIDATION_ERROR (oversized server-tier bodies return 413). See Events for the full endpoint reference.

Registration limit

Creating a new account is limited to 5 registrations per IP address per hour and 10 per email domain per day. Exceeding either limit returns 429 with code RATE_LIMITED and a Retry-After header.

Quotas are not rate limits

QUOTA_EXCEEDED (429), PAYMENT_REQUIRED (402), and SEND_CAP_REACHED (402) signal plan or billing limits, not request-frequency limits — retrying will not succeed until the quota resets, the plan changes, or the cap is raised.

Handling errors

  • Branch on code, never on message.
  • On 429, honor the Retry-After header before retrying; add jittered exponential backoff for repeated rejections.
  • Treat 500 and 503 as transient and safe to retry with backoff; 4xx responses (other than 429) will not succeed on retry without changing the request.