{
  "components": {
    "schemas": {
      "CreateMeetingRequest": {
        "description": "A new meeting. Only a title and a date are required.",
        "properties": {
          "date": {
            "description": "Calendar date, YYYY-MM-DD.",
            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
            "title": "Date",
            "type": "string"
          },
          "external_id": {
            "anyOf": [
              {
                "maxLength": 128,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Your own reference, unique within the organisation. A second call with the same value returns the existing meeting instead of a duplicate.",
            "title": "External Id"
          },
          "participant_ids": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Member ids of those attending. Pass them when creating the meeting: their names improve how names are spelled in the transcript and make speaker attribution in the minutes possible. The transcript itself keeps unattributed speaker labels.",
            "title": "Participant Ids"
          },
          "project_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Project to group this meeting under.",
            "title": "Project Id"
          },
          "shared_with": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "Member ids. Only meaningful when visibility is shared.",
            "title": "Shared With"
          },
          "template_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Template for the minutes. Empty means the organisation's default.",
            "title": "Template Id"
          },
          "time": {
            "anyOf": [
              {
                "pattern": "^\\d{2}:\\d{2}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start time, HH:MM. Display only.",
            "title": "Time"
          },
          "title": {
            "description": "Subject of the meeting.",
            "maxLength": 300,
            "minLength": 1,
            "title": "Title",
            "type": "string"
          },
          "visibility": {
            "anyOf": [
              {
                "enum": [
                  "private",
                  "organisation",
                  "shared"
                ],
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Empty means this integration's default visibility.",
            "title": "Visibility"
          }
        },
        "required": [
          "title",
          "date"
        ],
        "title": "CreateMeetingRequest",
        "type": "object"
      },
      "CreateMemberRequest": {
        "description": "A member without an account. Costs no licence and sends nothing.",
        "properties": {
          "description": {
            "anyOf": [
              {
                "maxLength": 300,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Job description. Helps attribute speakers in a recording.",
            "title": "Description"
          },
          "email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Unique within the organisation.",
            "title": "Email"
          },
          "name": {
            "description": "Name of the member.",
            "maxLength": 80,
            "minLength": 1,
            "title": "Name",
            "type": "string"
          },
          "role": {
            "anyOf": [
              {
                "maxLength": 80,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Role within the organisation.",
            "title": "Role"
          }
        },
        "required": [
          "name"
        ],
        "title": "CreateMemberRequest",
        "type": "object"
      },
      "CreateProjectRequest": {
        "properties": {
          "name": {
            "description": "Name of the project.",
            "maxLength": 120,
            "minLength": 1,
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "name"
        ],
        "title": "CreateProjectRequest",
        "type": "object"
      },
      "ErrorBody": {
        "properties": {
          "code": {
            "description": "Stable, machine-readable error code.",
            "title": "Code",
            "type": "string"
          },
          "details": {
            "additionalProperties": true,
            "description": "Extra context for this refusal, keyed per code. Useful when debugging, but not a contract to branch on.",
            "title": "Details",
            "type": "object"
          },
          "message": {
            "description": "Human-readable explanation. May change.",
            "title": "Message",
            "type": "string"
          },
          "request_id": {
            "description": "Quote this in a support request.",
            "title": "Request Id",
            "type": "string"
          }
        },
        "required": [
          "code",
          "message",
          "request_id"
        ],
        "title": "ErrorBody",
        "type": "object"
      },
      "ErrorResponse": {
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ErrorBody",
            "description": "The single envelope every refusal is wrapped in."
          }
        },
        "required": [
          "error"
        ],
        "title": "ErrorResponse",
        "type": "object"
      },
      "Meeting": {
        "properties": {
          "created_at": {
            "description": "Creation time, Unix seconds.",
            "title": "Created At",
            "type": "integer"
          },
          "date": {
            "description": "Calendar date, YYYY-MM-DD.",
            "title": "Date",
            "type": "string"
          },
          "duration_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Length of the recording. Absent until audio has been processed.",
            "title": "Duration Seconds"
          },
          "external_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Your own reference for this meeting, unique within the organisation. Only ever set through this API.",
            "title": "External Id"
          },
          "id": {
            "description": "Identifier of the meeting, prefixed `mtg_`.",
            "title": "Id",
            "type": "string"
          },
          "participant_ids": {
            "description": "Member ids of those attending.",
            "items": {
              "type": "string"
            },
            "title": "Participant Ids",
            "type": "array"
          },
          "project_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Project this meeting is grouped under, if any.",
            "title": "Project Id"
          },
          "status": {
            "description": "Where the meeting is in the pipeline. Poll this to follow a recording from upload to finished minutes.",
            "enum": [
              "created",
              "audio_uploaded",
              "transcribing",
              "transcribed",
              "generating_minutes",
              "minutes_ready",
              "transcription_failed",
              "minutes_failed",
              "transcribe_blocked",
              "audio_rejected"
            ],
            "title": "Status",
            "type": "string"
          },
          "template_id": {
            "description": "Template the minutes are shaped by.",
            "title": "Template Id",
            "type": "string"
          },
          "time": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start time, HH:MM. Display only.",
            "title": "Time"
          },
          "title": {
            "description": "Subject of the meeting.",
            "title": "Title",
            "type": "string"
          },
          "updated_at": {
            "description": "Time of the last change, Unix seconds.",
            "title": "Updated At",
            "type": "integer"
          },
          "visibility": {
            "description": "Who inside the organisation can see this meeting.",
            "enum": [
              "private",
              "organisation",
              "shared"
            ],
            "title": "Visibility",
            "type": "string"
          }
        },
        "required": [
          "id",
          "title",
          "date",
          "status",
          "visibility",
          "template_id",
          "created_at",
          "updated_at"
        ],
        "title": "Meeting",
        "type": "object"
      },
      "MeetingPage": {
        "properties": {
          "meetings": {
            "description": "One page of meetings, newest first.",
            "items": {
              "$ref": "#/components/schemas/Meeting"
            },
            "title": "Meetings",
            "type": "array"
          },
          "next_cursor": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Pass as `cursor` to fetch the next page. Absent means the end. A page may contain fewer items than `limit`.",
            "title": "Next Cursor"
          }
        },
        "required": [
          "meetings"
        ],
        "title": "MeetingPage",
        "type": "object"
      },
      "Member": {
        "properties": {
          "id": {
            "description": "Identifier of the member, prefixed `emp_`.",
            "title": "Id",
            "type": "string"
          },
          "name": {
            "description": "Name of the member.",
            "title": "Name",
            "type": "string"
          },
          "role": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Role within the organisation.",
            "title": "Role"
          },
          "status": {
            "description": "Whether this member can sign in. Only `active` and `invited` members can be shared a meeting with.",
            "enum": [
              "active",
              "invited",
              "no_account",
              "deactivated"
            ],
            "title": "Status",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "status"
        ],
        "title": "Member",
        "type": "object"
      },
      "MemberList": {
        "properties": {
          "members": {
            "description": "The organisation's human members. Integrations are never listed.",
            "items": {
              "$ref": "#/components/schemas/Member"
            },
            "title": "Members",
            "type": "array"
          }
        },
        "required": [
          "members"
        ],
        "title": "MemberList",
        "type": "object"
      },
      "Minutes": {
        "properties": {
          "content": {
            "description": "The minutes in the requested form.",
            "title": "Content",
            "type": "string"
          },
          "format": {
            "description": "The form the content is delivered in.",
            "enum": [
              "html",
              "markdown"
            ],
            "title": "Format",
            "type": "string"
          },
          "template_id": {
            "description": "Template the minutes were shaped by.",
            "title": "Template Id",
            "type": "string"
          }
        },
        "required": [
          "format",
          "template_id",
          "content"
        ],
        "title": "Minutes",
        "type": "object"
      },
      "ParticipantsRequest": {
        "description": "Replace the meeting's participants with exactly this list.",
        "properties": {
          "participant_ids": {
            "description": "Member ids of those attending. An empty list clears the list.",
            "items": {
              "type": "string"
            },
            "title": "Participant Ids",
            "type": "array"
          }
        },
        "required": [
          "participant_ids"
        ],
        "title": "ParticipantsRequest",
        "type": "object"
      },
      "Project": {
        "properties": {
          "id": {
            "description": "Identifier to pass as `project_id` on a meeting.",
            "title": "Id",
            "type": "string"
          },
          "name": {
            "description": "Name of the project.",
            "title": "Name",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name"
        ],
        "title": "Project",
        "type": "object"
      },
      "ProjectList": {
        "properties": {
          "projects": {
            "description": "The organisation's active projects.",
            "items": {
              "$ref": "#/components/schemas/Project"
            },
            "title": "Projects",
            "type": "array"
          }
        },
        "required": [
          "projects"
        ],
        "title": "ProjectList",
        "type": "object"
      },
      "Template": {
        "properties": {
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "What this template is meant for.",
            "title": "Description"
          },
          "id": {
            "description": "Identifier to pass as `template_id` on a meeting.",
            "title": "Id",
            "type": "string"
          },
          "is_default": {
            "default": false,
            "description": "What a meeting gets when no template is given.",
            "title": "Is Default",
            "type": "boolean"
          },
          "name": {
            "description": "Name of the template.",
            "title": "Name",
            "type": "string"
          },
          "source": {
            "description": "Where the template comes from, for example whether NotulAI supplies it or the organisation wrote it. Treat this as free text: new values may appear.",
            "title": "Source",
            "type": "string"
          },
          "version": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "description": "Revision of the template, if it is versioned.",
            "title": "Version"
          }
        },
        "required": [
          "id",
          "name",
          "source"
        ],
        "title": "Template",
        "type": "object"
      },
      "TemplateList": {
        "properties": {
          "templates": {
            "description": "The templates this organisation can choose from.",
            "items": {
              "$ref": "#/components/schemas/Template"
            },
            "title": "Templates",
            "type": "array"
          }
        },
        "required": [
          "templates"
        ],
        "title": "TemplateList",
        "type": "object"
      },
      "Transcript": {
        "description": "The transcript as plain text, with a speaker label per turn.",
        "properties": {
          "transcript": {
            "description": "Plain text with a speaker label per turn, such as `spk_0`. Those labels are not attributed: they say that speakers differ, not who they are. Attribution to named people happens when the minutes are generated, so the names appear there and not here.",
            "title": "Transcript",
            "type": "string"
          }
        },
        "required": [
          "transcript"
        ],
        "title": "Transcript",
        "type": "object"
      },
      "UpdateMeetingRequest": {
        "description": "Change a meeting. Send only the fields you want to change.",
        "properties": {
          "date": {
            "anyOf": [
              {
                "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Calendar date, YYYY-MM-DD.",
            "title": "Date"
          },
          "project_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Project to group this meeting under. Empty detaches it.",
            "title": "Project Id"
          },
          "time": {
            "anyOf": [
              {
                "pattern": "^(\\d{2}:\\d{2})?$",
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Start time, HH:MM. Empty clears it.",
            "title": "Time"
          },
          "title": {
            "anyOf": [
              {
                "maxLength": 300,
                "minLength": 1,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Subject of the meeting.",
            "title": "Title"
          }
        },
        "title": "UpdateMeetingRequest",
        "type": "object"
      },
      "UploadTarget": {
        "properties": {
          "expires_in": {
            "description": "Validity in seconds.",
            "title": "Expires In",
            "type": "integer"
          },
          "method": {
            "const": "PUT",
            "default": "PUT",
            "description": "The HTTP method the upload URL expects.",
            "title": "Method",
            "type": "string"
          },
          "upload_url": {
            "description": "Presigned URL. PUT the audio file here.",
            "title": "Upload Url",
            "type": "string"
          }
        },
        "required": [
          "upload_url",
          "expires_in"
        ],
        "title": "UploadTarget",
        "type": "object"
      },
      "UploadUrlRequest": {
        "description": "Ask for a one-time upload target for this meeting's audio.",
        "properties": {
          "content_type": {
            "description": "MIME type of the audio file.",
            "title": "Content Type",
            "type": "string"
          }
        },
        "required": [
          "content_type"
        ],
        "title": "UploadUrlRequest",
        "type": "object"
      },
      "Usage": {
        "properties": {
          "credits_remaining": {
            "description": "Credits left this period. Generating minutes spends credits.",
            "title": "Credits Remaining",
            "type": "integer"
          },
          "next_reset_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "Date of the next top-up, or empty when there is none.",
            "title": "Next Reset At"
          },
          "transcribe_seconds_remaining": {
            "description": "Seconds of audio that may still be transcribed this period.",
            "title": "Transcribe Seconds Remaining",
            "type": "integer"
          }
        },
        "required": [
          "credits_remaining",
          "transcribe_seconds_remaining"
        ],
        "title": "Usage",
        "type": "object"
      },
      "Vocabulary": {
        "properties": {
          "entries": {
            "description": "The same terms, each with the wrong spellings the system knows.",
            "items": {
              "$ref": "#/components/schemas/VocabularyEntry"
            },
            "title": "Entries",
            "type": "array"
          },
          "max_terms": {
            "description": "How many terms the list may hold at most.",
            "title": "Max Terms",
            "type": "integer"
          },
          "terms": {
            "description": "The organisation's complete vocabulary.",
            "items": {
              "type": "string"
            },
            "title": "Terms",
            "type": "array"
          }
        },
        "required": [
          "terms",
          "entries",
          "max_terms"
        ],
        "title": "Vocabulary",
        "type": "object"
      },
      "VocabularyEntry": {
        "properties": {
          "term": {
            "description": "The intended spelling.",
            "title": "Term",
            "type": "string"
          },
          "variants": {
            "description": "Known wrong spellings that are corrected to this term.",
            "items": {
              "$ref": "#/components/schemas/VocabularyVariant"
            },
            "title": "Variants",
            "type": "array"
          }
        },
        "required": [
          "term",
          "variants"
        ],
        "title": "VocabularyEntry",
        "type": "object"
      },
      "VocabularyRequest": {
        "description": "Replace the whole term list.",
        "properties": {
          "terms": {
            "description": "The organisation's complete vocabulary.",
            "items": {
              "type": "string"
            },
            "title": "Terms",
            "type": "array"
          }
        },
        "required": [
          "terms"
        ],
        "title": "VocabularyRequest",
        "type": "object"
      },
      "VocabularyTermRequest": {
        "properties": {
          "term": {
            "description": "A single term to add.",
            "minLength": 1,
            "title": "Term",
            "type": "string"
          }
        },
        "required": [
          "term"
        ],
        "title": "VocabularyTermRequest",
        "type": "object"
      },
      "VocabularyVariant": {
        "properties": {
          "source": {
            "description": "`auto` when learned from a confirmed correction, `manual` when typed in.",
            "title": "Source",
            "type": "string"
          },
          "text": {
            "description": "A known wrong spelling.",
            "title": "Text",
            "type": "string"
          }
        },
        "required": [
          "text",
          "source"
        ],
        "title": "VocabularyVariant",
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "description": "An API key issued to an integration. Send it as `Authorization: Bearer nla_live_...`.",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "description": "The public API of NotulAI. Every call needs an API key in the Authorization header: `Authorization: Bearer nla_live_...`.\n\nThis API is in alpha. While it carries that label, breaking changes are possible; every one of them is announced to the administrators of each organisation with a live key before it ships. Access is granted per organisation: request it at https://www.notulai.nl/contact.",
    "title": "NotulAI API",
    "version": "1.1.0"
  },
  "openapi": "3.0.0",
  "paths": {
    "/v1/employees": {
      "get": {
        "operationId": "list_employees_v1_employees_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberList"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "The organisation's human members, so participants can be assigned. Integrations are never in this list.",
        "tags": [
          "Members"
        ],
        "x-notulai-scope": "employees:read"
      },
      "post": {
        "operationId": "create_member_v1_employees_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMemberRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Member"
                }
              }
            },
            "description": "The member was created."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault. `INVALID_EMAIL`: The email address is not a valid address."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`EMAIL_TAKEN`: Another member already uses this address. `details` names the member that holds it. `MEMBER_LIMIT_EXCEEDED`: The organisation has reached the maximum number of member records."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Add a member without an account. Costs no licence.",
        "tags": [
          "Members"
        ],
        "x-notulai-scope": "employees:write"
      }
    },
    "/v1/meetings": {
      "get": {
        "operationId": "list_meetings_v1_meetings_get",
        "parameters": [
          {
            "description": "Meetings per page, 1 to 50. Defaults to 25.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Limit"
            }
          },
          {
            "description": "`next_cursor` from the previous page.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Cursor"
            }
          },
          {
            "description": "Look up the single meeting carrying this reference. Cannot be combined with the other filters.",
            "in": "query",
            "name": "external_id",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "External Id"
            }
          },
          {
            "description": "Earliest meeting date, YYYY-MM-DD, inclusive.",
            "in": "query",
            "name": "date_from",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Date From"
            }
          },
          {
            "description": "Latest meeting date, YYYY-MM-DD, inclusive.",
            "in": "query",
            "name": "date_to",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Date To"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeetingPage"
                }
              }
            },
            "description": "Success."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault. `INVALID_LIMIT`: `limit` is not a whole number within the allowed range. `INVALID_CURSOR`: `cursor` was not produced by a previous page of this list. `INVALID_DATE`: A date is not a calendar date in YYYY-MM-DD form. `INVALID_DATE_RANGE`: `date_from` lies after `date_to`."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Page through the organisation's meetings, newest first.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "meetings:read"
      },
      "post": {
        "operationId": "create_meeting_v1_meetings_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMeetingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meeting"
                }
              }
            },
            "description": "A meeting with this `external_id` already existed and is returned unchanged."
          },
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meeting"
                }
              }
            },
            "description": "The meeting was created."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault. `INVALID_DATE`: A date is not a calendar date in YYYY-MM-DD form. `INVALID_TIME`: `time` is not a time of day in HH:MM form. `INVALID_EXTERNAL_ID`: `external_id` is empty or longer than allowed. `INVALID_SHARED_WITH`: `shared_with` names members who cannot be shared with, because they have no account or are an integration. `details.invalid` lists them."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`EXTERNAL_ID_TAKEN`: Another meeting in this organisation already carries this `external_id`."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Create a meeting.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "meetings:write"
      }
    },
    "/v1/meetings/{meeting_id}": {
      "delete": {
        "description": "With a personal key you can delete meetings you created yourself, or any visible meeting if you are an organisation admin.",
        "operationId": "delete_meeting_v1_meetings__meeting_id__delete",
        "parameters": [
          {
            "description": "Identifier of the meeting, prefixed `mtg_`.",
            "in": "path",
            "name": "meeting_id",
            "required": true,
            "schema": {
              "title": "Meeting Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No content."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired. `FORBIDDEN`: The action is not allowed for this caller."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Delete a meeting and everything belonging to it. Irreversible.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "meetings:delete"
      },
      "get": {
        "operationId": "get_meeting_v1_meetings__meeting_id__get",
        "parameters": [
          {
            "description": "Identifier of the meeting, prefixed `mtg_`.",
            "in": "path",
            "name": "meeting_id",
            "required": true,
            "schema": {
              "title": "Meeting Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meeting"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Fetch a single meeting, including its status.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "meetings:read"
      },
      "patch": {
        "description": "Only the fields you send are touched. An empty `time` or `project_id` clears it; an empty `title` is refused. Allowed at any point in the meeting's life. With a personal key this follows the rule of the web application: you can change meetings you created yourself, or any visible meeting if you are an organisation admin. An integration key is bounded by visibility alone. Changing the title, the date or the project re-indexes the meeting for search, which costs one credit once its minutes have been indexed; moving only the start time is free.",
        "operationId": "update_meeting_v1_meetings__meeting_id__patch",
        "parameters": [
          {
            "description": "Identifier of the meeting, prefixed `mtg_`.",
            "in": "path",
            "name": "meeting_id",
            "required": true,
            "schema": {
              "title": "Meeting Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMeetingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meeting"
                }
              }
            },
            "description": "Success."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault. `BAD_REQUEST`: The request was refused and no more specific code applies. `INVALID_DATE`: A date is not a calendar date in YYYY-MM-DD form. `INVALID_TIME`: `time` is not a time of day in HH:MM form."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired. `FORBIDDEN`: The action is not allowed for this caller."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Change a meeting's title, date, start time or project.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "meetings:write"
      }
    },
    "/v1/meetings/{meeting_id}/minutes": {
      "get": {
        "operationId": "get_minutes_v1_meetings__meeting_id__minutes_get",
        "parameters": [
          {
            "description": "Identifier of the meeting, prefixed `mtg_`.",
            "in": "path",
            "name": "meeting_id",
            "required": true,
            "schema": {
              "title": "Meeting Id",
              "type": "string"
            }
          },
          {
            "description": "`html` (the default) or `markdown`.",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Format"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Minutes"
                }
              }
            },
            "description": "Success."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`MINUTES_NOT_READY`: The minutes have not been generated yet. Poll the meeting until its status says so."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Fetch the minutes as HTML or as Markdown.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "minutes:read"
      }
    },
    "/v1/meetings/{meeting_id}/participants": {
      "put": {
        "operationId": "set_participants_v1_meetings__meeting_id__participants_put",
        "parameters": [
          {
            "description": "Identifier of the meeting, prefixed `mtg_`.",
            "in": "path",
            "name": "meeting_id",
            "required": true,
            "schema": {
              "title": "Meeting Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParticipantsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Meeting"
                }
              }
            },
            "description": "Success."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`PARTICIPANTS_LOCKED`: Participants steer transcription, so they can only be changed while the meeting has no audio yet."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Replace the participants, as long as no audio has been uploaded yet.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "meetings:write"
      }
    },
    "/v1/meetings/{meeting_id}/transcript": {
      "get": {
        "operationId": "get_transcript_v1_meetings__meeting_id__transcript_get",
        "parameters": [
          {
            "description": "Identifier of the meeting, prefixed `mtg_`.",
            "in": "path",
            "name": "meeting_id",
            "required": true,
            "schema": {
              "title": "Meeting Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transcript"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`TRANSCRIPT_NOT_READY`: Transcription has not finished. Poll the meeting until its status says so."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Fetch a meeting's transcript.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "transcript:read"
      }
    },
    "/v1/meetings/{meeting_id}/upload-url": {
      "post": {
        "operationId": "create_upload_url_v1_meetings__meeting_id__upload_url_post",
        "parameters": [
          {
            "description": "Identifier of the meeting, prefixed `mtg_`.",
            "in": "path",
            "name": "meeting_id",
            "required": true,
            "schema": {
              "title": "Meeting Id",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadUrlRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadTarget"
                }
              }
            },
            "description": "Success."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`TRANSCRIBE_QUOTA_EXHAUSTED`: Not enough transcription credit left for this recording. `details.next_reset_at` says when the quota replenishes."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`AUDIO_ALREADY_PRESENT`: This meeting already has audio. A recording is uploaded once; create a new meeting to start over."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Request a one-time upload target for this meeting's audio.",
        "tags": [
          "Meetings"
        ],
        "x-notulai-scope": "meetings:write"
      }
    },
    "/v1/projects": {
      "get": {
        "operationId": "list_projects_v1_projects_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectList"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "The active projects: exactly what `project_id` on a meeting accepts.",
        "tags": [
          "Projects"
        ],
        "x-notulai-scope": "projects:read"
      },
      "post": {
        "operationId": "create_project_v1_projects_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProjectRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            },
            "description": "The project was created."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Create a project.",
        "tags": [
          "Projects"
        ],
        "x-notulai-scope": "projects:write"
      }
    },
    "/v1/projects/{project_id}": {
      "delete": {
        "operationId": "delete_project_v1_projects__project_id__delete",
        "parameters": [
          {
            "description": "Identifier of the project, prefixed `proj_`.",
            "in": "path",
            "name": "project_id",
            "required": true,
            "schema": {
              "title": "Project Id",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted. No content."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`NOT_FOUND`: No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Delete a project. Existing meetings stay valid.",
        "tags": [
          "Projects"
        ],
        "x-notulai-scope": "projects:write"
      }
    },
    "/v1/templates": {
      "get": {
        "operationId": "list_templates_v1_templates_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateList"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "The templates this organisation can choose from.",
        "tags": [
          "Templates"
        ],
        "x-notulai-scope": "templates:read"
      }
    },
    "/v1/usage": {
      "get": {
        "operationId": "get_usage_v1_usage_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usage"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "What is left of this period's quota.",
        "tags": [
          "Usage"
        ],
        "x-notulai-scope": "usage:read"
      }
    },
    "/v1/vocabulary": {
      "get": {
        "operationId": "get_vocabulary_v1_vocabulary_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Vocabulary"
                }
              }
            },
            "description": "Success."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "The spellings the transcript is corrected to.",
        "tags": [
          "Vocabulary"
        ],
        "x-notulai-scope": "vocabulary:read"
      },
      "put": {
        "operationId": "replace_vocabulary_v1_vocabulary_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VocabularyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Vocabulary"
                }
              }
            },
            "description": "Success."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`VOCABULARY_FULL`: The vocabulary already holds the maximum number of terms."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Replace the whole vocabulary.",
        "tags": [
          "Vocabulary"
        ],
        "x-notulai-scope": "vocabulary:write"
      }
    },
    "/v1/vocabulary/terms": {
      "post": {
        "operationId": "add_vocabulary_term_v1_vocabulary_terms_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VocabularyTermRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Vocabulary"
                }
              }
            },
            "description": "Success."
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INVALID_REQUEST`: The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault."
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`UNAUTHENTICATED`: The Authorization header is missing, malformed, or the key is unknown, expired or revoked."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`IP_NOT_ALLOWED`: The key has an IP allowlist and this caller's address is not on it. `API_ACCESS_DISABLED`: The organisation does not have API access, or the integration behind this key is no longer active. `PERSONAL_API_KEYS_DISABLED`: The organisation does not have personal API keys enabled, so this personal key cannot be used. `INSUFFICIENT_SCOPE`: The key is valid but does not carry the scope this endpoint requires. `ORGANISATION_SUSPENDED`: The organisation is blocked. `ORGANISATION_EXPIRED`: The organisation's access has expired."
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`VOCABULARY_FULL`: The vocabulary already holds the maximum number of terms."
          },
          "429": {
            "description": "Too many requests. Refused by the edge before it reaches the API, so this response does not carry the error envelope. Back off and retry."
          },
          "500": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "`INTERNAL_ERROR`: Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket."
          }
        },
        "summary": "Add a single term to the vocabulary, without having to read the rest.",
        "tags": [
          "Vocabulary"
        ],
        "x-notulai-scope": "vocabulary:write"
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "servers": [
    {
      "description": "Production",
      "url": "https://api.notulai.nl"
    }
  ],
  "tags": [
    {
      "description": "Create meetings, upload audio, follow the status, collect the results.",
      "name": "Meetings"
    },
    {
      "description": "The templates the minutes can be shaped by.",
      "name": "Templates"
    },
    {
      "description": "The people a meeting's participants are chosen from.",
      "name": "Members"
    },
    {
      "description": "Labels a meeting can be grouped under.",
      "name": "Projects"
    },
    {
      "description": "Terms that steer how transcription spells names and jargon.",
      "name": "Vocabulary"
    },
    {
      "description": "What is left of this period's quota.",
      "name": "Usage"
    }
  ],
  "x-notulai-alpha": "This API is in alpha. While it carries that label, breaking changes are possible; every one of them is announced to the administrators of each organisation with a live key before it ships. Access is granted per organisation: request it at https://www.notulai.nl/contact.",
  "x-notulai-error-codes": {
    "API_ACCESS_DISABLED": {
      "meaning": "The organisation does not have API access, or the integration behind this key is no longer active.",
      "status": 403
    },
    "AUDIO_ALREADY_PRESENT": {
      "meaning": "This meeting already has audio. A recording is uploaded once; create a new meeting to start over.",
      "status": 409
    },
    "BAD_REQUEST": {
      "meaning": "The request was refused and no more specific code applies.",
      "status": 400
    },
    "CONFLICT": {
      "meaning": "The resource is not in a state that allows this action.",
      "status": 409
    },
    "EMAIL_TAKEN": {
      "meaning": "Another member already uses this address. `details` names the member that holds it.",
      "status": 409
    },
    "EXTERNAL_ID_TAKEN": {
      "meaning": "Another meeting in this organisation already carries this `external_id`.",
      "status": 409
    },
    "FORBIDDEN": {
      "meaning": "The action is not allowed for this caller.",
      "status": 403
    },
    "INSUFFICIENT_SCOPE": {
      "meaning": "The key is valid but does not carry the scope this endpoint requires.",
      "status": 403
    },
    "INTERNAL_ERROR": {
      "meaning": "Something went wrong on our side. The response carries a `request_id`; quote it in a support ticket.",
      "status": 500
    },
    "INVALID_CURSOR": {
      "meaning": "`cursor` was not produced by a previous page of this list.",
      "status": 400
    },
    "INVALID_DATE": {
      "meaning": "A date is not a calendar date in YYYY-MM-DD form.",
      "status": 400
    },
    "INVALID_DATE_RANGE": {
      "meaning": "`date_from` lies after `date_to`.",
      "status": 400
    },
    "INVALID_EMAIL": {
      "meaning": "The email address is not a valid address.",
      "status": 400
    },
    "INVALID_EXTERNAL_ID": {
      "meaning": "`external_id` is empty or longer than allowed.",
      "status": 400
    },
    "INVALID_LIMIT": {
      "meaning": "`limit` is not a whole number within the allowed range.",
      "status": 400
    },
    "INVALID_REQUEST": {
      "meaning": "The request body or the combination of query parameters is not valid. `details.fields` names the offending fields where the body is at fault.",
      "status": 400
    },
    "INVALID_SHARED_WITH": {
      "meaning": "`shared_with` names members who cannot be shared with, because they have no account or are an integration. `details.invalid` lists them.",
      "status": 400
    },
    "INVALID_TIME": {
      "meaning": "`time` is not a time of day in HH:MM form.",
      "status": 400
    },
    "IP_NOT_ALLOWED": {
      "meaning": "The key has an IP allowlist and this caller's address is not on it.",
      "status": 403
    },
    "MEMBER_LIMIT_EXCEEDED": {
      "meaning": "The organisation has reached the maximum number of member records.",
      "status": 409
    },
    "MINUTES_NOT_READY": {
      "meaning": "The minutes have not been generated yet. Poll the meeting until its status says so.",
      "status": 409
    },
    "NOT_FOUND": {
      "meaning": "No such resource, or it is not visible to this integration. A private meeting of another member is answered as absent rather than as forbidden, so its existence is not revealed.",
      "status": 404
    },
    "NOT_READY": {
      "meaning": "The content is not available yet. Try again later.",
      "status": 409
    },
    "ORGANISATION_EXPIRED": {
      "meaning": "The organisation's access has expired.",
      "status": 403
    },
    "ORGANISATION_SUSPENDED": {
      "meaning": "The organisation is blocked.",
      "status": 403
    },
    "PARTICIPANTS_LOCKED": {
      "meaning": "Participants steer transcription, so they can only be changed while the meeting has no audio yet.",
      "status": 409
    },
    "PERSONAL_API_KEYS_DISABLED": {
      "meaning": "The organisation does not have personal API keys enabled, so this personal key cannot be used.",
      "status": 403
    },
    "QUOTA_EXHAUSTED": {
      "meaning": "The organisation's quota for this period is spent. `details.next_reset_at` says when it replenishes.",
      "status": 402
    },
    "TRANSCRIBE_QUOTA_EXHAUSTED": {
      "meaning": "Not enough transcription credit left for this recording. `details.next_reset_at` says when the quota replenishes.",
      "status": 402
    },
    "TRANSCRIPT_NOT_READY": {
      "meaning": "Transcription has not finished. Poll the meeting until its status says so.",
      "status": 409
    },
    "UNAUTHENTICATED": {
      "meaning": "The Authorization header is missing, malformed, or the key is unknown, expired or revoked.",
      "status": 401
    },
    "VOCABULARY_FULL": {
      "meaning": "The vocabulary already holds the maximum number of terms.",
      "status": 409
    }
  }
}
