openapi: 3.0.3 info: title: LinkedIn Profile Search API version: 1.0.0 (v1) description: Keyword search and faceted filtering over a LinkedIn profile dataset. Backed by Elasticsearch with a PostgreSQL full-text fallback. paths: /api/v1/auth/login/: post: operationId: auth_login_create description: Exchange credentials for an access/refresh token pair. tags: - auth requestBody: content: application/json: schema: $ref: '#/components/schemas/TokenObtainPairRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/TokenObtainPairRequest' multipart/form-data: schema: $ref: '#/components/schemas/TokenObtainPairRequest' required: true security: - {} responses: '200': description: No response body /api/v1/auth/logout/: post: operationId: auth_logout_create description: Blacklist a refresh token so it can no longer be rotated. tags: - auth requestBody: content: application/json: schema: $ref: '#/components/schemas/LogoutRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/LogoutRequest' multipart/form-data: schema: $ref: '#/components/schemas/LogoutRequest' required: true security: - jwtAuth: [] responses: '205': description: No response body /api/v1/auth/me/: get: operationId: auth_me_retrieve description: Identity and effective privileges of the calling user. tags: - auth security: - jwtAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/User' description: '' /api/v1/auth/refresh/: post: operationId: auth_refresh_create description: Rotate a refresh token; the presented token is blacklisted afterwards. tags: - auth requestBody: content: application/json: schema: $ref: '#/components/schemas/TokenRefreshRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/TokenRefreshRequest' multipart/form-data: schema: $ref: '#/components/schemas/TokenRefreshRequest' required: true security: - {} responses: '200': content: application/json: schema: $ref: '#/components/schemas/TokenRefresh' description: '' /api/v1/auth/register/: post: operationId: auth_register_create description: Self-service sign-up. New accounts always get the ``viewer`` role. tags: - auth requestBody: content: application/json: schema: $ref: '#/components/schemas/RegisterRequest' application/x-www-form-urlencoded: schema: $ref: '#/components/schemas/RegisterRequest' multipart/form-data: schema: $ref: '#/components/schemas/RegisterRequest' required: true security: - jwtAuth: [] - {} responses: '201': content: application/json: schema: $ref: '#/components/schemas/Register' description: '' /api/v1/health/live/: get: operationId: health_live_retrieve description: 'Cheap check: the process is up and can answer HTTP.' tags: - health security: - {} responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/health/ready/: get: operationId: health_ready_retrieve description: |- Deep check: verifies every dependency the API needs to serve traffic. Returns 503 when any dependency is down so an orchestrator stops routing traffic to this instance. tags: - health security: - {} responses: '200': content: application/json: schema: type: object additionalProperties: {} description: '' '503': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/profiles/: get: operationId: profiles_list description: |- Plain, unranked listing. Useful for browsing and for verifying the dataset; ranked keyword search is served by ``/api/v1/search/``. parameters: - name: page required: false in: query description: A page number within the paginated result set. schema: type: integer - name: page_size required: false in: query description: Number of results to return per page. schema: type: integer tags: - profiles security: - jwtAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaginatedProfileListList' description: '' /api/v1/profiles/{id}/: get: operationId: profiles_retrieve description: Full profile including work history, education and (masked) contacts. parameters: - in: path name: id schema: type: integer required: true tags: - profiles security: - jwtAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ProfileDetail' description: '' /api/v1/profiles/skills/: get: operationId: profiles_skills_list description: |- Skill dictionary ordered by popularity. The frontend uses it to power the skill filter's type-ahead without hitting Elasticsearch for every keystroke. tags: - profiles security: - jwtAuth: [] responses: '200': content: application/json: schema: type: array items: $ref: '#/components/schemas/Skill' description: '' /api/v1/search/: get: operationId: search_retrieve description: Ranked keyword search across name, job title, skills, employer, education, location and summary, combined with structured filters. Filter values are OR-ed inside one filter and AND-ed across filters. summary: Keyword search with filters and facets parameters: - in: query name: companies schema: type: string description: Current employer name. - in: query name: countries schema: type: string description: Country of residence. - in: query name: facets schema: type: boolean default: true - in: query name: industries schema: type: string description: Industry of the current employer. - in: query name: max_experience schema: type: integer maximum: 70 minimum: 0 - in: query name: min_experience schema: type: integer maximum: 70 minimum: 0 - in: query name: page schema: type: integer minimum: 1 default: 1 - in: query name: page_size schema: type: integer maximum: 100 minimum: 1 default: 20 - in: query name: q schema: type: string maxLength: 200 description: Free-text keyword. Supports quoted phrases and -exclusions. - in: query name: roles schema: type: string description: Job family, e.g. engineering, human_resources. - in: query name: seniority schema: type: string description: Seniority level, e.g. senior, manager, cxo. - in: query name: skills schema: type: string description: Skill names, OR-combined. - in: query name: sort schema: enum: - relevance - -experience - experience - name type: string default: relevance minLength: 1 description: |- * `relevance` - relevance * `-experience` - -experience * `experience` - experience * `name` - name tags: - search security: - jwtAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/SearchResponse' description: '' /api/v1/search/reindex/: post: operationId: search_reindex_create description: |- Triggers a zero-downtime rebuild of the Elasticsearch index. Restricted to the admin role: it is an expensive, cluster-wide operation. summary: Rebuild the search index (admin only) tags: - search security: - jwtAuth: [] responses: '202': content: application/json: schema: type: object additionalProperties: {} description: '' /api/v1/search/suggest/: get: operationId: search_suggest_retrieve description: Edge n-gram completions used by the search box. summary: Type-ahead suggestions parameters: - in: query name: limit schema: type: integer description: Maximum suggestions (1-20). - in: query name: q schema: type: string description: Partial name or skill. required: true tags: - search security: - jwtAuth: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/SuggestResponse' description: '' components: schemas: BlankEnum: enum: - '' Company: type: object properties: id: type: integer readOnly: true name: type: string maxLength: 255 industry: type: string maxLength: 128 size: type: string description: Head-count bucket, e.g. 51-200 maxLength: 32 founded: type: integer maximum: 2147483647 minimum: 0 nullable: true website: type: string maxLength: 255 location_name: type: string maxLength: 255 required: - id - name Education: type: object properties: id: type: integer readOnly: true school: allOf: - $ref: '#/components/schemas/School' readOnly: true school_name: type: string maxLength: 255 degrees: type: array items: type: string maxLength: 128 majors: type: array items: type: string maxLength: 128 minors: type: array items: type: string maxLength: 128 gpa: type: string format: decimal pattern: ^-?\d{0,2}(?:\.\d{0,2})?$ nullable: true start_date: type: string maxLength: 10 end_date: type: string maxLength: 10 end_year: type: integer maximum: 32767 minimum: 0 nullable: true required: - id - school Experience: type: object properties: id: type: integer readOnly: true title: type: string maxLength: 255 title_role: type: string maxLength: 64 title_sub_role: type: string maxLength: 64 levels: type: array items: type: string maxLength: 32 company: allOf: - $ref: '#/components/schemas/Company' readOnly: true company_name: type: string maxLength: 255 start_date: type: string maxLength: 10 end_date: type: string maxLength: 10 start_year: type: integer maximum: 32767 minimum: 0 nullable: true end_year: type: integer maximum: 32767 minimum: 0 nullable: true is_primary: type: boolean location_name: type: string maxLength: 255 summary: type: string required: - company - id FacetBucket: type: object properties: key: type: string count: type: integer required: - count - key GenderEnum: enum: - male - female type: string description: |- * `male` - Male * `female` - Female * `` - Unknown LogoutRequest: type: object properties: refresh: type: string minLength: 1 required: - refresh PaginatedProfileListList: type: object required: - count - results properties: count: type: integer example: 123 next: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=4 previous: type: string nullable: true format: uri example: http://api.example.org/accounts/?page=2 results: type: array items: $ref: '#/components/schemas/ProfileList' ProfileDetail: type: object description: Masks contact details unless the caller is allowed to see them. properties: id: type: integer readOnly: true external_id: type: string description: LinkedIn numeric id from the source export. maxLength: 64 full_name: type: string maxLength: 255 first_name: type: string maxLength: 128 last_name: type: string maxLength: 128 gender: oneOf: - $ref: '#/components/schemas/GenderEnum' - $ref: '#/components/schemas/BlankEnum' headline: type: string readOnly: true job_title: type: string maxLength: 255 job_title_role: type: string description: Coarse job family, e.g. engineering. maxLength: 64 job_title_sub_role: type: string maxLength: 64 seniority_levels: type: array items: type: string maxLength: 32 description: e.g. ['manager'], ['senior'], ['cxo']. current_company: allOf: - $ref: '#/components/schemas/Company' readOnly: true industry: type: string maxLength: 128 job_summary: type: string job_start_date: type: string maxLength: 10 location_name: type: string maxLength: 255 location_locality: type: string maxLength: 128 location_region: type: string maxLength: 128 location_country: type: string maxLength: 128 location_continent: type: string maxLength: 64 summary: type: string years_experience: type: integer maximum: 32767 minimum: 0 nullable: true inferred_salary: type: string maxLength: 32 connections: type: integer maximum: 2147483647 minimum: 0 nullable: true interests: type: array items: type: string maxLength: 128 languages: type: array items: type: string maxLength: 64 linkedin_url: type: string maxLength: 255 linkedin_username: type: string maxLength: 128 github_url: type: string maxLength: 255 twitter_url: type: string maxLength: 255 skills: type: array items: type: object additionalProperties: {} readOnly: true experiences: type: array items: $ref: '#/components/schemas/Experience' readOnly: true educations: type: array items: $ref: '#/components/schemas/Education' readOnly: true emails: type: array items: type: object additionalProperties: type: string readOnly: true phone_numbers: type: array items: type: string readOnly: true pii_masked: type: boolean readOnly: true required: - current_company - educations - emails - experiences - full_name - headline - id - phone_numbers - pii_masked - skills ProfileList: type: object description: Compact representation used for result cards. properties: id: type: integer readOnly: true full_name: type: string maxLength: 255 headline: type: string readOnly: true job_title: type: string maxLength: 255 job_title_role: type: string description: Coarse job family, e.g. engineering. maxLength: 64 seniority_levels: type: array items: type: string maxLength: 32 description: e.g. ['manager'], ['senior'], ['cxo']. company: type: string readOnly: true default: '' industry: type: string maxLength: 128 location_name: type: string maxLength: 255 location_country: type: string maxLength: 128 years_experience: type: integer maximum: 32767 minimum: 0 nullable: true linkedin_url: type: string maxLength: 255 skills: type: array items: type: string readOnly: true emails: type: array items: type: object additionalProperties: type: string readOnly: true required: - company - emails - full_name - headline - id - skills Register: type: object properties: email: type: string format: email title: Email address maxLength: 254 full_name: type: string maxLength: 150 required: - email RegisterRequest: type: object properties: email: type: string format: email minLength: 1 title: Email address maxLength: 254 full_name: type: string maxLength: 150 password: type: string writeOnly: true minLength: 1 password_confirm: type: string writeOnly: true minLength: 1 required: - email - password - password_confirm RoleEnum: enum: - admin - analyst - viewer type: string description: |- * `admin` - Administrator * `analyst` - Analyst * `viewer` - Viewer School: type: object properties: id: type: integer readOnly: true name: type: string maxLength: 255 type: type: string maxLength: 64 location_name: type: string maxLength: 255 required: - id - name SearchHit: type: object properties: id: type: integer score: type: number format: double full_name: type: string headline: type: string job_title: type: string job_title_role: type: string seniority_levels: type: array items: type: string company: type: string industry: type: string location_name: type: string location_country: type: string years_experience: type: integer nullable: true linkedin_url: type: string skills: type: array items: type: string highlight: type: object additionalProperties: type: array items: type: string required: - company - full_name - headline - highlight - id - industry - job_title - job_title_role - linkedin_url - location_country - location_name - score - seniority_levels - skills - years_experience SearchResponse: type: object properties: count: type: integer page: type: integer page_size: type: integer total_pages: type: integer took_ms: type: integer backend: type: string results: type: array items: $ref: '#/components/schemas/SearchHit' facets: type: object additionalProperties: type: array items: $ref: '#/components/schemas/FacetBucket' required: - backend - count - facets - page - page_size - results - took_ms - total_pages Skill: type: object properties: id: type: integer readOnly: true name: type: string maxLength: 128 slug: type: string maxLength: 140 pattern: ^[-a-zA-Z0-9_]+$ profile_count: type: integer maximum: 2147483647 minimum: 0 description: Denormalised counter used to rank filter suggestions. required: - id - name - slug SuggestResponse: type: object properties: suggestions: type: array items: type: string required: - suggestions TokenObtainPairRequest: type: object description: Adds identity claims to the access token and records an audit event. properties: email: type: string writeOnly: true minLength: 1 password: type: string writeOnly: true minLength: 1 required: - email - password TokenRefresh: type: object properties: access: type: string readOnly: true refresh: type: string required: - access - refresh TokenRefreshRequest: type: object properties: refresh: type: string minLength: 1 required: - refresh User: type: object properties: id: type: integer readOnly: true email: type: string format: email readOnly: true title: Email address full_name: type: string readOnly: true role: allOf: - $ref: '#/components/schemas/RoleEnum' readOnly: true description: |- Determines which fields and actions the user has access to. * `admin` - Administrator * `analyst` - Analyst * `viewer` - Viewer can_view_pii: type: boolean readOnly: true date_joined: type: string format: date-time readOnly: true required: - can_view_pii - date_joined - email - full_name - id - role securitySchemes: jwtAuth: type: http scheme: bearer bearerFormat: JWT