Skip to main content

Error Handling

NL EN

Updated June 15, 2026

The Recruitsome API uses standard HTTP response codes to indicate the success or failure of requests. This guide helps you understand and handle the different error scenarios.

Error Response Format

All error responses follow a consistent JSON structure:

JSON
{
  "message": "Human-readable error description",
  "errors": {
    "field_name": ["Specific validation error for this field"]
  }
}

The errors object is only present on validation errors (422). Some endpoints also include a machine-readable error code — see Structured error codes below.

HTTP Status Codes

Success Codes (2xx)

CodeDescription
200OK - Request succeeded
201Created - Resource created successfully
202Accepted - Request queued for background processing

Client Error Codes (4xx)

CodeDescription
400Bad Request - A business rule failed (e.g., vacancy no longer accepting applications)
401Unauthorized - Invalid or missing API key
403Forbidden - Valid API key but insufficient permissions
404Not Found - Resource doesn't exist
422Unprocessable Entity - Validation errors
429Too Many Requests - Rate limit exceeded

Server Error Codes (5xx)

CodeDescription
500Internal Server Error - Something went wrong on our end

Common Error Scenarios

Authentication Errors

Missing or Invalid API Key (401)

JSON
{
  "message": "Unauthenticated."
}

You get the same response whether the key is missing, mistyped, or revoked.

Resolution: Include a valid API key in the Authorization header:

Bash
Authorization: Bearer YOUR_API_KEY

If the header is set, verify the key is correct and hasn't been revoked under SettingsAPI Keys.

Insufficient Scope

Missing API Permission (403)

JSON
{
  "message": "This API key does not have the required permission: candidates:read",
  "error": "INSUFFICIENT_SCOPE",
  "required_scope": "candidates:read"
}

Resolution: Create a new API key with the required scope under SettingsAPI Keys, or ask your administrator to.

Available Scopes:

ScopeAccess
vacancies:readView published vacancies and facets
vacancies:writeReport canonical vacancy URLs back to Recruitsome
applications:writeSubmit job applications
candidates:readView candidate list and profiles
candidates:writeCreate candidates via resume upload
team:readView team members
locations:readView office locations
articles:readRead published articles

API keys created before the scoping system was introduced have full access (*) and are not affected by scope restrictions.

Validation Errors

Invalid Query Parameters (422)

JSON
{
  "message": "The given data was invalid.",
  "errors": {
    "per_page": ["The per page field must not be greater than 100."],
    "language": ["The language field must be 2 characters."]
  }
}

Resolution: Check the errors object for specific field issues.

Invalid Filter Values (422)

JSON
{
  "message": "The given data was invalid.",
  "errors": {
    "location_id": ["The selected location id is invalid."]
  }
}

Canonical URL Host Not Allowed (422)

POST /vacancies/{slug}/canonical-url only accepts URLs on your own career website domain:

JSON
{
  "message": "The given data was invalid.",
  "errors": {
    "url": ["The URL host must match your configured career website domain."]
  }
}

Resolution: Report the URL exactly as it appears on your career website. The host must match the career website URL configured in Recruitsome (or one of your own domains).

Resource Errors

Resource Not Found (404)

JSON
{
  "message": "Resource not found."
}

Possible Causes:

  • Invalid slug
  • Vacancy is unpublished
  • Vacancy is not available through the API channel
  • Vacancy has expired

Rate Limiting

Rate Limit Exceeded (429)

JSON
{
  "message": "Too Many Attempts."
}

Response Headers:

Code
Retry-After: 42
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705765200

Resolution: Wait the number of seconds in Retry-After (or until the X-RateLimit-Reset timestamp), or implement exponential backoff.

Structured error codes

Some write endpoints return a machine-readable error code alongside the message, so your integration can branch on the cause instead of parsing text:

Vacancy Closed (400)

POST /applications when the vacancy is no longer accepting applications:

JSON
{
  "message": "This vacancy is no longer accepting applications",
  "error": "VACANCY_CLOSED"
}

Vacancy Not Found (404)

POST /applications when the vacancy doesn't exist or isn't published:

JSON
{
  "message": "Vacancy not found",
  "error": "VACANCY_NOT_FOUND"
}

Processing Failed (500)

POST /candidates when the resume couldn't be processed:

JSON
{
  "message": "An unexpected error occurred while processing the resume.",
  "error": "PROCESSING_FAILED"
}

Error Handling Best Practices

1. Implement Retry Logic

JavaScript
async function apiRequestWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);

      if (response.status === 429) {
        // Rate limited - wait before retry
        const resetTime = response.headers.get('X-RateLimit-Reset');
        const waitTime = resetTime
          ? (parseInt(resetTime) * 1000) - Date.now()
          : Math.pow(2, i) * 1000; // Exponential backoff

        await new Promise(resolve => setTimeout(resolve, waitTime));
        continue;
      }

      if (response.status >= 500) {
        // Server error - retry with exponential backoff
        await new Promise(resolve =>
          setTimeout(resolve, Math.pow(2, i) * 1000)
        );
        continue;
      }

      return response;
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

2. Handle Validation Errors

JavaScript
async function createResource(data) {
  const response = await fetch('/api/v1/resource', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
  });

  if (response.status === 422) {
    const error = await response.json();
    // Display field-specific errors to user
    Object.entries(error.errors).forEach(([field, messages]) => {
      console.error(`${field}: ${messages.join(', ')}`);
    });
    return null;
  }

  return response.json();
}

Debugging Tips

  1. Validate JSON: Ensure request bodies are valid JSON
  2. Test with cURL: Isolate issues by testing with simple cURL commands
  3. Check the headers: The rate limit headers tell you exactly how much room you have left

Getting Help

If you encounter persistent errors, contact [email protected] with:

  • Your API key name (not the key itself)
  • Request details (endpoint, parameters)
  • The full error response and status code