Browse all guides
    AI REST API Connector

    Connect the bot to any backend system

    Custom tools let the AI agent call your backend during a live conversation, so answers come from real data instead of static content only: order status from an ERP, delivery tracking, support tickets, appointment availability, account data or CRM updates.

    Credentials

    The secret and configuration values needed to reach your backend, stored separately from the code so nothing is hardcoded.

    • API key, bearer token or username and password
    • Base API URL, tenant ID, company ID
    • Read in function code as credentials[:ERP_BASE_URL]
    • Use credentials for anything that differs per customer or environment

    Functions

    One function is one backend action the bot can perform: a small API operation it calls when needed.

    • Name: technical name in snake_case, e.g. get_order_delivery_status
    • Description: tells the AI when the function should be used
    • Parameters: the data needed from the customer or conversation
    • Code: the logic that calls your API, returning structured data

    Roles and intents

    A role tells the bot when a function is relevant in a conversation, and how to answer after calling it.

    • Description: what the customer is asking about
    • Instructions: which details to collect and how to answer
    • Examples: real customer phrasings that trigger the role
    • Without a role, the bot may never call your function

    How the pieces work together

    1. 1
      Customer asks

      "Where is my order 100391?"

    2. 2
      Role match

      The bot recognizes the Order delivery status intent.

    3. 3
      Missing data

      If the email is missing, the bot asks for the address used for the order.

    4. 4
      Function call

      The bot calls get_order_delivery_status with order_id and email.

    5. 5
      Live backend data

      Your ERP is called with the stored credentials and returns live order and delivery data.

    6. 6
      Natural answer

      "Your order 100391 has shipped and is in transit with DHL. Tracking ID JD014600009876543210, estimated delivery August 8."

    Setup example: ERP order status tool

    An online shop connects the bot to an ERP that holds customer orders and delivery data.

    1. Create the custom tool

    Give it a name such as ERP Order Lookup and a description like "Looks up customer order and delivery status from the ERP system." The tool groups all related functions.

    2. Add credentials

    Store the connection values as keys. They stay server side and are never exposed in the conversation.

    ERP_BASE_URL = https://erp.example-shop.com
    ERP_API_KEY  = your-api-key

    3. Add the function

    Define the name, a description that explains when to use it, and the parameter schema the AI must fill.

    {
      "type": "object",
      "properties": {
        "order_id": { "type": "string", "description": "The customer's order number" },
        "email":    { "type": "string", "description": "The email used for the order" }
      },
      "required": ["order_id", "email"]
    }

    4. Write the function code

    Read credentials and arguments, call your API, then return a structured success response with formatting guidelines for the answer.

    base_url = credentials[:ERP_BASE_URL]
    api_key  = credentials[:ERP_API_KEY]
    
    order_id = arguments[:order_id].to_s.strip
    email    = arguments[:email].to_s.strip
    
    if base_url.blank? || api_key.blank?
      failure_response("ERP credentials are missing")
    elsif order_id.blank? || email.blank?
      failure_response("Order number and email are required")
    else
      endpoint = "#{base_url}/api/orders/status"
      headers  = { "Authorization" => "Bearer #{api_key}", "Content-Type" => "application/json" }
      params   = { "order_id" => order_id, "email" => email }
    
      response = make_api_call(endpoint, params, :get, headers, false)
    
      if api_call_succeeded?(response)
        order = response[:result]
        success_response({
          "order_id" => order_id,
          "status" => order["status"],
          "delivery_status" => order["delivery_status"],
          "carrier" => order["carrier"],
          "tracking_id" => order["tracking_id"],
          "tracking_url" => order["tracking_url"],
          "estimated_delivery_date" => order["estimated_delivery_date"],
          "formatting_guidelines" => "Answer briefly. Mention order status, delivery status, carrier, tracking ID and estimated delivery date if available. Do not expose internal ERP fields."
        })
      else
        response
      end
    end

    5. Add the role or intent

    Connect customer language to the function, then select get_order_delivery_status for this role.

    Name: Order delivery status
    Description: Customer asks where their order is, whether it shipped,
    when it arrives, or asks for tracking information.
    Instructions: Ask for the order number and email if missing. Use the ERP
    order lookup function. Give the delivery status concisely and include the
    tracking ID and link when available. If the order is not found, ask the
    customer to check the order number and email.
    Examples:
      Where is my order 100391?
      Has my package shipped yet?
      Can I get the tracking number for my order?
      When will my order arrive?

    Setup example: Find the nearest office or branch

    Use OpenStreetMap to locate a visitor from their postcode, address, landmark or district, then return the three closest company locations with driving distance and time.

    1. Create the Custom API tool

    Name: OpenStreetMap office finder Description: Finds the company office nearest to a visitor’s stated location using OpenStreetMap geocoding and routing.

    2. Add a credential

    Add the following credential:

    api_key = YourCompany Office Finder (support@yourcompany.com)

    This value is used as the User-Agent for OpenStreetMap requests. Use a clear application name and contact address.

    3. Add office locations to the knowledge base

    Create or upload a source containing each office’s: - Name - Full address - Latitude - Longitude - Optional information, such as opening hours or a service note Example:

    [
      {
        "name": "Helsinki Office",
        "address": "Example Street 1, 00100 Helsinki",
        "lat": 60.1699,
        "lon": 24.9384,
        "info": "Open weekdays 09:00–17:00"
      }
    ]

    4. Create the function

    Function name: find_nearest_office Description: Find up to three of the company’s offices nearest to a visitor’s stated location. Call only after the visitor has provided a postcode and city, street address, landmark, or district and city. Use this parameter schema:

    {
      "type": "object",
      "properties": {
        "location_text": {
          "type": "string",
          "description": "The visitor's stated location. Never guess it."
        },
        "locations": {
          "type": "array",
          "description": "The company's office locations. Retrieve these from the knowledge base; never ask the visitor for them.",
          "items": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "address": { "type": "string" },
              "lat": { "type": "number" },
              "lon": { "type": "number" },
              "info": { "type": "string" }
            },
            "required": ["name", "address", "lat", "lon"]
          }
        }
      },
      "required": ["location_text"]
    }

    Configure locations to be populated from the knowledge base. The function should receive office locations automatically, rather than asking the visitor to choose from a list.

    5. Add the function code

    Use the configured implementation, changing country_hint if your business operates primarily outside Finland:

    location_text = arguments[:location_text].to_s.strip
    user_agent = credentials[:api_key].to_s.strip
    country_hint = "Finland"
    
    offices = (arguments[:locations] || []).take(20)
    
    usable_offices = offices.select do |office|
      office["name"].present? &&
        office["lat"].present? &&
        office["lon"].present? &&
        office["address"].present?
    end
    
    if location_text.blank?
      success_response({
        "status" => "location_needed",
        "message" => "Ask the visitor for a postcode and city, street address, landmark, or district and city."
      })
    elsif user_agent.blank?
      failure_response("Office finder User-Agent is missing")
    elsif usable_offices.empty?
      success_response({
        "status" => "office_locations_unavailable",
        "message" => "No office locations with coordinates were available from the knowledge base."
      })
    else
      query = "#{location_text}, #{country_hint}"
    
      geocode_response = make_api_call(
        "https://nominatim.openstreetmap.org/search",
        { "q" => query, "format" => "jsonv2", "limit" => 1, "addressdetails" => 0 },
        :get,
        { "User-Agent" => user_agent, "Accept-Language" => "en" },
        false
      )
    
      unless api_call_succeeded?(geocode_response)
        geocode_response
      else
        matches = geocode_response[:result] || []
    
        if matches.empty?
          success_response({
            "status" => "location_not_found",
            "message" => "Ask the visitor for a more precise street address or nearby landmark and city."
          })
        else
          origin = matches.first
          origin_lat = origin["lat"].to_f
          origin_lon = origin["lon"].to_f
    
          coordinates = usable_offices.map { |office| "#{office["lon"]},#{office["lat"]}" }.join(";")
    
          route_response = make_api_call(
            "https://router.project-osrm.org/table/v1/driving/#{origin_lon},#{origin_lat};#{coordinates}",
            { "annotations" => "distance,duration" },
            :get,
            {},
            false
          )
    
          unless api_call_succeeded?(route_response)
            route_response
          else
            data = route_response[:result] || {}
            distances = (data["distances"] || []).first || []
            durations = (data["durations"] || []).first || []
    
            results = usable_offices.each_with_index.filter_map do |office, index|
              distance = distances[index + 1]
              duration = durations[index + 1]
              next unless distance.present? && duration.present?
    
              {
                "name" => office["name"],
                "address" => office["address"],
                "info" => office["info"],
                "driving_distance_km" => format("%.1f", distance.to_f / 1000),
                "driving_duration_minutes" => (duration.to_f / 60).to_i,
                "maps_url" => "https://www.openstreetmap.org/directions?engine=fossgis_osrm_car&route=#{origin_lat}%2C#{origin_lon}%3B#{office["lat"]}%2C#{office["lon"]}"
              }
            end.sort_by { |office| office["driving_distance_km"].to_f }.take(3)
    
            success_response({
              "status" => "ok",
              "offices" => results,
              "attribution" => "© OpenStreetMap contributors",
              "attribution_url" => "https://www.openstreetmap.org/copyright"
            })
          end
        end
      end
    end

    6. Create the role or intent

    Name: Find nearest office Description: The visitor asks which company office, branch, store, or service point is nearest to them. Instructions: Ask for the visitor’s postcode and city, street address, landmark, or district and city if they have not provided one. Never infer their location. Call find_nearest_office as soon as a usable location is available. Present offices nearest first, including name, address, driving distance, estimated driving time, available opening-hours information, and the map link. Do not repeat the visitor’s home address. Include this attribution: © OpenStreetMap contributors If the location cannot be found, ask for a more precise address or nearby landmark. If office data is unavailable or the tool fails, explain that the nearest office cannot currently be determined: never guess.

    Security notes

    • •The backend must verify that the order belongs to the provided email address. Never return order details based on an order number alone.
    • •Do not expose internal fields, raw API errors, credentials, customer IDs or unnecessary personal data to the customer.
    • •Write clear function descriptions and role instructions: most tool failures come from the bot not knowing when to call the function.

    Ask more from LastBot support

    Send us your question and our team will get back to you.