> ## Documentation Index
> Fetch the complete documentation index at: https://docs.goldilocksai.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Jobs

> Stream real-time progress updates for asynchronous operations like searches and profile fetching using Server-Sent Events (SSE). This endpoint provides live updates on job status, current processing stage, and completion status. You'll receive events as the job progresses through different stages, with a final event when the job completes or encounters an error. The stream automatically closes after the final event.

**Important: Retrieving profiles during search**

During the "Aggregate Search Results" stage, you'll receive events containing `search_id` in the metadata whenever a new batch of profiles is matched. Each time you receive this event, you can call `GET /searches/{search_id}/profiles` to retrieve the latest profiles found so far. This allows you to display results progressively to users rather than waiting for the entire search to complete.




## OpenAPI

````yaml GET /jobs/{job_id}/stream
openapi: 3.1.0
info:
  title: Goldilocks AI Developer API
  version: 2.3.0
  description: >
    Natural language-powered professional profile search and enrichment API.


    ## Features

    - **Natural language searches**: Execute searches using plain English

    - **Real-time progress updates**: Stream job progress via Server-Sent Events

    - **Profile enrichment**: Add contact info (email, phone) and professional
    achievements (awards, publications, memberships, patents)


    ## Authentication

    All endpoints require API key authentication using the `X-API-Key` header.


    To obtain an API key:

    1. Log in to the Goldilocks web application

    2. Navigate to API Keys section

    3. Create a new API key with required scopes

    4. Copy the key (shown only once)


    ## Rate Limiting

    - **Searches API**: 10 requests/minute, 3 concurrent requests maximum

    - **Enrichment API**: 20 requests/minute

    - Rate limit headers are included in all responses
  contact:
    name: Goldilocks AI Support
    email: chris@goldilocksai.co.uk
    url: https://www.goldilocksai.co.uk/contact
  license:
    name: Proprietary
    url: https://www.goldilocksai.co.uk/terms-and-conditions
servers:
  - url: https://api.goldilocksai.app
    description: Goldilocks AI API
security:
  - ApiKeyAuth: []
tags:
  - name: Searches
    description: >
      Natural language search operations for finding professional profiles.


      Use these endpoints to execute searches, retrieve results, and fetch
      additional profiles.

      All search operations support real-time progress tracking via Server-Sent
      Events (SSE).
  - name: Enrichment
    description: >
      Profile enrichment operations for adding contact information and
      professional achievements.


      **Supported enrichment types**: email, phone, award, publication,
      membership, patent


      **Note**: Only one enrichment type per request. Use separate requests for
      multiple types.
  - name: Jobs
    description: >
      Job status tracking and real-time progress streaming via Server-Sent
      Events (SSE).


      Monitor long-running operations like searches and enrichments in
      real-time.

      Each job is identified by a unique `job_id` returned from the initiating
      operation.
paths:
  /jobs/{job_id}/stream:
    get:
      tags:
        - Jobs
      summary: Stream Job Updates
      description: >
        Stream real-time progress updates for asynchronous operations like
        searches and profile fetching using Server-Sent Events (SSE). This
        endpoint provides live updates on job status, current processing stage,
        and completion status. You'll receive events as the job progresses
        through different stages, with a final event when the job completes or
        encounters an error. The stream automatically closes after the final
        event.


        **Important: Retrieving profiles during search**


        During the "Aggregate Search Results" stage, you'll receive events
        containing `search_id` in the metadata whenever a new batch of profiles
        is matched. Each time you receive this event, you can call `GET
        /searches/{search_id}/profiles` to retrieve the latest profiles found so
        far. This allows you to display results progressively to users rather
        than waiting for the entire search to complete.
      operationId: streamJobUpdates
      parameters:
        - name: job_id
          in: path
          required: true
          description: Unique identifier of the job
          schema:
            type: string
            format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
      responses:
        '200':
          description: SSE stream established successfully
          content:
            text/event-stream:
              schema:
                type: string
                description: >
                  Server-Sent Events stream with job updates.


                  Each event contains a JSON payload with job progress
                  information.

                  Events are sent as they occur during job execution.


                  The stream closes automatically after the final event
                  (is_final: true).
              examples:
                Progress event:
                  summary: Progress update event
                  value: >
                    id: e1234567-e89b-12d3-a456-426614174000

                    event: job_update

                    data:
                    {"event_id":"e1234567-e89b-12d3-a456-426614174000","job_id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2025-12-23T10:30:05.000Z","stage":"Extract
                    Requirements","message":"Extracting requirements from your
                    query","status":"IN_PROGRESS","is_final":false,"metadata":null,"error_details":null}
                Aggregate results (new profiles available):
                  summary: New batch of profiles matched - use search_id to retrieve
                  value: >
                    id: e1234567-e89b-12d3-a456-426614174500

                    event: job_update

                    data:
                    {"event_id":"e1234567-e89b-12d3-a456-426614174500","job_id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2025-12-23T10:30:25.000Z","stage":"Aggregate
                    Search Results","message":"Search results aggregated
                    successfully","status":"COMPLETED","is_final":false,"metadata":{"search_id":"d7b7e1e3-2136-4eb4-872a-8c6dd265d518","new_relevant_profiles":15,"total_relevant_profiles":15},"error_details":null}
                Final event:
                  summary: Final completion event
                  value: >
                    id: e1234567-e89b-12d3-a456-426614174999

                    event: job_update

                    data:
                    {"event_id":"e1234567-e89b-12d3-a456-426614174999","job_id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2025-12-23T10:30:45.000Z","stage":"Complete
                    Processing","message":"Query processing
                    completed","status":"COMPLETED","is_final":true,"metadata":{"search_id":"d7b7e1e3-2136-4eb4-872a-8c6dd265d518"},"error_details":null}
                Error event:
                  summary: Final error event
                  value: >
                    id: e1234567-e89b-12d3-a456-426614175000

                    event: job_update

                    data:
                    {"event_id":"e1234567-e89b-12d3-a456-426614175000","job_id":"550e8400-e29b-41d4-a716-446655440000","timestamp":"2025-12-23T10:30:50.000Z","stage":"Error","message":"A
                    service is temporarily unavailable. Please try again
                    later.","status":"ERROR","is_final":true,"metadata":null,"error_details":{"code":"SERVICE_UNAVAILABLE","message":"A
                    service is temporarily unavailable. Please try again
                    later."}}
        '401':
          $ref: '#/components/responses/401_Unauthorized'
        '403':
          $ref: '#/components/responses/403_Forbidden'
        '404':
          description: Job not found or access denied
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: string
                    example: Job not found or access denied.
              example:
                detail: Job not found or access denied.
      security:
        - ApiKeyAuth: []
components:
  responses:
    401_Unauthorized:
      description: Missing or invalid API key
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            allOf:
              - $ref: '#/components/schemas/APIResponse'
              - type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: 'null'
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        enum:
                          - UNAUTHORIZED
                      message:
                        type: string
                        example: Missing or invalid API key
          example:
            success: false
            data: null
            metadata: null
            error:
              code: UNAUTHORIZED
              message: Missing or invalid API key
            request_id: 550e8400-e29b-41d4-a716-446655440000
            processing_time_ms: 20
    403_Forbidden:
      description: Insufficient permissions or access denied
      headers:
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
      content:
        application/json:
          schema:
            allOf:
              - $ref: '#/components/schemas/APIResponse'
              - type: object
                properties:
                  success:
                    type: boolean
                  data:
                    type: 'null'
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        enum:
                          - FORBIDDEN
                      message:
                        type: string
                        example: >-
                          Access denied. You don't have permission to access
                          this resource.
          example:
            success: false
            data: null
            metadata: null
            error:
              code: FORBIDDEN
              message: >-
                Access denied. You don't have permission to access this
                resource.
            request_id: 550e8400-e29b-41d4-a716-446655440000
            processing_time_ms: 30
  headers:
    X-RateLimit-Limit:
      description: Maximum requests allowed in the time window
      schema:
        type: integer
        example: 10
    X-RateLimit-Remaining:
      description: Requests remaining in current time window
      schema:
        type: integer
        example: 8
    X-RateLimit-Reset:
      description: Unix timestamp when rate limit resets
      schema:
        type: integer
        example: 1703347200
  schemas:
    APIResponse:
      type: object
      required:
        - success
        - request_id
        - processing_time_ms
      properties:
        success:
          type: boolean
          description: Whether the request was successful
          example: true
        data:
          oneOf:
            - $ref: '#/components/schemas/SearchQueryResponse'
            - $ref: '#/components/schemas/SearchProfilesResponse'
            - $ref: '#/components/schemas/EnrichmentResponse'
            - $ref: '#/components/schemas/MoreProfilesJobResponse'
            - type: object
            - type: 'null'
          description: Response data (null for errors)
        metadata:
          oneOf:
            - $ref: '#/components/schemas/SearchProfilesMetadata'
            - $ref: '#/components/schemas/EnrichmentMetadataAPI'
            - type: object
            - type: 'null'
          description: Endpoint-specific metadata
        error:
          oneOf:
            - $ref: '#/components/schemas/ErrorResponse'
            - type: 'null'
          description: Error details (null for success)
        request_id:
          type: string
          format: uuid
          description: Unique request identifier
          example: 550e8400-e29b-41d4-a716-446655440000
        processing_time_ms:
          type: integer
          description: Server processing time in milliseconds
          example: 1234
      description: Standard API response envelope for all endpoints
    SearchQueryResponse:
      type: object
      required:
        - job_id
        - query
        - user_id
      properties:
        job_id:
          type: string
          format: uuid
          description: Job ID for tracking search progress via SSE
          example: 550e8400-e29b-41d4-a716-446655440000
        query:
          type: string
          description: The original query text
          example: Find partnership managers at Google in UK
        user_id:
          type: string
          format: uuid
          description: User ID who initiated the search
          example: 123e4567-e89b-12d3-a456-426614174000
        api_key_id:
          type:
            - string
            - 'null'
          format: uuid
          description: API key ID used for the request (null if not applicable)
          example: abc12345-e89b-12d3-a456-426614174000
      description: Response data for POST /searches/query
    SearchProfilesResponse:
      type: object
      properties:
        summarised_query:
          type:
            - string
            - 'null'
          description: Summarised version of the search query
          example: Software engineers in San Francisco with Python experience
        profiles:
          type: array
          items:
            $ref: '#/components/schemas/ProfileData'
          description: Array of assembled profile objects with relevancy scores
      description: Response data for GET /searches/{search_id}/profiles
    EnrichmentResponse:
      type: object
      required:
        - profiles
      properties:
        profiles:
          type: array
          items:
            $ref: '#/components/schemas/EnrichmentProfileData'
          description: List of enriched profiles with their enrichment data
      description: >-
        Response data for POST /enrichment/profiles. Metadata is returned at the
        envelope level, not nested here.
    MoreProfilesJobResponse:
      type: object
      required:
        - job_id
        - search_id
        - created_at
        - status
        - profiles_requested
        - user_id
      properties:
        job_id:
          type: string
          format: uuid
          description: Job ID for tracking via SSE
          example: 550e8400-e29b-41d4-a716-446655440000
        search_id:
          type: string
          format: uuid
          description: Search ID being updated
          example: d7b7e1e3-2136-4eb4-872a-8c6dd265d518
        created_at:
          $ref: '#/components/schemas/Timestamp'
        user_id:
          type: string
          format: uuid
          description: User ID who initiated the request
          example: 123e4567-e89b-12d3-a456-426614174000
        status:
          type: string
          enum:
            - IN_PROGRESS
          description: Initial job status (always IN_PROGRESS)
          example: IN_PROGRESS
        profiles_requested:
          type: integer
          minimum: 1
          maximum: 200
          description: Number of additional profiles requested
          example: 20
      description: Response data for POST /searches/{search_id}/more-profiles
    SearchProfilesMetadata:
      type: object
      required:
        - results
      properties:
        results:
          type: object
          required:
            - total_profiles
          properties:
            total_profiles:
              type: integer
              minimum: 0
              description: >
                Total number of profiles available for this search.

                Calculated as min(relevant_profile_count,
                requested_profiles_count).

                Represents the actual number of profiles the user can access.
              example: 20
      description: Metadata for GET /searches/{search_id}/profiles
    EnrichmentMetadataAPI:
      type: object
      required:
        - results
      properties:
        results:
          type: object
          required:
            - total_profiles_requested_enrichment
            - total_profiles_enriched
          properties:
            total_profiles_requested_enrichment:
              type: integer
              minimum: 0
              description: Total profiles requested for enrichment
              example: 10
            total_profiles_enriched:
              type: integer
              minimum: 0
              description: Total profiles successfully enriched
              example: 8
            warnings:
              type: array
              items:
                type: object
              description: Warnings about unavailable enrichment types
              default: []
      description: Metadata for POST /enrichment/profiles
    ErrorResponse:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: External-facing error code
          enum:
            - INVALID_INPUT
            - RESOURCE_NOT_FOUND
            - NO_RESULTS_FOUND
            - UNAUTHORIZED
            - FORBIDDEN
            - RATE_LIMIT_EXCEEDED
            - CONFLICT
            - SERVICE_UNAVAILABLE
            - BAD_GATEWAY
            - INTERNAL_ERROR
          example: INVALID_INPUT
        message:
          type: string
          description: Human-readable error message
          example: >-
            Your request contains invalid data. Please check your input and try
            again.
        details:
          type:
            - object
            - 'null'
          additionalProperties: true
          description: Additional error context (e.g., validation errors)
      description: Error details structure
    ProfileData:
      type: object
      additionalProperties: true
      description: |
        Dynamic profile object with assembled data.

        **Core fields** (always present):
        - `people_id` (string, UUID): Profile identifier
        - `full_name` (string): Person's full name
        - `headline` (string): Professional headline
        - `current_company` (string): Current employer
        - `current_position` (string): Current job title
        - `location` (string): Geographic location

        **Relevancy fields** (search context only):
        - `relevancy_score` (integer, 0-100): Relevancy to search query
        - `relevancy_summary` (string): Why this profile matches

        **Enrichment fields** (when requested):
        - `email` (array): Email addresses with priority
        - `phone` (array): Phone numbers with type and priority
        - `award` (array): Professional awards
        - `publication` (array): Publications
        - `membership` (array): Professional memberships
        - `patent` (array): Patents

        **Note**: Only relevant profile fields are included in API responses.
      example:
        people_id: 123e4567-e89b-12d3-a456-426614174000
        full_name: John Doe
        headline: Senior Software Engineer at Tech Corp
        current_company: Tech Corp
        current_position: Senior Software Engineer
        location: San Francisco, CA
        relevancy_score: 85
        relevancy_summary: Strong Python experience with 7 years in San Francisco
    EnrichmentProfileData:
      type: object
      required:
        - people_id
      properties:
        people_id:
          type: string
          format: uuid
          description: Profile identifier
          example: 123e4567-e89b-12d3-a456-426614174000
      additionalProperties: true
      description: |
        Profile with enrichment data. Structure depends on enrichment_type:

        **Email enrichment**:
        - `email` (array): Email addresses with priority

        **Phone enrichment**:
        - `phone` (array): Phone numbers with type and priority

        **Award enrichment**:
        - `award` (array): Professional awards

        **Publication enrichment**:
        - `publication` (array): Publications

        **Membership enrichment**:
        - `membership` (array): Professional memberships

        **Patent enrichment**:
        - `patent` (array): Patents
      example:
        people_id: 123e4567-e89b-12d3-a456-426614174000
        email:
          - email: john.doe@example.com
            priority: 1
    Timestamp:
      type: string
      format: date-time
      description: ISO 8601 timestamp in UTC
      example: '2025-12-23T10:30:00.000Z'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: |
        API key for authentication. Obtain your API key via the web application.

````