Errors
The Perspective External API uses standard HTTP status codes and returns a consistent JSON body on every error response.
Error response shape
All error responses share the same schema:
{
"error": "A human-readable description of what went wrong",
"status": 400
}
| Field | Type | Description |
|---|---|---|
error | string | Human-readable error message |
status | number | HTTP status code (mirrors the HTTP status) |
Status codes
| Code | Name | When it occurs |
|---|---|---|
| 400 | Bad Request | The request is malformed or missing a required parameter (e.g. a required path param or invalid body). |
| 401 | Unauthorized | The x-perspective-api-key header is missing or the key is invalid. (For MCP HTTP authentication errors, see MCP Authentication.) |
| 403 | Forbidden | The key is valid but does not have the required permissions for this resource or operation. |
| 404 | Not Found | The requested resource (e.g. a contact or funnel) does not exist. |
| 429 | Too Many Requests | You have exceeded the rate limit of 100 requests per minute. Wait for the window to reset and retry. |
| 500 | Internal Server Error | An unexpected error occurred on Perspective's side. |
Handling errors in practice
Check response.ok (or the HTTP status code) before consuming the response body. Use the error field to log or surface a message, and the status field for programmatic branching.
const response = await fetch('https://api.perspective.co/v1/workspaces', {
headers: { 'x-perspective-api-key': process.env.PERSPECTIVE_API_KEY },
});
if (!response.ok) {
const { error, status } = await response.json();
if (status === 401) {
// Key is missing or invalid — check your API key configuration
} else if (status === 429) {
// Rate limit hit — back off and retry after the window resets
} else {
console.error(`API error ${status}: ${error}`);
}
}
Rate limit headers
When the rate limit is approaching or exceeded, the API returns standard RateLimit-* headers (RFC 6585 / draft-ietf-httpapi-ratelimit-headers) so you can inspect your current quota and reset time:
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 60
RateLimit-Reset is the number of seconds until the current rate-limit window resets.
On a 429 response, the retryAfter field is also included in the JSON body (value in seconds):
{
"error": "Rate limit exceeded",
"status": 429,
"retryAfter": 60
}
Related pages
- Authentication — how to authenticate requests correctly to avoid 401/403
- API Keys — managing and rotating keys