Creating OpenAPI specifications

You can import skills from OpenAPI Specification (OAS) files. The OAS file is converted to app and skills on watsonx Orchestrate. This document explains how to create OAS to import on watsonx Orchestrate.

Before you begin

  • You must have builder access on watsonx Orchestrate.
  • You need one text file editor that supports YAML or JSON formats or you can use OpenAPI builder in watsonx Orchestrate to create an OpenAPI specification.

Configuring the OpenAPI version

In the openapi object, you define the version of the OAS file. To import the OAS file to watsonx Orchestrate, use one of the following supported versions:

  • 3.0.3
  • 3.0.2
  • 3.0.1
  • 3.0.0

The following example in JSON shows how to use the openapi object to set the 3.0.3 OAS version.

{
  "openapi": "3.0.3"
}

Configuring the app

Use the info object to configure the metadata for the app on the OAS file. This metadata is used to create and reference an app on watsonx Orchestrate.

The app configured in the object is responsible for grouping all the skills that are configured in the paths object of the OAS file. To learn more about configuring skills, see Configuring skills.

Following are the required properties to configure an app on watsonx Orchestrate.

Property Description
title The unique app name on watsonx Orchestrate.
description The description of your app on watsonx Orchestrate.
The characters tab, new line, or carriage return are not supported.
version The app version on watsonx Orchestrate.
x-ibm The x-ibm used to enhance the app. The required x-ibm in one app are:

  • x-ibm-application-name
  • x-ibm-application-id
  • x-ibm-skill-type
  • x-ibm-skill-subtype
These properties are automatically generated if you don't configure it manually. For more information about x-ibm properties for apps, see x-ibm properties to configure the apps.

The following example in JSON shows how to configure the Petstore app:

{
  "info": {
    "title": "Petstore app",
    "description": "A app that contains a petsore skills",
    "version": "1.0.0",
    "x-ibm-application-id": "petstore-app",
    "x-ibm-application-name": "Petstore",
    "x-ibm-skill-type": "imported",
    "x-ibm-skill-subtype": "public"
  }
}

The values in the title and x-ibm-application-id properties are unique for each app present on watsonx Orchestrate. Therefore, to update or add more skills to an app previous imported on watsonx Orchestrate, use the same title and x-ibm-application-id values of this app in the info object. Otherwise, use new values to create a new app with a new set of skills.

Also, each app can have only one server. Therefore, you can't add skills to an app if it uses a different server. To learn more about how to configure server, see Configuring the API server.

Configuring the API server

Configure the API server with your API endpoint to provide connectivity information to a target server. You configure the API server by using the servers object.

The servers object is an array where you configure the API server. For watsonx Orchestrate, only one API server can be configured for each app.

The following table shows the required properties to configure the API server:

Proprety Description
url A URL of the target host, this property supports variable in {brackets}.
Only the HTTPS server URLs are supported

The following example in JSON shows how to use the servers object to configure the https://petstore3.swagger.io/api/v3 API server.

{
  "servers": [
    {
      "url": "https://petstore3.swagger.io/api/v3"
    }
  ]
}

Configuring skills

You can configure skills by using the paths object. In that object, configure the relative paths to the individual endpoints and their operations.

Each operation becomes a skill on watsonx Orchestrate and the skills added are grouped in the app that is configured in the info object. For more information about the info object, see Configuring the app.

To configure your skill on watsonx Orchestrate, set the relative path in the paths object and then use the supported operations: GET, PATCH, PUT, POST, or DELETE.

Note: When you use skills, make sure that the `limitparam` is set to a value greater than `0`. Setting `limitparam` to `0` or less is invalid and causes errors.

The operation configuration depends on the API that you use. The following table shows the properties that you can use to configure the operation.

Property Required Description
summary yes The skill name on watsonx Orchestrate. This name is displayed on the skill tile.

Configuring skills summary

Use the best practices to give better names to your skills, see Skill name.
description no The skill description on watsonx Orchestrate. This description is displayed on the skill tile.

Configuring skills description

The characters tab, new line, or carriage return are not supported.
Use the best practices to give better descriptions to your skills, see Skill description.
operationId no The operation ID. It is used to create the skill ID on watsonx Orchestrate. For more information about skill ID, see Building Skill IDs.
If this property is not configured in the OAS file, the operation ID is randomly generated.
requestBody yes The schemas of the skill inputs. The inputs are shown either as in an input form or as a multi-turn conversation when the skill is used in the AI chat or the legacy chat.
For your inputs correctly work, the content type of your skill inputs must be application/json.

Skill inputs

You can enhance the skill input format to give a better user experience for your users. For more information, see Configuring inputs and outputs types for your skills.
You can also use x-ibm properties to enhance your skill inputs. For more information, see Using x-ibm properties.
Then, use the best practices to give better inputs to the user, see Skill input.
Note: This property supports only the HTTP/1.1 specification with defined semantics for request bodies.
parameters no A list of parameters that are applicable for the skill. By default, the parameters are shown as input fields with the skill inputs configured on requestBody.

Skill parameters

You can use x-ibm properties to enhance your parameters, for example by using the x-ibm-show property to hide parameters for the user. For more information about x-ibm properties, see Using x-ibm properties.
responses yes The schemas of the skill outputs. You can map any HTTP response code to give a better answer to the user. The mapped responses are displayed in the chat after you use the skill.
For your output correctly work, the content type of your skill inputs must be application/json.

Skill outputs

You can enhance the skill output format to give a better user experience for your users. For more information, see Configuring inputs and outputs types for your skills.
You can also use x-ibm properties to enhance your skill outputs. For more information, see Using x-ibm properties.
Then, use the best practices to give better responses to the user, see Skill output.
Note: This property supports only the HTTP/1.1 specification with defined semantics for request bodies.
callbacks no Possibles out-of-band callbacks that are related to the parent skill. For more information about callbacks, see Optional: Configuring callback for asynchronous skills.
security no List of security schemas that are required to use the skill. For more information about security, see Configuring the API security scheme.
x-ibm no The x-ibm properties that you can use to enhance your skill on watsonx Orchestrate. For more information about the x-ibm property for skills, see x-ibm properties to configure the skills.

The following example shows the configuration of a skill based on the GET operation:

{
  "paths": {
    "/pet/findByStatus": {
      "get": {
        "summary": "Finds Pets by status",
        "description": "from Petstore",
        "operationId": "findPetsByStatus",
        "parameters": [
          {
            "$ref": "#/components/parameters/statusParam"
          }
        ],
        "responses": {
          "200": {
            "description": "successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Pet"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid status value"
          }
        }
      }
    }
  }
}

The following example shows the configuration of a skill based on the PATCH operation:

{
  "paths": {
    "/pet/{petId}": {
      "patch": {
        "operationId": "updatePetById",
        "security": [
          {
            "jwt": []
          }
        ],
        "description": "in Petstore",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "schema": {
              "type": "string"
            },
            "required": true
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tags": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The pet was updated."
          }
        }
      }
    }
  }
}

The following example shows the configuration of a skill based on the PUT operation:

{
  "paths": {
    "/pet": {
      "put": {
        "summary": "Update an existing pet",
        "description": "in Petstore",
        "operationId": "updatePet",
        "requestBody": {
          "description": "Update an existent pet in the store",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Pet"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pet"
                }
              }
            }
          }
        }
      }
    }
  }
}

The following example shows the configuration of a skill based on the POST operation:

{
  "paths": {
    "/pet": {
      "post": {
        "summary": "Add a new pet to the store",
        "description": "in Petstore",
        "operationId": "addPet",
        "requestBody": {
          "description": "Create a new pet in the store",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Pet"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful operation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pet"
                }
              }
            }
          }
        }
      }
    }
  }
}

The following example shows the configuration of a skill based on the DELETE operation:

{
  "paths": {
    "/pet/{petId}": {
      "delete": {
        "summary": "Deletes a pet",
        "description": "",
        "operationId": "from Petstore",
        "parameters": [
          {
            "name": "api_key",
            "in": "header",
            "description": "",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "petId",
            "in": "path",
            "description": "Pet id to delete",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "400": {
            "description": "Invalid pet value"
          }
        }
      }
    }
  }
}

Configuring the API security scheme

You configure the API authentication method in the securitySchemes property on components.

The following table provides details about the supported authentication schemes that you can use on watsonx Orchestrate. The watsonx Orchestrate does not support multiple authentication methods for imported apps. Therefore, if your API has multiple authentication methods, choose only one to be used on watsonx Orchestrate.

Status Description
Supported authentication schemes
  • Basic
  • Bearer
  • OAuth2 password flow, including client authentication, authorization code, and also the OAuth2 client credentials flow.
Note: Explicit refreshUrl is not supported. If the access token response includes a refresh_token, it is assumed that the refreshUrl is the same as tokenUrl. Thus, refreshUrl does not affect the behavior.

  • API key in header
  • Query parameter
  • Cookie
Note: For cookie, the value must be configured at the connection time.

Not supported authentication schemes
  • RFC 7325 http scheme support
  • Digest, HOBA, mutual, OAuth 1.0, negotiate, SCRAM-SHA-1, SCRAM-SHA-256, VAPID support
  • Cookie authentication
  • OIDC

The following examples in JSON show how to use the securitySchemes property to configure authentications.

Example of basic authentication.

{
  "components": {
    "securitySchemes": {
      "basic_auth": {
        "type": "http",
        "scheme": "basic"
      }
    }
  }
}

Example of bearer authentication.

{
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer"
      }
    }
  }
}

Example of API key authentication.

{
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization"
      }
    }
  }
}

In some services, you can pass the apiKey as a query parameter.

For example, if the OpenAPI spec defines the following apiKey schema, you can pass the key in the query parameter of the API endpoint.

{
  "securitySchemes": {
    "apiKey": {
        "type": "apiKey",
        "in": "query",
        "name": "MYAPIKEY"
        }
    }
}

For example:

https://myservice.com/api/v1/endpoint?apiKey=MYAPIKEY

Example of OAuth2 authentication.

{
  "components": {
    "securitySchemes": {
      "passwordGrant": {
        "type": "oauth2",
        "description": "Password grant authorization.",
        "flows": {
          "password": {
            "tokenUrl": "https://api.example.com/oauth2/authorize",
            "scopes": {}
          }
        }
      }
    }
  }
}

Example of OAuth2 authentication with authorization code.

{
  "components": {
    "securitySchemes": {
      "oAuth2AuthorizationCode": {
        "type": "oauth2",
        "x-ibm-visible": true,
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "/your_authorization_url",
            "tokenUrl": "/your_access_token_url",
            "scopes": {}
          }
        }
      }
    }
  }
}

It is possible to use OAuth 2.0 implicit grant flow on watsonx Orchestrate. In the implicit flow, you can find the authentication to run a skill in the OAuth providers login page. For more information, see OAuth implicit grant flow.

{
  "components": {
    "securitySchemes": {
      "oAuthSample": {
        "type": "oauth2",
        "description": "This API uses OAuth 2 with the implicit grant flow. [More info](https://api.example.com/docs/auth)",
        "flows": {
          "implicit": {
            "authorizationUrl": "https://api.example.com/oauth2/authorize",
            "scopes": {
              "read_pets": "read your pets",
              "write_pets": "modify pets in your account"
            }
          }
        }
      }
    }
  }
}

If the authentication is required to use the skills, you must configure it on the security object.

To configure one authentication as required, you must use the same name that you set in securitySchemes. The following examples in JSON show how to configure the previous authentication examples as required.

Example of basic authentication.

{
  "security": [
    {
      "basic_auth": []
    }
  ]
}

Example of bearer authentication.

{
  "security": [
    {
      "bearerAuth": []
    }
  ]
}

Example of API Key authentication.

{
  "security": [
    {
      "apiKey": []
    }
  ]
}

Example of OAuth2 authentication.

{
  "security": [
    {
      "passwordGrant": []
    }
  ]
}

Example of OAuth2 with authorization code.

{
  "security": [
    {
      "oAuth2AuthorizationCode": []
    }
  ]
}

Example of OAuth2 implicit authentication.

{
  "security": [
    {
      "oAuthSample": []
    }
  ]
}

Optional: Configuring callback for asynchronous skills

If you have an asynchronous API that returns its responses in other endpoints, you can configure its callback by using the parameters, responses and callbacks properties.

In the parameters property, configure an input for the callback URL of your API. The callback URL is the endpoint that returns your skill response after the skill is finished. If your API set the callback URL automatically during the skill usage, use x-ibm-show: false to hide this input.

The following example shows one callback input configuration:

{
  "paths": {
    "/register_user": {
      "post": {
        "parameters": [
          {
            "name": "callbackUrl",
            "in": "header",
            "description": "The URL to send the result of the operation to",
            "schema": {
              "type": "string",
              "format": "uri"
            },
            "x-ibm-order": 1,
            "x-ibm-multiline": "false"
          }
        ]
      }
    }
  }
}

In the callbacks property, configure the callback responses for your API. For each response, configure the callback endpoint and the methods that are used to receive the responses.

Then in each method, configure the requestBody and the response of the endpoint:

Property Description
requestBody The request body applicable for the callback endpoint. This property supports only the HTTP/1.1 specification with defined semantics for request bodies.
For the callback requestBody, wrap the response on output schema.
responses The expected HTTP responses for the callback. You can map any HTTP response code to give the better answer to the user. The mapped responses are displayed on the watsonx Orchestrate after you use the skill. Use the best practices to give better responses to the user, see Skill design content guidelines: Skill output.

The following example shows how to configure the callbacks property:

{
  "paths": {
    "/register_user": {
      "post": {
        "callbacks": {
          "postResponse": {
            "{$request.header.callbackUrl}": {
              "post": {
                "requestBody": {
                  "content": {
                    "application/json": {
                      "schema": {
                        "type": "object",
                        "properties": {
                          "output": {
                            "type": "object",
                            "properties": {
                              "userEmail": {
                                "type": "string"
                              },
                              "userUsername": {
                                "type": "string"
                              },
                              "userName": {
                                "type": "string"
                              },
                              "userPassword": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "responses": {
                  "202": {
                    "description": "Output received successfully."
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Configure the 202 response in your OpenAPI. The 202 response is used to return to the user that the request was accepted for processing, but the process itself might take time to complete.

The 202 response is not displayed on watsonx Orchestrate chat, but it's important to correctly document your API

You configure the 202 response in the responses property. The following example shows how to configure the 202 response:

{
  "paths": {
    "/register_user": {
      "post": {
        "responses": {
          "202": {
            "description": "The request was accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Optional: Configuring reusable objects

Different skills can have the same structure of requests or responses. You can configure the structure once and then referencing to each skill that uses this structure.

You can configure reusable objects in the components object, in this object is possible to configure schemas, responses, parameters, examples, requestBodies, headers, securitySchemes, links, callbacks, and x-ibm properties to reuse when needed in your OAS.

The following example in JSON shows how to use the components object to configure reusable parameters, schemas, and requestBodies.

{
  "components": {
    "parameters": {
      "statusParam": {
        "in": "query",
        "name": "status",
        "description": "Status values that need to be considered for filter",
        "required": false,
        "explode": true,
        "schema": {
          "default": "available",
          "type": "string",
          "enum": [
            "available",
            "pending",
            "sold"
          ]
        }
      }
    },
    "schemas": {
      "Pet": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "example": 10
          },
          "name": {
            "type": "string",
            "example": "doggie"
          }
        }
      }
    }
  }
}

To use one reusable object, use the $ref property and pass the path to the reusable object.

The following example in JSON shows how to use the Order reusable object.

{
  "responses": {
    "200": {
      "description": "successful operation",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Pet"
          }
        }
      }
    }
  }
}

The following example code shows how to built an Order Management API:

  {
  "paths": {
    "/instances": {
      "get": {
        "summary": "List Instances",
        "description": "Retrieves a list of all OMS instances associated with the specified service credentials.",
        "operationId": "listInstances",
        "tags": ["Instances"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstanceList"
                }
              }
            }
          },
          "default": {
            "$ref": "#/components/responses/default"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "InstanceList": {
        "type": "object",
        "properties": {
          "instances": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Instance"
            }
          }
        }
      },
      "Instance": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The instance ID."
          },
          "guid": {
            "type": "string",
            "description": "The instance GUID."
          },
          "region_id": {
            "type": "string",
            "description": "The region where the instance is located."
          },
          "service_id": {
            "type": "string",
            "description": "The ID of the service where the instance is provisioned."
          },
          "name": {
            "type": "string",
            "description": "The user-defined name for the instance."
          },
          "state": {
            "type": "string",
            "description": "The current state of the instance."
          },
          "enabled": {
            "type": "boolean",
            "description": "Indicates whether the instance is enabled."
          },
          "is_lite": {
            "type": "boolean",
            "description": "Indicates whether the instance is a Lite instance."
          },
          "crn": {
            "type": "string",
            "description": "The Cloud Resource Name (CRN) that uniquely identifies the instance."
          },
          "dashboard_url": {
            "type": "string",
            "description": "The URL for the instance's dashboard."
          },
          "trial_expiry": {
            "type": "string",
            "format": "date-time",
            "description": "The date when the trial period for the instance expires."
          }
        }
      }
    },
    "responses": {
      "default": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": ["code", "message"],
        "properties": {
          "code": {
            "type": "integer",
            "format": "int32"
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}

This example uses the GET instances endpoint to retrieve a list of all OMS instances associated with the specified service credentials. The response includes information such as the instance ID, name, region, and state. You can modify this example to suit your specific needs, such as retrieving specific information about an instance or performing actions on the instance, such as starting or stopping it.