openapi: 3.0.3
info:
  title: ProfileGlide
  description: Managed LinkedIn data API using reliable scraping infrastructure.
  version: 1.0.0
servers:
  - url: /
    description: Configure host
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key or JWT
  schemas:
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            request_id:
              type: string
            retry_after:
              type: number
          required:
            - code
            - message
      required:
        - error
    RunInputKeywords:
      type: object
      properties:
        keywords:
          type: string
          minLength: 1
          maxLength: 500
      required:
        - keywords
    RunInputIdentifier:
      type: object
      properties:
        identifier:
          type: string
          minLength: 1
          maxLength: 500
      required:
        - identifier
    RunInputSocialId:
      type: object
      properties:
        social_id:
          description: Exact social_id returned by profile posts or post search; do not derive it from an activity ID.
          type: string
          minLength: 1
          maxLength: 500
      required:
        - social_id
    RunInputStandardPerson:
      type: object
      additionalProperties: false
      required: [first_name, last_name, company]
      properties:
        first_name:
          type: string
          minLength: 1
          maxLength: 100
        last_name:
          type: string
          minLength: 1
          maxLength: 100
        company:
          type: string
          minLength: 1
          maxLength: 200
          description: Exact current company name or company ID.
        linkedin_profile_url:
          type: string
          format: uri
          maxLength: 500
          pattern: '^https://(?:www\.)?linkedin\.com/in/[^/?#]+/?$'
          description: Optional disambiguator matched only against search results; never visited.
    RunInputCompanyEmployees:
      type: object
      required: [company]
      properties:
        company:
          type: string
          minLength: 1
          maxLength: 200
          description: Company name or Sales Navigator company ID.
        keywords:
          type: string
          maxLength: 200
    RunInputSchoolAlumni:
      type: object
      required: [school]
      properties:
        school:
          type: string
          minLength: 1
          maxLength: 200
          description: School name or LinkedIn school ID.
        keywords:
          type: string
          maxLength: 200
    RunInputGroupMembers:
      type: object
      required: [group_id]
      properties:
        group_id:
          type: string
          minLength: 1
          maxLength: 100
          description: LinkedIn group ID.
    RunInputQuery:
      type: object
      required: [query]
      properties:
        query:
          type: string
          minLength: 1
          maxLength: 200
          description: Search query for entity parameter resolution.
    RunInput:
      oneOf:
        - $ref: '#/components/schemas/RunInputStandardPerson'
        - $ref: '#/components/schemas/RunInputKeywords'
        - $ref: '#/components/schemas/RunInputIdentifier'
        - $ref: '#/components/schemas/RunInputSocialId'
        - $ref: '#/components/schemas/RunInputCompanyEmployees'
        - $ref: '#/components/schemas/RunInputSchoolAlumni'
        - $ref: '#/components/schemas/RunInputGroupMembers'
        - $ref: '#/components/schemas/RunInputQuery'
    RunStatus:
      type: string
      enum:
        - queued
        - processing
        - completed
        - failed
        - cancelled
    RunResponse:
      type: object
      properties:
        id:
          type: string
        action:
          type: string
        status:
          $ref: '#/components/schemas/RunStatus'
        output:
          type: array
          items: {}
        credits_used:
          type: integer
        credits_reserved:
          type: integer
        created_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
          nullable: true
        completeness:
          type: object
          properties:
            has_more:
              type: boolean
            scope:
              type: string
          required:
            - has_more
            - scope
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
          required:
            - code
            - message
      required:
        - id
        - action
        - status
        - output
        - credits_used
        - credits_reserved
        - created_at
        - completeness
    ApiKeyResponse:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        prefix:
          type: string
        created_at:
          type: string
          format: date-time
      required:
        - id
        - name
        - prefix
        - created_at
  responses:
    BadRequest:
      description: Bad Request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Not Found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Conflict:
      description: Conflict
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    TooManyRequests:
      description: Rate Limit Exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalError:
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
security:
  - bearerAuth: []
paths:
  /v1/actions:
    get:
      operationId: listActions
      summary: List available extraction actions
      description: Returns the list of all supported action IDs, their input keys, credit costs, and pagination limits.
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  actions:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        input_keys:
                          type: array
                          items:
                            type: string
                          description: Required input field names. Standard person lookup also accepts optional linkedin_profile_url.
                        input_key:
                          type: string
                        credits_per_record:
                          type: integer
                        max_results:
                          type: integer
                      required:
                        - id
                        - input_key
                        - credits_per_record
                        - max_results
                required:
                  - actions
  /v1/actions/{action}/run/live:
    post:
      operationId: executeLiveRun
      summary: Execute a synchronous scrape action
      description: Run a live data extraction request. Blocks until scrape is completed or lease timeouts.
      parameters:
        - name: action
          in: path
          required: true
          schema:
            type: string
            enum:
              - salesnavigator-search-person
              - salesnavigator-search-people
              - salesnavigator-search-company-employees
              - salesnavigator-search-company-metrics
              - salesnavigator-search-companies
              - linkedin-search-companies
              - linkedin-search-schools
              - linkedin-search-groups
              - linkedin-extract-school-alumnis
              - linkedin-extract-group-members
              - linkedin-extract-people
              - linkedin-extract-company
              - linkedin-extract-people-post-activity
              - linkedin-search-content
              - linkedin-extract-post-commenters
              - linkedin-extract-post-likers
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: '^[a-zA-Z0-9_:-]+$'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                input:
                  $ref: '#/components/schemas/RunInput'
                max_results:
                  type: integer
                  minimum: 1
                  maximum: 100
                max_credits:
                  type: integer
                  minimum: 1
                  maximum: 300000
              required:
                - input
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunResponse'
        "202":
          description: Queued or Processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunResponse'
        "400":
          $ref: '#/components/responses/BadRequest'
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
        "404":
          $ref: '#/components/responses/NotFound'
        "409":
          $ref: '#/components/responses/Conflict'
        "429":
          $ref: '#/components/responses/TooManyRequests'
        "500":
          $ref: '#/components/responses/InternalError'
  /v1/actions/{action}/run/async:
    post:
      operationId: executeAsyncRun
      summary: Queue an asynchronous scrape action
      description: Enqueues a data extraction request for background execution.
      parameters:
        - name: action
          in: path
          required: true
          schema:
            type: string
            enum:
              - salesnavigator-search-person
              - salesnavigator-search-people
              - salesnavigator-search-company-employees
              - salesnavigator-search-company-metrics
              - salesnavigator-search-companies
              - linkedin-search-companies
              - linkedin-search-schools
              - linkedin-search-groups
              - linkedin-extract-school-alumnis
              - linkedin-extract-group-members
              - linkedin-extract-people
              - linkedin-extract-company
              - linkedin-extract-people-post-activity
              - linkedin-search-content
              - linkedin-extract-post-commenters
              - linkedin-extract-post-likers
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: '^[a-zA-Z0-9_:-]+$'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                input:
                  $ref: '#/components/schemas/RunInput'
                max_results:
                  type: integer
                  minimum: 1
                  maximum: 100
                max_credits:
                  type: integer
                  minimum: 1
                  maximum: 300000
              required:
                - input
      responses:
        "200":
          description: Success (Idempotent replay of a completed run)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunResponse'
        "202":
          description: Queued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunResponse'
        "400":
          $ref: '#/components/responses/BadRequest'
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
        "404":
          $ref: '#/components/responses/NotFound'
        "409":
          $ref: '#/components/responses/Conflict'
        "429":
          $ref: '#/components/responses/TooManyRequests'
        "500":
          $ref: '#/components/responses/InternalError'
  /v1/runs:
    get:
      operationId: listRuns
      summary: List runs
      description: "List recent API runs."
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  runs:
                    type: array
                    items:
                      $ref: '#/components/schemas/RunResponse'
                required:
                  - runs
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
  /v1/runs/{id}:
    get:
      operationId: getRun
      summary: Get run status
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunResponse'
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
        "404":
          $ref: '#/components/responses/NotFound'
  /v1/runs/{id}/outputs:
    get:
      operationId: getRunOutputs
      summary: Get run outputs
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  run_id:
                    type: string
                  status:
                    $ref: '#/components/schemas/RunStatus'
                  output:
                    type: array
                    items: {}
                  completeness:
                    type: object
                    properties:
                      has_more:
                        type: boolean
                      scope:
                        type: string
                    required:
                      - has_more
                      - scope
                required:
                  - run_id
                  - status
                  - output
                  - completeness
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
        "404":
          $ref: '#/components/responses/NotFound'
  /v1/runs/{id}/cancel:
    post:
      operationId: cancelRun
      summary: Cancel run
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RunResponse'
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
        "404":
          $ref: '#/components/responses/NotFound'
        "409":
          $ref: '#/components/responses/Conflict'
  /v1/workspace:
    get:
      operationId: getWorkspace
      summary: Get workspace and credit balance
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  workspace_id:
                    type: string
                  name:
                    type: string
                  credits_balance:
                    type: integer
                  credits_reserved:
                    type: integer
                  usage_today:
                    type: object
                    properties:
                      profiles:
                        type: integer
                      sales_nav_lines:
                        type: integer
                    required:
                      - profiles
                      - sales_nav_lines
                required:
                  - workspace_id
                  - name
                  - credits_balance
                  - credits_reserved
                  - usage_today
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
  /v1/keys:
    get:
      operationId: listKeys
      summary: List API keys
      description: Returns up to 100 recent API keys.
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                type: object
                properties:
                  keys:
                    type: array
                    items:
                      allOf:
                        - $ref: '#/components/schemas/ApiKeyResponse'
                        - type: object
                          properties:
                            revoked_at:
                              type: string
                              format: date-time
                              nullable: true
                required:
                  - keys
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: createKey
      summary: Create API key
      description: Generates a new API key. The secret is only returned once.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                  maxLength: 100
              required:
                - name
      responses:
        "200":
          description: Success
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ApiKeyResponse'
                  - type: object
                    properties:
                      api_key:
                        type: string
                    required:
                      - api_key
        "400":
          $ref: '#/components/responses/BadRequest'
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
  /v1/keys/{id}:
    delete:
      operationId: revokeKey
      summary: Revoke API key
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "204":
          description: No Content
        "401":
          $ref: '#/components/responses/Unauthorized'
        "403":
          $ref: '#/components/responses/Forbidden'
        "404":
          $ref: '#/components/responses/NotFound'