Errors & Status Codes

Parley uses standard HTTP status codes and returns structured JSON error bodies with machine-readable codes and human-readable messages.

Error Response Format

All error responses follow a consistent structure:

Error body shape
{  "error": {    "code": "MACHINE_READABLE_ERROR_CODE",    "message": "Human-readable explanation of what went wrong.",    "details": {}  }}
  • code -- Stable string for programmatic error handling
  • message -- Description suitable for logging or developer debugging
  • details -- Additional context (field-level validation errors, limits, etc.)

HTTP Status Codes

CodeMeaningWhen
200OKRequest succeeded. Response body contains the requested data.
201CreatedResource created successfully (e.g., new webhook subscription).
400Bad RequestInvalid or missing parameters. Check the details field for specifics.
401UnauthorizedMissing or invalid API key in the X-API-Key header.
403ForbiddenYour tier does not have access to this resource (e.g., Free tier accessing webhooks).
404Not FoundThe requested resource (facility, case, webhook) does not exist.
429Too Many RequestsDaily rate limit exceeded. Check rate limit headers for reset time.
500Internal Server ErrorSomething went wrong server-side. Retry the request or open a GitHub issue.
503Service UnavailableAPI is temporarily unavailable, usually during data ingestion. Retry after a few minutes.

Error Examples

400 -- Invalid parameters

400Bad Requestapplication/json
{  "error": {    "code": "INVALID_PARAMS",    "message": "One or more query parameters are invalid.",    "details": {      "fields": {        "state": "Must be a 2-letter state abbreviation",        "radius": "Must be between 0 and 50"      }    }  }}

401 -- Missing API key

401Unauthorizedapplication/json
{  "error": {    "code": "UNAUTHORIZED",    "message": "Missing or invalid API key. Include a valid key in the X-API-Key header."  }}

403 -- Tier restriction

403Forbiddenapplication/json
{  "error": {    "code": "TIER_RESTRICTED",    "message": "This endpoint requires pro tier or above"  }}

404 -- Resource not found

404Not Foundapplication/json
{  "error": {    "code": "NOT_FOUND",    "message": "Facility 'f47ac10b-0000-0000-0000-000000000000' not found"  }}

429 -- Rate limited

429Too Many Requestsapplication/json
{  "error": {    "code": "RATE_LIMIT_EXCEEDED",    "message": "You have exceeded your daily rate limit of 5000 requests.",    "details": {      "limit": 5000,      "remaining": 0,      "resets_at": "2026-03-21T00:00:00Z"    }  }}

Handling Errors in Code

error-handling.js
async function getFacility(id) {  const res = await fetch(    `https://api.parley.dev/v1/facilities/${id}`,    { headers: { "X-API-Key": process.env.PARLEY_API_KEY } }  );  if (!res.ok) {    const { error } = await res.json();    switch (res.status) {      case 401:        throw new Error("Invalid API key");      case 404:        return null; // facility not found      case 429:        // Retry after rate limit resets        const resetAt = new Date(error.details.resets_at);        const waitMs = resetAt.getTime() - Date.now();        await new Promise(r => setTimeout(r, waitMs));        return getFacility(id); // retry      default:        throw new Error(error.message);    }  }  const { data } = await res.json();  return data;}

Best practices

  • Always check the HTTP status code before parsing the response body.
  • Use the error.code field for programmatic branching, not the message text (which may change).
  • Log the meta.request_id field from successful responses and the full error body from failures for debugging.
  • Implement exponential backoff for 429 and 503 responses rather than immediate retries.
  • Monitor the X-RateLimit-Remaining header to preemptively slow down before hitting the limit.