openapi: 3.0.1
info:
  title: Genway Public API
  version: 1.0.0
  description: >-
    Genway's API enables you to programmatically manage various aspects of your
    projects, prototypes, and interviews using our AI interviewer.


    - **Projects** - Create and manage Contextual Interviews or Prototype
    Testing projects.

    - **Interviews** - Manage and export interview data, including transcripts,
    summaries, audio, and video.


    ![Genway API overview](./images/flow.png)


    ## Authentication


    Genway API uses **dual-header authentication** for all requests to ensure
    secure access and proper tenant isolation.


    **Required Headers:**

    ```

    X-Api-Key: YOUR_API_KEY

    X-Tenant-Id: YOUR_TENANT_UUID

    ```


    Both headers are mandatory for every API call. Missing either header will
    result in authentication failure.


    ## Versioning and stability


    We strongly aim for backward compatibility for the documented endpoints. If
    backwards-incompatible changes are made, we will aim to release a new
    version.


    - URLs’ entry point is `https://api.genway.ai/`.

    - URLs are versioned `https://api.genway.ai/v1/{endpoint}`, e.g.
    `https://api.genway.ai/v1/projects`.


    ## Rate limits and API status


    The Genway API enforces per-IP rate limits to keep the platform responsive:


    | **Scope** | **Limit** | **Endpoints / Examples** |

    |-----------|-----------|--------------------------|

    | Global throughput | Up to 50 requests per minute per IP | Applies to every
    endpoint, including [Export interview
    video](#tag/Interviews/operation/exportInterviewVideo) and [Activate
    project](#tag/Projects/operation/activateProject). |

    | Project creation | 10 requests per minute per IP | [Create a new
    project](#tag/Projects/operation/createProject) (`POST /projects`). |


    When a limit is exceeded the API responds with `429 Too Many Requests`,
    includes a `Retry-After` header indicating when you can resume sending
    requests, and returns the rate-limit payload documented in the `429`
    response example for endpoints such as [Create a new
    project](#tag/Projects/operation/createProject).


    You can subscribe to our [status page](https://genway.instatus.com/).


    ## API support


    If you require help you can contact our support team at
    [support@genway.ai](mailto:support@genway.ai).
servers:
  - url: https://api.genway.ai/v1
    description: Production environment
security:
  - api_key: []
    tenant_id: []
tags:
  - name: Multi-Tenancy
    description: >-
      Genway provides a secure tenant-based authentication system that ensures
      strong data isolation between customers.


      ## Getting Started with Multi-Tenancy


      1. **Create a Tenant**: Use the [tenant creation
      endpoint](#operation/createTenant) to get your credentials

      2. **Test the Platform**: Use our standard onboarding to familiarize
      yourself with Genway's features

      3. **Review API Documentation**: Identify the endpoints needed for your
      integration


      For enterprise and partnership setup and support, contact us at
      [support@genway.ai](mailto:support@genway.ai).


      ## API Key Types


      Genway uses API keys with different scopes for different purposes:


      1. **Partnership API Keys**
         - Used exclusively for creating new tenants via the [tenant creation endpoint](#operation/createTenant)
         - Provided manually by the Genway team for partners and enterprises

      2. **Standard Tenant API Keys**
         - Used for all regular API operations (projects, interviews, webhooks, etc.)
         - Generated automatically when a tenant is created
         - Each tenant receives their own unique API key for data isolation

      ## Tenant Creation


      **Partnership Key Requirement**

      - Tenant creation requires a special Partnership Key provided by the
      Genway team

      - Contact [support@genway.ai](mailto:support@genway.ai) to obtain your
      partnership key

      - This key is generated manually and is required for the [tenant creation
      endpoint](#operation/createTenant)


      **Automated Tenant Creation**

      - Use the [tenant creation endpoint](#operation/createTenant) to
      programmatically create new tenants

      - Include the partnership API key in the `X-Api-Key` header

      - Each tenant receives a unique `TENANT_ID` and corresponding
      `TENANT_API_KEY`

      - Keys do not expire and are unique per tenant


      ## Security & Data Isolation


      - **1:1 Mapping**: Each `TENANT_API_KEY` is strictly matched to its
      corresponding `TENANT_ID`

      - **Dual Header Verification**: Both headers act as security layers for
      all operations

      - **Tenant Isolation**: Prevents data leakage and misuse between different
      tenants

      - **Validation**: Mismatched keys and tenant IDs will result in
      authentication failure
  - name: Tenants
    description: Manage tenant creation and multi-tenancy setup.
  - name: Projects
    description: Manage your projects programmatically.
  - name: Interviews
    description: Manage and export interview data.
  - name: Webhooks
    description: >-
      Webhooks deliver event data to your applications as it happens, offering
      an alternative to frequent data polling.


      - The `secret` created via the `/webhooks/secrets` endpoint is permanent
      and should be stored securely in your system. This secret will serve for
      the [verifying section](#tag/Webhooks/Verifying).

      - The `x-hook-secret` is temporary and should be used only once during the
      confirmation process.

      - Until the webhook is confirmed, no events will be sent to the
      subscriber's endpoint.



      ## Subscribing


      ### Flow Diagram

      The flow below shows the inbound nature of hook configuration. This is
      what is required to register your subscription.


      ![Genway Webhooks Flow](./images/webhooks_flow.png)


      ### Double Opt-In (DOI)

      We use a Double Opt-In (DOI) approach for webhooks to prevent abuse,
      misconfigurations, and unintended subscriptions. This mechanism ensures
      that the webhook consumer explicitly confirms their intent to receive
      webhook events before we start sending them.


      ### Listing event types

      To get started, make a `GET` request to `/webhooks/event-types` to
      retrieve an up-to-date list of all the event types that we currently
      support. All event types will follow the `noun.verb` pattern, e.g.
      `project.published`.


      Make a note of the event type you’d like to subscribe to. You’ll need this
      later when setting up a subscription.


      ### Creating a secret

      In order to subscribe to an event, you’ll need to first set up a secret.
      Secrets are used to verify the authenticity of our webhook requests to
      your system. It allows you to prove we have sent them and the payload
      hasn't been fiddled with. There is more about that in the Verifying
      section below.


      Make a `POST` request to `/webhooks/secrets/` with the payload below. This
      will create a new secret for your workspace and be returned in the
      response body. Keep this safe, and note that you can only have one active
      secret per workspace at a time.


      ```json

      {"workspace_id": <workspace_id>}

      ```


      ### Subscribing to an event (Opt-In Step 1)

      Next, make a `POST` request to `/webhooks/subscriptions/` with the payload
      below to subscribe to your desired event.


      **Note.** `<target_url>` must be use `https://` and be publicly accessible
      i.e. **not** `https://localhost`.


      ```json

      {"workspace_id": <workspace_id>, "event_type": <event_type>, "target_url":
      <target_url>}

      ```


      If successful, the endpoint will return a response that includes:


      1. An `id` field in the body - This is the unique identifier for your
      subscription.

      2. An `X-Hook-Secret` header - Used to confirm your intention to subscribe
      to the desired event type.


      Make a note of both the id and the X-Hook-Secret. We’ll use these to
      confirm our intention to subscribe to the desired event type.


      ### Confirming the subscription (Opt-In Step 2)

      Make a `POST` request to `/webhooks/subscriptions/<subscription_id>/` with
      the payload below. Replace `<x-hook-secret>` with the value of the
      X-Hook-Secret header in the previous subscription request.


      ```json

      {"secret": <x-hook-secret>}

      ```


      If subscription confirmation is successful, you should receive a `200`
      status code.


      ## Receiving


      Having successfully subscribed to our desired event type, our target url
      will be notified each and every time the associated event is triggered.
      You can react to this event in any way you see fit. The response body will
      adhere to the following structure:


      ### project.published

      ```json

      {
        "project_id": "<project_id>",
        "published_at": "<published_at>",
      }

      ```


      | Field           |
      Description                                                                   
      |

      |-----------------|--------------------------------------------------------------------------------|

      | project_id      | The unique identifier of the project
      resource.                                 |

      | event_type      | The type of event
      `project.published`.                                         |

      | published_at    | The timestamp when the project was
      published.                                  |


      ---


      ### project.completed

      ```json

      {
        "project_id": "<project_id>",
        "completed_at": "<completed_at>",
      }

      ```


      | Field           |
      Description                                                                   
      |

      |-----------------|--------------------------------------------------------------------------------|

      | project_id      | The unique identifier of the project
      resource.                                 |

      | event_type      | The type of event
      `project.completed`.                                         |

      | completed_at    | The timestamp when the project was
      completed.                                  |


      ---


      ### interview.finished

      ```json

      {
        "project_id": "<project_id>",
        "interview_id": "<interview_id>",
        "interviewee_id": "<interviewee_id>",
        "finished_at": "<finished_at>",
      }

      ```


      | Field           |
      Description                                                                   
      |

      |-----------------|--------------------------------------------------------------------------------|

      | project_id      | The unique identifier of the project
      resource.                                 |

      | event_type      | The type of event
      `interview.finished`.                                        |

      | interview_id    | The unique identifier for the
      interview.                                       |

      | interviewee_id  | The unique identifier of the
      interviewee.                                      |

      | finished_at     | The timestamp when the interviewee finished the
      interview.                     |


      ## Responding to events

      When developing your system to handle incoming webhooks, it is crucial to
      respond with a 200 status code within 20 seconds to avoid timeouts and
      retries.


      If your processing logic involves long-running tasks, it is recommended to
      handle these tasks asynchronously. This ensures that the webhook endpoint
      can quickly acknowledge receipt of the event, while the actual processing
      is offloaded to a separate service. By doing so, you can maintain
      responsiveness and reliability in your webhook handling system.


      ## Event Error Handling

      In the case of a network error or a non-200 response, our system will
      retry the event another 2 times.


      The first retry will occur after 1 minute, and if it fails again, the
      second retry will occur after an additional 2 minutes with a full jitter.
      This approach ensures that transient issues are handled gracefully, while
      also preventing overwhelming the system with immediate retries.


      Here is an example table with timestamps when the events will happen:


      | Attempt | Timestamp          | Delay   |

      |---------|--------------------|---------|

      | Initial | 2023-10-01 12:00:00| -       |

      | Retry 1 | 2023-10-01 12:01:00| 1 minute|

      | Retry 2 | 2023-10-01 12:03:00| 2 minutes|


      In this example, the initial event occurs at 12:00:00. If it fails, the
      first retry happens at 12:01:00, and if it fails again, the second retry
      happens at 12:03:00.


      ## Idempotency and the X-Event-ID Header

      `X-Event-ID` is added as a header to the request. It is a unique
      identifier assigned to each event.


      - **Uniqueness**: Each `X-Event-ID` value will be globally unique for each
      event that occurs.

      - **Re-Delivery**: Events are delivered **at least once**. We will
      redeliver events on failure due to network issues, timeouts and listener
      errors. The `X-Event-ID` will remain the same across retries.

      - **Idempotent Processing**: We recommend that you use the `X-Event-ID` to
      handle events in an idempotent way. If you encounter the same `X-Event-ID`
      again, simply skip and acknowledge the duplicate event rather than
      processing it a second time.


      ## Handling event order with X-Timestamp

      The `X-Timestamp` header is added to the request. It contains a UNIX
      timestamp indicating when the event was sent.


      You can use this timestamp to determine if you are processing an
      out-of-order update. In some cases, you may want to ignore older events
      and only process the latest event.


      As a webhook system, we do not guarantee the order of events. This can be
      affected by multiple factors such as errors sending events and retrying
      after a delay, where a newer event may have already been sent.


      ## Verifying


      Webhooks have been implemented to provide a measure to verify the
      authenticity of a payload. This helps to ensure only payloads sent by
      Genway are being accepted by your endpoint. Hook requests will contain two
      headers, `X-Genway-Request-Signature` and `X-Genway-Request-Timestamp`.
      The former represents signature and the latter represents a UNIX timestamp
      of when the request was sent.


      In order to verify the signature, you can create the same SHA256 Hashed
      Message Authentication Code (HMAC) signature and then compare it to
      `X-Genway-Request-Signature`. To do this, sign the request body and
      timestamp with your secret key using SHA256 and then base64 encode the
      resulting digest.


      ### Example with Python


      ```python

      import hmac

      import hashlib

      import base64

      import json


      SECRET = 'your_secret_key'

      timestamp = request.headers.get('X-Genway-Request-Timestamp')  # from
      request headers

      signature = request.headers.get('X-Genway-Request-Signature')  # from
      request headers

      body = request.get_json()  # from request body


      encoded_secret = SECRET.encode()

      body = json.dumps(body)

      calculated_signature = base64.b64encode(
          hmac.new(
              encoded_secret,
              str.encode(timestamp + body),
              hashlib.sha256
          ).digest()
      )

      is_valid = hmac.compare_digest(
          calculated_signature, str.encode(signature)
      )

      print(is_valid)

      ```
  - name: Errors
    description: >-
      The Genway API uses standard HTTP response codes to indicate the success
      or failure of the request. Codes follow this pattern:


      - 2xx codes indicate success.

      - 4xx codes indicate a request that failed given the information provided
      (e.g., a required parameter was omitted).

      - 5xx codes indicate an error with Genway's platform.


      ## Error codes

      | Code |
      Description                                                                                                                                 
      |

      | ---- |
      --------------------------------------------------------------------------------------------------------------------------------------------
      |

      | 400  | Bad Request - The request was unacceptable. Check the response
      for more
      details.                                                             |

      | 401  | Unauthorized - No valid token was
      provided.                                                                                                 
      |

      | 403  | Forbidden - You do not have access to this
      resource.                                                                                        
      |

      | 404  | Not Found - The resource does not
      exist.                                                                                                    
      |

      | 405  | Method Not Allowed - You tried to access a resource with an
      invalid
      method.                                                                  |

      | 422  | Unprocessable entity - A validation error on a well-formed
      request. Check the response for more
      details.                                     |

      | 429  | Too many requests - You have sent too many requests (either in
      general, for a resource or for a related resource) in a given amount of
      time. |


      If the error is unclear or none of the above applies, please contact our
      support team at [support@genway.ai](mailto:support@genway.ai).
paths:
  /tenants:
    post:
      tags:
        - Tenants
      summary: Create a new tenant
      description: >-
        Create a new tenant with automatic API key provisioning. This endpoint
        creates a unique tenant with its own isolated data space and dedicated
        API credentials.


        **Authentication**: This endpoint requires a special Partnership API Key
        (starts with `sk-partner-`) with the `tenants:create` scope. The
        partnership key is passed via the standard `x-api-key` header along with
        the tenant ID that owns the partnership key.


        **Required Headers:**

        - `X-Api-Key: sk-partner-...` (Partnership key provided by Genway
        team)  

        - `X-Tenant-Id: YOUR_TENANT_UUID` (Tenant UUID that owns the partnership
        key)


        Contact [support@genway.ai](mailto:support@genway.ai) to obtain your
        partnership key.
      operationId: createTenant
      security:
        - api_key: []
          tenant_id: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - organization_name
                - contact_email
              properties:
                organization_name:
                  type: string
                  description: Name of the organization/customer
                  example: Acme Corporation
                contact_email:
                  type: string
                  format: email
                  description: Primary contact email for this tenant
                  example: admin@acme.com
                description:
                  type: string
                  description: Optional description of the tenant/organization
                  example: Enterprise customer for user research platform
      responses:
        '201':
          description: Tenant created successfully
          content:
            application/json:
              schema:
                type: object
                required:
                  - tenant_id
                  - api_key
                  - organization_name
                  - contact_email
                  - created_at
                properties:
                  tenant_id:
                    type: string
                    format: uuid
                    description: Unique identifier for the tenant
                    example: 123e4567-e89b-12d3-a456-426614174000
                  api_key:
                    type: string
                    description: Unique API key for this tenant (store securely)
                    example: gw_live_123abc456def789ghi012jkl345mno678pqr
                  organization_name:
                    type: string
                    example: Acme Corporation
                  contact_email:
                    type: string
                    format: email
                    example: admin@acme.com
                  description:
                    type: string
                    nullable: true
                    example: Enterprise customer for user research platform
                  created_at:
                    type: string
                    format: date-time
                    example: '2025-06-29T10:30:00Z'
        '400':
          description: Bad request - Invalid input data
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: Invalid email format
                  message:
                    type: string
                    example: The provided email address is not in a valid format
        '401':
          description: Unauthorized - Invalid or missing partnership key
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: Unauthorized
                  message:
                    type: string
                    example: >-
                      Invalid or missing partnership key. Contact
                      support@genway.ai to obtain a valid partnership key.
        '409':
          description: Conflict - Organization already exists
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: Organization already exists
                  message:
                    type: string
                    example: A tenant with this organization name already exists
        '429':
          $ref: '#/components/responses/429'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: Internal server error
                  message:
                    type: string
                    example: An unexpected error occurred while creating the tenant
  /projects:
    post:
      tags:
        - Projects
      summary: Create a new project
      description: |-
        Create a new project (Contextual Interview)

        **Note:** Prototype Testing projects creation is not yet supported.
      operationId: createProject
      security:
        - api_key: []
          tenant_id: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/ContextualInterviewProject'
                - $ref: '#/components/schemas/PrototypeTestingProject'
      responses:
        '201':
          description: Project created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  project_id:
                    type: string
                    format: uuid
                    example: 123e4567-e89b-12d3-a456-426614174000
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/429'
  /projects/{project_id}:
    patch:
      tags:
        - Projects
      summary: Update project details
      description: Update the details of a project by its projectId.
      operationId: updateProjectDetails
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: project_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the project to update
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateContextualInterviewProject'
      responses:
        '200':
          description: Project details updated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  project_id:
                    type: string
                    format: uuid
                    example: 123e4567-e89b-12d3-a456-426614174000
        '404':
          description: Project not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: not_found
                      message:
                        type: string
                        example: Project not found.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /projects/{project_id}/activate:
    post:
      tags:
        - Projects
      summary: Publish/resume a project
      description: Publish or resume a project
      operationId: activateProject
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: project_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the project to activate
      responses:
        '200':
          description: Project activated successfully
        '404':
          description: Project not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: not_found
                      message:
                        type: string
                        example: Project not found.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /projects/{project_id}/deactivate:
    post:
      tags:
        - Projects
      summary: Pause a project
      description: >-
        Pause an active project, making it inactive. This is useful for
        temporarily halting a project.
      operationId: deactivateProject
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: project_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the project to deactivate
      responses:
        '200':
          description: Project deactivated successfully
        '404':
          description: Project not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: not_found
                      message:
                        type: string
                        example: Project not found.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /projects/{project_id}/interviews-export:
    get:
      tags:
        - Projects
      summary: Export all interviews transcripts and summaries
      description: Export all interviews transcripts and summaries for a specific project.
      operationId: exportInterviews
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: project_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the project
      responses:
        '200':
          description: Export successful
          content:
            text/csv:
              schema:
                type: string
                format: binary
                description: >-
                  CSV file containing interview data with the following columns:

                  - interview_id: The unique identifier for the interview

                  - identifier: The identifier for the interviewee (email,
                  user_id, or external_user_id)

                  - country_code: The country code of the interviewee

                  - interview_status: The status of the interview (INITIATED,
                  PARTIAL, COMPLETED)

                  - opt_in_for_followup: Whether the interviewee opted in for
                  follow-up

                  - created_at: Timestamp of when the interview was started

                  - external_metadata: External metadata associated with the
                  interviewee (JSON format)

                  - transcription: Transcription of the interview

                  - interview_summary: Summary of the interview
        '404':
          description: Project not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: not_found
                      message:
                        type: string
                        example: Project not found.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /projects/{project_id}/interviewees-export:
    get:
      tags:
        - Projects
      summary: Export all interviewees' information
      description: >-
        Export all interviewees' information for a specific project as a CSV
        file.
      operationId: exportInterviewees
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: project_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the project
      responses:
        '200':
          description: Export successful
          content:
            text/csv:
              schema:
                type: string
                format: binary
                description: >-
                  CSV file containing interviewee data with the following
                  columns:

                  - interview_id: The unique identifier for the interview.

                  - identifier: The identifier for the interviewee, which can be
                  an email, user_id, or external_user_id.

                  - country_code: The country code of the interviewee.

                  - interview_status: The status of the interview (INITIATED,
                  PARTIAL, COMPLETED).

                  - opt_in_for_followup: Indicates if the interviewee has opted
                  in for follow-up.

                  - created_at: The timestamp when the interview was started.

                  - external_metadata: External metadata associated with the
                  interviewee (JSON format).
        '404':
          description: Project not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: not_found
                      message:
                        type: string
                        example: Project not found.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /projects/{project_id}/url:
    get:
      tags:
        - Projects
      summary: Get project URL for sharing with interviewees
      description: >-
        Get the URL for a project to share with interviewees. Accepts a
        parameter to specify sandbox or production URL.
      operationId: getProjectUrl
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: project_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the project
        - name: environment
          in: query
          required: true
          schema:
            type: string
            enum:
              - sandbox
              - production
          description: >-
            Specify whether the URL should be for a sandbox or production
            interview
      responses:
        '200':
          description: URL retrieved successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  project_id:
                    type: string
                    format: uuid
                    example: 123e4567-e89b-12d3-a456-426614174000
                  url:
                    type: string
                    format: uri
                    example: >-
                      https://app.genway.ai/meet/123e4567-e89b-12d3-a456-426614174000
        '400':
          description: Bad request or project is not active for production URL
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Project not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: not_found
                      message:
                        type: string
                        example: Project not found.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /interviews/{interview_id}/audio-export:
    get:
      tags:
        - Interviews
      summary: Export specific interview audio
      description: Export the audio of a specific interview.
      operationId: exportInterviewAudio
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: interview_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the interview
      responses:
        '200':
          description: Export successful
          content:
            audio/mpeg:
              schema:
                type: string
                format: binary
        '404':
          description: Interview not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: not_found
                      message:
                        type: string
                        example: Interview not found.
        '409':
          description: Audio export is currently in progress
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: audio_export_in_progress
                      message:
                        type: string
                        example: >-
                          Audio export is currently in progress. Please try
                          again later.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying
              schema:
                type: string
              example: '30'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /interviews/{interview_id}/video-export:
    get:
      tags:
        - Interviews
      summary: Export specific interview video
      description: Export the video of a specific interview.
      operationId: exportInterviewVideo
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: interview_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the interview
      responses:
        '200':
          description: Export successful
          content:
            video/mp4:
              schema:
                type: string
                format: binary
        '404':
          description: Interview not found
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: not_found
                      message:
                        type: string
                        example: Interview not found.
        '409':
          description: Video export is currently in progress
          content:
            application/json:
              schema:
                type: object
                properties:
                  detail:
                    type: object
                    properties:
                      error:
                        type: string
                        example: video_export_in_progress
                      message:
                        type: string
                        example: >-
                          Video export is currently in progress. Please try
                          again later.
          headers:
            Retry-After:
              description: Number of seconds to wait before retrying
              schema:
                type: string
              example: '30'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /interviews/{interview_id}/flag:
    post:
      tags:
        - Interviews
      summary: Flag interview as fraud
      description: |-
        ⚠️ **Not Supported** - This endpoint is not currently supported.

        Flag a specific interview as fraud with a reason.
      operationId: flagInterviewAsFraud
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: interview_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: The ID of the interview
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  example: suspicious_behavior_detected
      responses:
        '200':
          description: Interview flagged successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: flagged
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          $ref: '#/components/responses/429'
  /webhooks/event-types:
    get:
      tags:
        - Webhooks
      summary: List event types
      description: >-
        Retrieve an up-to-date list of all the event types that we currently
        support.
      operationId: listEventTypes
      security:
        - api_key: []
          tenant_id: []
      responses:
        '200':
          description: List of event types retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
                  example: project.published
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '429':
          $ref: '#/components/responses/429'
  /webhooks/secrets:
    post:
      tags:
        - Webhooks
      summary: Create a secret
      description: Create a new secret for your workspace.
      operationId: createSecret
      security:
        - api_key: []
          tenant_id: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: string
                  format: uuid
                  example: 4e1b58da-06de-4173-a276-15609442c470
      responses:
        '201':
          description: Secret created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  secret:
                    type: string
                    example: sec_af245ede-a9d0-40b4-9ffc-a4bf11fdfebb
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '429':
          $ref: '#/components/responses/429'
  /webhooks/subscriptions:
    post:
      tags:
        - Webhooks
      summary: Subscribe to an event
      description: Subscribe to your desired event.
      operationId: subscribeToEvent
      security:
        - api_key: []
          tenant_id: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                workspace_id:
                  type: string
                  example: 4e1b58da-06de-4173-a276-15609442c470
                event_type:
                  type: string
                  example: project.published
                target_url:
                  type: string
                  format: uri
                  example: https://yourapp.com/webhook
      responses:
        '201':
          description: Subscription created successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    example: subscription_123
                  x_hook_secret:
                    type: string
                    example: x_hook_secret_value
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '429':
          $ref: '#/components/responses/429'
    get:
      tags:
        - Webhooks
      summary: List all subscriptions
      description: Retrieve a list of all subscriptions.
      operationId: listSubscriptions
      security:
        - api_key: []
          tenant_id: []
      responses:
        '200':
          description: List of subscriptions retrieved successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      example: subscription_123
                    workspace_id:
                      type: string
                      example: workspace_123
                    event_type:
                      type: string
                      example: project.published
                    target_url:
                      type: string
                      format: uri
                      example: https://yourapp.com/webhook
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '429':
          $ref: '#/components/responses/429'
  /webhooks/subscriptions/{subscription_id}:
    post:
      tags:
        - Webhooks
      summary: Confirm subscription
      description: Confirm your intention to subscribe to the desired event type.
      operationId: confirmSubscription
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: subscription_id
          in: path
          required: true
          schema:
            type: string
          description: The ID of the subscription to confirm
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                secret:
                  type: string
                  example: <x-hook-secret>
      responses:
        '200':
          description: Subscription confirmed successfully
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '429':
          $ref: '#/components/responses/429'
    delete:
      tags:
        - Webhooks
      summary: Delete subscription
      description: Delete a subscription by its subscription_id.
      operationId: deleteSubscription
      security:
        - api_key: []
          tenant_id: []
      parameters:
        - name: subscription_id
          in: path
          required: true
          schema:
            type: string
          description: The ID of the subscription to delete
      responses:
        '204':
          description: Subscription deleted successfully
        '400':
          $ref: '#/components/responses/400'
        '401':
          $ref: '#/components/responses/401'
        '403':
          $ref: '#/components/responses/403'
        '404':
          $ref: '#/components/responses/404'
        '429':
          $ref: '#/components/responses/429'
components:
  securitySchemes:
    api_key:
      type: apiKey
      in: header
      name: X-Api-Key
      description: API key for authentication. Use your tenant-specific API key.
    tenant_id:
      type: apiKey
      in: header
      name: X-Tenant-Id
      description: >-
        Required tenant identifier (UUID format). Must match the tenant
        associated with the provided API key.
  schemas:
    ContextualInterviewProject:
      type: object
      required:
        - project_type
        - project_name
        - project_description
        - project_objective
        - research_questions
        - success_criteria
        - recruiting_criteria
      properties:
        project_type:
          type: string
          enum:
            - contextual_interview
          example: contextual_interview
        project_name:
          type: string
          example: The Impact of Formula 1 Excitement on Fan Enthusiasm
        project_description:
          type: string
          example: Forumla 1 - US based fans
        project_objective:
          type: string
          example: >-
            The research on 'The Impact of Formula 1 Excitement on Fan
            Enthusiasm' is crucial for understanding how the thrill of racing
            influences spectator engagement and loyalty. Current insights
            suggest that the suspense and unpredictability of races enhance
            viewer excitement and attachment to the sport. This study aims to
            delve deeper into these aspects, providing strategies to boost fan
            engagement and expand the sport's audience.
        research_questions:
          type: string
          example: >-
            Our primary research questions focus on understanding the impact of
            remote work on employee productivity and well-being. We hope to
            learn how different remote work policies affect job satisfaction and
            efficiency across various industries. Additionally, we aim to
            identify key factors that contribute to a successful remote work
            environment.
        success_criteria:
          type: string
          example: >-
            Success for this project would be clearly evidenced by its direct
            influence on enhancing our product features, refining our design
            aesthetics, and strategically informing our marketing campaigns.
            Ideally, the research findings will provide actionable insights that
            directly correlate with increased user engagement and satisfaction.
            Ultimately, the goal is to leverage this research to drive
            meaningful improvements across all departments, ensuring that every
            decision is data-informed and aligned with our users' needs.
        recruiting_criteria:
          type: string
          example: >-
            For this project, we are targeting participants who fall within the
            30-50 age range, have a background in engineering or product
            management, and are currently employed in the tech industry. We are
            specifically focusing on individuals residing in North America and
            Europe to capture insights from key tech hubs. This demographic and
            customer segment approach ensures that we obtain targeted and
            relevant data for our research objectives.
        specific_guidelines:
          type: string
          nullable: true
          example: >-
            Ask from the participants to mute notifications during the
            interview.
        redirect_url:
          type: string
          format: uri
          pattern: ^https://.*
          nullable: true
          description: HTTPS URL to redirect participants after completing the interview
          example: https://example.com/thank-you
        interview_modes:
          type: array
          items:
            $ref: '#/components/schemas/InterviewMode'
          nullable: true
          default:
            - talking
          description: Interview modes available for participants
          example:
            - typing
            - talking
        camera_access:
          allOf:
            - $ref: '#/components/schemas/CameraAccessType'
          default: not_allowed
          description: Camera access requirements for the interview
          example: optional
        logo_url:
          type: string
          format: uri
          maxLength: 2083
          nullable: true
          default: https://app.genway.ai/assets/images/logoa1.svg
          description: >-
            URL to the organization's logo for branding. Recommended: minimum
            resolution of 160x160px with 1:1 aspect ratio for optimal display.
          example: https://example.com/logo.png
        primary_color:
          type: string
          pattern: ^#[0-9A-F]{6}$
          nullable: true
          default: '#6759DF'
          description: Primary brand color in hex format
          example: '#FF6B35'
        secondary_color:
          type: string
          pattern: ^#[0-9A-F]{6}$
          nullable: true
          default: '#3B337F'
          description: Secondary brand color in hex format
          example: '#004E89'
        text_color:
          type: string
          pattern: ^#[0-9A-F]{6}$
          nullable: true
          default: '#1C1842'
          description: Text color in hex format
          example: '#FFFFFF'
        interview_languages:
          type: array
          items:
            type: string
            enum:
              - en
              - fr
              - de
              - es
              - it
              - ar
              - ru
              - ja
              - he
              - el
              - uk
          nullable: true
          default:
            - en
          description: List of languages supported for the interview using ISO 639-1 codes
          example:
            - en
            - fr
            - es
        interview_length:
          type: integer
          enum:
            - 10
            - 15
            - 20
          nullable: true
          default: 10
          description: Duration of the interview in minutes
          example: 15
    PrototypeTestingTask:
      type: object
      required:
        - header
        - description
        - start_screen_external_id
        - end_screen_external_id
      properties:
        header:
          type: string
          example: Onboarding flow test
        description:
          type: string
          example: Users will navigate the onboarding process.
        start_screen_external_id:
          type: string
          example: screen_123
        end_screen_external_id:
          type: string
          example: screen_456
    Screen:
      type: object
      required:
        - screen_external_id
      properties:
        screen_external_id:
          type: string
          example: screen_001
        specific_questions:
          type: string
          example: What is the main action users take here?
    PrototypeTestingLink:
      type: object
      required:
        - link
        - name
        - version_id
      properties:
        link:
          type: string
          format: uri
          example: https://www.figma.com/proto/mhG9l7fG0mD0V684lblPUJ/
        name:
          type: string
          example: Prototype Test 1
        version_id:
          type: string
          example: v1.0
    PrototypeTestingProject:
      type: object
      description: ⚠️ Not supported yet.
      required:
        - project_type
        - project_name
        - prototype_link
        - task
        - screens
      properties:
        project_type:
          type: string
          enum:
            - prototype_testing
          example: prototype_testing
        project_name:
          type: string
          example: New Onboarding Flow Test
        prototype_link:
          $ref: '#/components/schemas/PrototypeTestingLink'
        task:
          $ref: '#/components/schemas/PrototypeTestingTask'
        screens:
          type: array
          items:
            $ref: '#/components/schemas/Screen'
        specific_guidelines:
          type: string
          example: Ensure all users complete the task within 5 minutes.
        redirect_url:
          type: string
          format: uri
          pattern: ^https://.*
          nullable: true
          description: HTTPS URL to redirect participants after completing the interview
          example: https://example.com/thank-you
    UpdateContextualInterviewProject:
      type: object
      properties:
        project_name:
          type: string
          nullable: true
          example: The Impact of Formula 1 Excitement on Fan Enthusiasm
        project_description:
          type: string
          nullable: true
          example: Forumla 1 - US based fans
        project_objective:
          type: string
          nullable: true
          example: >-
            The research on 'The Impact of Formula 1 Excitement on Fan
            Enthusiasm' is crucial for understanding how the thrill of racing
            influences spectator engagement and loyalty. Current insights
            suggest that the suspense and unpredictability of races enhance
            viewer excitement and attachment to the sport. This study aims to
            delve deeper into these aspects, providing strategies to boost fan
            engagement and expand the sport's audience.
        research_questions:
          type: string
          nullable: true
          example: >-
            Our primary research questions focus on understanding the impact of
            remote work on employee productivity and well-being. We hope to
            learn how different remote work policies affect job satisfaction and
            efficiency across various industries. Additionally, we aim to
            identify key factors that contribute to a successful remote work
            environment.
        success_criteria:
          type: string
          nullable: true
          example: >-
            Success for this project would be clearly evidenced by its direct
            influence on enhancing our product features, refining our design
            aesthetics, and strategically informing our marketing campaigns.
            Ideally, the research findings will provide actionable insights that
            directly correlate with increased user engagement and satisfaction.
            Ultimately, the goal is to leverage this research to drive
            meaningful improvements across all departments, ensuring that every
            decision is data-informed and aligned with our users' needs.
        recruiting_criteria:
          type: string
          nullable: true
          example: >-
            For this project, we are targeting participants who fall within the
            30-50 age range, have a background in engineering or product
            management, and are currently employed in the tech industry. We are
            specifically focusing on individuals residing in North America and
            Europe to capture insights from key tech hubs. This demographic and
            customer segment approach ensures that we obtain targeted and
            relevant data for our research objectives.
        specific_guidelines:
          type: string
          nullable: true
          example: >-
            Ask from the participants to mute notifications during the
            interview.
        redirect_url:
          type: string
          format: uri
          pattern: ^https://.*
          nullable: true
          description: HTTPS URL to redirect participants after completing the interview
          example: https://example.com/thank-you
        interview_modes:
          type: array
          items:
            $ref: '#/components/schemas/InterviewMode'
          nullable: true
          description: Interview modes available for participants
          example:
            - typing
            - talking
        camera_access:
          allOf:
            - $ref: '#/components/schemas/CameraAccessType'
          description: Camera access requirements for the interview
          example: optional
        logo_url:
          type: string
          format: uri
          maxLength: 2083
          nullable: true
          description: >-
            URL to the organization's logo for branding. Recommended: minimum
            resolution of 160x160px with 1:1 aspect ratio for optimal display.
          example: https://example.com/logo.png
        primary_color:
          type: string
          pattern: ^#[0-9A-F]{6}$
          nullable: true
          description: Primary brand color in hex format
          example: '#FF6B35'
        secondary_color:
          type: string
          pattern: ^#[0-9A-F]{6}$
          nullable: true
          description: Secondary brand color in hex format
          example: '#004E89'
        text_color:
          type: string
          pattern: ^#[0-9A-F]{6}$
          nullable: true
          description: Text color in hex format
          example: '#FFFFFF'
        interview_languages:
          type: array
          items:
            type: string
            enum:
              - en
              - fr
              - de
              - es
              - it
              - ar
              - ru
              - ja
              - he
              - el
              - uk
          nullable: true
          description: List of languages supported for the interview using ISO 639-1 codes
          example:
            - en
            - fr
            - es
        interview_length:
          type: integer
          enum:
            - 10
            - 15
            - 20
          nullable: true
          description: Duration of the interview in minutes
          example: 15
    UpdatePrototypeTestingProject:
      type: object
      required:
        - project_name
        - prototype_link
        - task
        - screens
      properties:
        project_name:
          type: string
          example: Updated Prototype Testing Project Name
        prototype_link:
          $ref: '#/components/schemas/PrototypeTestingLink'
        task:
          $ref: '#/components/schemas/PrototypeTestingTask'
        screens:
          type: array
          items:
            $ref: '#/components/schemas/Screen'
        specific_guidelines:
          type: string
          example: Updated Specific Guidelines
        redirect_url:
          type: string
          format: uri
          pattern: ^https://.*
          nullable: true
          description: HTTPS URL to redirect participants after completing the interview
          example: https://example.com/thank-you
    InterviewMode:
      type: string
      enum:
        - typing
        - talking
      description: Available interview modes for participants
    CameraAccessType:
      type: string
      enum:
        - not_allowed
        - optional
        - required
      description: Camera access requirements for interviews
    Error:
      type: object
      properties:
        message:
          type: string
          example: Invalid request parameters.
        code:
          type: integer
          example: 400
    HTTPValidationError:
      type: object
      properties:
        detail:
          type: array
          items:
            $ref: '#/components/schemas/ValidationError'
          title: Detail
      title: HTTPValidationError
    ValidationError:
      type: object
      properties:
        loc:
          type: array
          items:
            anyOf:
              - type: string
              - type: integer
          title: Location
        msg:
          type: string
          title: Message
          example: field required
        type:
          type: string
          title: Error Type
          example: value_error.missing
      required:
        - loc
        - msg
        - type
      title: ValidationError
    ErrorDetail:
      type: object
      properties:
        status:
          type: integer
          example: 400
        detail:
          type: string
          example: Request cannot be processed. Check the response details.
  responses:
    '400':
      description: >-
        Bad Request - The request was unacceptable or project is not active for
        production URL. Check the response for more details.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorDetail'
          example:
            status: 400
            detail: The request was unacceptable. Check the response for more details.
    '401':
      description: Unauthorized - No valid token was provided.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorDetail'
          example:
            status: 401
            detail: Authentication failed. Verify the API key and tenant headers.
    '403':
      description: Forbidden - You do not have access to this resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorDetail'
          example:
            status: 403
            detail: You do not have permission to access this resource.
    '404':
      description: Not Found - The resource does not exist.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorDetail'
          example:
            status: 404
            detail: The requested resource was not found.
    '422':
      description: >-
        Unprocessable entity - A validation error on a well-formed request.
        Check the response for more details.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorDetail'
          example:
            status: 422
            detail: Validation failed. Check the payload for required fields.
    '429':
      description: >-
        Too many requests - You have sent too many requests (either in general,
        for a resource or for a related resource) in a given amount of time.
      headers:
        Retry-After:
          description: Number of seconds to wait before retrying the request.
          schema:
            type: integer
            minimum: 0
      content:
        text/plain:
          schema:
            type: string
            description: Raw rate limit error payload.
          example: |-
            HTTP/2 429
            retry-after: 60

            error code: 1015
