{"id":27775309,"url":"https://github.com/rainmanjam/jobspy-api","last_synced_at":"2026-05-09T15:23:20.095Z","repository":{"id":290439148,"uuid":"974420439","full_name":"rainmanjam/jobspy-api","owner":"rainmanjam","description":"Dockerized version of JobSpy job search utility with API key auth, rate limiting, and proxy support.","archived":false,"fork":false,"pushed_at":"2025-04-29T21:58:44.000Z","size":90,"stargazers_count":177,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-30T03:53:42.775Z","etag":null,"topics":["docker","fastapi","glassdoor","google-jobs","job-scraper","jobspy","linkedin","pyrhon","remote-jobs"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rainmanjam.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":"SUPPORT.md","governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-04-28T18:47:48.000Z","updated_at":"2025-04-30T03:21:02.000Z","dependencies_parsed_at":"2025-04-28T21:28:56.832Z","dependency_job_id":"58702718-c30f-4f0e-9b64-b479756c04c2","html_url":"https://github.com/rainmanjam/jobspy-api","commit_stats":null,"previous_names":["rainmanjam/jobspy-api"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rainmanjam%2Fjobspy-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rainmanjam%2Fjobspy-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rainmanjam%2Fjobspy-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rainmanjam%2Fjobspy-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rainmanjam","download_url":"https://codeload.github.com/rainmanjam/jobspy-api/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251638760,"owners_count":21619663,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","fastapi","glassdoor","google-jobs","job-scraper","jobspy","linkedin","pyrhon","remote-jobs"],"created_at":"2025-04-30T03:53:46.450Z","updated_at":"2026-05-09T15:23:20.088Z","avatar_url":"https://github.com/rainmanjam.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JobSpy Docker API\n\nA Docker-containerized FastAPI application that provides secure API access to the Python JobSpy library, allowing you to search for jobs across multiple platforms including LinkedIn, Indeed, Glassdoor, Google, ZipRecruiter, Bayt, and Naukri.\n\n## Features\n\n- **Comprehensive Job Search**: Search across multiple job boards with a single API call\n- **API Key Authentication**: Secure your API with x-api-key header authentication\n- **Rate Limiting**: Prevent abuse with configurable rate limits\n- **Caching**: Improve performance with response caching\n- **Proxy Support**: Configure global proxies via environment variables\n- **Customizable Defaults**: Set default search parameters via environment variables\n- **CORS Support**: Enable cross-origin requests for frontend integration\n- **Health Checks**: Monitor application health with dedicated endpoints\n- **Comprehensive Logging**: Track API usage and troubleshoot issues\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=rainmanjam/jobspy-api\u0026type=Date)](https://www.star-history.com/#rainmanjam/jobspy-api\u0026Date)\n\n## Support the Project\n\nIf you find JobSpy Docker API useful, please consider:\n- ⭐️ Star this repository on GitHub: https://github.com/rainmanjam/jobspy-api\n- 🍴 Fork it to contribute and customize.\n- 👤 Follow the repo to stay updated with new features and releases.\n- 📥 Pull the Docker image from Docker Hub:\n```bash\n  docker pull rainmanjam/jobspy-api:latest\n```\n  or visit https://hub.docker.com/r/rainmanjam/jobspy-api and doing the same there.\n\n## Getting Started\n\n### Prerequisites\n\n- [Docker](https://docs.docker.com/get-docker/)\n- [Docker Compose](https://docs.docker.com/compose/install/) (optional, but recommended)\n\n### Running with Docker\n\n#### Build and run the Docker container\n\n```bash\n# Build the Docker image\ndocker build -t jobspy-api .\n\n# Run the container\ndocker run -p 8000:8000 \\\n  -e API_KEYS=your-api-key-1 \\\n  -e ENABLE_API_KEY_AUTH=true \\\n  jobspy-api\n```\n\n#### Additional Docker run options\n\nYou can configure the application by passing environment variables:\n\n```bash\ndocker run -p 8000:8000 \\\n  -e API_KEYS=your-api-key-1,your-api-key-2 \\\n  -e DEFAULT_COUNTRY_INDEED=USA \\\n  -e DEFAULT_PROXIES=user:pass@host:port,user:pass@host:port \\\n  -e LOG_LEVEL=INFO \\\n  jobspy-api\n```\n\n### Running with Docker Compose\n\n#### Production setup\n\n1. Edit the environment variables in `docker-compose.yml` to match your requirements:\n\n```yaml\nenvironment:\n  # API Security\n  - API_KEYS=your-api-key-1,your-api-key-2\n  - ENABLE_API_KEY_AUTH=true\n  \n  # Proxy Configuration (if needed)\n  - DEFAULT_PROXIES=user:pass@host:port,user:pass@host:port\n  \n  # Other settings as needed\n  - DEFAULT_COUNTRY_INDEED=USA\n```\n\n2. Start the application with Docker Compose:\n\n```bash\ndocker-compose up -d\n```\n\n3. Access the API documentation at [http://localhost:8000/docs](http://localhost:8000/docs)\n\n#### Development setup\n\nFor development with auto-reload:\n\n```bash\n# Uses docker-compose.dev.yml which mounts local directory and enables auto-reload\ndocker-compose -f docker-compose.dev.yml up\n```\n\n### Stopping the application\n\n```bash\n# If running with docker-compose\ndocker-compose down\n\n# If running with docker\ndocker stop \u003ccontainer_id\u003e\n```\n\n### Using the Makefile\n\nThe project includes a Makefile for common tasks:\n\n```bash\n# Show all available commands\nmake help\n\n# Basic commands\nmake install            # Install dependencies\nmake run                # Run development server\nmake test               # Run tests\nmake docker-build       # Build Docker image with both version and latest tags\nmake docker-buildx      # Build multi-arch Docker image with both version and latest tags\nmake docker-push        # Push Docker image to Docker Hub (both version and latest tags)\nmake docker-pushx       # Push multi-arch Docker image to Docker Hub (both version and latest tags)\nmake docker-compose-up  # Start with Docker Compose (production)\nmake docker-compose-dev # Start with Docker Compose (development)\n\n# Combined commands for streamlined workflows\nmake dev                # Run development server with auto-reload\nmake prod               # Build and run production container\nmake clean-start        # Remove containers, rebuild and start\nmake update             # Update dependencies and rebuild\nmake test-and-build     # Run tests and build if they pass\nmake ci                 # Run full CI pipeline (test, build, run)\nmake logs               # Show logs from running containers\nmake restart            # Restart running containers\nmake rebuild            # Rebuild and restart containers\n```\n\n## Configuration\n\n### Environment Variables\n\nYou can configure the application using environment variables:\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| **API Security** | | |\n| API_KEYS | Comma-separated list of valid API keys | [] |\n| ENABLE_API_KEY_AUTH | Enable API key authentication | true |\n| API_KEY_HEADER_NAME | Header name for API key | x-api-key |\n| **Rate Limiting** | | |\n| RATE_LIMIT_ENABLED | Enable rate limiting | true |\n| RATE_LIMIT_REQUESTS | Maximum requests per timeframe | 100 |\n| RATE_LIMIT_TIMEFRAME | Timeframe for rate limiting in seconds | 3600 |\n| **Proxy Configuration** | | |\n| DEFAULT_PROXIES | Comma-separated list of proxies | [] |\n| CA_CERT_PATH | Path to CA Certificate file for proxies | null |\n| **JobSpy Default Settings** | | |\n| DEFAULT_SITE_NAMES | Default job boards to search | all available boards |\n| DEFAULT_RESULTS_WANTED | Default number of results per site | 20 |\n| DEFAULT_DISTANCE | Default distance in miles | 50 |\n| DEFAULT_DESCRIPTION_FORMAT | Format of job description | markdown |\n| DEFAULT_COUNTRY_INDEED | Default country for Indeed searches | null |\n| **Caching** | | |\n| ENABLE_CACHE | Enable response caching | true |\n| CACHE_EXPIRY | Cache expiry time in seconds | 3600 |\n| **Logging \u0026 CORS** | | |\n| LOG_LEVEL | Logging level (INFO, DEBUG, etc.) | INFO |\n| ENVIRONMENT | Environment name (development, production) | development |\n| CORS_ORIGINS | Allowed origins for CORS | * |\n| **API Documentation** | | |\n| ENABLE_SWAGGER_UI | Enable Swagger UI docs | true |\n| ENABLE_REDOC | Enable ReDoc documentation | true |\n| SWAGGER_UI_PATH | URL path for Swagger UI | /docs |\n| REDOC_PATH | URL path for ReDoc | /redoc |\n\n### Environment Variable Override Chain\n\nThe application follows a specific precedence for loading environment variables:\n\n1. Command line arguments\n2. Docker Compose environment section\n3. `.env` file in the project root\n4. Dockerfile ENV values\n5. Dockerfile ARG defaults\n\nNote: `.env.local` is **not** loaded automatically by default. It's only used when:\n- Explicitly loaded in your code\n- Specified in the `env_file` section of docker-compose.yml\n- Using the development setup with docker-compose.dev.yml\n\nTo explicitly load `.env.local`:\n```bash\n# Run the helper script before starting the application\npython scripts/load_local_env.py\n```\n\nThis loading order is important to understand when troubleshooting environment variable issues:\n- Values from higher in the list override values from lower in the list\n- When values appear to be incorrect, check at which level they're being defined\n- Docker Compose environment variables can override `.env` values, which is a common source of confusion\n\n### Debugging Environment Variables\n\nThe project includes several scripts to help debug environment variable issues:\n\n```bash\n# Check environment variables and configuration\npython scripts/check_env.py\n\n# Verify environment variable loading\npython scripts/verify_env_loading.py\n\n# Debug environment variable conflicts\npython scripts/debug_env_conflicts.py\n\n# Check configuration consistency\npython scripts/check_config_consistency.py\n\n# Inside Docker container\ndocker-compose run --rm jobspy-api python /app/scripts/check_env.py\n```\n\n## Examples of Disabling Documentation\n\n### In docker-compose.yml:\n```yaml\nservices:\n  jobspy-api:\n    # ...\n    environment:\n      # Disable API documentation in production\n      - ENABLE_SWAGGER_UI=false\n      - ENABLE_REDOC=false\n```\n\n### Using Docker run command:\n```bash\ndocker run -p 8000:8000 \\\n  -e ENABLE_SWAGGER_UI=false \\\n  -e ENABLE_REDOC=false \\\n  jobspy-api\n```\n\n### In .env file:\n```env\nENABLE_SWAGGER_UI=false\nENABLE_REDOC=false\n```\n\n## API Usage\n\nAll API endpoints require an API key to be passed in the `x-api-key` header if authentication is enabled.\n\n### Endpoints\n\n- `GET /api/v1/search_jobs` - Search for jobs with optional pagination and output format (`format=json|csv`)\n- `GET /health` - Returns the health status of the API\n- `GET /ping` - Simple ping endpoint for monitoring\n\n### Parameters for `search_jobs`\n\n| Parameter                | Type           | Description                                                                                  | Default      |\n|--------------------------|----------------|----------------------------------------------------------------------------------------------|--------------|\n| format                   | string         | Output format: `json` (default) or `csv`. If `csv`, returns a downloadable CSV file.         | json         |\n| site_name                | list or string | Job sites to search on (indeed, linkedin, zip_recruiter, glassdoor, google, bayt, naukri)    | all          |\n| search_term              | string         | Job search term                                                                              |              |\n| google_search_term       | string         | Search term for Google jobs (only parameter for filtering Google jobs)                       |              |\n| location                 | string         | Job location                                                                                 |              |\n| distance                 | integer        | Distance in miles                                                                            | 50           |\n| job_type                 | string         | Job type (fulltime, parttime, internship, contract)                                          |              |\n| proxies                  | list           | List of proxies in format `user:pass@host:port`                                              |              |\n| is_remote                | boolean        | Remote job filter                                                                            |              |\n| results_wanted           | integer        | Number of job results per site                                                               | 20           |\n| easy_apply               | boolean        | Filters for jobs hosted on the job board site                                                |              |\n| description_format       | string         | Format of job description (`markdown`, `html`)                                               | markdown     |\n| offset                   | integer        | Start search from this offset                                                                |              |\n| hours_old                | integer        | Filter jobs by hours since posted                                                            |              |\n| verbose                  | integer        | Controls verbosity (0=errors, 1=warnings, 2=all logs)                                        | 2            |\n| linkedin_fetch_description | boolean      | Fetch full description and direct job url for LinkedIn                                       |              |\n| linkedin_company_ids     | list[int]      | Search LinkedIn jobs with specific company ids                                               |              |\n| country_indeed           | string         | Country for Indeed \u0026 Glassdoor                                                               |              |\n| enforce_annual_salary    | boolean        | Converts wages to annual salary                                                              |              |\n| ca_cert                  | string         | Path to CA Certificate file for proxies                                                      |              |\n\n## CSV Output Example\n\nYou can request results as a CSV file by adding `?format=csv` to your request:\n\n```bash\ncurl -X 'GET' 'http://localhost:8000/api/v1/search_jobs?site_name=indeed\u0026search_term=engineer\u0026format=csv' -H 'accept: text/csv' -o jobs.csv\n```\n\nThe response will be a downloadable CSV file with all job fields.\n\n## JobPost Schema\n\nThe API returns job objects with the following fields (fields may vary by provider):\n\n| Field                  | Description                                      | Providers                |\n|------------------------|--------------------------------------------------|--------------------------|\n| title                  | Job title                                        | All                      |\n| company                | Company name                                     | All                      |\n| company_url            | Company website                                  | All                      |\n| job_url                | Direct job posting URL                           | All                      |\n| location.country       | Country                                          | All                      |\n| location.city          | City                                             | All                      |\n| location.state         | State                                            | All                      |\n| is_remote              | Remote job flag                                  | All                      |\n| description            | Job description                                  | All                      |\n| job_type               | Job type (fulltime, parttime, etc.)              | All                      |\n| job_function           | Job function/category                            | All                      |\n| interval               | Salary interval (yearly, monthly, etc.)          | All                      |\n| min_amount             | Minimum salary                                   | All                      |\n| max_amount             | Maximum salary                                   | All                      |\n| currency               | Salary currency                                  | All                      |\n| salary_source          | Source of salary info                            | All                      |\n| date_posted            | Date posted                                      | All                      |\n| emails                 | Emails found in posting                          | All                      |\n| job_level              | Job level                                        | LinkedIn                 |\n| company_industry       | Company industry                                 | LinkedIn, Indeed         |\n| company_country        | Company country                                  | Indeed                   |\n| company_addresses      | Company addresses                                | Indeed                   |\n| company_employees_label| Company size label                               | Indeed                   |\n| company_revenue_label  | Company revenue label                            | Indeed                   |\n| company_description    | Company description                              | Indeed                   |\n| company_logo           | Company logo URL                                 | Indeed                   |\n| skills                 | Required skills                                  | Naukri                   |\n| experience_range       | Experience range                                 | Naukri                   |\n| company_rating         | Company rating                                   | Naukri                   |\n| company_reviews_count  | Company reviews count                            | Naukri                   |\n| vacancy_count          | Number of vacancies                              | Naukri                   |\n| work_from_home_type    | Work from home type                              | Naukri                   |\n\n## Supported Countries for Indeed/Glassdoor\n\n|                      |              |            |                |\n|----------------------|--------------|------------|----------------|\n| Argentina            | Australia*   | Austria*   | Bahrain        |\n| Belgium*             | Brazil*      | Canada*    | Chile          |\n| China                | Colombia     | Costa Rica | Czech Republic |\n| Denmark              | Ecuador      | Egypt      | Finland        |\n| France*              | Germany*     | Greece     | Hong Kong*     |\n| Hungary              | India*       | Indonesia  | Ireland*       |\n| Israel               | Italy*       | Japan      | Kuwait         |\n| Luxembourg           | Malaysia     | Mexico*    | Morocco        |\n| Netherlands*         | New Zealand* | Nigeria    | Norway         |\n| Oman                 | Pakistan     | Panama     | Peru           |\n| Philippines          | Poland       | Portugal   | Qatar          |\n| Romania              | Saudi Arabia | Singapore* | South Africa   |\n| South Korea          | Spain*       | Sweden     | Switzerland*   |\n| Taiwan               | Thailand     | Turkey     | Ukraine        |\n| United Arab Emirates | UK*          | USA*       | Uruguay        |\n| Venezuela            | Vietnam*     |            |                |\n\n(\\* indicates also supported by Glassdoor)\n\n## Troubleshooting\n\n### API Issues\n- If you receive a 429 error, you've exceeded the rate limit or the underlying job boards are blocking requests\n- For Google jobs, use very specific search terms in the google_search_term parameter\n- For Indeed searches, use precise search syntax with quotes and operators\n- For high-volume usage, configure proxies to avoid being blocked\n\n### Docker Troubleshooting\n\n- **Container exits immediately**: Check the logs with `docker logs \u003ccontainer_id\u003e`\n- **Can't access the API**: Make sure ports are correctly mapped and the container is running\n- **API key issues**: Ensure API_KEYS environment variable is set correctly\n- **Proxy issues**: If using proxies, make sure they're correctly formatted and working\n- **Permission issues**: If mounting volumes, ensure proper permissions are set\n  - Shell scripts need execute permissions: `chmod +x scripts/*.sh`\n  - For Windows users, Git may change line endings - use `git config --global core.autocrlf input` \n  - The container uses a special entrypoint script that fixes permissions automatically\n- **Image tags**: Both `latest` and the version number are pushed to Docker Hub. If you don't see the version tag, ensure you are using the latest Makefile and pushing with `make docker-push` or `make docker-pushx`.\n\n### Script Permission Issues\n\n- Ensure all scripts have execute permissions:\n  ```bash\n  chmod +x scripts/*.sh\n  ```\n\n- For Windows users, ensure line endings are correct:\n  ```bash\n  git config --global core.autocrlf input\n  ```\n\n### Environment Variable Issues\n\nIf you're experiencing issues with environment variables:\n\n1. **Verify variable values**: Use the debugging scripts to see which values are active\n   ```bash\n   python scripts/check_env.py\n   ```\n\n2. **Check variable precedence**: Remember that Docker Compose environment values override `.env` files\n   ```bash\n   # See the full override chain\n   bash scripts/debug_env_load_order.sh\n   ```\n\n3. **Watch for conflicts**: Look for conflicting definitions in different places\n   ```bash\n   python scripts/debug_env_conflicts.py\n   ```\n\n4. **Docker environment**: When running in Docker, use this command to debug\n   ```bash\n   docker-compose run --rm jobspy-api bash -c \"env | grep -E 'API_KEY|ENABLE_|LOG_LEVEL'\"\n   ```\n\n5. **Inspect container**: If necessary, inspect the container directly\n   ```bash\n   docker-compose exec jobspy-api bash\n   ```\n\n6. **API configuration endpoint**: If the application is running, check\n   ```\n   http://localhost:8000/api-config\n   http://localhost:8000/config-sources\n   ```\n\n### Common Issues and Solutions\n\n1. **API authentication not working**:\n   - Ensure `ENABLE_API_KEY_AUTH=true` and `API_KEYS` is set correctly\n   - Verify you're including the proper header in requests (`x-api-key`)\n   - Check `/auth-status` endpoint for diagnostics\n\n2. **Container fails to start**:\n   - Check logs with `docker-compose logs jobspy-api`\n   - Ensure script permissions are correct: `chmod +x scripts/*.sh`\n   - Try running with the debug configuration: `docker-compose -f docker-compose.dev.yml up`\n\n3. **API errors with 500 status code**:\n   - Check Docker logs for detailed error information\n   - Increase logging level: `LOG_LEVEL=DEBUG`\n   - Look for specific scraper errors related to job boards\n\n4. **Changes to `.env` file not taking effect**:\n   - Remember Docker Compose may have overriding environment variables\n   - Rebuild container: `docker-compose build` then `docker-compose up -d`\n   - Check effective values with `/config-sources` endpoint\n\n## Versioning and Releases\n\nThe JobSpy Docker API follows [Semantic Versioning](https://semver.org/) (MAJOR.MINOR.PATCH).\n\n### Current Version\n\n```bash\n# View the current version\npython -c \"from app import __version__; print(__version__)\"\n\n# Or using make\nmake version\n```\n\nCurrent version: **1.0.0**\n\n### Version Management\n\nThe project provides convenient commands for updating version numbers:\n\n```bash\n# Increment patch version (1.0.0 -\u003e 1.0.1)\nmake version-patch\n\n# Increment minor version (1.0.0 -\u003e 1.1.0)\nmake version-minor\n\n# Increment major version (1.0.0 -\u003e 2.0.0)\nmake version-major\n```\n\nThese commands update the version in `app/__init__.py` automatically.\n\n### Release Process\n\n#### Creating a GitHub Release\n\n1. Update the version number using the appropriate make command\n2. Update the CHANGELOG.md with details of changes\n3. Commit changes: `git commit -am \"Bump version to X.Y.Z\"`\n4. Create a git tag: `git tag -a vX.Y.Z -m \"Version X.Y.Z\"`\n5. Push changes: `git push \u0026\u0026 git push --tags`\n6. Go to GitHub and create a new release based on the tag\n   - Navigate to: https://github.com/[username]/job-spy-fastapi/releases/new\n   - Select the tag\n   - Add release notes\n   - Publish the release\n\n#### Docker Image Releases\n\nReleases are automatically published to Docker Hub on new GitHub releases:\n\n```bash\n# Build and push to Docker Hub (both version and latest tags)\nmake docker-push\n```\n\nThis will build the Docker image with the current version tag **and** the `latest` tag and publish both to Docker Hub.\n\nFor multi-arch builds:\n\n```bash\nmake docker-pushx\n```\n\n#### Using Specific Versions\n\nYou can run a specific version of the API using Docker:\n\n```bash\n# Pull a specific version\ndocker pull username/jobspy-api:1.0.0\n\n# Or pull the latest tag\ndocker pull username/jobspy-api:latest\n\n# Run a specific version\ndocker run -p 8000:8000 username/jobspy-api:1.0.0\n\n# Or run the latest\ndocker run -p 8000:8000 username/jobspy-api:latest\n```\n\n### Changelog\n\nThe project maintains a detailed changelog in the CHANGELOG.md file, which includes:\n- New features\n- Bug fixes\n- Breaking changes\n- Deprecation notices\n\nAlways check the changelog before upgrading to a new version, especially for major releases.\n\n## API Versioning\n\nThe JobSpy Docker API uses URL path versioning to ensure backward compatibility as the API evolves.\n\n### Current Version\n\n- **v1** - The current stable API version (e.g., `/api/v1/search_jobs`)\n\n### Versioning Strategy\n\n- All API endpoints are versioned with a `v{number}` in the URL path\n- Breaking changes will only be introduced in new API versions\n- Older API versions will remain supported for a reasonable deprecation period\n- Non-breaking enhancements may be added to existing versions\n\n### Using API Versions\n\nAlways include the version in your API requests:\n\n```bash\n# Using the v1 API\ncurl -X 'GET' \\\n  'http://localhost:8000/api/v1/search_jobs?site_name=indeed\u0026search_term=software%20engineer' \\\n  -H 'accept: application/json' \\\n  -H 'x-api-key: your-api-key'\n```\n\n### Version Lifecycle\n\n- **Current** - v1 (active development, fully supported)\n- **Future** - When v2 is released, v1 will enter maintenance mode\n- **Deprecated** - Versions in this state will be announced with a timeline for removal\n- **Retired** - Versions that are no longer available\n\nVersion deprecation notices will be posted in release notes and the API will return deprecation warning headers for endpoints approaching retirement.\n\n## Available Parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| **Pagination Parameters** | | |\n| paginate | boolean | Enable pagination (default: false) |\n| page | integer | Page number when pagination is enabled (default: 1) |\n| page_size | integer | Number of results per page when pagination is enabled (default: 10, max: 100) |\n| **Basic Search Parameters** | | |\n| site_name | list or string | Job sites to search on (indeed, linkedin, zip_recruiter, glassdoor, google, bayt, naukri) |\n| search_term | string | Job search term |\n| google_search_term | string | Search term for Google jobs (only parameter for filtering Google jobs) |\n| location | string | Job location |\n| distance | integer | Distance in miles (default: 50) |\n| **Job Filters** | | |\n| job_type | string | Job type (fulltime, parttime, internship, contract) |\n| is_remote | boolean | Remote job filter |\n| hours_old | integer | Filters jobs by the number of hours since the job was posted |\n| easy_apply | boolean | Filters for jobs that are hosted on the job board site |\n| **Advanced Parameters** | | |\n| results_wanted | integer | Number of results per site (default: 20) |\n| description_format | string | Format of job description (markdown, html) (default: markdown) |\n| offset | integer | Starts the search from an offset |\n| verbose | integer | Controls verbosity (0: errors only, 1: errors+warnings, 2: all logs) (default: 2) |\n| linkedin_fetch_description | boolean | Fetch full LinkedIn descriptions (slower) (default: false) |\n| linkedin_company_ids | list of integers | LinkedIn company IDs to filter by |\n| country_indeed | string | Country filter for Indeed \u0026 Glassdoor (default: USA) |\n| enforce_annual_salary | boolean | Convert wages to annual salary (default: false) |\n| ca_cert | string | Path to CA Certificate file for proxies |\n\n## Response Format\n\nThe API returns results in two possible formats, depending on whether pagination is enabled:\n\n### Standard Response (paginate=false)\n\n```json\n{\n  \"count\": 42,\n  \"jobs\": [\n    {\n      \"SITE\": \"linkedin\",\n      \"TITLE\": \"Software Engineer\",\n      \"COMPANY\": \"Example Corp\",\n      \"LOCATION\": \"San Francisco, CA\",\n      \"DATE\": \"2023-06-01\",\n      \"LINK\": \"https://www.linkedin.com/jobs/view/123456789\",\n      \"DESCRIPTION\": \"Job description markdown text...\",\n      // ...additional job fields\n    },\n    // ...more jobs\n  ],\n  \"cached\": false\n}\n```\n\n### Paginated Response (paginate=true)\n\n```json\n{\n  \"count\": 42,\n  \"total_pages\": 5,\n  \"current_page\": 1,\n  \"page_size\": 10,\n  \"jobs\": [\n    // ...array of job objects (max 10 in this example)\n  ],\n  \"cached\": false,\n  \"next_page\": \"http://localhost:8000/api/v1/search_jobs?paginate=true\u0026page=2\u0026...\",\n  \"previous_page\": null\n}\n```\n\n## Caching Behavior\n\nResults are cached based on search parameters to improve performance and reduce load on job sites:\n\n- Cache is enabled by default but can be disabled using the `ENABLE_CACHE` environment variable\n- Default cache expiry is 1 hour (3600 seconds), configurable via `CACHE_EXPIRY`\n- The `cached` field in the response indicates whether results came from cache\n- Cached results are returned only when the exact same search parameters are used\n\n## Limitations\n\n### Indeed limitations\nOnly one from this list can be used in a search:\n- hours_old\n- job_type \u0026 is_remote\n- easy_apply\n\n### LinkedIn limitations\nOnly one from this list can be used in a search:\n- hours_old\n- easy_apply\n\n## Error Handling\n\nThe API provides descriptive error responses with suggestions for fixing common issues:\n\n### Validation Errors\n\nWhen you provide invalid parameters, the API will return:\n- The invalid parameter\n- What was wrong with it\n- Valid options to use instead\n- Suggestions for fixing the issue\n\nExample response for an invalid site name:\n\n```json\n{\n  \"error\": \"Invalid job site name(s)\",\n  \"invalid_values\": [\"linkdin\"],\n  \"valid_sites\": [\"indeed\", \"linkedin\", \"zip_recruiter\", \"glassdoor\", \"google\", \"bayt\", \"naukri\"],\n  \"suggestions\": [\n    {\n      \"parameter\": \"site_name\",\n      \"message\": \"'linkdin' is not a valid job site\",\n      \"suggestion\": \"Use one or more of the valid job sites: indeed, linkedin, zip_recruiter, glassdoor, google, bayt, naukri\",\n      \"expected_type\": \"string or list\",\n      \"description\": \"Job sites to search on (e.g., indeed, linkedin)\"\n    }\n  ]\n}\n```\n\n### Parameter Combination Errors\n\nSome parameters cannot be used together. The API will explain these limitations:\n\n```json\n{\n  \"error\": \"Invalid parameter combination for Indeed\",\n  \"message\": \"Indeed searches cannot combine hours_old with job_type, is_remote, or easy_apply\",\n  \"suggestion\": \"Use either hours_old OR job filtering parameters, but not both\"\n}\n```\n\n### General Error Suggestions\n\nFor other errors, the API will suggest potential fixes:\n\n```json\n{\n  \"error\": \"Error scraping jobs\",\n  \"message\": \"Connection timed out\",\n  \"suggestion\": \"The request timed out. Try reducing the number of job sites or results_wanted\"\n}\n```\n\n### Error Handling\n\nThe API returns standard HTTP status codes:\n\n- `200 OK` - Request was successful\n- `400 Bad Request` - Invalid parameters\n- `403 Forbidden` - Missing or invalid API key\n- `404 Not Found` - Requested page not found (when using pagination)\n- `429 Too Many Requests` - Rate limit exceeded\n- `500 Internal Server Error` - Server error (usually from job board sites)\n\nError responses include detailed information:\n\n```json\n{\n  \"error\": \"Error type\",\n  \"detail\": \"Detailed error message\",\n  \"status_code\": 400,\n  \"path\": \"/api/v1/search_jobs\"\n}\n```\n\n## Troubleshooting\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frainmanjam%2Fjobspy-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frainmanjam%2Fjobspy-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frainmanjam%2Fjobspy-api/lists"}