# Genway Public API 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). Version: 1.0.0 ## Servers Production environment ``` https://api.genway.ai/v1 ``` ## Security ### api_key API key for authentication. Use your tenant-specific API key. Type: apiKey In: header Name: X-Api-Key ### tenant_id Required tenant identifier (UUID format). Must match the tenant associated with the provided API key. Type: apiKey In: header Name: X-Tenant-Id ## Download OpenAPI description [Genway Public API](https://docs.genway.ai/_bundle/openapi.yaml) ## Tenants Manage tenant creation and multi-tenancy setup. ### Create a new tenant - [POST /tenants](https://docs.genway.ai/openapi/tenants/createtenant.md): 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 to obtain your partnership key. ## Projects Manage your projects programmatically. ### Create a new project - [POST /projects](https://docs.genway.ai/openapi/projects/createproject.md): Create a new project (Contextual Interview) Note: Prototype Testing projects creation is not yet supported. ### Update project details - [PATCH /projects/{project_id}](https://docs.genway.ai/openapi/projects/updateprojectdetails.md): Update the details of a project by its projectId. ### Publish/resume a project - [POST /projects/{project_id}/activate](https://docs.genway.ai/openapi/projects/activateproject.md): Publish or resume a project ### Pause a project - [POST /projects/{project_id}/deactivate](https://docs.genway.ai/openapi/projects/deactivateproject.md): Pause an active project, making it inactive. This is useful for temporarily halting a project. ### Export all interviews transcripts and summaries - [GET /projects/{project_id}/interviews-export](https://docs.genway.ai/openapi/projects/exportinterviews.md): Export all interviews transcripts and summaries for a specific project. ### Export all interviewees' information - [GET /projects/{project_id}/interviewees-export](https://docs.genway.ai/openapi/projects/exportinterviewees.md): Export all interviewees' information for a specific project as a CSV file. ### Get project URL for sharing with interviewees - [GET /projects/{project_id}/url](https://docs.genway.ai/openapi/projects/getprojecturl.md): Get the URL for a project to share with interviewees. Accepts a parameter to specify sandbox or production URL. ## Interviews Manage and export interview data. ### Export specific interview audio - [GET /interviews/{interview_id}/audio-export](https://docs.genway.ai/openapi/interviews/exportinterviewaudio.md): Export the audio of a specific interview. ### Export specific interview video - [GET /interviews/{interview_id}/video-export](https://docs.genway.ai/openapi/interviews/exportinterviewvideo.md): Export the video of a specific interview. ### Flag interview as fraud - [POST /interviews/{interview_id}/flag](https://docs.genway.ai/openapi/interviews/flaginterviewasfraud.md): ⚠️ Not Supported - This endpoint is not currently supported. Flag a specific interview as fraud with a reason. ## Webhooks 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": } ``` ### 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.** `` must be use `https://` and be publicly accessible i.e. **not** `https://localhost`. ```json {"workspace_id": , "event_type": , "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//` with the payload below. Replace `` with the value of the X-Hook-Secret header in the previous subscription request. ```json {"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": "", "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": "", "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": "", "interview_id": "", "interviewee_id": "", "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) ``` ### List event types - [GET /webhooks/event-types](https://docs.genway.ai/openapi/webhooks/listeventtypes.md): Retrieve an up-to-date list of all the event types that we currently support. ### Create a secret - [POST /webhooks/secrets](https://docs.genway.ai/openapi/webhooks/createsecret.md): Create a new secret for your workspace. ### Subscribe to an event - [POST /webhooks/subscriptions](https://docs.genway.ai/openapi/webhooks/subscribetoevent.md): Subscribe to your desired event. ### List all subscriptions - [GET /webhooks/subscriptions](https://docs.genway.ai/openapi/webhooks/listsubscriptions.md): Retrieve a list of all subscriptions. ### Confirm subscription - [POST /webhooks/subscriptions/{subscription_id}](https://docs.genway.ai/openapi/webhooks/confirmsubscription.md): Confirm your intention to subscribe to the desired event type. ### Delete subscription - [DELETE /webhooks/subscriptions/{subscription_id}](https://docs.genway.ai/openapi/webhooks/deletesubscription.md): Delete a subscription by its subscription_id.