openapi: 3.2.0
info:
description: "## Overview\nThe Riot API is a (mostly) RESTful API. Typically, both POST bodies and responses are JSON-encoded.\n\n## Base URL\nThe base URL for the Riot API is https://public-api.tryriot.com/v1.\n\n## Authentication\n\nEvery API request must include an authentication key in the `x-api-key` header.\n\nTo acquire an API key, customers must contact the technical team.\n\n## Authorization\n\nEach key is scoped to either a single organization or a single workspace, ensuring that access and data are restricted to the appropriate entity.\n\n- **Organization-scoped keys** can access any workspace belonging to the organization. Endpoints that take a `workspace_id` parameter accept any workspace of that organization.\n- **Workspace-scoped keys** are restricted to a single workspace. Requests targeting a different workspace through a `workspace_id` parameter are rejected with a **403** status code.\n\nKeys can also be limited by specific scopes, such as `awareness:read`, `simulation:read`, `breach:read`, or `workspace:read` which define the endpoints that can be accessed.\n\n## Pagination\n\nAll endpoints that return an array of objects support cursor-based pagination.\nEven for endpoints with a limited number of items (e.g., `/courses`), pagination is available to maintain consistency across all endpoints.\n\n**Request**\n\n- **`limit`** (query parameter): Maximum number of items per page. The maximum allowed value is `100`, with a default of `50`.\n- **`cursor`** (query parameter): Pagination cursor for retrieving the next page of results. On the first request, omit this parameter. For subsequent requests, pass the `next_cursor` value from the previous response's `metadata` object unchanged.\n\n**Response**\n\nPaginated responses include a `metadata` object alongside the `data` array:\n\n```json\n{\n \"data\": [...],\n \"metadata\": {\n \"next_cursor\": \"eyJpZCI6...\",\n \"limit\": 50\n }\n}\n```\n\n- **`next_cursor`**: The cursor to pass in the next request. `null` when there are no more pages.\n- **`limit`**: The maximum number of items per page.\n\n**Link header**\n\nPaginated responses also include a standard `link` response header with `rel=\"next\"` when there are more results.\nThis header contains a fully constructed URL for the next page, including the cursor and any query parameters from the original request.\n\nExample: `<https://public-api.tryriot.com/v1/groups?workspace_id=abc&cursor=eyJpZCI6...>; rel=\"next\"`\n\nWhen the last page is reached, the `link` header is omitted.\n\n## Rate limits\n\nRate limiting is enforced across all API endpoints and is scoped by the authentication key. This ensures fair usage and prevents abuse of the system.\n\n- **Scope**: Rate limits are applied **per key**, meaning all requests made with the same key share the same limit.\n- **Configuration**: Specific rate limits are defined and managed by the technical team.\n- **Behavior**: The rate limiting mechanism operates within fixed time intervals. If the limit is exceeded within a given interval, further requests will return **429** status code until the next interval begins.\n\n## Webhooks\n\nRiot can push server-to-server events to a customer-configured HTTPS endpoint when something happens in a workspace (e.g. an inbox email being classified).\n\nThe implementation follows the [Standard Webhooks specification](https://github.com/standard-webhooks/standard-webhooks), so any Standard-Webhooks-compatible library can verify and consume payloads without bespoke code.\n\n**Envelope**\n\nEvery event body is wrapped in the Standard Webhooks envelope:\n\n```json\n{\n \"type\": \"inbox_email_analysis.classified\",\n \"timestamp\": \"2026-06-03T08:42:11.812Z\",\n \"data\": { /* event-specific payload */ }\n}\n```\n\n**Headers**\n\n- `webhook-id`: unique event identifier. The same id is sent on every retry; use it as an idempotency key.\n- `webhook-timestamp`: Unix timestamp (seconds) of the delivery attempt.\n- `webhook-signature`: space-delimited list of `v1,<base64-hmac>` signatures, one per active endpoint secret, computed over `<webhook-id>.<webhook-timestamp>.<body>` using HMAC-SHA256 with the raw request body. Multiple signatures support zero-downtime secret rotation.\n\n**Delivery**\n\n- Method: `POST` with `content-type: application/json`.\n- Success: any `2xx` status returned within 15 seconds.\n- Failure: any non-`2xx` status, connection error, or timeout. Retries follow the Standard Webhooks recommended schedule: 10 attempts spread over ~75 hours (immediate, 5s, 5m, 30m, 2h, 5h, 10h, 14h, 20h, 24h).\n\n**Endpoint management**\n\nContact your account manager to add or rotate an endpoint. Self-service management is not available for now.\n\n**Compatibility**\n\nEvent payloads evolve over time. To stay forward-compatible, **ignore unknown fields** in the `data` object — new fields may be added at any time without notice and without a version bump.\n\nThe following changes to an existing event type are **not** considered breaking:\n\n- Adding a new field to the payload.\n- Adding a new event type.\n\nThe following changes **are** breaking and will be shipped under a new event type (e.g. `inbox_email_analysis.classified.v2`), leaving the original event type unchanged:\n\n- Removing or renaming a field.\n- Changing the type of a field.\n- Changing the meaning of an existing value (e.g. repurposing an enum value).\n\n**Event types**\n\nSee the **Webhook Events** section in the sidebar for the list of supported event types and their payload schemas.\n"
title: Riot Team awareness API
version: v1
servers:
- url: https://public-api.tryriot.com/
security:
- apiKeyAuth: []
tags:
- name: Team awareness
x-scalar-ignore: true
paths:
/v1/courses:
get:
description: 'Lists all active awareness courses of a workspace and their delivery settings.
**Scopes required:**
- awareness:read'
operationId: courses_get_paginated_DJESCNQ
parameters:
- in: header
name: x-item-limit
required: false
schema:
default: 50
deprecated: true
maximum: 100
minimum: 1
type: integer
- in: header
name: x-next-cursor
required: false
schema:
deprecated: true
type: string
- in: query
name: cursor
required: false
schema:
type: string
- in: query
name: limit
required: false
schema:
default: 50
maximum: 100
minimum: 1
type: integer
- in: query
name: workspace_id
required: true
schema:
format: uuid
type: string
responses:
'200':
content:
application/json:
schema:
properties:
data:
items:
$ref: '#/components/schemas/PaginatedCoursePayload'
type: array
metadata:
properties:
limit:
type: integer
next_cursor:
type:
- string
- 'null'
required:
- next_cursor
- limit
type: object
required:
- data
type: object
description: Courses list
headers:
link:
description: 'Link header with rel="next" pointing to the next page URL. Format: `<url>; rel="next"`'
required: false
schema:
type: string
x-next-cursor:
description: Pagination cursor for the next page
required: false
schema:
deprecated: true
type: string
'401':
$ref: '#/components/responses/UnauthorizedErrorResponse'
'403':
$ref: '#/components/responses/ForbiddenErrorResponse'
'422':
$ref: '#/components/responses/UnprocessableContentErrorResponse'
'429':
$ref: '#/components/responses/RateLimitExceededErrorResponse'
security:
- apiKeyAuth:
- awareness:read
summary: List courses
tags:
- Team awareness
x-riot-team-ownership: awareness
/v1/courses/employees_progress:
get:
description: 'Retrieves a paginated list of all employees and their progress across all courses in the workspace''s awareness program, as well as courses manually assigned to them.
For each employee, returns detailed information including their identification data and a comprehensive breakdown of their course progress.
For program courses, the response includes the completion status of each course (completed, missed, or upcoming) for all program years up to the employee''s current program year.
For manually assigned courses, only the completion status is returned and `years` is an empty array.
**Scopes required:**
- awareness:read'
operationId: courses_get_employees_progress_DJESCNQ
parameters:
- in: header
name: x-item-limit
required: false
schema:
default: 500
deprecated: true
maximum: 500
minimum: 1
type: integer
- in: header
name: x-next-cursor
required: false
schema:
deprecated: true
type: string
- in: query
name: cursor
required: false
schema:
type: string
- in: query
name: limit
required: false
schema:
default: 500
maximum: 500
minimum: 1
type: integer
- in: query
name: workspace_id
required: true
schema:
format: uuid
type: string
responses:
'200':
content:
application/json:
schema:
properties:
data:
items:
$ref: '#/components/schemas/PaginatedEmployeesCoursesProgressPayload'
type: array
metadata:
properties:
limit:
type: integer
next_cursor:
type:
- string
- 'null'
required:
- next_cursor
- limit
type: object
required:
- data
type: object
description: Employees courses progress
headers:
link:
description: 'Link header with rel="next" pointing to the next page URL. Format: `<url>; rel="next"`'
required: false
schema:
type: string
x-next-cursor:
description: Pagination cursor for the next page
required: false
schema:
deprecated: true
type: string
'401':
$ref: '#/components/responses/UnauthorizedErrorResponse'
'403':
$ref: '#/components/responses/ForbiddenErrorResponse'
'422':
$ref: '#/components/responses/UnprocessableContentErrorResponse'
'429':
$ref: '#/components/responses/RateLimitExceededErrorResponse'
security:
- apiKeyAuth:
- awareness:read
summary: List all employees' courses progress
tags:
- Team awareness
x-riot-team-ownership: awareness
/v1/courses/statistics:
get:
description: 'Retrieves statistics about awareness program in general for a given workspace. Feedbacks of only last 90 days are considered.
**Scopes required:**
- awareness:read'
operationId: courses_get_statistics_DJESCNQ
parameters:
- in: query
name: workspace_id
required: true
schema:
format: uuid
type: string
responses:
'200':
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/CoursesStatisticsPayload'
required:
- data
type: object
description: Awareness program statistics
'401':
$ref: '#/components/responses/UnauthorizedErrorResponse'
'403':
$ref: '#/components/responses/ForbiddenErrorResponse'
'422':
$ref: '#/components/responses/UnprocessableContentErrorResponse'
'429':
$ref: '#/components/responses/RateLimitExceededErrorResponse'
security:
- apiKeyAuth:
- awareness:read
summary: Get awareness program statistics
tags:
- Team awareness
x-riot-team-ownership: awareness
/v1/courses/{course_id}:
get:
description: 'Lists employees enrolled in the course, ordered by their creation date (most recent first).
For courses in the workspace''s awareness program, the current year''s enrolment status is provided
along with a history of course statuses from previous years.
For courses manually assigned to employees, `years` is always empty and `status` is either
`completed` or `upcoming` based on whether the employee finished the course.
**Scopes required:**
- awareness:read'
operationId: courses_get_course_statuses_of_employees_DJESCNQ
parameters:
- in: header
name: x-item-limit
required: false
schema:
default: 50
deprecated: true
maximum: 100
minimum: 1
type: integer
- in: header
name: x-next-cursor
required: false
schema:
deprecated: true
type: string
- in: query
name: cursor
required: false
schema:
type: string
- in: query
name: limit
required: false
schema:
default: 50
maximum: 100
minimum: 1
type: integer
- in: path
name: course_id
required: true
schema:
format: uuid
type: string
- in: query
name: workspace_id
required: true
schema:
format: uuid
type: string
- explode: false
in: query
name: status
required: false
schema:
items:
$ref: '#/components/schemas/EmployeeCourseStatusSchema'
minItems: 1
type: array
uniqueItems: true
style: form
responses:
'200':
content:
application/json:
schema:
properties:
data:
items:
$ref: '#/components/schemas/PaginatedCourseStatusPayload'
type: array
metadata:
properties:
limit:
type: integer
next_cursor:
type:
- string
- 'null'
required:
- next_cursor
- limit
type: object
required:
- data
type: object
description: Courses statuses list of employees
headers:
link:
description: 'Link header with rel="next" pointing to the next page URL. Format: `<url>; rel="next"`'
required: false
schema:
type: string
x-next-cursor:
description: Pagination cursor for the next page
required: false
schema:
deprecated: true
type: string
'401':
$ref: '#/components/responses/UnauthorizedErrorResponse'
'403':
$ref: '#/components/responses/ForbiddenErrorResponse'
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/CourseNotFoundErrorResponse'
description: no description
'422':
$ref: '#/components/responses/UnprocessableContentErrorResponse'
'429':
$ref: '#/components/responses/RateLimitExceededErrorResponse'
security:
- apiKeyAuth:
- awareness:read
summary: List courses status of employees
tags:
- Team awareness
x-riot-team-ownership: awareness
components:
schemas:
CourseNotFoundErrorResponse:
additionalProperties: false
properties:
error:
const: Course is not included in the program
required:
- error
title: CourseNotFoundErrorResponse
type: object
PaginatedCourseStatusPayload:
additionalProperties: false
properties:
employee:
$ref: '#/components/schemas/EmployeeOverviewSchema'
quiz_score:
description: Score obtained on the in-course quiz, formatted as `"correct/total"`. For program courses, this reflects the current program year; for manually assigned courses, this reflects the latest assignment. `null` if not completed yet or no quiz.
examples:
- 4/5
type:
- string
- 'null'
status:
$ref: '#/components/schemas/EmployeeCourseStatusSchema'
years:
description: The history of employee's course statuses until current program year.
items:
$ref: '#/components/schemas/EmployeeCourseStatusPerYearSchema'
type: array
required:
- years
- quiz_score
- status
- employee
title: PaginatedCourseStatusPayload
type: object
EmployeeCourseStatusSchema:
enum:
- completed
- missed
- upcoming
title: EmployeeCourseStatusSchema
type: string
ForbiddenErrorResponse:
additionalProperties: false
properties:
errors:
items:
additionalProperties: false
properties:
code:
const: forbidden
detail:
type: string
source:
properties:
pointer:
type: string
required:
- pointer
type: object
title:
const: Forbidden
required:
- title
- source
- detail
type: object
type: array
required:
- errors
title: ForbiddenErrorResponse
type: object
WorkspaceCourseSettingsSchema:
additionalProperties: false
properties:
delivery:
$ref: '#/components/schemas/CourseDeliverySettingSchema'
year:
description: The year of the course in the program
type: integer
required:
- year
- delivery
title: WorkspaceCourseSettingsSchema
type: object
PaginatedCoursePayload:
additionalProperties: false
properties:
created_at:
format: date-time
type: string
description:
description: Description of the course, provided in the workspace's default locale.
examples:
- Learn how to manage your digital presence effectively
type: string
duration:
description: Average duration in minutes
type: integer
id:
format: uuid
type: string
name:
description: Name of the course, provided in the workspace's default locale.
examples:
- Digital Footprint
type: string
settings:
items:
$ref: '#/components/schemas/WorkspaceCourseSettingsSchema'
type: array
slug:
description: Slug of the course
examples:
- digital_footprint
type: string
theme:
$ref: '#/components/schemas/CourseTheme'
updated_at:
format: date-time
type: string
required:
- settings
- theme
- duration
- description
- name
- slug
- updated_at
- created_at
- id
title: PaginatedCoursePayload
type: object
CoursesStatisticsPayload:
additionalProperties: false
properties:
active_employees:
description: Number of active employees in the workspace
type: integer
average_courses_completed:
description: Average number of courses completed per employee. Only active employees are considered
type: integer
covered_employees:
description: Number of employees covered by the program
type: integer
negative_feedbacks:
description: Number of negative feedbacks about courses
type: integer
neutral_feedbacks:
description: Number of neutral feedbacks about courses
type: integer
positive_feedbacks:
description: Number of positive feedbacks about courses
type: integer
required:
- average_courses_completed
- active_employees
- covered_employees
- neutral_feedbacks
- negative_feedbacks
- positive_feedbacks
title: CoursesStatisticsPayload
type: object
EmployeeOverviewSchema:
additionalProperties: false
properties:
id:
description: UUID of the employee
format: uuid
type: string
name:
description: Name of the employee
examples:
- John Doe
type:
- string
- 'null'
primary_email_address:
description: Email address
examples:
- john.doe@tryriot.com
format: email
type:
- string
- 'null'
username:
description: Username of the employee
type:
- string
- 'null'
required:
- primary_email_address
- username
- name
- id
title: EmployeeOverviewSchema
type: object
UnauthorizedErrorResponse:
additionalProperties: false
properties:
errors:
items:
additionalProperties: false
properties:
code:
const: unauthorized
detail:
type: string
source:
properties:
pointer:
type: string
required:
- pointer
type: object
title:
const: Unauthorized
required:
- title
- source
- detail
type: object
type: array
required:
- errors
title: UnauthorizedErrorResponse
type: object
UnprocessableContentErrorResponse:
additionalProperties: false
properties:
errors:
items:
additionalProperties: false
properties:
code:
type: string
detail:
type: string
source:
properties:
pointer:
type: string
required:
- pointer
type: object
title:
type: string
required:
- title
- source
- detail
type: object
type: array
required:
- errors
title: UnprocessableContentErrorResponse
type: object
PaginatedEmployeesCoursesProgressPayload:
additionalProperties: false
properties:
courses_progress:
description: List of courses progress for the employee
items:
$ref: '#/components/schemas/CourseProgressSchema'
type: array
employee:
$ref: '#/components/schemas/EmployeeOverviewSchema'
required:
- courses_progress
- employee
title: PaginatedEmployeesCoursesProgressPayload
type: object
CourseOverviewSchema:
additionalProperties: false
properties:
description:
description: Description of the course, provided in the workspace's default locale.
examples:
- Learn how to manage your digital presence effectively
type: string
id:
format: uuid
type: string
name:
description: Name of the course, provided in the workspace's default locale.
examples:
- Digital Footprint
type: string
slug:
description: Slug of the course
examples:
- digital_footprint
type: string
required:
- description
- name
- slug
- id
title: CourseOverviewSchema
type: object
EmployeeCourseStatusPerYearSchema:
additionalProperties: false
properties:
completed_at:
format: date-time
type:
- string
- 'null'
due_at:
format: date-time
type: string
quiz_score:
description: Score obtained on the in-course quiz for that year, formatted as `"correct/total"`. `null` if the course has not been completed yet or has no quiz.
examples:
- 4/5
type:
- string
- 'null'
status:
$ref: '#/components/schemas/EmployeeCourseStatusSchema'
year:
description: The year of the course in the program
type: integer
required:
- quiz_score
- completed_at
- due_at
- year
- status
title: EmployeeCourseStatusPerYearSchema
type: object
CourseDeliverySettingSchema:
enum:
- a_week_after_event
- directly_after_event
- first_day
- first_month
- none
- sent_after_the_first_year
- yearly
- yearly_at_end_of_program
title: CourseDeliverySettingSchema
type: string
RateLimitExceededErrorResponse:
additionalProperties: false
properties:
errors:
items:
additionalProperties: false
properties:
code:
const: too_many_requests
detail:
type: string
source:
properties:
pointer:
type: string
required:
- pointer
type: object
title:
const: Too Many Requests
required:
- title
- source
- detail
type: object
type: array
required:
- errors
title: RateLimitExceededErrorResponse
type: object
CourseTheme:
description: The theme of the course
enum:
- digital_footprint
- gdpr
- general
- irl
- it
- legal
- passwords
- social_engineering
- technical
examples:
- passwords
title: CourseTheme
type: string
CourseProgressSchema:
additionalProperties: false
properties:
course:
$ref: '#/components/schemas/CourseOverviewSchema'
quiz_score:
description: Score obtained on the in-course quiz, formatted as `"correct/total"`. For program courses, this reflects the current program year; for manually assigned courses, this reflects the latest assignment. `null` if not completed yet or no quiz.
examples:
- 4/5
type:
- string
- 'null'
status:
anyOf:
- type: 'null'
- $ref: '#/components/schemas/EmployeeCourseStatusSchema'
description: The current status of the employee for this course. For program courses, this reflects the current program year; for manually assigned courses, this reflects the latest assignment.
years:
description: The history of employee's course statuses until current program year. Empty for manually assigned courses, which are not tied to a program year.
items:
$ref: '#/components/schemas/EmployeeCourseStatusPerYearSchema'
type: array
required:
- years
- quiz_score
- status
- course
title: CourseProgressSchema
type: object
responses:
RateLimitExceededErrorResponse:
content:
application/json:
schema:
$ref: '#/components/schemas/RateLimitExceededErrorResponse'
description: Rate limit is exceeded
UnauthorizedErrorResponse:
content:
application/json:
schema:
$ref: '#/components/schemas/UnauthorizedErrorResponse'
description: Missing API key or the key is invalid
ForbiddenErrorResponse:
content:
application/json:
schema:
$ref: '#/components/schemas/ForbiddenErrorResponse'
description: Requested resource cannot be accessed
UnprocessableContentErrorResponse:
content:
application/json:
schema:
$ref: '#/components/schemas/UnprocessableContentErrorResponse'
description: Unprocessable content
securitySchemes:
apiKeyAuth:
in: header
name: x-api-key
type: apiKey