string, // Job title keywords * 'company_name' => string, * 'category' => string, // e.g., 'software-dev', 'customer-support' * 'limit' => int, // Number of results (default 50) * ] * @return array */ public function fetchJobs(array $params = []): array { try { $queryParams = $this->buildQueryParams($params); $response = $this->makeRequest('GET', 'remote-jobs', $queryParams); $data = $response->json(); if (!isset($data['jobs']) || !is_array($data['jobs'])) { throw new ApiException( 'Invalid response structure from Remotive API', $this->source->name, ['response' => $data] ); } $this->updateLastFetched(); return $this->transformer->transformMany($data['jobs']); } catch (ApiException $e) { throw $e; } catch (\Throwable $e) { throw new ApiException( 'Failed to fetch jobs from Remotive', $this->source->name, ['error' => $e->getMessage()], 0, $e ); } } /** * Build query parameters for the API request */ private function buildQueryParams(array $params): array { $queryParams = []; if (!empty($params['search'])) { $queryParams['search'] = $params['search']; } if (!empty($params['company_name'])) { $queryParams['company_name'] = $params['company_name']; } if (!empty($params['category'])) { $queryParams['category'] = $params['category']; } if (!empty($params['limit'])) { $queryParams['limit'] = min((int) $params['limit'], 100); } return $queryParams; } /** * Get available job categories from Remotive */ public function getCategories(): array { // Remotive categories (as of API documentation) return [ 'software-dev', 'customer-support', 'design', 'marketing', 'sales', 'product', 'business', 'data', 'devops', 'finance', 'hr', 'legal', 'operations', 'qa', 'writing', ]; } }