Connect Your API

Open in CMS

This tutorial walks you through registering an external API so your agent can call it automatically during conversations. You give Atlas, Kirana Group's operations assistant, a way to check live project data: when someone asks "What is the status of KG-2041?", Atlas calls Kirana's Projects API and answers with the status, approval stage, progress and budget. By the end, you have a working API action, know how to test it without leaving qlar, and know which advanced options exist when you need them.


Before you start

  • Your agent already answers correctly from its own knowledge. If not, start with Teach Your Agent.
  • You know how to test and publish changes. See Preview and Publish Changes.
  • You have the URL of the API you want to call, plus its credentials if it needs any. For this tutorial you only need internet access: the example API is a public, read-only sample.
  • Looking for a ready-made integration instead? Check Using Plugins first.

How qlar Calls Your API

qlar does not require you to write any code to connect an API. Instead, you describe the API in plain language and qlar passes that description to the AI model as a function tool. Here is what happens on every conversation turn:

  1. The AI reads the user's message and decides, based on your description, whether it needs to call the API to give an accurate answer.
  2. qlar makes the HTTP request to your endpoint, filling in the parameters it extracted from the conversation.
  3. Your server responds with data in any format (JSON, plain text, and so on).
  4. The AI reads the response and turns it into a natural-language reply.

This cycle happens automatically. You register the API once; the AI decides when and how to use it.


Scenario Used in This Tutorial

Kirana keeps the status of every project in its Projects API. This tutorial uses a public, read-only sample of that API, so you can follow along and test the result right away. It knows three projects:

Project codeProject
KG-2041Surabaya warehouse expansion
KG-2052Jakarta head office fit-out
KG-2063Bekasi rooftop solar

Any other code returns HTTP 404 Not Found.

FieldValue
Action nameget_project_status
PurposeReturn the status, progress, budget and current approval stage of one project
EndpointGET https://stpusakaappassetprod.blob.core.windows.net/docs-media/samples/kirana-api/projects/{projectCode}.json
ParameterprojectCode, the project code, for example KG-2041
AuthenticationNone

Once you are comfortable with the steps, swap in your own endpoint.


Step 1: Open Custom API

Move your pointer over the icon sidebar on the left edge of the CMS to expand it (on a narrow screen, click the menu button (☰) at the top left instead). Expand Tools, then click Custom API.

The Custom API page loads. At the top are four buttons: Import OpenAPI Schema, Add New API, Add Category and Set Authentication. Below them is the list of API actions already registered for this agent.


Step 2: Add a New API

Click Add New API. The New API panel slides in from the right with three sections: Basic Information, Authentication and Properties. The screenshot shows the panel as it looks when you have finished this tutorial; the next steps fill it in section by section.

New API panel filled in for get_project_status: Basic Information with Action Name, Description, HTTP Method GET, the Kirana Projects API Target URI, Loading Text Type Fixed with Checking the project status..., Rules and Response Prompt; Authentication with Auth Type None; Properties with projectCode, String, Path, Required Parameter on and its description; buttons Add New Property and Add New API

Step 3: Fill in the Action Name and Description

The Basic Information section is the most important part. The AI uses the name and description to decide when to call this API, so clarity here directly affects how well the integration works.

Action Name

Type get_project_status in the Action Name field.

Tip: Use snake_case and keep names short but specific. The AI model reads this name, so get_project_status is clearer than projects or lookup.

Description

In the Description field, explain what the API returns and when it should be called. Write it as if you are briefing the AI:

Returns the status, progress, budget and current approval stage of one Kirana Group project. Call it when the user asks about a project by its code, for example "What is the status of KG-2041?".
Basic Information section with Action Name get_project_status, the Description, HTTP Method GET, Target URI starting with https://stpusakaappassetprod.blob.core.windows.net/docs-media/samples/kirana-api/, Loading Text Type Fixed, Loading Text Checking the project status..., the Rules and Response Prompt texts, and the Additional Properties and Send Metadata switches turned off

Step 4: Set the HTTP Method and Endpoint

  1. Set HTTP Method to GET.

  2. In Target URI, enter the full URL of the endpoint:

    https://stpusakaappassetprod.blob.core.windows.net/docs-media/samples/kirana-api/projects/{projectCode}.json
    

Note: {projectCode} is a path parameter. qlar replaces it with the value the AI extracts from the conversation, so "What is the status of KG-2041?" calls .../projects/KG-2041.json. You define the parameter as a property in Step 8.


Step 5: Configure a Loading Text

While qlar waits for your API to respond, it shows a short message to the user. A new API starts with Loading Text Type set to Auto.

  1. Set Loading Text Type to Fixed.

  2. In the Loading Text field that appears, enter:

    Checking the project status...
    

Tip: Keep loading text short and action-oriented. It disappears as soon as the answer arrives. See Loading Text Types for the other options.


Step 6: Add Rules and a Response Prompt

Both fields are optional, but they make the answer far more reliable.

Rules tell the AI how to interpret the response: what to use, and what to do when something is missing. Enter:

Use only the fields in the response. If the project is not found (HTTP 404), say that the code is unknown and ask the user to check it (codes look like KG-2041).

Response Prompt tells the AI how to present the result. Enter:

Start with the status and the current approval stage, then progress, budget spent versus total, and the latest update. Keep it under six lines.

Leave Additional Properties and Send Metadata off. Both are explained under Advanced Features.


Step 7: Skip Authentication (Public Endpoint)

The sample endpoint is public. In the Authentication section, leave Auth Type on None and move on.

If your own API requires credentials, see Authentication Options at the bottom of this page.


Step 8: Add a Property

Properties tell the AI which values to extract from the conversation and pass to your API. In the Properties section, click Add New Property. A new property row appears. Fill it in:

FieldValue
Property NameprojectCode
Property TypeString
LocationPath
Required ParameterOn
Property EnumLeave empty
Property DescriptionKirana project code in the form KG-0000, for example KG-2041. Use upper case.
Properties section with Property Name projectCode, Property Type String, Location Path, Required Parameter switched on, empty Property Enum, Property Description Kirana project code in the form KG-0000, for example KG-2041. Use upper case., and the Add New Property button

Tip: The Property Description is read by the AI. A precise description with an example of a valid value reduces the chance of the AI sending something unexpected, such as kg 2041 instead of KG-2041.

About Location: Path means the value replaces {projectCode} in the URL. Use Querystring for parameters appended as ?key=value, Header for values sent as an HTTP header, and Body for the payload of a POST request. Property Enum limits the property to a fixed list of values: type a value and press Enter to add it.


Step 9: Add the API to the List

Click Add New API at the bottom of the panel. The panel closes and get_project_status appears in the list, with its description, a None chip for its authentication, an on/off switch and a delete button.

Custom API page with the buttons Import OpenAPI Schema, Add New API, Add Category and Set Authentication, one row get_project_status with its description, a None chip, an enabled switch and a delete button, and the Save all changes button below

Note: The API is only in the form so far. It is not saved yet.


Step 10: Save All Changes

Click Save all changes at the bottom of the Custom API page. The CMS asks Are you sure to save your changes? Click Yes. A message confirms Custom API successfully updated!

The change is saved as a draft. You can try get_project_status in the preview right away, and real users get it after you click Publish in the top bar.


Step 11: Test the API

Before you try it in a conversation, check that qlar can reach the endpoint and that the response looks right.

  1. In the list, click the get_project_status row to open its panel again.
  2. At the bottom left of the panel, click Test API. The panel changes to Test API: get_project_status and shows the API Details (method, authentication, endpoint, description).
  3. Under Parameters, type KG-2041 in Project Code.
  4. Click Call API.
  5. Under API Response, a 200 OK badge appears, with Response Headers and Response Body below it.

The response body for KG-2041 looks like this:

{
  "projectCode": "KG-2041",
  "name": "Surabaya warehouse expansion",
  "site": "Surabaya",
  "projectManager": "Dewi Lestari",
  "status": "Delayed",
  "percentComplete": 62,
  "budgetUsd": 2500000,
  "spentUsd": 1480000,
  "approval": {
    "stage": "Regional Director",
    "waitingSince": "2026-09-29",
    "nextApprover": "CFO"
  },
  "latestUpdate": "Steel delivery slipped two weeks; new completion date 15 December 2026.",
  "plannedCompletion": "2026-11-30",
  "forecastCompletion": "2026-12-15"
}
Test API: get_project_status panel with Back to Configuration, API Details (HTTP Method GET, Authentication None, the endpoint and description), Parameters with Project Code KG-2041, the Call API button, a 200 OK badge, and the Response Body showing the KG-2041 JSON with status Delayed, percentComplete 62, budgetUsd 2500000, spentUsd 1480000 and approval stage Regional Director

Click Back to Configuration to return to the form.

Tip: Also try KG-9999. You get 404, which is exactly the case your Rules handle: Atlas should say the code is unknown and ask the user to check it.


Check the result

In the preview panel on the right, click the reload button to start a fresh conversation and ask:

What is the status of project KG-2041?

The loading text Checking the project status... appears briefly. Then Atlas answers in the layout of your Response Prompt:

  • Status: Delayed, approval is at the Regional Director stage; next approver: CFO.
  • Progress: 62% complete.
  • Budget: US$1.48M spent of US$2.5M.
  • Latest update: steel delivery slipped two weeks; forecast completion is 15 December 2026.
Atlas preview: the user asks What is the status of project KG-2041? and Atlas answers Status: Delayed, approval is at the Regional Director stage, next approver CFO, followed by bullets for Progress 62% complete, Budget US$1.48M spent of US$2.5M, and Latest update steel delivery slipped two weeks with forecast completion 15 December 2026

Then ask about a code that does not exist, for example "And KG-9999?". Atlas should say the code is unknown and ask you to check it, instead of inventing a project.

If the answer is not right:

  • Atlas answers without calling the API. Make the Description more specific about when to call it, and check that the API's switch in the list is on.
  • Atlas says the project cannot be found for a valid code. Open Test API and call it with the same code. A 404 usually means the code reached the API in the wrong form; tighten the Property Description.

When the answers look right, click Publish so real users get the new API. See Preview and Publish Changes.


Advanced Features

The steps above cover the most common setup. The sections below explain features you may need as your integration grows.


Import APIs from an OpenAPI Schema

Instead of adding actions one by one, you can register several at once from an existing OpenAPI (Swagger) definition. Click Import OpenAPI Schema and follow the four steps of the wizard. See Import an OpenAPI Schema for the full walkthrough with Kirana's sample schema.


Set Authentication for Multiple APIs at Once

When several APIs share the same credentials, for example all actions imported from one schema, click Set Authentication to configure the authentication once and apply it to every API you tick. See Set Authentication.


Authentication Options

Select the Auth Type in the Authentication section and the required fields appear.

Auth TypeWhen to use
NonePublic endpoints, no credentials needed
BearerAPIs secured with a static Bearer token
BasicAPIs that use a username and password
CustomAPIs with a custom header name (for example X-API-Key)
OauthAPIs secured with OAuth 2.0 (Client Credentials or Google Service Account)

For Bearer, enter the token in the Key field. For Basic, enter a Username and Password. For Custom, enter the Header Name (for example X-API-Key) and the Key value. For Oauth, select the provider type, enter the Token URL, and supply the credentials for your grant type.


Response Prompt

The Response Prompt field describes how the AI should present the API result to the user: tone, format, and level of detail. This is separate from Rules, which governs how the AI interprets the raw data.

Example for Atlas:

Start with the status and the current approval stage, then progress, budget spent versus total, and the latest update. Keep it under six lines.
FieldControls
RulesHow the AI processes and constrains the API response (logic, fallbacks)
Response PromptHow the AI formats and delivers the result to the user (tone, structure)

Send Metadata

When Send Metadata is on, qlar attaches conversation and identity context to every request sent to your API. Use this when your API needs to personalize the response based on the user's identity, channel, or permissions.

Metadata is always sent as HTTP headers, and is also included in the query string (for GET/DELETE) or the JSON request body (for POST/PUT/PATCH), depending on the action's HTTP Method.

Always sent as headers

HeaderDescription
X-AgentIdID of the agent handling the conversation
X-UserIdUnique identifier of the user chatting
X-UserEmailEmail of the user chatting (empty string if not available)
X-InquiryMessageIdID of the message that triggered the API call
X-MediaTypeChannel the user is on (web, WhatsApp, etc.)
X-TargetAgentIdID of the target agent, if the conversation was handed off
X-MessengerAccount-ProductMessenger product being used, only sent if available
X-MessengerAccount-AccountCodeSpecific messenger account code, only sent if available
X-User-PermissionsJSON array of the user's permissions, only sent if non-empty

Also sent in the query string, for GET/DELETE

Query parameterSame value as
agentIdX-AgentId
userIdX-UserId
userEmailX-UserEmail
inquiryMessageIdX-InquiryMessageId
mediaTypeX-MediaType
targetAgentIdX-TargetAgentId

Note: the messenger account and user permissions fields are only available via the headers above for GET/DELETE requests. They are not appended to the query string.

Also sent in the JSON body, for POST/PUT/PATCH

A metadata object is added alongside your declared body parameters:

{
  "metadata": {
    "AgentId": "...",
    "UserId": "...",
    "UserEmail": "...",
    "InquiryMessageId": "...",
    "MediaType": "...",
    "TargetAgentId": "...",
    "MessengerAccount": { "Product": "...", "AccountCode": "..." },
    "UserPermissions": ["..."]
  }
}

Note: unlike the headers and query string above, the fields inside the metadata body object use PascalCase (for example AgentId, not agentId). MessengerAccount is null when the user isn't on a messenger channel.


Example Server Implementation

The examples below show a server you build to receive calls from qlar. The sample Projects API used earlier is a set of static files and needed no server code at all. The scenario here is a simple order_status action: given an orderId, it looks up and returns the order's shipping status. Authentication uses Auth Type: Custom, with a header named X-Api-Key.

Use the controls to see how the request and server code change with HTTP Method, Send Metadata, and Media Type:

HTTP Method
Send Metadata
Media Type

Sample request qlar sends

POST /api/order-status HTTP/1.1
Content-Type: application/json
X-Api-Key: sk_live_abc123
X-AgentId: 3fa85f64-5717-4562-b3fc-2c963f66afa6
X-UserId: user_8231
X-UserEmail: 
X-InquiryMessageId: msg_9f21
X-MediaType: web
X-TargetAgentId: 
X-User-Permissions: []

{
  "orderId": "ORD-1001",
  "metadata": {
    "AgentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "UserId": "user_8231",
    "UserEmail": "",
    "InquiryMessageId": "msg_9f21",
    "MediaType": "web",
    "TargetAgentId": "",
    "MessengerAccount": null,
    "UserPermissions": []
  }
}

Server implementation

const express = require("express");
const app = express();
app.use(express.json());

const API_KEY_HEADER = "x-api-key";
const API_KEY = process.env.CUSTOM_API_KEY; // must match the "Key" set in CMS Auth Type: custom

const ORDERS = {
  "ORD-1001": { status: "shipped", carrier: "JNE", eta: "2026-08-02" },
};

app.post("/api/order-status", (req, res) => {
  // 1. Verify the custom auth header configured in CMS (Auth Type: custom)
  if (req.get(API_KEY_HEADER) !== API_KEY) {
    return res.status(401).json({ error: "Invalid or missing API key" });
  }

  // 2. Read the declared parameter
  const { orderId } = req.body;
  if (!orderId) return res.status(400).json({ error: "orderId is required" });

  // Metadata is always sent as headers (also duplicated in the query string for
  // GET/DELETE, or under "metadata" in the JSON body for POST/PUT/PATCH)
  const agentId = req.get("X-AgentId");
  const userId = req.get("X-UserId");
  const inquiryMessageId = req.get("X-InquiryMessageId");
  const mediaType = req.get("X-MediaType"); // "web" | "whatsapp" | ...
  const userPermissions = JSON.parse(req.get("X-User-Permissions") || "[]");

  console.log("Call from agent " + agentId + ", user " + userId + ", channel " + mediaType);

  // 3. Look up the order
  const order = ORDERS[orderId];
  if (!order) return res.status(404).json({ error: "Order " + orderId + " not found" });

  // Personalise the response by channel when metadata is available
  if (mediaType === "whatsapp") {
    // Keep WhatsApp replies short; no rich formatting
    return res
      .status(200)
      .send("Order " + orderId + " is " + order.status + " via " + order.carrier + ", arriving " + order.eta + ".");
  }

  return res.status(200).json({ orderId, ...order });
});

app.listen(3000, () => console.log("Listening on :3000"));

Note: Media Type only changes the sample values shown above. The server code itself reads X-MediaType at runtime and already handles both web and whatsapp, so it works no matter which channel the real request comes from.


Additional Properties

By default, the AI is restricted to the parameters you define in the Properties section. Turning on Additional Properties allows the AI to pass extra key-value pairs beyond what is explicitly listed. This is useful for flexible or dynamic API contracts.


Categories and the On/Off Switch

Click Add Category to group related APIs in the list, for example Projects and Procurement. APIs without a category are listed under Uncategorized. Drag a row by its handle to reorder it.

Each row has a switch. Turn it off to stop the agent from using that API without deleting its configuration. Like every change on this page, it takes effect after Save all changes (and Publish for real users).


Loading Text Types

TypeBehavior
AutoThe default. The AI writes a short loading message that fits the current request.
NoneNo loading message is shown to the user.
FixedThe exact text you enter in Loading Text is shown every time.
DynamicThe AI writes the loading message, guided by the instruction you enter in Loading Text Prompt.

Fixed gives you full control over the wording. Dynamic is useful when one API action is used in different contexts and a single fixed text would feel out of place.


Next steps