# Develop your app  

Each app has its own architecture and components required, but the overall process of developing your app is the same.

1. [Create the app shell](https://www.infobip.com/docs/develop-your-app#create-the-app-shell)
2. [Develop the core functionality of your app](https://www.infobip.com/docs/develop-your-app#develop-core-functionality-of-your-app)
3. [Create and connect the configuration page and settings DB, and connect to middleware/context card](https://www.infobip.com/docs/develop-your-app#creating-a-configuration-page-and-settings-db) (optional)
4. [Connect your app to Infobip by updating the manifest](https://www.infobip.com/docs/develop-your-app#update-the-manifest)
5. [Test your app](https://www.infobip.com/docs/develop-your-app#tips-for-testing).
6. [List to marketplace](https://www.infobip.com/docs/list-your-app) (optional)
## Create the app shell
  
To get started creating an app, you’ll need to create the app shell which contains the information Infobip needs to use your app’s functionality. This also creates the app’s Client ID and Client Secret that can be used in the OAuth process.
  
When the app shell is first created, it is available to your account, but not available to anyone else. This is called private access. To make your app available to additional accounts, see the section on [Listing your app on the Exchange marketplace](https://www.infobip.com/docs/list-your-app).
  
To create your app shell:

1. Log into your Infobip account and go to [Exchange](https://portal.infobip.com/exchange/).
2. Click **Publish**.
If you can't see the **Publish** option, contact the [Infobip Support](https://www.infobip.com/contact) team to request access.
3. Click **Create App**.
4. Enter a name for your app in the **App Name**
You can choose any name you prefer, but if you want to list your app on the public Exchange marketplace, you need to choose a unique name.
5. From the **Works with** drop-down list, select the products that your app uses. You can select all the relevant products.
  
    | Product | Notes |
    | --- | --- |
    | Conversations | If your app is a context card, you do not need to select a channel as the app works natively with the channels supported by Conversations. |
    | Answers | If your app is a chatbot block, you do not need to select a channel as the app works natively with the channels supported by Answers. |
    | Moments  Flow | If your app is a Moments Flow element, you do not need to select a channel as the app works natively with the channels supported by Moments. |
    | People | If your app syncs data via the People API, then you do not need to select the channel as the app works with the channels supported by People. |
    | Channels | If you have integrated a channel into your product using an API, then select the relevant channel. |
  
    You'll then see an embedded text editor where you can build your manifest by editing the values. If you have chosen more than one product from the **Works with** drop-down list, you see separate tabs for each integration point manifest. Choose whether to use YAML or JSON to define your manifest.
  
6. Edit the example manifest in the embedded text editor to define how your app connects to Infobip. At this stage, you can still create the app using default or dummy values, but be sure to update your manifest when you have the relevant information.
  See [Update the manifest](https://www.infobip.com/docs/develop-your-app#update-the-manifest) to correctly structure your manifest.
7. Specify the URLs for:
  **Settings URL** for the location of the settings and configuration for the app. This is a web page where users can save settings and configure your app. This field is optional.
  **Redirect URL** for redirecting after authentication. If you use OAuth to connect your app to Infobip, this is the URL that redirects back to your app after authentication.
8. Add a URL to an image for the logo in the **Logo URL** field. The logo file must be SVG format (.svg), with a size of 40 x 40 pixels.
9. When using [Infobip OAuth](https://www.infobip.com/docs/authorization-oauth), or using Infobip APIs as part of the functionality of your app, select the [API scopes](https://www.infobip.com/docs/essentials/api-essentials/api-authorization#api-scopes) that your integration will use. For best practice, select only the scopes that are necessary for your integration.
10. Click **Create App** to save your app settings and generate the app's credentials for connecting to Infobip.
  
You see the app created and listed in the Exchange Publish page.
  
The app details show the name and a **Private** label to show that it is available only to your account.
  
You'll also see the Infobip products that relate to this app.
  
The three-dot menu gives you a number of options.
  
|  |  
| --- |  
| Edit | Make changes to the settings that you entered in the publish stage. You can also view the Client ID, Client Secret and Signing secret. |  
| Configure | Open the settings URL page for the app settings and configuration. |  
| View ID | View the client ID and client secret, the OAuth credentials used in authorization. |  
| Delete | Remove the app from Exchange. |
  
Once you've created your app, it is active for your account only. If the app includes a context card, the card is available to all agents in your account. If the app includes an Answers bot block, the block is available in the bot builder canvas.
  
If you intend to use the OAuth 2.0 flow with your app, you need to save the client ID and client secret. To validate the execution signature in Answers, you need to save the signing secret.
## Develop core functionality of your app
  
In this step, you create the core functionality for the app. Depending on the needs of your app, you may create a UI experience through a website embedded via an iframe, an API, or middleware to interpret the call from Answers to your API endpoint.
  
### Conversations [#conversations-develop-core-functionality-of-your-app]
  
The following core functionality can be developed for Conversations:

- Context Card UI: standard and XL sizes
- Full page UI

#### Context Card UI [#context-card-ui-develop-core-functionality-of-your-app]
  
Conversations context cards allow you to show custom information to contact center agents in their workspace, as they assist end customers. Your context card UI should be a web page or web site that can be embedded into the agent experience using an iframe.
  
Context cards are available in two sizes: standard and XL.
  
#### Standard size context cards [#standard-size-context-cards-develop-core-functionality-of-your-app]
  
Standard size context cards are loaded in the right-side panel of the agent’s workspace in My Work. By default, standard size context cards are not expanded. Agents can open the context card by clicking on the context card’s title to expand it.
  
To ensure the best display in the context card, design the content in your app with a maximum size of 425 x 500.

#### XL size context cards [#xl-size-context-cards-develop-core-functionality-of-your-app]
  
XL size context cards are loaded in a separate panel in the agent’s workspace in My Work. By default, XL context cards are expanded when the conversation is loaded. Agents only see one XL card, even if multiple are installed. Not all Infobip accounts are configured to support XL cards, so please reach out to us if you plan to use this setup.
  
The area available to the XL card changes based on the screen available, so responsive UI displays best. If the user has a screen less than 750px wide, the XL card is not visible.

#### Creating the context card UI and functionality [#creating-the-context-card-ui-and-functionality-develop-core-functionality-of-your-app]
  
Your context card UI can be created however you like. There is some information available from Infobip that can help tailor the user’s experience.
  
On page load, Conversations loads your UI, and include the Conversations ID as a query parameter in the referrer header.
  
If you have selected the `conversations:manage` scope, you can use the Conversations ID and OAuth to get more information about the Conversation using the [Conversations API](https://www.infobip.com/docs/api/customer-engagement/conversations). To use Infobip APIs on behalf of the customer, you need to complete the [OAuth 2.0 flow](https://www.infobip.com/docs/authorization-oauth).
  
Example header content:
  
```json
{
  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
  "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
  "accept-encoding": "gzip, deflate, br",
  "accept-language": "en-US,en;q=0.9",
  "referer": "https://portal.infobip.com/conversations/my-work?conversationId=1f073950-5c7f-417e-990d-ae0efd8af797",
  "sec-ch-ua": "\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\"",
  "sec-ch-ua-mobile": "?0",
  "sec-ch-ua-platform": "\"Windows\"",
  "sec-fetch-dest": "iframe",
  "sec-fetch-mode": "navigate",
  "sec-fetch-site": "cross-site",
  "sec-fetch-user": "?1",
  "upgrade-insecure-requests": "1",
  "x-forwarded-for": "89.164.98.239",
  "x-forwarded-host": "appendpoint.free.beeceptor.com",
  "x-forwarded-proto": "https"
}
```
  
The following table shows the features commonly used on Context cards:
  
| Action | Source | Required scopes |
| --- | --- | --- |
| Get customer’s account key | OAuth 2.0 | None |
| Get user’s email | OAuth 2.0 | None |
| Get user’s preferred language | OAuth 2.0 | None |
| Get Infobip token to use in API calls | OAuth 2.0 | None |
| Get customer’s channel | Conversations API:get Messages | conversations:manage |
| Get customer phone or email address | Conversations API:get Messages | conversations:manage |
| Get conversation messages | Conversations API:get Messages | conversations:manage |
| Send message in conversation | Conversations API:create Message | conversations:manage |
| Create note | Conversations API:create Note | conversations:manage |
| Get customer information | People API:get Person | people:read |
| Update customer information | People API:update Person | people:manage |
| Create a new customer | People API:create Person | people:manage |
| Create an event to a customer | People API:create Event | people:managepeople:use |

#### Full page UI [#full-page-ui-develop-core-functionality-of-your-app]
  
Conversations full page apps allow you to show custom information to contact center agents and supervisors on a separate area within Conversations. Your full page UI should be a web page or web site that can be embedded using an iframe. There are no limitations on the size of the content for this app, but we recommend creating the UI in a responsive way so that it displays correctly on a variety of screen sizes, including mobile.
  
Your full page UI can be created however you like. There is some information available to your UI from Infobip that can help tailor the user’s experience.
  
On page load, Conversations loads your UI. As this experience isn’t tied to a specific conversation, the referrer does not include a Conversations ID. To get information about the customer’s account, use Infobip APIs on behalf of the customer, you need to complete the [OAuth 2.0 flow](https://www.infobip.com/docs/authorization-oauth).
  
The following table shows the features commonly used on full page apps:
  
| Action | Source | Required scopes |
| --- | --- | --- |
| Get customer’s account key | OAuth 2.0 | None |
| Get user’s email | OAuth 2.0 | None |
| Get user’s preferred language | OAuth 2.0 | None |
| Get Infobip token to use in API calls | OAuth 2.0 | None |
| Get agents | Conversations API:get Agents | conversations:manage |
| Get Queues | Conversations API:get Queues | conversations:manage |
| Update working hours | Conversations API:update Working Hours | conversations:manage |
| Get Conversation routing information | Conversations API:get Routing | conversations:manage |
| Get customer information | People API:get Person | conversations:manage |
| Get list of tags | People API:get Tags | people:read |
| Add a tag to a batch of people | People API:add Tag | people:manage |
| Get a list of custom attributes | People API:get Tag | people:read |
| Create a custom attribute | People API:add Tag | people:manage |

### Answers [#answers-develop-core-functionality-of-your-app]
  
The following core functionality can be developed for Answers:

- API connection to Answers
- Passing variables to your API
- Designer experience
- Account level variables
- Arrays and complex data lists
- Webhooks

#### Setting up the API to connect Answers [#setting-up-the-api-to-connect-answers-develop-core-functionality-of-your-app]
  
Answers connects to your app via an API call. It can call your API directly or through a middleware. Direct connections can be a quick way to create your app, however there are some limitations. Depending on the needs of your API and the experience you want to offer to users, you may need or want to develop middleware to translate the call from Answers into the call format needed for your API. Once your API is ready, [update the Manifest](https://www.infobip.com/docs/develop-your-app#update-the-manifest) to connect Answers to your API.
  
#### Passing variables to your API [#passing-variables-to-your-api-develop-core-functionality-of-your-app]
  
Answers can send chatbot variables to your API in two ways query and path parameters. Header parameters are not currently supported. If your API requires that variables be sent using a header you must use a middleware API to translate the call from Answers into the correct format for your API.
  
Note We do not recommend this option for information like platform credentials tokens etc as data set in bot attributes are not stored securely.
  
#### Answers Designer experience [#answers-designer-experience-develop-core-functionality-of-your-app]
  
When setting and receiving variables in the API call Answers uses values set in bot [Attributes](https://www.infobip.com/docs/answers/chatbot-structure/attributes) by the Answers Designer. If the Answers Designer is unlikely to know how to populate a specific variable as an attribute we recommend having the integration manager define the variable in the Configuration page and use a middleware to combine the attributes set in the bot with the variables set in the configuration page.
  
#### Account level variables [#account-level-variables-develop-core-functionality-of-your-app]
  
If some variables are always the same for a specific account such as account credentials we recommend having the integration manager define the variable in the Configuration page and use a middleware to combine the attributes set in the bot with the variables set in the configuration page.
  
#### Arrays and complex data types [#arrays-and-complex-data-types-develop-core-functionality-of-your-app]
  
Arrays are stored as a List in Answers. At this time there isn’t a way to map a variable-length array response from your API directly to a List. We recommend returning the array to a JSON or Text attribute then requiring the Answers Designer to parse the response to a List using a Code Block.
  
#### Handling webhooks [#handling-webhooks-develop-core-functionality-of-your-app]
  
If the chatbot needs to wait for a change in state in your app you need to manage this in your API or middleware. The Answers Designer can create a webhook for the bot instance as part of their bot setup. If the Answers Designer assigns the sessionId to an attribute using a Code Block it can be sent to your API. Then your app can continue the bot by calling the webhook at `https://api.infobip.com/bots/webhook/{{sessionId}}`.
  
### Moments - Flow [#moments--flow-develop-core-functionality-of-your-app]
  
The following core functionality can be developed for Moments - Flow:

- API connection to Flow
- Passing variables to your API

#### Setting up the API to connect Flow [#setting-up-the-api-to-connect-flow-develop-core-functionality-of-your-app]
  
Flow connects to your app via an API call. It can call your API directly or through middleware.
  
Direct connections are a quick way to create your app however there are some limitations.
  
Depending on the needs of your API and the experience you want to offer to users you may need or want to develop middleware to translate the call from Flow into the call format needed for your API. Once your API is ready [update the Manifest](https://www.infobip.com/docs/develop-your-app#update-the-manifest) to connect Flow to your API.
  
#### Passing Flow variables and People attributes to your API [#passing-flow-variables-and-people-attributes-to-your-api-develop-core-functionality-of-your-app]
  
You can send variables to your API in the following ways:

- path and query - also known as the URL parameters
- body
- headers - only supported in Flow

### Handling authorization tokens [#handling-authorization-tokens-develop-core-functionality-of-your-app]
  
If your API requires authorization tokens and especially if they expire you need to manage the token lifecycle within your API or middleware.

## Creating a configuration page and settings DB
  
In this optional step, you’ll set up the configuration page UI and any supporting database and API connections needed. We recommend using a configuration page for the best user experience when your API requires account level information or you have additional settings that is used by your middleware, or if you would like to have more information available to the person who sets up your app for use. The configuration page can also be used to help with the onboarding process, offering access to templates and additional documentation users need to best use your app. You can store any settings defined by the Integrations Manager in a settings database, and use your middleware to insert the appropriate calls into your API endpoint call.
  
### Configuration page UI [#configuration-page-ui-creating-a-configuration-page-and-settings-db]
  
Configuration pages allow integration managers to define settings that can apply to any usage of the app.  Integrations managers can access this page through the My Apps section of Exchange. Your configuration page UI should be a web page or web site that can be embedded using an iframe. There are no limitations on the size of the content for this page, but we recommend creating the UI in a responsive way so that it displays correctly on a variety of screen sizes, including mobile. This page is defined in the App shell by populating the Settings URL field.

Your configuration page UI can be created however you like. There is some information available to your UI from Infobip that can help tailor the user’s experience.
  
On page load, Exchange loads your UI. To get information about the customer’s account, use Infobip APIs on behalf of the customer, you need to complete the [OAuth 2.0 flow](https://www.infobip.com/docs/authorization-oauth). Some features commonly used on the configuration page:
  
| Action | Source |
| --- | --- |
| Get customer’s account key | OAuth 2.0 |
| Get user’s email | OAuth 2.0 |
| Get user’s preferred language | OAuth 2.0 |
| Get Infobip token to use in API calls | OAuth 2.0 |

Additional information can be accessed using Infobip’s APIs, if the scopes for that API have been defined in your [app shell](https://www.infobip.com/docs/develop-your-app#create-the-app-shell). You can point to the location of page in the Settings URL when publishing your app, or select the Edit option on your app to change this location.
  
When you have entered a settings page URL for your app, your app three-dot menu also shows a Configure option.
  
To open the settings page so that you can see the app settings, select Configure.
## Update the manifest
  
The manifest is the interface between your app and Infobip. The manifest contains all the information that Infobip needs to display and use your app.
  
Manifests can be in either JSON or YAML format. The full structure of the manifest depends on whether you are building an app for Conversations, Answers, or Moments.
  
### Conversations [#conversations-update-the-manifest]
  
A Conversations manifest includes dictionaries for each entry point that the app supports. Currently each app can support one context card and full-page app.
  
The Conversations manifest contains the following key-value pairs for context card.
  
|  |
|  |
| card | The integration point type for context card. |
| title | The name of the app that is displayed to the user. This is a required field. The default example is My App Name. |
| src | The URL of the page that is inserted into the iframe in Conversations. HTTPS links are strongly recommended. This is a required field. The default example is  `https://awesome.app.com/context-card` . |
| size | The size of the context card in the Conversations right-side panel. The default is standard.·         standard: context card is shown along with other cards·         XL: the context card is shown on its own and spans the whole height of the screen |
  
The Conversations manifest contains the following key-value pairs for a full page app.
  
|  |
|  |
| page | The integration point type for full-page. |
| title | The name of the app that is displayed to the user. This is a required field. The default example is My App Name. |
| src | The URL of the page that is inserted into the iframe in Conversations. HTTPS links are strongly recommended. This is a required field. The default example is `https://awesome.app.com/context-card`. |
| path | The path where the integration is presented. The path should start with "/". For example, `/my-app` |
  
This is an example YAML manifest for Conversations:
  
``` 
card: 
    title: My App Name 
    src: https://awesome.app.com/context-card 
```  
  
This is an example JSON manifest for Conversations:
  
```json
{  
    "page": {
        "title": "My full-page app",
        "src": "https://awesome.app.com/fullpage-source",

         "path": "/documents/my-app"
    }
}
```  
  
This is an example YAML manifest for Conversations using both entry points:
  
``` 
card:
  title: My Super Context Card
  src: https://awesome.app.com/context-card
page:
  title: My Super Full-Page App
  src: https://awesome.app.com/fullpage
```  
  
### Answers [#answers-update-the-manifest]
  
You can choose one of the following layout types when creating your manifest for Answers:

- **Verbose layout**: defining the full structure of the functions used in your api call, including input and output fields
- **Simplified layout**: specifying an endpoint in the manifest that returns the full function details

Each of the manifest layouts are outlined below.
  
The Answers manifest may contain some or all of the following key-value pairs.
  
|  |
|  |
| functions | Define a list of all available functions in this dictionary. |
| name | The name of the function (default is My Order App). This value is shown to the chatbot editor. Each app can have multiple functions. |
| method | Defines how to call your function. The accepted methods are GET, POST, DELETE, POST, and PATCH. |
| description | Use this field to describe what the function does. For example, this function retrieves order details by Order ID. This description is shown to the chatbot editor. |
| uri | This is the endpoint the chatbot calls to execute the function. For example, `https://my-shopping-app.com/app/8/invoke/getOrderDetails`. |
| inSchema | Defines the variables that are inputs to your function request, including variable type, customer readable descriptions, variable names and whether the variable is required. type: The type, for example, object. required: Lists the properties that are required. These are the properties that you describe in the properties field. properties: A list of each property that could be passed to your endpoint call. You can define multiple properties. property_name: The name of any input property used in the endpoint request, for example, a property name like order_id.  type: The type of property. The possible values are: string, number. title: A UI-friendly name of the input property. This property title is displayed to the chatbot editor. example: Provides example values for the property. This is used to show the user how this information will look. |
| outSchema | Defines the variables that are outputs from your function response, including variable type, customer readable descriptions and variable names. type: The type, for example, object. required: Lists the properties that are required. These are the properties that you describe in the properties field. properties: A list of each property that could be returned in your endpoint response. You can define multiple properties. property_name: The name of any output property used in the endpoint request.  type: The type of property, for example, integer or string. title: A UI-friendly name of the input property. This property title is displayed to the chatbot editor. default: The default value of the property. For integer types, the default is 0. For string types, the default is ''. example: Provides example values for the property. This is used to show the user how this information will look. pattern: The expected schema pattern. The default is ^(.*)$ |
  
#### Making changes to the manifest [#making-changes-to-the-manifest-update-the-manifest]
  
Take care when updating your manifest after users have implemented your integration. Adding optional variables to your inSchema and outSchema are likely to have minimal impact, but adding required variables to the inSchema may break users in production. If you need to make significant changes to a manifest for a listed app, [contact Infobip](mailto:exchange@infobip.com) to help migrate customers to a new version of your manifest.
  
#### Query parameters and path parameters [#query-parameters-and-path-parameters-update-the-manifest]
  
The Answers manifest gives you the ability to add supporting query parameters and path parameters. This means that you can include chatbot attributes as parameters within your function. To use chatbot attributes within your functions, you surround the attribute with curly braces `{ }`.
  
For example, a function that calls the endpoint:
  
`[https://my-shoping-app.com/app/8/invoke/getOrderDetails`
  
If you obtain the `orderId` from your chatbot, the uri value in your manifest becomes:
  
`https://my-shoping-app.com/app/8/invoke/getOrderDetails/\{orderId\}`
  
Another example of using query parameters is:
  
`https://my-shoping-app.com/app/orders?limit=\{limit\}`
  
You do not need to include the parameters as inSchema properties.
  
When using the bot block within Answers, you can choose the value of each of the defined parameters.
  
#### Verbose manifest layout [#verbose-manifest-layout-update-the-manifest]
  
Use this layout if the overall structure for your app does not change from user to user, and you don't anticipate the endpoints or function schemas changing frequently.
  
To define your manifest, you'll specify each function that your app uses, its endpoint, and all input and output fields that the function uses.
  
This is an example YAML verbose manifest for Answers:
  
```yaml
functions:
  - name: getOrderDetails
    method: GET
    description: Gets Order details by Order ID
    uri: https://my-shoping-app.com/app/8/invoke/getOrderDetails
    inSchema:
      type: object
      required:
        - order_id
      properties:
        order_id:
          type: number
          title: Order ID
    outSchema:
      type: object
      title: The Items Schema
      required:
        - id
        - email
      properties:
        id:
          type: integer
          title: The Id schema
          default: 0
          examples:
            - 450789469
        email:
          type: string
          title: The Email Schema
          default: ''
          examples:
            - bob.norman@hostmail.com
          pattern: ^(.*)$
```  
  
This is an example JSON verbose manifest for Answers:
  
```json
{
    "functions": [
        {
            "name": "getOrderDetails",
            "method": "GET",
            "description": "Gets Order details by Order ID",
            "uri": "https://my-shoping-app.com/app/8/invoke/getOrderDetails",
            "inSchema": {
                "type": "object",
                "required": [
                    "order_id"
                ],
                "properties": {
                    "order_id": {
                        "type": "number",
                        "title": "Order ID"
                    }
                }
            },
            "outSchema": {
                "type": "object",
                "title": "The Items Schema",
                "required": [
                    "id",
                    "email"
                ],
                "properties": {
                    "id": {
                        "type": "integer",
                        "title": "The Id schema",
                        "default": 0,
                        "examples": [
                            450789469
                        ]
                    },
                    "email": {
                        "type": "string",
                        "title": "The Email Schema",
                        "default": "",
                        "examples": [
                            "bob.norman@hostmail.com"
                        ],
                        "pattern": "^(.*)$"
                    }
                }
            }
        }
    ]
}
```  
  
This is an example YAML verbose manifest for Answers with two functions: getOrderDetails and getShippingDetails.
  
```yaml
functions:
  - name: getOrderDetails
    method: GET
    description: Gets Order details by Order ID
    uri: https://my-shoping-app.com/app/8/invoke/getOrderDetails
    inSchema:
      type: object
      required:
        - order_id
      properties:
        order_id:
          type: number
          title: Order ID
    outSchema:
      type: object
      title: The Items Schema
      required:
        - id
        - email
      properties:
        id:
          type: integer
          title: The Id schema
          default: 0
          examples:
            - 450789469
        email:
          type: string
          title: The Email Schema
          default: ''
          examples:
            - bob.norman@hostmail.com
          pattern: ^(.*)$
  - name: getShippingDetails
    method: POST
    description: Get shipping details based on an input order id.
    uri: https://awesome.app.com/getShippingDetails
    inSchema:
      type: object
      required: 
      - orderId
      properties:
        orderId:
          type: number
          title: Order ID
    outSchema:
      type: object
      properties:
        shippingStatus:
          type: string
          title: Order status
        trackingNumber:
          type: number
          title: Number of items in order
        expectedDeliveryDate:
          type: string
          title: Expected delivery date
```  
  
#### Simplified manifest layout [#simplifiedmanifest-layout-update-the-manifest]
  
Use this layout if you plan to use different endpoints based on the logged-in user. Answers queries this endpoint to get the list of functions and their inputs and outputs.
  
This is an example of a YAML simplified manifest:
  
```yaml
uri:  https://awesome.app.com/getFunctions
```  
  
This is an example of a JSON simplified manifest:
  
```json
{"url":  "https://awesome.app.com/getFunctions"
}
```  
  
### Moments - Flow [#moments--flow-update-the-manifest]
  
A Moments - Flow manifest includes the functions that define Flow elements in the Flow editor. A Moments – Flow manifest consists of the parameters that build an element and define how it is rendered in the Flow.
  
The Moments - Flow manifest consists of the following main sections:

- Functions - define any procedure that can be executed on a third-party service
- Action - every action defines an element in Flow and it will execute some function when the flow is started
- Render - defines the list of input fields used by an action and which specifics how the user sees the function in the Flow editor
  
Use the following information about the function fields and examples from the default manifest in Exchange.
  
Both inSchema and outSchema support the [https://json-schema.org/](https://json-schema.org/) standard.
  
#### name
  
Defines the name of the function as the function identifier. Each app can have multiple functions. This is the function that will be executed when the flow element is processed. When you define an action, make sure that the action name has a corresponding function with the same name. For every render option that has the field *model* set, there needs to be a defined function with the same name as the *model*. This is the function that will be executed when the predefined values for this field are fetched.
  
```json
{
  "functions": [
    {
      "name": "Create reservation",
      ...
    }
  ]
}
```
  
#### method
  
Defines how to call your function. The valid methods are `GET`, `POST`, `DELETE`, `POST`, and `PATCH`.
  
```json
{
  "functions": [
    {
      "name": "Create reservation",
      "method": "POST",
      ...
    }
  ]
}
```
  
#### description
  
Use this field to describe what the function does. This description is shown to the user as the function definition in the Flow editor.
  
```json
{
  "functions": [
    {
      "name": "Create reservation",
      "method": "POST",
      "description": "Creates a reservation",
      ...
    }
  ]
}
```
  
#### uri
  
This is the endpoint call to execute the function. This endpoint is used by Exchange when executing the function.
  
```json
{
  "functions": [
    {
      "name": "Create reservation",
      "method": "POST",
      "description": "Creates a reservation",
      "uri": "https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations",
      ...
    }
  ]
}
```
  
Optionally, you can add supporting query parameters and path parameters. This allows you to include attributes as parameters within your function. To use attributes within your functions, surround the attribute with curly braces `{ }`.
  
For example, a function that calls the endpoint:  
`https://api.example.com/{path1}/v1?query1={query1}`  
  
Map parameters to the properties in `inSchema`. For example, the query parameter `query1={query1}` maps to the property as:
  
```json
"_query1": {
  "title": "Query 1",
  "type": "string"
}
```
  
The property must be defined with the underscore prefix (`_query1`).
  
```json
"uri": "https://api.example.com/{path1}/v1?query1={query1}",
"inSchema": {
  "properties": {
    "_path1": {
      "title": "Path 1",
      "type": "string"
    },
    "_query1": {
      "title": "Query 1",
      "type": "string"
    }
  }
}
```
  
#### inSchema
  
Defines the input parameters to a function, including variable type, customer-readable descriptions, variable names, and whether the variable is required.  
  
**inSchema** must include the following parameters:
  
- **type**: Set the type as object.
- **properties**: A map of each property that could be passed to your endpoint call. You can define multiple properties.
- **required**: List the input properties that must be included in the function.
  
For each of the properties, you must define:
  
- **property_name**: The name of any input property used in the endpoint request. The property names must match field names from the render options this field depends on (for example, `date` or `host_email`).
- **type**: The type of property (`string`, `number`).
- **title**: A UI-friendly name of the input property. This property title is displayed in the Flow editor.
  
You can also include example values for the property. This is used to show the user how this information will look.
  
```json
"inSchema": {
  "type": "object",
  "properties": {
    "host_name": {
      "type": "string",
      "title": "Host's Name"
    },
    "host_email": {
      "type": "string",
      "title": "Host's email"
    },
    "date": {
      "type": "string",
      "title": "Reservation date"
    }
  },
  "required": [
    "date",
    "host_name"
  ]
}
```
  
#### outSchema
  
Defines the output parameters from your function response, including variable type, customer-readable descriptions, and variable names.  
  
`outSchema` must include the following parameters:
  
- **type**: The top-level type is object.
- **properties**: A map of each property that can be returned in your endpoint response. You may define multiple properties.
  
For each property, define:
  
- **property_name**: The name for the output property used in the endpoint request. The name of the property should match the name of the field in the render options.
- **path**: Defines where the response is located (for example, header or body). The default is `body`. You can also define *statusCode*.
- **type**: The property type (`integer`, `string`, `number`, `boolean`, `object`).  
  Type may also contain `array` for functions that fetch predefined values for drop-down lists. Define the type `array` when using the render option `viewClass: SelectView.`
- **title**: A name for the property.
  
```json
"outSchema": {
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "title": "Reservation ID"
    },
    "host_name": {
      "type": "string",
      "title": "Host's Name"
    },
    "host_email": {
      "type": "string",
      "title": "Host's email"
    },
    "date": {
      "type": "string",
      "title": "Reservation date"
    },
    "status": {
      "path": "statusCode",
      "type": "string",
      "title": "Reservation status"
    }
  }
}
```
  
A map of properties should include two properties to identify which values will be used for the **SelectView** (dropdown) field as Option Name and Option ID.
  
- `selectViewOptionIdPath`
- `selectViewOptionNamePath`
  
Define the value of these properties as a JSON path to reach the ID and Name in the given array.
  
```json
"outSchema": {
  "properties": {
    "selectValue": {
      "selectViewOptionIdPath": "$.array[*].id",
      "selectViewOptionNamePath": "$.array[*].name",
      "title": "selectValue",
      "type": "array"
    }
  }
}
```
  
#### Example Manifest [#example-manifest-update-the-manifest]
  
The following is an example JSON manifest for Moments Flow. This manifest represents a working integration with a demo application to manage imaginary restaurant reservations.
  
Go to the demo application at the following link: [https://restaurant-reservations-demo.azurewebsites.net/](https://restaurant-reservations-demo.azurewebsites.net/)
  
The demo application is published on Github: [https://github.com/infobip-community/restaurant-reservations-demo](https://github.com/infobip-community/restaurant-reservations-demo)
  
You may use this manifest and test how integration works with the app from your Infobip account.
  
Note
The app is used only as an example representation of an Exchange integration and to show the manifest capabilities. Do not use the demo application in any production scenarios and do not share personal data with the application.
  
```json
{
    "icon": "https://cdn-web.infobip.com/uploads/2023/01/Infobip-logo.svg",
    "functions": [
        {
            "name": "Get all reservations",
            "description": "Get all reservations",
            "method": "GET",
            "uri": "https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations",
            "inSchema": {},
            "outSchema": {
                "type": "object",
                "properties": {
                    "_id": {
                        "type": "array",
                        "items": [
                            {
                                "type": "object",
                                "properties": {
                                    "id": {
                                        "type": "string",
                                        "title": "Reservation ID"
                                    },
                                    "host_name": {
                                        "type": "string",
                                        "title": "Host's Name"
                                    }, 
                                    "host_email": {
                                        "type": "string",
                                        "title": "Host's email"
                                    },
                                    "date": {
                                        "type": "string",
                                        "title": "Reservation date"
                                    },
                                    "hour": {
                                        "type": "string",
                                        "title": "Reservation time"
                                    },
                                    "party_size": {
                                        "type": "number",
                                        "title": "Number of participants"
                                    }
                                }
                            }
                        ],
                        "selectViewOptionIdPath": "$.reservations[*].id",
                        "selectViewOptionNamePath": "$.reservations[*].host_email"
                    }
                }
            }
        },
        {
            "name": "Create reservation",
            "description": "Creates a reservation",
            "method": "POST",
            "uri": "https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations",
            "inSchema": {
                "type": "object",
                "properties": {
                    "host_name": {
                        "type": "string",
                        "title": "Host's Name"
                    },
                    "host_email": {
                        "type": "string",
                        "title": "Host's email"
                    },
                    "date": {
                        "type": "string",
                        "title": "Reservation date"
                    },
                    "hour": {
                        "type": "string",
                        "title": "Reservation time"
                    },
                    "party_size": {
                        "type": "number",
                        "title": "Number of participants"
                    }
                },
                "required": [
                    "date",
                    "host_name",
                    "host_email",
                    "hour",
                    "party_size"
                ]
            },
            "outSchema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "title": "Reservation ID"
                    },
                    "host_name": {
                        "type": "string",
                        "title": "Host's Name"
                    }, 
                    "host_email": {
                        "type": "string",
                        "title": "Host's email"
                    },
                    "date": {
                        "type": "string",
                        "title": "Reservation date"
                    },
                    "hour": {
                        "type": "string",
                        "title": "Reservation time"
                    },
                    "party_size": {
                        "type": "number",
                        "title": "Number of participants"
                    }
                }
            }
        },
        {
            "name": "Update reservation",
            "description": "Updates a reservation",
            "method": "PUT",
            "uri": "https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations/{id}",
            "inSchema": {
                "type": "object",
                "properties": {
                    "_id": {
                        "type": "string",
                        "title": "Reservation ID"
                    },
                    "host_name": {
                        "type": "string",
                        "title": "Host's Name"
                    },
                    "host_email": {
                        "type": "string",
                        "title": "Host's email"
                    },
                    "date": {
                        "type": "string",
                        "title": "Reservation date"
                    },
                    "hour": {
                        "type": "string",
                        "title": "Reservation time"
                    },
                    "party_size": {
                        "type": "number",
                        "title": "Number of participants"
                    }
                },
                "required": ["_id"]
            },
            "outSchema": {
                "type": "object",
                "properties": {
                    "id": {
                        "type": "string",
                        "title": "Reservation ID"
                    }, 
                    "host_email": {
                        "type": "string",
                        "title": "Host Email"
                    },
                    "host_name": {
                        "type": "string",
                        "title": "Host Name"
                    },
                    "hour": {
                        "type": "string",
                        "title": "Hour"
                    },
                    "date": {
                        "type": "string",
                        "title": "Date"
                    },
                    "party_size": {
                        "type": "number",
                        "title": "Party Size"
                    }                  
                }
            }
        },
        {
            "name": "Delete reservation",
            "description": "Deletes a reservation",
            "method": "DELETE",
            "uri": "https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations/{id}",
            "inSchema": {
                "type": "object",
                "properties": {
                    "_id": {
                        "type": "string",
                        "title": "Reservation ID"
                    }
                },
                "required": ["_id"]
            },
            "outSchema": {}
        }
    ],
    "actions": [
        {
            "name": "Create reservation",
            "render": [
                {
                    "field": "host_name",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                },
                {
                    "field": "host_email",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                },
                {
                    "field": "date",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                },
                {
                    "field": "hour",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                },
                {
                    "field": "party_size",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                }
            ],
            "async": false
        },
        {
            "name": "Update reservation",
            "render": [
                {
                    "field": "_id",
                    "viewClass": "SelectView",
                    "model": "Get all reservations",
                    "personalization": false,
                    "dependencies": []
                },
                {
                    "field": "host_name",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                },
                {
                    "field": "host_email",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                },
                {
                    "field": "date",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                },
                {
                    "field": "hour",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                },
                {
                    "field": "party_size",
                    "viewClass": "TextFieldView",
                    "personalization": true,
                    "dependencies": []
                }
            ],
            "async": false
        },
        {
            "name": "Delete reservation",
            "render": [
                {
                    "field": "_id",
                    "viewClass": "SelectView",
                    "model": "Get all reservations",
                    "personalization": false,
                    "dependencies": []
                }
            ],
            "async": false
        }
    ],
  
  "triggers": []
}
```  
  
#### API request example [#api-request-example-update-the-manifest]
  
The following is an example of an API request. Exchange calls the defined uri with the data provided in this format.
  
The example show the raw body for function the "Creation reservation" [https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations](https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations).
  
```json
{
    "host_email": "test@test.com",
    "host_name": "Test",
    "hour": "11:00",
    "date": "2/15/2024",
    "party_size": "2"
}
```  
  
#### API response example [#api-response-example-update-the-manifest]
  
The following is an examples of an API response. Exchange expects the function to return data in this format for the manifest configuration.
  
The example shows the response for the function "Get all reservations" [https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations](https://restaurant-reservations-demo.azurewebsites.net/exchange/restaurant/reservations).
  
```json
{
    "reservations": [
        {
            "host_email": "test@test.com",
            "host_name": "Test",
            "hour": "15:30",
            "date": "2/14/2024",
            "party_size": "2",
            "additionalFields": [],
            "id": "fde30afb-f563-40b1-aa6c-d8106e3f278d"
        },
        {
            "host_email": "bob@test.com",
            "host_name": "Bob",
            "hour": "11:00",
            "date": "2/15/2024",
            "party_size": "2",
            "additionalFields": [],
            "id": "c96734da-1f1c-4aba-8129-5c3e9848ba14"
        }
    ]
}
```  
  
#### Model [#model-update-the-manifest]
  
If a function corresponds to a model for an input field, then its inSchema properties can be any from the list except array, and its outSchema properties should be array. In the outSchema, the name of the property should match the name of the field in the render option. Also, in inSchema, property names should match the field names from the render options that this field depends upon. The following is an example of the manifest.
  
The field definition for render in the actions (fields field3 , field4  and field5  are defined in the same list as field6 ):
  
```json
{
  "field": "field6",
  "viewClass": "SelectView",
  "model": "ref6",
  "dependencies": [
    "field3",
    "field4",
    "field5"
  ],
  "personalization": false
}
```
  
The function definition for the model of the field:
  
```json
{
  "name": "ref6",
  "description": "",
  "method": "GET",
  "uri": "some uri",
  "inSchema": {
    "properties": {
      "field3": {
        "type": "string",
        "title": "field3"
      },
      "field4": {
        "type": "string",
        "title": "field4"
      },
      "field5": {
        "type": "string",
        "title": "field5"
      }
    }
  },
  "outSchema": {
    "properties": {
      "field6": {
        "type": "array",
        "title": "field6"
      }
    }
  }
}
```
  
The format for the values from array is:
  
```json
[
  {
    "id": "value1",
    "name": "Value 1"
  },
  {
    "id": "value2",
    "name": "Value 2"
  }
]
```
  
This is a list of objects with the fields id (used during processing) and name (shown in the drop-down menu).
  
#### Dependencies [#dependencies-update-the-manifest]
  
The dependencies field for the render options has a number of use cases. This example demonstrates how it works:
  
*Select continent, and once you select the continent another select field appears which allows you to select a country, and once you select a country a third select field appears to select a city.*
  
In this example, field0 is TextFieldView, and the other fields are SelectView. The dependencies are:
  
- field1  has no dependencies
- field2  depends on field1
- field3  depends on field1  and field2
- field4  depends on field3
- field5  depends on field3  and field4
- field6  depends on field3 , field4  and field5
  
The order in which the fields are resolved is numerical, from field1 to field6.
  
If you choose a value for field1, the field2 gets its predefined values and becomes unlocked.
  
Choose the values for the next fields.
  
If you change the value of field2, all the fields that transitively but not directly depend on it are erased and disabled, in this example field4 . Fields that directly depend on it are also be erased, but new predefined values are fetched and the fields are disabled, as they can be resolved. In this example field3.
  
#### Making changes to the manifest [#making-changes-to-the-manifest-update-the-manifest]
  
Take care when updating your manifest after users have implemented your integration. Adding optional variables to your inSchema and outSchema are likely to have minimal impact, but adding required variables to the inSchema may break users in production. If you need to make significant changes to a manifest for a listed app, [contact Infobip](mailto:exchange@infobip.com) to help migrate customers to a new version of your manifest.
  
## Tips for testing
  
To test your app, first ensure that you have access to and are familiar with the Infobip product. Depending on the communication channel you want to use, you may need to configure [senders](https://www.infobip.com/docs/whatsapp/get-started)/[numbers](https://www.infobip.com/docs/sms/get-started/senders-and-numbers).
  
It’s recommended to create a simple app first, then start to layer on more complex experiences like managing additional variables, page navigation and OAuth.
  
See the [Troubleshooting](https://www.infobip.com/docs/troubleshooting) section for common issues.
  
### Testing Answers chatbots [#testing-answers-chatbots-tips-for-testing]
  
For Answers apps, we recommend setting up a bot outlining the full experience, to ensure all pieces are connected properly. You can also export the chatbot and provide it to customers to use as a template for their own chatbots.
  
### Testing Moments - Flow elements [#testing-moments--flow-elements-tips-for-testing]
  
For Moments - Flow elements, we recommend setting up a flow outlining the full customer journey to ensure all pieces are connected properly. You can also save the flow as a template to use again.
  
For more information about using the Flow editor and managing a flow, see [Manage flow](https://www.infobip.com/docs/moments/manage-flow).