Scripting
The Scripting OpenAPI tag maps to execute_scripting: POST /scripting/execute with ExecuteScriptingRequest (script — Rhai/OpenApp DSL source) and ExecuteScriptingResponse (result — JSON value). The operation requires bearer_auth and, per OpenAPI, execute permission in at least one organization for the authenticated principal (no X-Org header on this route).
For script syntax, built-ins, CLI, and the interactive shell, see OpenApp Scripting reference and Getting started: Scripting.
Operations vs wire routes
Section titled “Operations vs wire routes”| Concern | HTTP | operationId | Notes |
|---|---|---|---|
| Execute program | POST /scripting/execute | execute_scripting | Body ExecuteScriptingRequest; response ExecuteScriptingResponse. Runs with caller permissions (see reference doc). |
SDK coverage
Section titled “SDK coverage”| Capability | Python | Rust (openapp_sdk) | Go | TypeScript (AsyncClient) |
|---|---|---|---|---|
| Execute | client.scripting.execute(script=…) | client.scripting().execute(...) | ScriptingAPI.ExecuteScripting | Not on façade yet |
| Execute file | client.scripting.execute_file(path) | — | — | — |
Python’s execute also accepts program= as a backward-compatible alias for script; extra keyword arguments are merged into the JSON body (script remains the only documented field).
Typical errors
Section titled “Typical errors”401 without a valid API key/session. 403 when the caller lacks scripting execute permission (or equivalent policy). 400 when the Rhai/runtime rejects the script. Surfaces ApiErrorResponse where applicable — see Errors & retries. Usage may count toward the scripting_executions quota key on the QuotaKey schema in OpenAPI.
Examples
Section titled “Examples”Run an inline script
Section titled “Run an inline script”out = await client.scripting.execute(script="1 + 1")assert out.get("result") == 2ExecuteScripting expects ExecuteScriptingRequest with Script set.
import ( "context"
openapiclient "github.com/tomers/openapp-sdk/go")
body := *openapiclient.NewExecuteScriptingRequest(`1 + 1`)resp, httpResp, err := client.ScriptingAPI.ExecuteScripting(context.Background()). ExecuteScriptingRequest(body). Execute()if err != nil { return err}defer httpResp.Body.Close()_ = respuse openapp_sdk::Client;use serde_json::json;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let out = client .scripting() .execute(&json!({ "script": "1 + 1" })) .await?;The Node AsyncClient does not expose /scripting/execute yet. Use POST /scripting/execute via fetch/your HTTP stack, extend the façade, or use Python/Rust/Go.
Run a .openapp file from disk
Section titled “Run a .openapp file from disk”Only Python ships a filesystem helper. The other SDKs read the file and pass script in the JSON body — same wire shape, no extra endpoint.
out = await client.scripting.execute_file("setup.openapp")The helper resolves the path, reads UTF-8, and forwards the contents as script.
import ( "context" "os"
openapiclient "github.com/tomers/openapp-sdk/go")
source, err := os.ReadFile("setup.openapp")if err != nil { return err}
body := *openapiclient.NewExecuteScriptingRequest(string(source))resp, httpResp, err := client.ScriptingAPI.ExecuteScripting(context.Background()). ExecuteScriptingRequest(body). Execute()if err != nil { return err}defer httpResp.Body.Close()_ = respuse openapp_sdk::Client;use serde_json::json;use tokio::fs;
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
let source = fs::read_to_string("setup.openapp").await?;let out = client .scripting() .execute(&json!({ "script": source })) .await?;import { readFile } from "node:fs/promises";
const source = await readFile("setup.openapp", "utf8");const res = await fetch("https://api.openapp.house/api/v1/scripting/execute", { method: "POST", headers: { "content-type": "application/json", authorization: "Bearer v1_openapp_YOUR_SECRET", }, body: JSON.stringify({ script: source }),});const out = await res.json();Replace the fetch call with AsyncClient.executeScripting once the Node façade exposes it.
Read the result and handle script errors
Section titled “Read the result and handle script errors”ExecuteScriptingResponse is { "result": <any> } — the runtime preserves whatever JSON-shaped value the script returned. Treat it as untyped at the SDK boundary and assert / deserialize at the call site. 400 signals a Rhai parse / runtime error (the body carries an ApiErrorResponse with the failure reason); 401 / 403 signal API-key or permission issues, never script faults.
from openapp_sdk.errors import ApiError
try: out = await client.scripting.execute(script='let xs = [1, 2, 3]; xs.len()')except ApiError as err: if err.status == 400: # Rhai runtime/parse error — `err.body` carries `ApiErrorResponse` ... raiseelse: n: int = int(out["result"])import ( "context" "errors"
openapiclient "github.com/tomers/openapp-sdk/go")
body := *openapiclient.NewExecuteScriptingRequest(`let xs = [1, 2, 3]; xs.len()`)resp, httpResp, err := client.ScriptingAPI.ExecuteScripting(context.Background()). ExecuteScriptingRequest(body). Execute()if err != nil { var apiErr *openapiclient.GenericOpenAPIError if errors.As(err, &apiErr) && httpResp != nil && httpResp.StatusCode == 400 { // Rhai parse/runtime error — apiErr.Body() has the ApiErrorResponse JSON } return err}defer httpResp.Body.Close()
if v, ok := resp.Result.(float64); ok { _ = int(v)}The generated ExecuteScriptingResponse.Result is interface{} — type-assert (or json.Marshal + json.Unmarshal into a concrete struct) at the call site.
use openapp_sdk::{Client, SdkError};use serde_json::{json, Value};
let client = Client::builder() .api_key("https://api.openapp.house/api/v1_openapp_YOUR_SECRET") .build()?;
match client .scripting() .execute(&json!({ "script": "let xs = [1, 2, 3]; xs.len()" })) .await{ Ok(out) => { let n: i64 = out .get("result") .and_then(Value::as_i64) .ok_or("expected integer result")?; let _ = n; } Err(SdkError::Api { status, .. }) if status == 400 => { // Rhai parse/runtime error } Err(err) => return Err(err.into()),}const res = await fetch("https://api.openapp.house/api/v1/scripting/execute", { method: "POST", headers: { "content-type": "application/json", authorization: "Bearer v1_openapp_YOUR_SECRET", }, body: JSON.stringify({ script: "let xs = [1, 2, 3]; xs.len()" }),});
if (res.status === 400) { const body = await res.json(); // body matches ApiErrorResponse — surface to the user}const { result } = (await res.json()) as { result: unknown };Move to AsyncClient.executeScripting once the Node façade exposes it; the response shape will not change.
HTTP contract: API reference · OpenAPI JSON · OpenApp Scripting