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.
| Subflow | Signature → 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.
| Subflow | Signature → 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.
| Subflow | Signature → 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.
| Subflow | Signature → 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.
| Subflow | Signature → 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.
| Subflow | Signature → 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.
| Subflow | Signature → 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).
| Subflow | Signature → 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
- Statement Reference → HTTP — for APIs without a bundled library
- Weather tutorial