Skip to content

Postbox uses different error formats depending on the endpoint type.

Endpoints under /api/forms/*:

StatusScenarioBody
401Invalid or missing API keyUnauthorized (plain text)
404Form not found{ "errors": "Form not found" }
422Validation errors{ "errors": { "field": ["message"] } }

Endpoints under /api/forms/{id}/submissions/*:

StatusScenarioBody
400Invalid pagination parameters{ "error": { "code": 400, "message": "Invalid pagination parameters" } }
404Form or submission not found{ "error": { "code": 404, "message": "Form not found" } }
422Could not delete submission{ "error": { "code": 422, "message": "Could not delete submission" } }

The submission endpoint (POST /api/.../f/{slug}):

StatusScenarioBody
400Validation error{ "error": { "code": "validation_error", "message": "Validation failed", "details": { "field": ["message"] } } }
401Missing auth for private form{ "error": { "code": "unauthorized", "message": "..." } }
404Form not found{ "error": { "code": "form_not_found", "message": "Not found" } }
429Submission limit reached (free){ "error": { "code": "plan_limit_exhausted", "message": "...", "upgrade_url": "https://usepostbox.com/settings/billing" } }

When rate limited, the response returns 429 Too Many Requests with retry_after in seconds:

{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded. Try again in 45 seconds."
}
}

Best practices:

  • Always check the HTTP status code first
  • Parse the code field for programmatic handling
  • Display the message field to users
  • On 429, respect the retry_after value
  • On 5xx, retry with exponential backoff
  • Check for upgrade_url in the error body to surface upgrade prompts to users