

# Custom plugins for Amazon Q Business
Custom plugins

You can use the Amazon Q Business console or APIs to create custom plugins for your Amazon Q application.

With custom plugins, you can choose to integrate Amazon Q with any third-party application for a variety of different use cases. Once enabled, end users can use natural language to query data (like available calendar slots, stock prices, vacation balance), and take actions (like booking a meeting, submitting vacation time, updating a record).

To create a custom plugin, you need to perform the following steps:
+ Configure authentication and network information to connect Amazon Q Business to your third-party application.
+ Create or edit an OpenAPI schema outlining the different API operations you want to enable for your custom plugin in JSON or YAML format.

  You can upload the OpenAPI schema file to Amazon S3 or you can paste it in the OpenAPI text editor in the Amazon Q Business console, which will validate your schema. You can configure up to 20 API operations per custom plugin.

Once your custom plugin is deployed, Amazon Q Business will dynamically determine the appropriate APIs to call to accomplish an end user requested task. In order to maximize plugin accuracy, review the [best practices for configuring OpenAPI schema definitions](https://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/plugins-api-schema-best-practices.html) for custom plugins.

**Note**  
Creating custom forms with array fields (fields with nested objects inside an array) for custom plugins isn't supported on the console. 

**Topics**
+ [

# Prerequisites for Amazon Q Business custom plugins
](custom-plugin-prereqs.md)
+ [

# Service access roles for Amazon Q Business custom plugins
](create-plugin-iam-role.md)
+ [

# Defining OpenAPI schemas for custom plugins
](plugins-api-schema.md)
+ [

# Best practices for OpenAPI schema definition for custom plugins
](plugins-api-schema-best-practices.md)
+ [

# Creating an Amazon Q Business custom plugin
](custom-plugin-create.md)
+ [

# Using an Amazon Q Business custom plugin
](using-custom-plugin.md)

# Prerequisites for Amazon Q Business custom plugins
Prerequisites

**Before you configure your Amazon Q custom plugin, you must ensure you have the following:**
+ A defined OpenAPI schema in JSON or YAML (maximum size is 1 MB). In order to maximize accuracy with Amazon Q Business custom plugin, follow the [best practices for configuring OpenAPI schema definitions](https://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/plugins-api-schema-best-practices.html) for custom plugins.
+ If authentication is required to connect Amazon Q to your third-party application, create OAuth authentication credentials. You need to store these authentication credentials in a Secrets Manager secret to connect your third-party application to Amazon Q.

# Service access roles for Amazon Q Business custom plugins
Service access roles

To connect Amazon Q Business to third party applications that require authentication, you need to give the Amazon Q role permissions to access your Secrets Manager secret. This will enable an Amazon Q Business custom plugin to access the credentials needed to log in to the third party service.
+ Permission to access your Secrets Manager secret to get the credentials you use to log in to the third party service instance you are creating a plugin for.

You don't have to provide this role for custom plugins that don't require authentication.

**Important**  
If you're changing response settings for an Amazon Q application created and deployed before 16 April, 2024, you need to update your web experience service role. For information on service role permissions needed, see [IAM role for an Amazon Q web experience](https://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/iam-roles.html#deploy-experience-iam-role). For information on how to update your web experience service role, see [Updating a web experience](https://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/supported-exp-actions.html#update-web-experience).

The following is the service access IAM role required:

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "AllowQBusinessToGetSecretValue",
            "Effect": "Allow",
            "Action": [
                "secretsmanager:GetSecretValue"
            ],
            "Resource": [
                "arn:aws:secretsmanager:us-east-1:111122223333:secret:[[secret_id]]"
            ]
        }
    ]
}
```

------

**To allow Amazon Q to assume a role, use the following trust policy:**

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "QBusinessApplicationTrustPolicy",
            "Effect": "Allow",
            "Principal": {
                "Service": "qbusiness.amazonaws.com"
            },
            "Action": "sts:AssumeRole",
            "Condition": {
                "StringEquals": {
                    "aws:SourceAccount": "111122223333"
                },
                "ArnLike": {
                    "aws:SourceArn": "arn:aws:qbusiness:us-east-1:111122223333:application/application-id"
                }
            }
        }
    ]
}
```

------

Amazon Q assumes this role to access your third party service instance credentials.

If you use the console and choose to create a new IAM role, Amazon Q creates the IAM role for you. If you use the console and choose to use an existing secret, or you use the API, make sure your secret contains the permissions above. For more information on creating IAM roles, see [Creating IAM roles](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create.html).

# Defining OpenAPI schemas for custom plugins
Defining OpenAPI schemas

Amazon Q Business uses the configured third-party OpenAPI specifications to dynamically determine which API operations to perform in order to fulfill an end user requests. To configure a custom plugin you must define at least 1 API operation and a maximum of 20 API operations that can be invoked. To define the API operations, create an OpenAPI schema in JSON or YAML format. You can create OpenAPI schema files and upload them to Amazon Simple Storage Service (Amazon S3). Alternatively, you can use the OpenAPI text editor in the console, which will validate your schema.

This section will first cover the required definitions for the OpenAPI schema. The next section will cover [best practices and examples for configuring OpenAPI schema definitions](https://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/plugins-api-schema-best-practices.html) to maximize the accuracy of your Amazon Q Business custom plugins. For more details about OpenAPI schemas, see [OpenAPI specification](https://swagger.io/specification/) on the Swagger website.

**Topics**
+ [

## OpenAPI Schema definitions for custom plugins
](#plugins-api-schema-definition)

## OpenAPI Schema definitions for custom plugins
OpenAPI Schema definitions

The following is the general format of an OpenAPI schema for a custom plugin.

```
{
    "openapi": "3.0.0",
    "servers": [
    {
      "url": "https://api.example.com"
    }
  ],
    "paths": {
        "/path": {
            "method": {
                "description": "string",
                "operationId": "string",
                "parameters": [ ... ],
                "requestBody": { ... },
                "responses": { ... },
                "security": [ ... ]
           }
       }
    },
    "security": [
        {
            "OAuth2": ["read", "write"]
        }
    ],
    "components": {
    "securitySchemes": {}
 }
}
```

The following list describes fields in the OpenAPI schema
+ `openapi` – (Required) The version of OpenAPI that's being used. This value must be `"3.0.0"` or higher for custom plugins.
+ `servers` – (Required) The identifier for application connectivity from API clients. This is required for the custom plugin call to succeed.
+ `paths` – (Required) Contains relative paths to individual endpoints. Each path must begin with a forward slash (`/`). Amazon Q Business supports only one configured endpoint per custom plugin.
+ `method` – (Required) Defines the method to use.
+ `securitySchemes` – (Optional) Defines the OAuth security parameters.
+ `security` – (Required when using authentication) Defines which security schemes are applied to the whole API or specific operations. This is required when using OAuth authentication.

Minimally, each method requires the following fields:
+ `description` – A description of the API operation. Use this field to let the custom plugin know when to call this API operation and what the operation does.
+ `responses` – Contains properties that the custom plugin returns in the API response. The custom plugin uses the response properties to construct prompts, accurately process the results of an API call, and determine a correct set of steps for performing an action.

The fields within the following two objects provide more information for your custom plugin to effectively select API operations that are needed to fulfill an end user request. For each field, set the value of the `required` field to `true` if required and to `false` if optional.
+ `parameters` – Contains information about parameters that can be included in the request.
+ `requestBody` – Contains the fields in the request body for the operation. Don't include this field for `GET` and `DELETE` methods.

For details on configuring the fields review the following sections:

**Topics**
+ [

### OpenAPI Schema responses
](#plugins-api-schema-responses)
+ [

### OpenAPI Schema parameters
](#plugins-api-schema-parameters)
+ [

### OpenAPI Schema request body
](#plugins-api-schema-request-body)
+ [

### OpenAPI Schema security schemes
](#plugins-api-schema-security-scheme)

### OpenAPI Schema responses


The following is a sample response.

```
"responses": {
    "200": {
        "content": {
            "<media type>": {
                "schema": {
                    "properties": {
                        "<property>": {
                            "type": "string",
                            "description": "string"
                        },
                        ...
                    }
                }
            }
        },
    },
    ...
}
```

Each key in the `responses` object is a response code, which describes the status of the response. The response code maps to an object that contains the following information for the response:
+ `content` – (Required for each response) The content of the response.
+ *<media type>* – The format of the response body. At this time, only `application/json` is supported by custom plugins. For more information, see [Media types](https://swagger.io/docs/specification/media-types/) on the Swagger website.
+ `schema` – (Required for each media type) Defines the data type of the response body and its fields.
+ `properties` – (Required if there are `items` in the schema) Your custom plugins uses properties that you define in the schema to determine the information it needs to return to the end user in order to fulfill a task. Each property contains the following fields:
  + `type` – (Required for each property) The data type of the response field.
  + `description` – (Optional) Describes the property. The custom plugin can use this information to determine the information that it needs to return to the end user.

### OpenAPI Schema parameters


The following are examples of parameters.

```
"parameters": [
    {
        "name": "string", // e.g. "userName"
        "description": "string",
        "required": boolean,
        "x-amzn-form-display-name": "string" // e.g. "User Name"
        "schema": {
            ...
        }
    },
    {
        "name": "string", // e.g. "employeeId"
        "description": "string",
        "required": boolean,
        "x-amzn-form-hide": boolean //e.g. true
        "schema": {
            ...
        }
    }
    ...
]
```

Your custom plugin uses the following fields to determine the information it must get from the end user to perform the plugin's requirements.
+ `name` – (Required) The name of the parameter.
+ `description` – (Required) A description of the parameter. Use this field to help the plugin to understand how to elicit this parameter from the user or determine that it already has that parameter value from prior actions or from the user’s request to the custom plugin.
+ `required` – (Optional) Whether the parameter is required for the API request. Use this field to indicate to the custom plugin whether this parameter is needed for every invocation or if it's optional.
+ `schema` – (Optional) The definition of input and output data types. For more information, see [Data Models (Schemas)](https://swagger.io/docs/specification/data-models/) on the Swagger website.
+ Extension support – (Optional) For a write API operation, an Amazon Q Business custom plugin may dynamically create a confirmation form that is presented to end users. This form allows users to confirm and/or correct parameters Amazon Q populated based on the end user’s request or past actions. The following extensions can be used to modify how that form is created:
  + `x-amzn-form-display-name` – (Optional) This can be used at parameter level to override the default name visible in the form.
  + `x-amzn-form-hide` – (Optional) This can be used to hide a parameter from being displayed in the user facing form.
+ Schemas containing composition keywords (`allOf`, `not`, `oneOf`, or `anyOf`) are not supported.
+ Schemas containing array types are not supported. For example, schemas such as `{"type": "array", "items": {"string"}}` are not supported.

### OpenAPI Schema request body


The following is the general structure of a `requestBody` field:

```
"requestBody": {
    "required": boolean,
    "content": {
        "<media type>": {
            "schema": {
                "properties": {
                    "<property>": {
                        "type": "string",
                        "description": "string"
                    },
                    ...
                }
            }
        }
    }
}
```

The following list describes each field:
+ `required` – (Optional) Whether the request body is required for the API request.
+ `content` – (Required) The content of the request body.
+ *<media type>* – (Optional) The format of the request body. At this time, only `application/json` is supported by custom plugins. For more information, see [Media types](https://swagger.io/docs/specification/media-types/) on the Swagger website.
+ `schema` – (Optional) Defines the data type of the request body and its fields.
+ `properties` – (Optional) Your custom plugin uses properties that you define in the schema to determine the information it must get from the end user to make the API request. Each property contains the following fields:
  + `type` – (Optional) The data type of the request field.
  + `description` – (Optional) Describes the property. The custom plugin can use this information to determine the information it needs to return to the end user.
+ Schemas containing composition keywords (`allOf`, `not`, `oneOf`, or `anyOf`) are not supported.
+ Schemas containing array types are not supported. For example, schemas such as `{"type": "array", "items": {"string"}}` are not supported.

### OpenAPI Schema security schemes


Following is the general structure of a `securityScheme` field:

```
"securitySchemes": {
      "OAuth2": {
        "type": "oauth2",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://example.com/oauth/authorize",
            "tokenUrl": "https://example.com/oauth/token",
            "scopes": {
              "read": "Read access to resources",
              "write": "Write access to resources"
            }
          }
        }
      }
    }
```

If your API requires OAuth authorization, the OpenAPI schema needs to include security schemes. We support the following authorization code flow of OAuth:
+ `type` – Must be `oauth2`.
+ `flows` – Must contain `authorizationCode`.
+ `authorizationUrl` – The URL to which the user will be sent to begin the authorization process.
+ `tokenUrl` – (Optional) The URL that the custom plugin will use to exchange the authorization code for an access token.
+ `scopes` – Defines the permissions that the custom plugin will request.

Successful authorization using OAuth also requires an OAuth client ID, client secret, and a redirect url. These will need to be provided as secrets when creating the custom plugin. 

# Best practices for OpenAPI schema definition for custom plugins
Best practices for OpenAPI schema definition

While application programming interfaces (APIs) have traditionally been used by developers to integrate with external applications, today APIs are increasingly being used by generative AI-powered assistants, such as Amazon Q Business custom plugins. However, its important to note that APIs being used with AI assistants may require design optimizations that were not critical for traditional application integrations. Following the best practices below will help Amazon Q Business to maximize the accuracy and improve efficiency when resolving end user requests.

**Topics**
+ [

## Optimizing OpenAPI schema accuracy
](#plugins-api-schema-accuracy)
+ [

## Best practices for OpenAPI Schema names
](#plugins-api-schema-names)
+ [

## Best practices for OpenAPI Schema descriptions
](#plugins-api-schema-descriptions)
+ [

## Best practices for JSON input schemas
](#plugins-api-schema-json-input)
+ [

## Other important considerations for OpenAPI specifications
](#plugins-api-schema-misc)
+ [

## Example of API Schema optimization
](#plugins-api-schema-optimization)

## Optimizing OpenAPI schema accuracy


To create a custom plugin, you need to create or edit an OpenAPI schema outlining the different API actions you want to enable for your custom plugin. Once the custom plugin is deployed, Amazon Q Business will process an end user prompt and use the OpenAPI schema to dynamically determine the appropriate APIs to call to accomplish the user’s goal. Therefore, the OpenAPI schema definition has a big impact on API selection accuracy.

The following are the OpenAPI schema sections you need to optimize to maximize the accuracy of your Amazon Q Business plugins:
+ **Names** – Names for operation IDs, parameters, object schema property keys, title in info section, and more.
+ **Descriptions** – Descriptions for operations, parameters, schemas, and more.
+ **JSON schemas** – JSON schemas for API inputs (schemas defined in parameters and request body). Within these schemas, important information includes the data type of each schema and format information (for example, date/date-time for ISO-8601 date strings), as well as names and descriptions mentioned above. 

In the next sections, we outline how you can maximize the accuracy of your custom plugin by following best practices for your OpenAPI schema parameters.

## Best practices for OpenAPI Schema names

+ Names and IDs should be human-readable, descriptive, and unambiguous while being as concise as possible.
+ Operation IDs provide important signals for understanding the function of each operation. Though not required, it is recommended to add `operationIds` to your API schema. The following outlines some Operation ID naming best practices:
  + Avoid noun-only `operationIds`, like `contacts`. Instead, prefix operation names with descriptive verbs like `get`, `find`, `search`, `create`, `update`, and `delete`. For example, `getContacts`.
  + Ensure `operationIds` meaningfully relate to the function of the operation. Avoid including `operationIds` with meaningless suffixes/prefixes, like `search_1` and `search_2`. If multiple operations perform similar functions, but differ only by inputs, consider creating IDs like `searchByName` or `searchByEmail`, or even merging these operations.
  + Avoid adding long, redundant prefixes to names. For example, avoid `contactsPlugin.getContacts` and `contactsPlugin.createContact`. Instead, use `getContacts` and `createContact`.
+ Names of input request body properties and parameters are important for determining the role and purpose of each input needed for invoking an operation. The following outlines some input request naming best practices:
  + Avoid non-descriptive parameter names like `id`. Instead include a descriptive noun, like `contactId`.
  + It’s not necessary to include information that is redundant with the JSON data type of the input. For example, avoid using `recipientEmailsArray` and instead just use `recipientEmails`.
+ Be consistent with parameter names. Generally, parameters and response properties with the same name should mean the same thing across all operations in your schema. The following outlines some parameter naming best practices:
  + Avoid using different names for parameters with the same meaning. For example, `start_date` in one API and `begin_date` in another API if they mean the same thing.
  + Ensure parameter names and property names in responses are consistent with each other. For example, if an API returns `begin_date`, then also use the name `begin_date` in the input parameters if they have the same meaning.

## Best practices for OpenAPI Schema descriptions

+ Descriptions should be self-contained, providing sufficient guidance for how and when to use the operation or parameter they describe. The following outlines some description creation best practices:
  + Operation descriptions should describe what the operation does, including when, when not, and how to use it.
  + Avoid verbose descriptions. Parameter descriptions should concisely describe their purpose and how they impact the behavior of the operation. For example, rather than write “this field accepts an ISO-8601 date, which is of the format YYYY-MM-DD”, assign date to the format field.
  + Concise explanations are generally more useful than examples.
  + Make dependencies between operations explicit in the description. If an operation always requires another operation to be called first (such as, populating an input parameter from the other operation’s outputs), make this clear in the description of the operation or parameter.
+ Use descriptions only where there is ambiguity or missing context. Avoid adding descriptions that provide no additional information. Restrict the description to information needed to use the API for the use cases Amazon Q Business custom plugin is intended to handle.
+ Descriptions should not reference external links/URLs. Amazon Q Business custom plugins may not be able to access these.
+ Avoid referencing operations by their *path* or *verb*. Instead use their operation ID when referring to other operations in descriptions.
+ Avoid referencing schema components or API paths (except dependency `operationIds`) in the description. Ensure that descriptions are self-contained. As an exception to this, descriptions may reference dependency operations by their `operationIds` but should avoid providing specific usage examples of the operation. The following outlines some referencing best practices:
  + Don’t refer to operations by their API paths (e.g. `/api/v1/timeoff/requests`). Instead, use `operationIds` to refer to operations in descriptions. For example, `GetTimeOffRequests`.
  + Don’t refer to schema components like `#/components/schemas/TimeOffRequest`.
  + If examples are necessary, describe them in abstract terms. “For example, use `{operationId}` to do `{X}`” or “Use `{operationId}` when the end user asks for...”.
  + Internally, Amazon Q Business may use generate API calls differently than described in the OpenAPI schema. So, including usage examples may not always be helpful.

## Best practices for JSON input schemas

+ Simpler interfaces will lead to more efficient, consistent, and accurate plugin usage from Amazon Q Business. Thus, having fewer input parameters of lower complexity is best.
+ Keep the total number of parameter schemas per operation low. Keeping the total number of parameter schemas to 10 at most, but less than 4 on average, will give the best results. Having more parameters may result in slower responses because Amazon Q Business custom plugins will need to fill out each field.
+ Avoid including unnecessary optional input parameters. For example, for search APIs with many parameters for filtering results, use the most informative/important filters. Or, split into multiple operations to search by alternate criteria. 
+ Avoid structurally complex/nested inputs when possible. The following outlines some input parameter structure best practices:
  + **Instead of** `{"start": {"type": "object", "properties": {"date": {...}, "time": {...}}, "end": {...}}` **input** `{"start_date": {...}, "start_time": {...}, ..., "end_time": {...}}`.
  + Avoid schemas containing array types, which are not supported. For example, schemas such as `{"type": "array", "items": {"string"}}` are not supported..
  + Avoid circular references (`$ref` inside of `$ref`). Circular references can occur in nested structures when the same reference (`$ref`) appears inside of its de-referenced value. Although these are valid OpenAPI specifications, Amazon Q Business custom plugin may not reliably resolve these recursive definitions.
  + Avoid composition keywords (`allOf`, `not`, `oneOf`, or `anyOf` ), which are not supported
+ Use standard values in the format field for string parameters. For example, `date-time` or `date` for capturing ISO-8601 dates/times.

## Other important considerations for OpenAPI specifications

+ Never expose sensitive information in the API schema or API outputs. If information should not be exposed to the end user, do not include it in your API specification or use an API that produces such outputs.
+ If it is undesirable for an Amazon Q Business custom plugin to reference certain information in the API schemas to the end user, you can use instructions in the operation descriptions to help discourage this. However, you should not rely on this mechanism for highly sensitive information.
+ Only include essential information in API responses. Redundant or excessively verbose information will reduce the efficiency of an Amazon Q Business custom plugin. 
+ Limit paginated search results explicitly, particularly if each result returned is large/complex. Large API responses may result in slower responses for end users. Consider setting guidance or limits in the description of the parameter (for example, set to five at most).
+ Only 2XX responses may be shared with Amazon Q Business custom plugin end users. 4xx and 5xx responses will not be shared with end users. If you want to expose specific errors from the API, consider using a 2XX code for such errors. Ensure you include information that is appropriate to share with the end user.
+ The OpenAPI specification should be self-contained. Ensure that the set of API operations described in the schema support complete use cases without relying on APIs not defined or other plugins.

## Example of API Schema optimization


This section shows you an example of an API schema before and after our best practices are applied. The example API is used for managing Paid Time Off (PTO) requests for employees and supports two operations: checking the status of requests (with `api.V1.TimeOffRequest`) and making new requests (with `api.V1.RequestTimeOff`).

The following is the example unoptimized API Schema:

```
openapi: 3.0.3
info:
  # title is too long
  title: API for PTO Request Management
  version: 1.0.0
servers:
  - url: https://api.example.com
paths:
  /api/v1/timeoff/requests:
    get:
      # operation ID is ambiguous (is it to get a time off request or make one?) and contains unnecessary details ("api.V1")
      operationId: example.api.V1.TimeOffRequest
      # description is not self-contained (references an external link) and does not describe what the API returns or how to use it.
      description: Existing requests for the authenticated user. See the docs <a href=https://example.com>here</a> for more details.
      parameters:
        - name: type
          in: path
          # description does not include what a "type" is
          description: type to filter by
          required: false
          schema:
            type: string
        - name: status
          in: path
          # description does not include what a "status" is
          description: status to filter by
          required: false
          schema:
            type: string
        - name: start
          in: path
          # description is ambiguous
          description: start of range to include
          required: false
          schema:
            type: string
            # no formatting information is provided, e.g. `format: date`
        - name: end
          in: path
          # description is ambiguous
          description: end of range to include
          required: false
          schema:
            type: string
            # no formatting information is provided, e.g. `format: date`
        - name: limit
          in: path
          # guidance should be provided on how many results to return by default, e.g. less than 5
          description: limit on the number of requests to return
          required: false
          schema:
            type: integer
        - name: page
          in: path
          description: specific page of results to return if results are paginated
          required: false
          schema:
            type: integer
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TimeOffRequests"
  /api/v1/timeoff/request:
    post:
      # operation ID is ambiguous (is it to get a time off request or make one?) and contains unnecessary details ("api.V1")
      operationId: example.api.V1.RequestTimeOff
      # description is not self-contained (references an external link) and ambiguous.
      description: Make a request for the authenticated user. <a href=https://example.com/>API docs</a> for more details.-->
      requestBody: 
        content:
          application/json:
            schema:
              type: object
              properties:
                # this field adds unnecessary nesting to the inputs. Separate `start_date`, and `end_date` fields would be preferred
                range:
                  # missing a description, non-descriptive field name
                  type: object
                  properties:
                    start:
                      # start of what?
                      type: string
                      format: date
                    end:
                      # end of what?
                      type: string
                      format: dat
                  required:
                    - start
                    - end 
                type:
                  description: the type of request to make, e.g. `Personal` or `Vacation`
                  type: string
                  # use enums where possible
                note:
                  description: a short note describing the reason for the request
                  type: string  
      responses:
        "201":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TimeOffRequest"
components: 
  schemas: 
    TimeOffRequest:
      type: object
      properties:
        # this ID is not necessary for the end user (and is used nowhere else in the API), consider removing
        id:
          type: string
        status:
          # no descriptions provided
          type: string
        type:
          type: string
        start:
          type: string
        end:
          type: string
        note:
          type: string
        duration:
          type: integer
        # this ID is not necessary for the end user (and is used nowhere else in the API), consider removing
        approver_id:
          type: string
        approver_display_name:
          type: string  
    TimeOffRequests:
      type: array
      items:
        $ref: "#/components/schemas/TimeOffRequest"
```

Applying the best practices defined above, there are multiple updates that should be made to this API schema to get the best results when using Amazon Q Business custom plugins.

First, based on guidance to make names concise, descriptive and unambiguous, we’ll make a few updates to the operation IDs, parameter names, and schema title:
+ Change `example.api.V1.RequestTimeOff` to `CreateTimeOffRequest`
+ Change `example.api.V1.RequestTimeOff` to `GetTimeOffRequests`
+ Change the schema title in the info section from `API for PTO Request Management` to `TimeOff`

If you are able to change the API itself, we’d also like you to fix parameter names. Change parameters named `type` and `status` to `request_type` and `request_status` respectively

Next, based on best practices for descriptions, we’ll make the following updates:
+ Modify the description of `/api/v1/timeoff/requests` and `/api/v1/timeoff/request` to make them self-contained (remove URL) and describe what they do and how to use them. For example:
  + Change `Existing requests for the authenticated user. See the docs <a href=https://example.com>here</a> for more details.` to `Return existing time off requests (including information like the current approval status, dates/days used) for the authenticated user.`
  + Change `Make a request for the authenticated user. See <a href=https://example.com/>API docs</a> for more details.` to `Create a new time off request of a particular type (e.g. Personal or Vacation) for the authenticated user based on a start and end date (inclusive)`.
+ Add descriptions for ambiguous parameters. For example:
  + For the end date of a request, add a description: `Last day for the request (inclusive) in ISO-8601 format (for example, YYYY-MM-DD)`.
  + For the start date, add a description: `First day of the request in ISO-8601 format (e.g. YYYY-MM-DD)`.
+ Based on guidance to limit paginated search results explicitly, we’ll add a description to the `limit` field in `GetTimeOffRequests`. For example, `Limit on the number of requests to return. Limit to 5 unless otherwise instructed`.

Finally, we’ll apply changes based on the API input schema best practices:
+ Assuming we have control over the API implementation, we’d like to apply guidance on avoiding unnecessary nesting. For this, we can convert `range` (which contains start and end dates) to two top-level properties called `startDate` and `endDate`.
+ Following guidance to use standard format fields, we’ll add format: `date` to start/end date fields (assuming we are expecting standard date formats). 

After making corrections, we end up with a vastly improved API specification that will maximize the Amazon Q Business custom plugin accuracy and efficiency in resolving user requests.

The following is the API Schema after we've added optimization fixes:

```
openapi: 3.0.3
info:
  title: TimeOff
  version: 1.0.0
servers:
  - url: https://api.example.com
paths:
  /api/v1/timeoff/requests:
    get:
      operationId: GetTimeOffRequests
      description: Return existing time off requests (including information like the current approval status, dates/days used) for the authenticated user
      parameters:
        - name: request_type
          in: path
          required: false
          schema:
            type: string
            enum:
              - Vacation
              - Personal
              - JuryDuty
              - Sick
        - name: request_status
          in: path
          required: false
          schema:
            type: string
            enum:
              - Approved
              - Pending
              - Cancelled
        - name: start
          in: path
          description: Include requests ending on or after this date
          required: false
          schema:
            type: string
            format: date
        - name: end
          in: path
          description: Include requests starting before this date
          required: false
          schema:
            type: string
            format: date
        - name: limit
          in: path
          description: Limit on the number of requests to return. Limit to 5 unless otherwise instructed
          schema:
            type: integer
        - name: page
          in: path
          description: Specific page of results to return if results are paginated
          required: false
          schema:
            type: integer
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TimeOffRequests"
  /api/v1/timeoff/request:
    post:
      operationId: CreateTimeOffRequest
      description: Create a new time off request for the authenticated user
      requestBody: 
        content:
          application/json:
            schema:
              type: object
              properties:
                startDate:
                  description: First day of the request in ISO-8601 format (e.g. YYYY-MM-DD)
                  type: string
                  format: date
                endDate:
                  description: Last day for the request (inclusive) in ISO-8601 format (e.g. YYYY-MM-DD)
                  type: string
                  format: date
                request_type:
                  description: The type of request to make, either `Personal`, `Vacation`, `Sick` or `JuryDuty`
                  type: string
                  enum:
                    - Personal
                    - Vacation
                    - Sick
                    - JuryDuty
                note:
                  description: A short (one to two sentence) note describing the reason for the request
                  type: string
              required:
                - startDate
                - endDate
                - request_type
                - note
      responses:
        "201":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TimeOffRequest"
components: 
  schemas: 
    TimeOffRequest:
      type: object
      properties:
        # this ID is not necessary for the end user (and is used nowhere else in the API), consider removing
        request_id:
          type: string
        request_status:
          description: the current status of the request, either `Pending`, `Approved`, or `Cancelled`
          type: string
          enum:
            - Pending
            - Approved
            - Cancelled
        request_type:
          type: string
        start:
          description: the start date of the request
          type: string
        end:
          description: the last date of the request (inclusive)
          type: string
        note:
          description: brief note describing the reason for the request
          type: string
        duration:
          description: the number of working days used for the request
          type: integer
        approver_display_name:
          description: the name of the person of who approved the request
          type: string  
    TimeOffRequests:
      type: array
      items:
        $ref: "#/components/schemas/TimeOffRequest"
```

# Creating an Amazon Q Business custom plugin
Creating a custom plugin

**Note**  
To validate accuracy before deploying to end users, we recommend creating a Amazon Q Business test application to configure and test new features. To create a new custom plugin, first ensure that you have a test application with the same settings and configurations as your production application (the one deployed for your end users). Using the console, configure a custom plugin in the test application following the steps below. After you finish configuring your custom plugin, launch a test web experience and login as an end user. Issue a number of expected user prompts and confirm you are getting the expected results. If you are not getting the expected results, return to the console page and modify the OpenAPI specification to ensure it follows [best practices](https://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/plugins-api-schema-best-practices.html) for configuring OpenAPI specifications. Repeat this process until you are satisfied with the test application results and then replicate the same custom plugins settings in your production application before you share it with your end users.

You use the [https://docs.aws.amazon.com/amazonq/latest/api-reference/API_CreatePlugin.html](https://docs.aws.amazon.com/amazonq/latest/api-reference/API_CreatePlugin.html) action to create an Amazon Q custom plugin for your web experience chat. The following tabs provide a procedure for the AWS Management Console and code examples for the AWS CLI.

**To create a custom plugin,** choose a tab based on your access preference for Amazon Q.

------
#### [ Console ]

**To create a application-name plugin** 

1. Sign in to the AWS Management Console and open the Amazon Q Business console.

1. From the Amazon Q Business console, in **Applications**, click on the name of your application from the list of applications.

1. From the left navigation menu, choose **Actions**, and then choose **Plugins**.

1. In **Plugins**, choose **Add plugin**.

1. In **Add plugins**, choose **Custom plugin**.

1. In **Custom plugin**, enter the following information:

   1. In **Name and description**, for **Plugin name** – A name for your Amazon Q plugin. The name can include hyphens (-) but not spaces and can have a maximum of 1000 alphanumeric characters.

   1. In **API schema**, for **API schema source**, choose from the following options:
      + **Select from Amazon S3** – Choose this to select an existing API schema from an Amazon S3 bucket. Your API schema must have an API description, structure, and parameters for your custom plugin. Then, enter the **Amazon S3 URL** to your API schema.
      + **Define with in-line OpenAPI schema editor** – Choose this to write your custom plugin API schema in the inline OpenAPI schema editor in the Amazon Q console. A sample schema appears that you can edit. Then, you can choose to do the following:
        + Select the format for the schema, whether **JSON** or **YAML**.
        + To import an existing schema from S3 to edit, select **Import schema**, provide the S3 URL, and select **Import**.
        + To restore the schema to the original sample schema, select **Reset** and then confirm the message that appears by selecting **Reset** again. 

   1. **Authentication** – Choose between **Authentication required** or **No authentication required**. If no authentication is required, there is no further action needed. If authentication is required, choose to **Create and add a new secret** or **Use an existing one**. Your secret must contain:

      1. **Secret name** – A name for your Secrets Manager secret.

      1. **Client ID** – The client ID you copied from your third-party application.

      1. **Client secret** – The client secret you copied from your third-party application.

      1. **OAuth callback URL** – The URL to which user needs to be redirected after authentication. If your deployed web url is `<q-endpoint>`, use `<q-endpoint>/oauth/callback` . Amazon Q Business will handle OAuth tokens in this URL. This callback URL needs to be allowlisted in your third-party application.

      1. In **Choose a method to authorize Amazon Q Business** – Choose to **Create and add a new service role** or **Use an existing service role**. Make sure your service role has the necessary permissions.

         The console will generate a **Service role name**.

1. **Tags – *optional*** – An optional tag to track your plugin.

1. Select **Add plugin** to add your plugin.

------
#### [ CLI ]

**To create a custom plugin**

```
aws qbusiness create-plugin \
--application-id application-id \
--display-name display-name \
--type CUSTOM \
--auth-configuration basicAuthConfiguration="'{"noAuthConfiguration": {}}' \
--custom-plugin-configuration '{"description":"description, "apiSchemaType": "OPEN_API_V3", "apiSchema": {"s3": {"bucket": s3_bucket_with_openapi_schema "key":s3_key_with_openapi_schema}}}'"
```

------

# Using an Amazon Q Business custom plugin
Using a custom plugin

Once a custom plugin is deployed, end users can launch it from the menu icon in the Amazon Q Business web experience.

**Note**  
If your [Admin controls and guardrails](https://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/guardrails.html) settings allow Amazon Q to automatically orchestrate end user chat queries across plugins and data sources, plugin actions will be automatically activated by Amazon Q for your end user during chat. In that case, your end user won't have to follow the steps below.

![\[Screenshot showing the Amazon Q Business web experience menu with the custom plugin option highlighted, allowing users to select and activate the plugin.\]](http://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/images/1-custom-plugin-select-menu@2x.png)


End users can then type a prompt.

![\[Screenshot showing a user typing a prompt in the Amazon Q Business chat interface to interact with the custom plugin, demonstrating how users can make requests to the plugin.\]](http://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/images/2-custom-plugin-prompt@2x.png)


If it is the first time an end user is accessing the custom plugin or their past login has expired, they will need to authenticate. After authenticating successfully, Amazon Q Business will perform the requested task. For a write API operation, end users will always get a confirmation form that allows them to confirm or correct parameters that were populated based on the request or past actions.

![\[Screenshot showing a confirmation form displayed by the custom plugin, allowing users to verify and modify parameters before the plugin performs the requested action.\]](http://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/images/3-custom-plugin-form@2x.png)


Once the user confirms the action, Amazon Q Business will submit the request and give the user confirmation once it is complete.

![\[Screenshot showing a success message after the custom plugin has completed the requested action, confirming to the user that their request was processed successfully.\]](http://docs.aws.amazon.com/amazonq/latest/qbusiness-ug/images/4-custom-plugin-success@2x.png)
