openapi: 3.1.0
info:
description: |
# Overview
Welcome to the developer documentation for the Knak Enterprise API.
We provide a RESTful interface to key resources within the Knak platform to enable your own custom integration and automation workflows.
This API will allow you to automate processes regarding user management within your Knak environment.
You can download the formal definition of this public interface in OpenAPI 3 (formerly Swagger) format using the link above.
## Endpoint
`https://enterprise.knak.io/api/published/v1`
## Additional APIs
- [SCIM API Reference](https://enterprise.knak.io/docs/scim-api)
## Authentication
All requests are authenticated using a Bearer token in the `Authorization` header:
```
curl --location --request GET 'http://enterprise.knak.io/api/published/v1/emails' \
--header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbG...'
```
There are two ways to obtain tokens:
### 1 - API Key
A user generates a non-expiring token through the Enterprise UI, via the [API Access menu](https://enterprise.knak.io/account/api-access). This is generally only recommended for testing and development, or if the Oauth2 flow is not applicable to your particular use case.
### 2 - OAuth2 via Authorization Code Grant Flow
This is the **recommended** method for users to allow your application access to their data in Knak. You can manage your own OAuth2 applications in Knak [**here**](http://enterprise.knak.io/account/oauth-applications). Please contact support to enable this feature if unauthorized, or if you need a specific developer account set up for Knak.
- **Authorization URL**
- `https://enterprise.knak.io/oauth/authorize`
- **Token URL**
- `https://enterprise.knak.io/oauth/token`
Creating an OAuth2 application will provide you with a *client_id*, *client_secret* and a *redirect_uri* of your choosing. Users can then authorize your application to access their Knak account by being directed to the Authorization URL:
```
http://enterprise.knak.io/oauth/authorize?client_id=<your client ID>&redirect_uri=http://your.redirect.url/callback&response_type=code&state=xyzABC123
```
| Query Parameter | Description |
| ----------------| ----------- |
| client_id | **(Required)** The client ID for your application|
| redirect_uri | **(Required)** The url the client will be redirected to. HTTPS required. Must match the url specified in your OAuth2 application|
| response_type | **(Required)** Only a value of `code` is currently supported|
| state | (Optional) This value will be included as part of the redirect response. Your OAuth2 client library most likely uses this parameter to prevent CSRF attacks|
The user will be redirected to your `redirect_uri` with the authorization code included as the `code` query parameter:
```http
HTTP/1.1 302 Found
Location: https://your.redirect.url/callback?code=AUTHORIZATION_CODE&state=xyzABC123
```
You can then use this code to request a `(access_token, refresh_token)` pair from the Token URL:
```http
POST /oauth/token HTTP/1.1
Host: enterprise.knak.io
Accept: application/json
Authorization: Bearer ...
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&client_id=<client_id>&client_secret=<client_secret>&redirect_uri=<redirect_uri>&code=AUTHORIZATION_CODE
```
## Errors
Errors in requests made to the API can be viewed directly from the response code that is returned.
Below are a list of the common error responses returned and an explanation of what they mean.
| Code | Reason |Description |
| ----------------| ----------- | ----------- |
| **400** | **Bad Request** | Request is malformed or invalid. |
| **401** | **Unauthenticated** | Need to be signed in with a proper account to make this request. |
| **403** | **Forbidden** | The request cannot be completed because the account that is being used does not have sufficient permissions to perform the action in question. |
| **404** | **Not Found** | The requested resource could not be found. Verify that the resource you are looking for exists and that you are using the proper key to search for it. |
## Pagination
Our API supports pagination, allowing you to navigate through large sets of data efficiently. This is particularly useful for endpoints that can return a lot of data, such as listings of users, assets, or other entities. To manage the amount of data returned, we use two query parameters: `page` and `per_page`.
### Parameters
page (Integer, optional): This parameter specifies the page number in the results set. Each page contains a subset of the total data based on the per_page value. The default value is 1 if not specified.
per_page (Integer, optional): This parameter controls the number of items returned per page. It allows you to specify the page size, i.e., how many items you want to be included in each page of results. The default value is 10, and the maximum allowable value is 100.
### Defaults and Limits
If neither page nor per_page is specified, the API will return the first page with the default size of 10 items.
The per_page parameter defaults to 10 but can be set to any integer up to a maximum of 100. Requests for more than 100 items per page will be capped at 100.
## Filtering
Our API supports filtering on specific fields of resources for GET requests. This allows clients to retrieve a subset of records based on certain criteria. Supported filters will be listed in each endpoint.
### Parameters
filter[field_name]:To apply filters, add a filter query parameter to your GET request, followed by the field name you wish to filter on.
Each filter can have one of the following types:
#### Exact
This filter type is used to match the exact value of a field.
#### Partial
This filter type will return all matches that contain the specified value.
#### Scope
This filter type is used to filtered on a static list of values. Supported items will be listed in each endpoint.
## Sorting
Our API provides sorting functionality, allowing clients to order the results of a GET request based on specified fields. Sorting makes it easier to organize and navigate through lists of records.
### Parameters
sort (string, optional): To apply sorting, use the sort query parameter followed by the field name you wish to sort by:
- updated_at: Sorts records by the last update timestamp.
- created_at: Sorts records by the creation timestamp.
## Webhook Setup
Webhooks are a way to notify your application when a specific event occurs in your Knak environment. When the event occurs, Knak sends an HTTP POST request to the webhook's configured URL. You can use webhooks to trigger custom workflows, send notifications, or update external systems based on events that occur in Knak.
For information on how to create and manage webhooks, please visit the [Knak Custom Integration Setup](https://help.knak.io/en/articles/7950399-knak-custom-integration-setup) page in the Knak Help Center, and the events section below.
## Retry Policy
Webhooks will be sent out up to a maximum of three times, with a delay of 60 seconds between each request, until a Successful response status is returned.
## Verifying Webhook Signatures
Webhooks are signed using a SHA-256 HMAC with the secret generated in Knak. The signature is included in the `knak-signature` header of the request. You can use this signature to verify that the request was sent by Knak, and not a third party.
Before you can verify the signature, you will need to obtain the secret from Knak. You can do this by navigating to the [Webhooks](https://enterprise.knak.io/account/webhooks) page in the Enterprise UI. Select the webhook you want to obtain the secret for, and click the reveal icon next to the secret. In the code sample below we assume that the secret is stored in an environment variable called `WEBHOOK_SECRET`.
You can perform this verification in any language that supports HMAC-SHA256. You provide the request body and secret as input to the HMAC-SHA256 algorithm, and then compare the output to the signature provided in the request header.
View the sample code below for an example of how to verify the signature using Node and express.js.
```javascript
const crypto = require('crypto');
const express = require("express");
const app = express();
app.post("/sync-requested", express.raw({type: 'application/json'}), (req, res) => {
try {
// Get the knak-signature header from the request
const signature = req.headers['knak-signature'];
// Generate the hash value from the request body
const payload = req.body.toString();
const secret = process.env.WEBHOOK_SECRET;
const hmac = crypto.createHmac('sha256', secret).update(payload);
// Generate hexidecimal hash value
const calculatedHash = hmac.digest('hex');
// Compare the calculated hash to the knak-signature header
if (crypto.timingSafeEqual(Buffer.from(calculatedHash), Buffer.from(signature))) {
// continue processing the request
res.send("Payload is authentic");
} else {
// reject the request
res.send("Payload has been tampered with");
}
} catch (err) {
res.status(500).send("An error occurred");
}
});
```
version: V1
title: Knak Enterprise API — TranslationRequests
x-logo:
url: https://s3.amazonaws.com/assets.knak.io/img/Knak-Logo-Medium.png
servers:
- url: https://enterprise.knak.io/api/published/v1
description: production
tags:
- name: TranslationRequests
paths:
/translation-requests:
get:
description: |-
Retrieve all [translation requests](#tag/translation_request) that the API user has access to based on their brand scopes.
**NOTE:** Only translation requests created from custom translation integrations will be visible. Steps to set up a custom translation integration can be found [here](https://help.knak.io/en/articles/9687639-knak-custom-translation-integration-setup-guide).
summary: List all translation requests
parameters:
- name: page
in: query
required: false
description: Page number
example: 1
schema:
type: integer
- name: per_page
in: query
required: false
description: Number of items per page
example: 10
schema:
type: integer
- name: filter[status]
in: query
description: Filter by status. Exact match filter.
required: false
schema:
type: string
example: requested
- name: filter[asset_id]
in: query
description: Filter by asset ID. Exact match filter. (Corresponds to `base_asset_id` in response)
required: false
schema:
type: string
example: 609ca344d1b1b
- name: filter[created_at_before]
in: query
description: Filter translation requests created before a specific date, formatted in ISO 8601
format. Can be used in conjunction with `created_at_after` filter
required: false
schema:
type: string
example: '2023-04-01T00:00:00Z'
- name: filter[created_at_after]
in: query
description: Filter translation requests created after a specific date, formatted in ISO 8601
format. Can be used in conjunction with `created_at_before` filter
required: false
schema:
type: string
example: '2023-04-03T00:00:00Z'
- name: sort
in: query
description: Sort by field (`created_at`, `updated_at`), use '-' to reverse order of sort (e.g.
-created_at).
required: false
schema:
type: string
example: created_at
tags:
- TranslationRequests
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/TranslationRequestList'
'401':
description: Unauthenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Unauthenticated.
detail: Authenticate before continuing.
'403':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Forbidden.
detail: This user is not authorized to perform this action. Please adjust permissions
before continuing.
post:
description: |-
Create one or more [translation requests](#tag/translation_request) for an asset using a custom translation integration. One translation request is created per code supplied in `language_codes`, and newly created requests start with a `status` of `requested`.
The `integration_id` must reference a `custom_translation` integration that belongs to your company. Every code in `language_codes` must be one of your company's supported translation languages — call `GET /translation-languages` first to retrieve the valid set.
**NOTE:** Only `custom_translation` integrations are supported by this endpoint. Integrations for marketing platforms or other translation providers (Smartling, TransPerfect, Lazarus) are rejected with `422 Unprocessable Entity`. Steps to set up a custom translation integration can be found [here](https://help.knak.io/en/articles/9687639-knak-custom-translation-integration-setup-guide).
summary: Create translation requests
tags:
- TranslationRequests
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- integration_id
- asset_id
- language_codes
properties:
integration_id:
type: string
description: ID of the `custom_translation` integration to use. Must belong to your
company.
example: 609ca344d1caa
asset_id:
type: string
description: ID of the asset (email or landing page) to translate.
example: 609ca344d1b1b
language_codes:
type: array
description: One or more target language codes. Each must be a supported translation
language for your company (see `GET /translation-languages`). Values must be unique;
one translation request is created per code.
minItems: 1
items:
type: string
example:
- fr-CA
- es-ES
notes:
type: string
nullable: true
description: Optional notes or context stored on each created request. If omitted, the
value will be null.
example: Please prioritize this campaign
due_date:
type: string
nullable: true
description: Optional due date for the translation, in ISO 8601 format. If omitted,
the value will be null.
example: '2026-07-01'
responses:
'201':
description: Created. Returns the translation requests that were created, one per language code.
content:
application/json:
schema:
$ref: '#/components/schemas/TranslationRequestCreatedList'
example:
data:
- type: translation-request
id: 609d7ce223411
attributes:
id: 609d7ce223411
language_code: fr-CA
status: requested
base_asset_id: 609ca344d1b1b
asset_version_id: 67d19607cbb1d4.78284760
integration_id: 609ca344d1caa
user:
id: 609d7ce223400
name: John Doe
email: john.doe@email.com
roles:
- Email Creator
notes: Please prioritize this campaign
due_date: '2026-07-01'
created_at: '2026-06-08T17:07:12+00:00'
updated_at: '2026-06-08T17:07:12+00:00'
- type: translation-request
id: 609d7ce223412
attributes:
id: 609d7ce223412
language_code: es-ES
status: requested
base_asset_id: 609ca344d1b1b
asset_version_id: 67d19607cbb1d4.78284760
integration_id: 609ca344d1caa
user:
id: 609d7ce223400
name: John Doe
email: john.doe@email.com
roles:
- Email Creator
notes: Please prioritize this campaign
due_date: '2026-07-01'
created_at: '2026-06-08T17:07:12+00:00'
updated_at: '2026-06-08T17:07:12+00:00'
'400':
description: Validation error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Validation Error for language_codes
detail: The language codes field is required.
'401':
description: Unauthenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Unauthenticated.
detail: Authenticate before continuing.
'403':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Forbidden.
detail: This user is not authorized to perform this action. Please adjust permissions
before continuing.
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Resource Not Found.
detail: Could not find the asset you were looking for.
'422':
description: Unprocessable Entity. Returned when `integration_id` is not a `custom_translation`
integration belonging to your company, or when one or more `language_codes` are not supported
for your company.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
examples:
invalid_integration:
summary: integration_id is not a valid custom_translation integration
value:
errors:
- status: '422'
title: Unprocessable Entity
detail: The integration_id is not a custom_translation integration belonging to
your company.
meta:
integration_id: 609ca344d1caa
unsupported_language_code:
summary: One or more language codes are not supported
value:
errors:
- status: '422'
title: Unprocessable Entity
detail: 'These language codes are not supported for your company: zz-ZZ, ja-JP.
Use GET /v1/translation-languages to list supported codes.'
meta:
unsupported_language_codes:
- zz-ZZ
- ja-JP
/translation-requests/{id}:
get:
description: Retrieve a [translation request](#tag/translation_request) created from a custom translation
integration.
summary: Retrieve a translation request
tags:
- TranslationRequests
parameters:
- name: id
in: path
required: true
description: ID of the translation request to retrieve
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/TranslationRequest'
'401':
description: Unauthenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Unauthenticated.
detail: Authenticate before continuing.
'403':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Forbidden.
detail: This user is not authorized to perform this action. Please adjust permissions
before continuing.
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Resource Not Found.
detail: Could not find the translation request you were looking for.
patch:
description: Update the status of a [translation request](#tag/translation_request).
summary: Update a translation request
tags:
- TranslationRequests
parameters:
- name: id
in: path
required: true
description: ID of the translation request to update
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
status:
type: string
enum:
- processing
- completed
- failed
- cancelled
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/TranslationRequest'
'401':
description: Unauthenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Unauthenticated.
detail: Authenticate before continuing.
'403':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Forbidden.
detail: This user is not authorized to perform this action. Please adjust permissions
before continuing.
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Resource Not Found.
detail: Could not find the translation request you were looking for.
/translation-requests/{id}/download-source:
get:
description: Download the source file for a [translation request](#tag/translation_request) in
the specified format. The `content-type` of the response will change depending on the format requested.
summary: Download source file for translation request
tags:
- TranslationRequests
parameters:
- name: id
in: path
required: true
description: ID of the translation request to download the source file for
schema:
type: string
- name: format
in: query
required: false
description: Format of the source file to download
schema:
type: string
enum:
- arb
- xliff-1.2
- xliff-2.0
responses:
'200':
description: Success
content:
application/xml:
schema:
type: string
format: binary
'401':
description: Unauthenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Unauthenticated.
detail: Authenticate before continuing.
'403':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Forbidden.
detail: This user is not authorized to perform this action. Please adjust permissions
before continuing.
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Resource Not Found.
detail: Could not find the translation request you were looking for.
/translation-requests/{id}/upload-translation:
post:
description: Upload a completed translation file for a [translation request](#tag/translation_request).
The file is validated synchronously and the result of the validation is given by the response.
If the file is valid (indicated by a 200 response), then the translation will be applied in Knak
asynchronously. Once applied, the `status` of the translation request will be updated to `completed`
automatically.
summary: Upload translated file
tags:
- TranslationRequests
parameters:
- name: id
in: path
required: true
description: ID of the translation request to upload a translation file for
schema:
type: string
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
description: The translated file to apply
responses:
'200':
description: The file was uploaded successfully
'400':
description: File validation failed
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Validation error for file.
detail: The file must be a valid XLIFF file.
'401':
description: Unauthenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Unauthenticated.
detail: Authenticate before continuing.
'403':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Forbidden.
detail: This user is not authorized to perform this action. Please adjust permissions
before continuing.
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Resource Not Found.
detail: Could not find the translation request you were looking for.
/translation-languages:
get:
description: Retrieve the translation languages supported for your company, ordered by ISO code.
Each `iso_code` returned is a valid value for the `language_codes` field when creating a [translation
request](#tag/translation_request) via `POST /translation-requests`.
summary: List supported translation languages
tags:
- TranslationRequests
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/TranslationLanguageList'
example:
data:
- type: translation_language
id: en-US
attributes:
iso_code: en-US
name: English (United States)
- type: translation_language
id: es-ES
attributes:
iso_code: es-ES
name: Spanish (Spain)
- type: translation_language
id: fr-CA
attributes:
iso_code: fr-CA
name: French (Canada)
'401':
description: Unauthenticated
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Unauthenticated.
detail: Authenticate before continuing.
'403':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
errors:
- title: Forbidden.
detail: This user is not authorized to perform this action. Please adjust permissions
before continuing.
components:
schemas:
TranslationRequestItem:
type: object
properties:
type:
type: string
example: translation-request
id:
type: string
example: 609d7ce223411
attributes:
$ref: '#/components/schemas/TranslationRequestItemAttributes'
TranslationRequestList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/TranslationRequestItem'
links:
type: object
properties:
first:
type: string
example: https://enterprise.knak.io/api/published/v1/translation-requests?page=1
last:
type: string
example: https://enterprise.knak.io/api/published/v1/translation-requests?page=3
prev:
type: string
nullable: true
example: https://enterprise.knak.io/api/published/v1/translation-requests?page=1
next:
type: string
nullable: true
example: https://enterprise.knak.io/api/published/v1/translation-requests?page=3
meta:
type: object
properties:
current_page:
type: integer
example: 2
from:
type: integer
example: 1
last_page:
type: integer
example: 3
links:
type: array
items:
type: object
# --- truncated at 32 KB (39 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/knak/refs/heads/main/openapi/knak-translationrequests-api-openapi.yml