External Functions
External Functions
External functions fetch data, call AI, query databases, or run work that may not finish immediately. Their results are written back into your model asynchronously.
Use external functions when a formula depends on something outside the workbook: market data, HTTP JSON, model scoring, AI prompts, or a bounded database query.
1. Built-In External Functions
| Function | Returns | Common use |
|---|---|---|
FX_RATE(base, quote) |
fx_rate number |
Currency conversion |
HTTP_JSON(url) |
object | Fetch JSON from an HTTP endpoint |
ML_SCORE(features) |
score number |
Score a feature vector with a configured model |
AI_PROMPT(prompt, options) |
ai_text string |
Generate text from a prompt |
ASK(question, context, options) |
ai_answer string |
Ask a question over context |
ASK_TEXT(question, context, options) |
ai_answer string |
Ask for a text answer |
ASK_NUMERIC(question, context, options) |
ai_number number |
Ask for a numeric answer |
ASK_BOOLEAN(question, context, options) |
ai_boolean boolean |
Ask for a boolean answer |
ASK_JSON(question, context, options) |
ai_json object |
Ask for structured JSON |
PG_SELECT(table, query) |
postgres_query_result |
Read bounded PostgreSQL results |
REDIS_QUERY(connection, query, context) |
redis_query_result |
Read an allow-listed Redis value with argument and response caps |
REDIS_MUTATE(connection, mutation, context) |
redis_mutation_result |
Run a fingerprinted, result-replaying idempotent Redis mutation |
Your Grid workspace may expose additional model-backed functions such as
CHURN_SCORE(features). Treat them like any other external function: add a
fallback and make downstream formulas resilient while the value is pending.
Schema-backed APIs can add namespaced functions without extending the built-in catalog:
USE "api:example/catalog@1.0.0" AS catalog
items = catalog.listItems(limit: 100)The imported package fixes the operation ID, argument names, result shape, and package digest. Only query operations are callable from formulas; effect, publish, and subscribe operations require an explicit action surface.
2. Calling An External Function
External functions are called like ordinary functions:
A1 = FX_RATE("EUR", "USD")
A2 = HTTP_JSON("https://api.example.com/widgets/42")
A3 = ML_SCORE([0.1, 0.2, 0.3, 0.4])
A4 = AI_PROMPT("Summarize this note", { temperature: 0.2 })
A5 = ASK_NUMERIC("What is the forecasted revenue?", B1:B12, { temperature: 0 } AS options)
A6 = SELECT id, amount FROM finance.public.orders WHERE amount >= 100 ORDER BY id DESC LIMIT 25
A7 = REDIS_QUERY("default", { operation: "get", key: "pricing:current" }, {})Named arguments work too:
A1 = FX_RATE("GBP" AS base, "USD" AS quote)The binding eventually contains the external result. Until then, it moves through a defined status lifecycle.
3. Status Lifecycle
A binding that depends on an external function can be:
| Status | Meaning |
|---|---|
dirty |
Needs recomputation; no work has started yet |
queued |
Waiting to be processed |
running |
Work is in progress |
ready |
A current value is available |
stale |
An older value is available while a refresh is wanted |
failed |
The latest attempt failed and no satisfactory value is available |
You usually do not need to branch on these statuses inside formulas. Instead, write formulas with fallbacks so downstream bindings remain computable.
4. Eager Vs Lazy Calls
Both eager and lazy assignments can call external functions.
Eager =
rate = FX_RATE("EUR", "USD")Use eager = when the value is central to the model and should be requested as
soon as the model runs.
Lazy ~=
score ~= ML_SCORE([0.1, 0.2, 0.3, 0.4])Use lazy ~= when the value is expensive or rarely viewed. The work starts when
something reads the binding.
5. Always Add A Fallback
External calls are network- and provider-dependent. Pair them with DEFAULT,
IFERROR, or WITH ... ELSE:
rate = FX_RATE("EUR", "USD")
price_usd = ROUND(price_eur * (rate DEFAULT 1.08), 2)For longer chains:
converted = WITH rate = FX_RATE("EUR", "USD"), price = base * rate
THEN ROUND(price, 2) ELSE 0If any step fails, WITH returns the ELSE value.
6. Nested External Calls
You can nest an external call inside a larger formula:
A1 = ROUND(FX_RATE("EUR", "USD") + 0.01, 4)Grid tracks the external call separately from the wrapping expression. That lets the fetched value be cached and retried independently while the surrounding formula stays ordinary spreadsheet logic.
For clarity, prefer naming the boundary explicitly when the value is reused:
eur_usd = FX_RATE("EUR", "USD") DEFAULT 1.08
quoted_rate = ROUND(eur_usd + 0.01, 4)7. Caching, TTL, And Refresh
Each external function declares a cache policy:
| Field | Meaning |
|---|---|
ttlMs |
Intended time-to-live for a fetched value |
maxStalenessMs |
Hard staleness bound after which a value should be refreshed before use |
refreshMode |
"blocking" or "background" refresh behavior |
Typical behavior:
- Within
ttlMs, the cached value is served as current. - Past
ttlMsbut withinmaxStalenessMs, background refresh may serve the cached value while asking for a new one. - At or past
maxStalenessMs, the value is treated as expired and refreshed before it is served. ttlMs: 0means the value does not age out on its own.
Refresh is access-driven: a value is checked when the binding, or a dependent binding, is read. A fully idle model does not refresh just because wall-clock time passed.
8. Failure Handling
If an external call fails:
- A stale cached value may be used if one is available and the function allows stale fallback.
- Otherwise the binding reports an error value.
Detect failures with ordinary error tools:
ISERROR(rate)
rate IS ERROR
price = rate DEFAULT 1.08Your model should never depend on an external value being immediately available.
9. Worked Example
MODEL "External Enrichment"
VERSION "1.0.0"
# Inputs
A1 is currency = 250000
A2 = "EUR"
A3 = "USD"
# External values
B1 = FX_RATE(A2 AS base, A3 AS quote) DEFAULT 1.08
B2 ~= ML_SCORE([0.12, 0.18, 0.27, 0.43]) DEFAULT 0
# Fallback-safe analytics
C1 is currency = ROUND(A1 * B1, 2)
C2 = B2 > 0.35 THEN "manual-review" ELSE "auto-approve"
END MODELB1 requests a rate as soon as the model runs. B2 waits until something reads
it. Both provide fallback values so C1 and C2 stay useful.
10. Restrictions
| Constraint | Notes |
|---|---|
| External calls cannot supply a rule assignment RHS | Bind value-producing calls at the top level or in DO |
| A bare external call in a rule is an effect | Grid commits rule state first, then enqueues the call with a distinct firing identity |
External calls in DO follow formula lifecycle |
Dependency staging is deterministic, but recalculation/cache invalidation may revisit the call; use a rule action for a durable per-firing mutation |
| Schema-backed effects cannot run as ordinary formulas | Table mutations use an explicit top-level command or a post-commit rule action |
| External calls may time out or be rate-limited | Always provide a fallback |
| External writebacks are revision-checked | Older results cannot overwrite newer inputs |
11. See Also
assignments.md—~=operator details.errors.md— handling failed external calls.rules-and-schedules.md— atomic rule commits and post-commit effects.