Errors & rate limits

Errors use a consistent JSON shape and standard HTTP status codes.

Error shape

{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Insufficient company permissions."
}

Status codes

  • 400: malformed request or invalid parameters.
  • 401: missing, invalid, expired or revoked key.
  • 402: no active plan yet.
  • 403: the key lacks the action on that wallet (or its creator lacks the role), the endpoint is dashboard-only, the chain/network isn't in your plan, or a hard plan cap is reached (free Developer tier only; on paid plans, wallets/addresses beyond your included limits are created normally and bill as monthly overage).
  • 404: resource not found (or not in your company).
  • 409 / 422: conflict or unprocessable request.
  • 429: rate limited.
  • 5xx: server error; retry with backoff.

Policy refusals

When one of the organization's spending policies refuses a withdrawal, the 403 carries two extra fields: code, and policyIds (comma-separated, for support and your logs). Nothing was reserved, signed or sent.

{
  "statusCode": 403,
  "error": "Forbidden",
  "message": "Blocked by policy. "Daily limit": $52,400.00 in the last 24 hours by this person would be over the $50,000.00 limit ($51,150.00 already sent).",
  "code": "policy_denied",
  "policyIds": "4"
}
  • policy_denied: not allowed at all. Don't retry it unchanged; the message names the rule.
  • policy_approval_required: a direct withdrawal needs approval. Propose it with POST /withdrawal-requests and a person approves it.
  • policy_approvals_pending: an approval was attempted before every sign-off a policy asks for was in.

The SDKs raise these as PolicyError, a subclass of ApiError, with policyCode and policyIds (policy_code and policy_ids in Python).

Rate limits

A relaxed global ceiling of 300 requests per minute per IP applies to every endpoint. On top of that, value-moving writes have a tighter, per-caller limit, counted per API key and scoped to each endpoint:

  • 20/min per caller: withdrawal prepare/broadcast and wallet create/update/delete.

Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds). A 429 additionally sets Retry-After (seconds) and returns the standard error shape:

{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "Rate limit exceeded. Try again in 30 seconds."
}

On a 429, wait for Retry-After before retrying; don't retry in tight loops. Rate limits guard burst traffic only; there is no monthly cap on API requests.

Need a hand integrating? Email support@guveno.com.
API reference v1.10.0 · Last updated October 17, 2026