Skip to main content

Integration Libraries

Libraries that call external APIs. Network calls can fail — attach on error { }. Pass any API key from a global.* variable (set in the Variables panel), never hardcoded.

ai — LLM helpers

Provider-agnostic chat completions for any OpenAI-compatible endpoint (OpenAI, Groq, OpenRouter, or a local Ollama/LM Studio server). Pass the endpoint as base_url and your key as api_key.

SubflowSignature → outputs
chat(api_key, base_url, model, system, prompt){text}
classify(api_key, base_url, model, input, labels){label} (single label from the set)
summarize(api_key, base_url, model, input, max_words){summary}
extract(api_key, base_url, model, input, instruction){result} (raw JSON — json.parse it)
moderate(api_key, base_url, model, input){flagged}
import ai from "ai"

bot Helper {
global openai_key: String = ""

flow ask on message [text] {
let { text } = await ai.chat(
api_key: global.openai_key,
base_url: "https://api.openai.com/v1",
model: "gpt-4o-mini",
system: "You are a concise support agent.",
prompt: message.text
) on error {
send.text("🤖 AI is busy — try again shortly.")
stop
}
send.text(text)
}
}

Reference blueprint: business-concierge.botgami.

notion — pages & databases

Create and query Notion pages. Pass an integration token and the target database_id / page_id.

SubflowSignature → outputs
create_page(token, database_id, properties){id, url}
append_text(token, page_id, text){ok}
query_database(token, database_id, filter){results}
import notion from "notion"

flow log on command "/note" {
let { url } = await notion.create_page(
token: global.notion_token,
database_id: global.notion_db,
properties: { Name: { title: [{ text: { content: "New lead" } }] } }
) on error {
send.text("Couldn't save to Notion.")
stop
}
send.text(`📝 Saved: ${url}`)
}

airtable — records

Create and list Airtable records. Pass a personal-access token, the base_id, and the table name.

SubflowSignature → outputs
create_record(token, base_id, table, fields){id}
list_records(token, base_id, table, max){records}
import airtable from "airtable"

flow save on command "/save" {
let { id } = await airtable.create_record(
token: global.airtable_token,
base_id: global.airtable_base,
table: "Leads",
fields: { Name: user.first_name, Source: "Telegram" }
) on error {
send.text("Couldn't save the record.")
stop
}
send.text(`✅ Saved record ${id}`)
}

translate — text translation

LibreTranslate-compatible translation. Works with the public libretranslate.com (key required) or any self-hosted instance (pass api_key: ""). source: "auto" detects the language.

SubflowSignature → outputs
to(base_url, api_key, q, source, target){text}
detect(base_url, api_key, q){language, confidence}
import translate from "translate"

flow tr on message [text] {
let { text } = await translate.to(
base_url: "https://libretranslate.com",
api_key: global.lt_key,
q: message.text, source: "auto", target: "en"
) on error {
send.text("Translation failed.")
stop
}
send.text(`🌐 ${text}`)
}

geocode — place ↔ coordinates

Forward and reverse geocoding via OpenStreetMap Nominatim (no key). Nominatim's policy requires a contact — pass your email and keep volume low (≤1 req/s). Pairs with the geo.* builtins for distance.

SubflowSignature → outputs
search(query, email){lat, lon, display_name}
reverse(lat, lon, email){display_name}
import geocode from "geocode"

flow find on command "/find" {
let { lat, lon, display_name } = await geocode.search(
query: "Eiffel Tower, Paris",
email: global.contact_email
) on error {
send.text("Couldn't find that place.")
stop
}
send.location(latitude: types.float(lat), longitude: types.float(lon))
send.text(`📍 ${display_name}`)
}

openweather — current weather

OpenWeatherMap wrappers (metric units). Pass your API key as a parameter.

SubflowSignature → outputs
current_weather(city, api_key){temp, feels_like, humidity, description, wind_speed, city_name}
weather_by_coords(lat, lon, api_key){temp, humidity, description}
import openweather from "openweather"

bot Weather {
global openweather_api_key: String = ""

flow check on command "/weather" {
let { temp, description, city_name } = await openweather.current_weather(
city: "London",
api_key: global.openweather_api_key
) on error {
send.text("⚠️ Couldn't reach the weather service.")
stop
}
send.text(`${city_name}: ${temp}°C, ${description}`)
}
}

fx_rates — currency exchange rates

Uses a free rates API — no key required.

SubflowSignature → outputs
latest(base){rate_usd, rate_gbp, rate_eur, result}
convert(base, amount){usd}
import fx_rates from "fx_rates"

flow rate on command "/rate" {
let { rate_usd } = await fx_rates.latest(base: "EUR") on error {
send.text("Rates unavailable right now.")
stop
}
send.text(`1 EUR = ${rate_usd} USD`)
}

mailtm — disposable email inboxes

Create throwaway email accounts and read incoming mail (great for verification-code flows and testing).

SubflowSignature → outputs
list_domains(){domains}
create_account(address, password){id, address}
login(address, password){token, account_id}
register(address, password){id, address, token}
register_random(){id, address, password, token}
account_info(token){address, used, quota}
list_messages(token){messages, status}
list_messages_page(token, page){messages, page, has_more, status}
get_message(token, id){sender, subject, intro, text, seen}
get_message_full(token, id){sender, subject, text, html, to, attachments, has_attachments, created_at}
get_message_source(token, id){eml, download_url}
latest_message(token){has_message, id, sender, subject, text, seen}
find_from(token, sender){found, id, subject, intro}
unseen_count(token){unseen, total}
mark_seen(token, id){ok}
delete_message(token, id){ok}
delete_account(token, id){ok}
import mailtm from "mailtm"

flow inbox on command "/inbox" {
let { address, token } = await mailtm.register_random() on error {
send.text("Couldn't create an inbox.")
stop
}
set { user.mail_token = token }
send.text(`📬 Your temporary inbox: \`${address}\``, parse_mode: "Markdown")
}

flow check on command "/check" {
let { has_message, sender, subject } = await mailtm.latest_message(token: user.mail_token) on error {
send.text("Couldn't check the inbox.")
stop
}
when has_message {
send.text(`📨 From ${sender}: ${subject}`)
} else {
send.text("No mail yet.")
}
}

See also