Criar uma extensão de mensagem baseada em API

Observação

As extensões de mensagem baseadas em API dão suporte apenas a comandos de pesquisa.

As extensões de mensagem baseadas em API são um recurso do aplicativo Microsoft Teams que integra APIs externas diretamente ao Teams, aprimorando a usabilidade do aplicativo e oferecendo uma experiência de usuário perfeita. As extensões de mensagem baseadas em API oferecem suporte a comandos de pesquisa e podem ser usadas para buscar e exibir dados de serviços externos no Teams, simplificando os fluxos de trabalho ao reduzir a necessidade de alternar entre aplicativos.

Observação

Os agentes fornecem uma experiência mais flexível, inteligente e pronta para o futuro que permite um raciocínio mais avançado, um desenvolvimento mais simples e um melhor alinhamento com o Teams em evolução e a plataforma Microsoft 365. Recomendamos que você explore e crie agentes.

Para obter mais informações, confira Criar agentes declarativos e Criar agentes no Teams.

Se você tiver uma extensão de mensagem baseada em bot existente, também poderá estendê-la como um agente .

Antes de começar, verifique se você atende aos seguintes requisitos:


1. Descrição do OpenAPI (OAD)

Certifique-se de seguir as seguintes diretrizes para o documento Descrição do OpenAPI (OAD):

  • As versões 2.0 e 3.0.x do OpenAPI são suportadas.
  • JSON e YAML são os formatos com suporte.
  • O corpo da solicitação, se presente, deve ser application/Json.
  • Defina uma URL do servidor de protocolo HTTPS para a servers.url propriedade.
  • Há suporte apenas para os métodos POST e GET HTTP.
  • O documento de descrição do OpenAPI deve ter um operationIdarquivo .
  • Somente um parâmetro necessário sem um valor padrão é permitido.
  • Um parâmetro necessário com um valor padrão é considerado opcional.
  • Os usuários não devem inserir um parâmetro para um cabeçalho ou cookie.
  • A operação não deve ter um cabeçalho obrigatório ou parâmetros de cookie sem valores padrão.
  • Certifique-se de que não haja referências remotas no documento Descrição do OpenAPI.
  • Não há suporte para a construção de matrizes para a solicitação; no entanto, há suporte para objetos aninhados em um corpo de solicitação JSON.
  • O Teams não dá suporte às oneOfconstruções , anyOf, allOf, e not (swagger.io).

O código a seguir é um exemplo de documento de descrição do OpenAPI:

openapi: 3.0.1
info:
title: OpenTools Plugin
description: A plugin that allows the user to find the most appropriate AI tools for their use cases, with their pricing information.
version: 'v1'
servers:
- url: https://gptplugin.opentools.ai
paths:
/tools:
 get:
   operationId: searchTools
   summary: Search for AI Tools
   parameters:
     - in: query
       name: search
       required: true
       schema:
         type: string
       description: Used to search for AI tools by their category based on the keywords. For example, ?search="tool to create music" will give tools that can create music.
   responses:
     "200":
       description: OK
       content:
         application/json:
           schema:
             $ref: '#/components/schemas/searchToolsResponse'
     "400":
       description: Search Error
       content:
         application/json:
           schema:
             $ref: '#/components/schemas/searchToolsError'
components:
schemas:
 searchToolsResponse:
   required:
     - search
   type: object
   properties:
     tools:
       type: array
       items:
         type: object
         properties:
           name:
             type: string
             description: The name of the tool.
           opentools_url:
             type: string
             description: The URL to access the tool.
           main_summary:
             type: string
             description: A summary of what the tool is.
           pricing_summary:
             type: string
             description: A summary of the pricing of the tool.
           categories:
             type: array
             items:
               type: string
             description: The categories assigned to the tool.
           platforms:
             type: array
             items:
               type: string
             description: The platforms that this tool is available on.
       description: The list of AI tools.
 searchToolsError:
   type: object
   properties:
     message:
       type: string
       description: Message of the error.

Para obter mais informações, consulte Estrutura do OpenAPI.


2. Manifesto do aplicativo

Certifique-se de seguir as seguintes diretrizes para o manifesto do aplicativo:

  • Defina a versão do manifesto do aplicativo como 1.17.

  • Defina composeExtensions.composeExtensionType como apiBased.

  • Defina composeExtensions.apiSpecificationFile como o caminho relativo para o arquivo de descrição do OpenAPI dentro da pasta. Isso vincula o manifesto do aplicativo à especificação da API.

  • Defina apiResponseRenderingTemplateFile como o caminho relativo para o modelo de renderização de resposta. Isso especifica o local do modelo usado para renderizar respostas da API.

  • Cada comando deve ter um link para o modelo de renderização de resposta. Isso conecta cada comando ao seu formato de resposta correspondente.

  • A Commands.id propriedade no manifesto do aplicativo deve corresponder à descrição do operationId OpenAPI.

  • Se um parâmetro necessário não tiver um valor padrão, o comando parameters.name no manifesto do aplicativo deverá corresponder ao no documento Descrição do parameters.name OpenAPI.

  • Se não houver nenhum parâmetro obrigatório, o comando parameters.name no manifesto do aplicativo deverá corresponder ao opcional parameters.name na Descrição do OpenAPI.

  • Certifique-se de que os parâmetros de cada comando correspondam exatamente aos nomes dos parâmetros definidos para a operação na especificação OpenAPI.

  • Um modelo de renderização de resposta deve ser definido por comando, que é usado para converter respostas de uma API.

  • A descrição completa não deve exceder 128 caracteres.

    {
    "$schema": "https://developer.microsoft.com/json-schemas/teams/v1.17/MicrosoftTeams.schema.json",
    +  "manifestVersion": "1.17",
    "version": "1.0.0",
    "id": "04805b4b-xxxx-xxxx-xxxx-4dbc1cac8f89",
    "packageName": "com.microsoft.teams.extension",
    "developer": {
        "name": "Teams App, Inc.",
        "websiteUrl": "https://www.example.com",
        "privacyUrl": "https://www.example.com/termofuse",
        "termsOfUseUrl": "https://www.example.com/privacy"
    },
    "icons": {
        "color": "color.png",
        "outline": "outline.png"
    },
    "name": {
        "short": "AI tools",
        "full": "AI tools"
    },
    "description": {
        "short": "AI tools",
        "full": "AI tools"
    },
    "accentColor": "#FFFFFF",
    "composeExtensions": [
        {
    +      "composeExtensionType": "apiBased",
    +      "authorization": {
    +        "authType": "apiSecretServiceAuth ",
    +        "apiSecretServiceAuthConfiguration": {
    +            "apiSecretRegistrationId": "9xxxxxxx-7xxx-4xxx-bxxx-1xxxxxxxxxxx"
    +        }
    +      },
    +      "apiSpecificationFile": "aitools-openapi.yml",
           "commands": [
           {
              "id": "searchTools",
              "type": "query",
              "context": [
                 "compose",
                 "commandBox"
              ],
              "title": "search for AI tools",
              "description": "search for AI tools",
              "parameters": [
                 {
                 "name": "search",
                 "title": "search query",
                 "description": "e.g. search='tool to create music'"
                 }
              ],
    +          "apiResponseRenderingTemplateFile": "response-template.json"
           }
           ]
        }
    ],
    "validDomains": []
    }
    

Parâmetros

Nome Descrição
composeExtensions.composeExtensionType Compose tipo de extensão. Atualize o valor para apiBased.
composeExtensions.authorization Informações relacionadas à autorização para a extensão de mensagem baseada em API
composeExtensions.authorization.authType Enumeração de possíveis tipos de autorização. Os valores com suporte são none, apiSecretServiceAuthe microsoftEntra.
composeExtensions.authorization.apiSecretServiceAuthConfiguration Detalhes de captura de objeto necessários para fazer a autenticação de serviço. Aplicável somente quando o tipo de autenticação é apiSecretServiceAuth.
composeExtensions.authorization.apiSecretServiceAuthConfiguration.apiSecretRegistrationId ID de registro retornada quando o desenvolvedor envia a chave de API por meio do Portal do desenvolvedor.
composeExtensions.apiSpecificationFile Faz referência a um arquivo de Descrição do OpenAPI no pacote do aplicativo. Incluir quando o tipo é apiBased.
composeExtensions.commands.id ID exclusiva que você atribui ao comando de pesquisa. A solicitação do usuário inclui essa ID. A ID deve corresponder ao OperationId disponível na descrição do OpenAPI.
composeExtensions.commands.context Matriz em que os pontos de entrada para extensão de mensagem estão definidos. Os valores padrão são compose e commandBox.
composeExtensions.commands.parameters Define uma lista estática de parâmetros para o comando. O nome deve ser mapeado para o na descrição do parameters.name OpenAPI. Se você estiver fazendo referência a uma propriedade no esquema do corpo da solicitação, o nome deverá ser mapeado para properties.name ou consultar parâmetros.
composeExtensions.commands.apiResponseRenderingTemplateFile Modelo usado para formatar a resposta JSON da API do desenvolvedor para a resposta do Cartão Adaptável. [Obrigatório]

Para obter mais informações, consulte composeExtensions.


3. Modelo de renderização de resposta
  • Defina a URL de referência de esquema na $schema propriedade para estabelecer a estrutura do seu modelo.
  • Os valores com suporte para responseLayout são list e grid, que determinam como a resposta é apresentada visualmente.
  • A jsonPath é recomendado para matrizes ou quando os dados do Cartão Adaptável não são o objeto raiz. Por exemplo, se os dados estiverem aninhados em productDetails, o caminho JSON seria productDetails.
  • Defina jsonPath como o caminho para os dados ou matrizes relevantes na resposta da API. Se o caminho apontar para uma matriz, cada entrada na matriz será associada ao modelo de Cartão Adaptável e retornará como um resultado separado. [Opcional]
  • Obtenha uma resposta de exemplo para validar o modelo de renderização de resposta. Isso serve como um teste para garantir que seu modelo funcione conforme o esperado.
  • Use ferramentas como Fiddler ou Postman para chamar a API e garantir que a solicitação e a resposta sejam válidas. Esta etapa é crucial para solucionar problemas e confirmar se sua API está funcionando corretamente.
  • Você pode usar o Adaptive Card Designer para vincular a resposta da API ao modelo de renderização de resposta e visualizar o Cartão Adaptável. Insira o modelo no EDITOR DE CONTEÚDO DO CARTÃO e insira a entrada de resposta de exemplo no EDITOR DE DADOS DE EXEMPLO.

O código a seguir é um exemplo de um modelo de renderização de resposta:

Exemplo de modelo de renderização de resposta
{
"version": "1.0",
"jsonPath": "repairs",
"responseLayout": "grid",
"responseCardTemplate": {
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "type": "AdaptiveCard",
  "version": "1.4",
  "body": [
    {
      "type": "Container",
      "items": [
        {
          "type": "ColumnSet",
          "columns": [
            {
              "type": "Column",
              "width": "stretch",
              "items": [
                {
                  "type": "TextBlock",
                  "text": "Title: ${if(title, title, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "TextBlock",
                  "text": "Description: ${if(description, description, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "TextBlock",
                  "text": "Assigned To: ${if(assignedTo, assignedTo, 'N/A')}",
                  "wrap": true
                },
                {
                  "type": "Image",
                  "url": "${image}",
                  "size": "Medium",
                  "$when": "${image != null}"
                }
              ]
            },
            {
              "type": "Column",
              "width": "auto",
              "items": [
                {
                  "type": "Image",
                  "url": "${if(image, image, '')}",
                  "size": "Medium"
                }
              ]
            }
          ]
        },
        {
          "type": "FactSet",
          "facts": [
            {
              "title": "Repair ID:",
              "value": "${if(id, id, 'N/A')}"
            },
            {
              "title": "Date:",
              "value": "${if(date, date, 'N/A')}"
            }
          ]
        }
      ]
    }
  ]
  },
  "previewCardTemplate": {
  "title": "Title: ${if(title, title, 'N/A')}",
  "subtitle": "Description: ${if(description, description, 'N/A')}",
  "text": "Assigned To: ${if(assignedTo, assignedTo, 'N/A')}",
  "image": {
    "url": "${image}",
    "$when": "${image != null}"
    }
  }
 }

Cartão de visualização

A captura de tela mostra um exemplo de extensão de composição exibindo uma matriz de cartões de visualização ao pesquisar uma palavra específica. Nesse caso, pesquisar por 'a' no 'aplicativo de teste SME' retorna cinco cartões mostrando as propriedades e valores 'Title', 'Description' (truncated) e 'AssignedTo' em cada um.

Cartão Adaptável Expandido

Exemplo de como o Cartão Adaptável parece expandido depois que um usuário seleciona um card de visualização. O Cartão Adaptável mostra os valores Title, the complete Description, AssignedTo, RepairId e Date.

Parâmetros

Propriedade Tipo Descrição Obrigatório
version string A versão do esquema do modelo de renderização de resposta atual. Sim
jsonPath string O caminho para a seção relevante nos resultados ao qual o responseCardTemplate e o previewCardTemplate devem ser aplicados. Se não for definido, o objeto raiz será tratado como a seção relevante. Se a seção relevante for uma matriz, cada entrada será mapeada para responseCardTemplate e previewCardTemplate. Não
responseLayout responseLayoutType Especifica o layout dos resultados no submenu da extensão de mensagem. Os tipos com suporte são list e grid. Sim
responseCardTemplate adaptiveCardTemplate Um modelo para criar um Cartão Adaptável a partir de uma entrada de resultado. Sim
previewCardTemplate previewCardTemplate Um modelo para criar um card de visualização a partir de uma entrada de resultado. O card de visualização resultante é exibido no menu de submenu da extensão de mensagem. Sim

Caminho JSON

O caminho JSON é opcional, mas pode ser usado para matrizes ou quando o objeto a ser usado como dados para um Cartão Adaptável não é o objeto raiz. O caminho JSON deve seguir o formato definido pela Newtonsoft. Se o caminho JSON apontar para uma matriz, cada entrada nessa matriz será associada ao modelo de Cartão Adaptável e retornará como resultados separados.

Exemplo Digamos que você tenha o JSON abaixo para uma lista de produtos e queira criar um resultado de card para cada entrada.

{
   "version": "1.0",
   "title": "All Products",
   "warehouse": {
      "products": [
        ...
      ]
   }
}

Como você pode ver, a matriz de resultados está em "produtos", que está aninhada em "warehouse", portanto, o caminho JSON seria "warehouse.products".

Use o Adaptive Card Designer para visualizar um Cartão Adaptável inserindo o modelo no Editor de Carga de Cartão. Pegue uma entrada de resposta de amostra de sua matriz ou para seu objeto e insira-a no Editor de Dados de Amostra. Certifique-se de que o card seja renderizado corretamente e seja do seu agrado.

Mapeamento de esquema

As propriedades no documento Descrição do OpenAPI são mapeadas para o modelo de Cartão Adaptável da seguinte maneira:

  • string, number, integerboolean , tipos são convertidos em um TextBlock.

    Exemplo
    • Esquema de origem: string, number, integere boolean

       name:
         type: string
         example: doggie
      
    • Esquema de destino: Textblock

      {
      "type": "TextBlock",
      "text": "name: ${if(name, name, 'N/A')}",
      "wrap": true
      }
      
  • array: uma matriz é convertida em um contêiner dentro do Cartão Adaptável.

    Exemplo
    • Esquema de origem: array

          type: array
                    items:
                    required:
                      - name
                    type: object
                      properties:
                      id:
                        type: integer
                      category:
                        type: object
                        properties:
                        name:
                          type: string
      
    • Esquema de destino: Container

          {
                    "type": "Container",
                    "$data": "${$root}",
                    "items": [
                      {
                        "type": "TextBlock",
                        "text": "id: ${if(id, id, 'N/A')}",
                        "wrap": true
                      },
                      {
                        "type": "TextBlock",
                        "text": "category.name: ${if(category.name, category.name, 'N/A')}",
                        "wrap": true
                      }
                    ]
                  }
      
      
  • object: Um objeto é convertido em uma propriedade aninhada no Cartão Adaptável.

    Exemplo
    • Esquema de origem: object

      components:
        schemas:
          Pet:
              category:
                type: object
              properties:
                id:
                  type: integer
                name:
                  type: string
      
      
    • Esquema de destino: propriedade aninhada em um Cartão Adaptável

      {
        "type": "TextBlock",
        "text": "category.id: ${if(category.id, category.id, 'N/A')}",
        "wrap": true
      },
      {
        "type": "TextBlock",
        "text": "category.name: ${if(category.name, category.name, 'N/A')}",
        "wrap": true
      }
      
      
  • image: se uma propriedade for uma URL de imagem, ela será convertida em um elemento Image no Cartão Adaptável.

    Exemplo
    • Esquema de origem: image

          image:
            type: string
            format: uri
            description: The URL of the image of the item to be repaired
      
      
    • Esquema de destino: "Image"

      {
            "type": "Image",
            "url": "${image}",
            "$when": "${image != null}"
          }
      
      

Você pode criar uma extensão de mensagem baseada em API usando o Portal do desenvolvedor para Teams, o Microsoft 365 Agents Toolkit (anteriormente conhecido como Teams Toolkit) para Visual Studio Code, interface de linha de comando (CLI) ou Visual Studio.

Para criar uma extensão de mensagem baseada em API usando o Portal do Desenvolvedor, siga estas etapas:

  1. Acesse o portal do desenvolvedor.

  2. Vá para Aplicativos.

  3. Selecione + Novo aplicativo.

  4. Insira um nome para o aplicativo e selecione a versão do manifesto como versão prévia do desenvolvedor público (devPreview).

  5. Selecione Adicionar.

    A captura de tela mostra o nome do aplicativo e a versão do manifesto selecionado como Pré-lançamento mais recente (devPreview) no Portal do Desenvolvedor.

  6. No painel esquerdo, em Configurar, atualize as seguintes Informações básicas:

    1. Nome completo
    2. Descrição curta
    3. Descrição longa
    4. Nome do desenvolvedor ou da empresa
    5. Site (deve ser uma URL HTTPS válida)
    6. Política de privacidade
    7. Termos de uso
  7. Selecione Salvar.

  8. Selecione Recursos do aplicativo.

  9. Selecione a Extensão de mensagem.

    A captura de tela mostra a opção de extensão de mensagem no Portal do Desenvolvedor.

  10. Em Tipo de extensão de mensagem, selecione API.

    1. Se você receber um aviso de isenção de responsabilidade que diz que a extensão da mensagem do bot já está em uso pelos usuários. Deseja alterar o tipo de extensão de mensagem para API?, selecione Sim, alterar.
  11. Em Especificação OpenAPI, selecione Carregar agora.

    A captura de tela mostra a opção Carregar agora no Portal do Desenvolvedor.

  12. Selecione o documento de descrição da OpenAPI no formato JSON ou YAML e selecione Abrir.

  13. Selecione Salvar. Um pop-up é exibido com a especificação de API da mensagem salva com sucesso.

  14. Selecione Entendi.

    A captura de tela mostra um exemplo da especificação de API salva com êxito mensagem e botão Entendi.

Adicionar comandos

Observação

As extensões de mensagem criadas a partir de uma API dão suporte apenas a um único parâmetro.

Você pode adicionar comandos e parâmetros à sua extensão de mensagem para adicionar comandos:

  1. Em Tipo de extensão de mensagem, selecione Adicionar.

    A captura de tela mostra a opção adicionar para adicionar comandos no Portal do Desenvolvedor.

    Um pop-up Adicionar um comando é exibido com uma lista de todas as APIs disponíveis no documento Descrição do OpenAPI.

  2. Selecione uma API na lista e selecione Avançar.

    A captura de tela mostra a lista de APIs do Documento de Descrição do OpenAPI na janela pop-up Adicionar um comando.

  3. Em Modelo de resposta, selecione Carregar agora.

    A captura de tela mostra a opção Carregar agora para adicionar o modelo de Cartão Adaptável para o comando.

    Observação

    Se você tiver mais de uma API, certifique-se de carregar o modelo de resposta do Cartão Adaptável para cada API.

  4. Selecione o arquivo de modelo de resposta do Cartão Adaptável no formato JSON e selecione Abrir.

    Os seguintes atributos são atualizados automaticamente a partir do modelo de Cartão Adaptável:

    • Tipo de Comando
    • ID do comando
    • Título do comando
    • Nome do parâmetro
    • Descrição do parâmetro
  5. Em Detalhes, atualize a Descrição do comando.

  6. Se você quiser iniciar um comando usando um gatilho no Microsoft 365 Copilot, ative a opção Executar este comando automaticamente quando um usuário abrir a alternância de extensão.

  7. Selecione Adicionar. O comando é adicionado com êxito.

    A captura de tela mostra os campos disponíveis na página de detalhes do comando.

  8. Selecione Salvar.

  9. Em Autenticação e autorização, selecione qualquer uma das seguintes opções:

    • Sem autenticação (não recomendado)
    • Chave de API
    • OAuth

Uma extensão de mensagem baseada em API é criada.

A captura de tela mostra o plug-in para o Microsoft 365 Copilot criado na página de recursos do aplicativo no Portal do Desenvolvedor.

Para testar a extensão de mensagem baseada em API criada no Portal do Desenvolvedor, você pode usar os seguintes métodos:

  • Visualizar no Teams: abra sua extensão de mensagem e selecione Visualizar no Teams no canto superior direito. Você será redirecionado para o Teams, onde poderá adicionar o aplicativo ao Teams para visualizá-lo.

  • Baixar pacote do aplicativo: na página de extensão de mensagem, selecione Pacote do aplicativo no painel esquerdo e, em seguida, no canto superior esquerdo da janela, selecione Baixar pacote do aplicativo. O pacote do aplicativo é baixado em seu computador local em um arquivo .zip. Você pode carregar o pacote do aplicativo no Teams e testar a extensão de mensagem.

Vários parâmetros

Vários parâmetros permitem que extensões de mensagem baseadas em API tenham mais de um tipo de entrada para comandos de consulta. Por exemplo, você pode pesquisar animes por gênero, classificação, status e data.

Você pode especificar os tipos de entrada, títulos, descrições e campos obrigatórios para os parâmetros no manifesto.

  • A isRequired propriedade no campo parâmetro indica se um parâmetro é obrigatório para o comando de consulta.
  • A name propriedade do parameters campo no manifesto do aplicativo deve corresponder ao id campo no documento Descrição do OpenAPI para o parâmetro correspondente.

Exemplo

"composeExtensions": [
        {
            "composeExtensionType": "apiBased",
            "apiSpecificationFile": "apiSpecificationFiles/openapi.json",
            "commands": [
                {
                    "context": [
                        "compose"
                    ],
                    "type": "query",
                    "title": "Search Animes",
                    "id": "getAnimeSearch",
                    "parameters": [
                        {
                            "name": "q",
                            "title": "Search Query",
                            "description": "The search query",
                            "isRequired": true
                        },
                        {
                            "name": "type",
                            "inputType": "choiceset",
                            "title": "Type",
                            "description": "Available anime types",
                            "choices": [
                                {
                                    "title": "TV",
                                    "value": "tv"
                                },
                                {
                                    "title": "OVA",
                                    "value": "ova"
                                },
                                {
                                    "title": "Movie",
                                    "value": "movie"
                                },
                                {
                                    "title": "Special",
                                    "value": "special"
                                },
                                {
                                    "title": "ONA",
                                    "value": "ona"
                                },
                                {
                                    "title": "Music",
                                    "value": "music"
                                }
                            ]
                        },
                        {
                            "name": "status",
                            "inputType": "choiceset",
                            "title": "Status",
                            "description": "Available airing statuses",
                            "choices": [
                                {
                                    "title": "Airing",
                                    "value": "airing"
                                },
                                {
                                    "title": "Completed",
                                    "value": "complete"
                                },
                                {
                                    "title": "Upcoming",
                                    "value": "upcoming"
                                }
                            ]
                        },
                        {
                            "name": "rating",
                            "inputType": "choiceset",
                            "title": "Rating",
                            "description": "Available ratings",
                            "choices": [
                                {
                                    "title": "G",
                                    "value": "g"
                                },
                                {
                                    "title": "PG",
                                    "value": "pg"
                                },
                                {
                                    "title": "PG-13",
                                    "value": "pg13"
                                },
                                {
                                    "title": "R",
                                    "value": "r17"
                                },
                                {
                                    "title": "R+",
                                    "value": "r"
                                },
                                {
                                    "title": "Rx",
                                    "value": "rx"
                                }
                            ]
                        }
                    ],
                    "description": "Search animes",
                    "apiResponseRenderingTemplateFile": "response_json/getAnimeSearch.json"
                },
                {
                    "context": [
                        "compose"
                    ],
                    "type": "query",
                    "title": "Search mangas",
                    "id": "getMangaSearch",
                    "parameters": [
                        {
                            "name": "q",
                            "title": "Search Query",
                            "description": "The search query",
                            "isRequired": true
                        },
                        {
                            "name": "type",
                            "inputType": "choiceset",
                            "title": "Type",
                            "description": "Available manga types",
                            "choices": [
                                {
                                    "title": "Manga",
                                    "value": "manga"
                                },
                                {
                                    "title": "Novel",
                                    "value": "novel"
                                },
                                {
                                    "title": "Light Novel",
                                    "value": "lightnovel"
                                },
                                {
                                    "title": "One Shot",
                                    "value": "oneshot"
                                },
                                {
                                    "title": "Doujin",
                                    "value": "doujin"
                                },
                                {
                                    "title": "Manhwa",
                                    "value": "manhwa"
                                },
                                {
                                    "title": "Manhua",
                                    "value": "manhua"
                                }
                            ]
                        },
                        {
                            "name": "status",
                            "inputType": "choiceset",
                            "title": "Status",
                            "description": "Available manga statuses",
                            "choices": [
                                {
                                    "title": "Publishing",
                                    "value": "publishing"
                                },
                                {
                                    "title": "Complete",
                                    "value": "complete"
                                },
                                {
                                    "title": "Hiatus",
                                    "value": "hiatus"
                                },
                                {
                                    "title": "Discontinued",
                                    "value": "discontinued"
                                },
                                {
                                    "title": "Upcoming",
                                    "value": "upcoming"
                                }
                            ]
                        },
                        {
                            "name": "start_date",
                            "title": "Start Date",
                            "description": "Start date of the manga",
                            "inputType": "date"
                        },
                        {
                            "name": "end_date",
                            "title": "End Date",
                            "description": "End date of the manga",
                            "inputType": "date"
                        }
                    ],

Guias passo a passo

Para criar uma extensão de mensagem baseada em API, consulte criar uma extensão de mensagem baseada em API.

Confira também

Autenticação para extensões de mensagem baseadas em API