Manage tenant creation and multi-tenancy setup.
- interview.finished
Genway Public API (1.0.0)
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 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_UUIDBoth headers are mandatory for every API call. Missing either header will result in authentication failure.
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.
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 and Activate project. |
| Project creation | 10 requests per minute per IP | Create a new project (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.
You can subscribe to our status page.
If you require help you can contact our support team at support@genway.ai.
https://api.genway.ai/v1/
Webhooks
Webhooks deliver event data to your applications as it happens, offering an alternative to frequent data polling.
- The
secretcreated via the/webhooks/secretsendpoint is permanent and should be stored securely in your system. This secret will serve for the verifying section. - The
x-hook-secretis 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.
The flow below shows the inbound nature of hook configuration. This is what is required to register your subscription.

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.
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.
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.
{"workspace_id": <workspace_id>}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.
{"workspace_id": <workspace_id>, "event_type": <event_type>, "target_url": <target_url>}If successful, the endpoint will return a response that includes:
- An
idfield in the body - This is the unique identifier for your subscription. - An
X-Hook-Secretheader - 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.
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.
{"secret": <x-hook-secret>}If subscription confirmation is successful, you should receive a 200 status code.
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_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_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. |
{
"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. |
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.
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.
X-Event-ID is added as a header to the request. It is a unique identifier assigned to each event.
- Uniqueness: Each
X-Event-IDvalue 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-IDwill remain the same across retries. - Idempotent Processing: We recommend that you use the
X-Event-IDto handle events in an idempotent way. If you encounter the sameX-Event-IDagain, simply skip and acknowledge the duplicate event rather than processing it a second time.
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.
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.
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)- Production environment
https://api.genway.ai/v1/webhooks/event-types
- curl
- JavaScript
- Node.js
- Python
- Java
- C#
- PHP
- Go
- Ruby
- R
- Payload
curl -i -X GET \
https://api.genway.ai/v1/webhooks/event-types \
-H 'X-Api-Key: YOUR_API_KEY_HERE' \
-H 'X-Tenant-Id: YOUR_API_KEY_HERE'[ "project.published" ]
- Production environment
https://api.genway.ai/v1/webhooks/secrets
- curl
- JavaScript
- Node.js
- Python
- Java
- C#
- PHP
- Go
- Ruby
- R
- Payload
curl -i -X POST \
https://api.genway.ai/v1/webhooks/secrets \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: YOUR_API_KEY_HERE' \
-H 'X-Tenant-Id: YOUR_API_KEY_HERE' \
-d '{
"workspace_id": "4e1b58da-06de-4173-a276-15609442c470"
}'{ "secret": "sec_af245ede-a9d0-40b4-9ffc-a4bf11fdfebb" }
- Production environment
https://api.genway.ai/v1/webhooks/subscriptions
- curl
- JavaScript
- Node.js
- Python
- Java
- C#
- PHP
- Go
- Ruby
- R
- Payload
curl -i -X POST \
https://api.genway.ai/v1/webhooks/subscriptions \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: YOUR_API_KEY_HERE' \
-H 'X-Tenant-Id: YOUR_API_KEY_HERE' \
-d '{
"workspace_id": "4e1b58da-06de-4173-a276-15609442c470",
"event_type": "project.published",
"target_url": "https://yourapp.com/webhook"
}'{ "id": "subscription_123", "x_hook_secret": "x_hook_secret_value" }
- Production environment
https://api.genway.ai/v1/webhooks/subscriptions
- curl
- JavaScript
- Node.js
- Python
- Java
- C#
- PHP
- Go
- Ruby
- R
- Payload
curl -i -X GET \
https://api.genway.ai/v1/webhooks/subscriptions \
-H 'X-Api-Key: YOUR_API_KEY_HERE' \
-H 'X-Tenant-Id: YOUR_API_KEY_HERE'[ { "id": "subscription_123", "workspace_id": "workspace_123", "event_type": "project.published", "target_url": "https://yourapp.com/webhook" } ]
- Production environment
https://api.genway.ai/v1/webhooks/subscriptions/{subscription_id}
- curl
- JavaScript
- Node.js
- Python
- Java
- C#
- PHP
- Go
- Ruby
- R
- Payload
curl -i -X POST \
'https://api.genway.ai/v1/webhooks/subscriptions/{subscription_id}' \
-H 'Content-Type: application/json' \
-H 'X-Api-Key: YOUR_API_KEY_HERE' \
-H 'X-Tenant-Id: YOUR_API_KEY_HERE' \
-d '{
"secret": "<x-hook-secret>"
}'- Production environment
https://api.genway.ai/v1/webhooks/subscriptions/{subscription_id}
- curl
- JavaScript
- Node.js
- Python
- Java
- C#
- PHP
- Go
- Ruby
- R
- Payload
curl -i -X DELETE \
'https://api.genway.ai/v1/webhooks/subscriptions/{subscription_id}' \
-H 'X-Api-Key: YOUR_API_KEY_HERE' \
-H 'X-Tenant-Id: YOUR_API_KEY_HERE'Errors
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.