Run Direct Script
Operation REST Write AdminExecute an arbitrary SQL script passed inline in the request body. Restricted to tenant administrators for emergency or setup use cases.
Endpoint
| Method | URL |
|---|---|
| POST | /api/v1/expressions/multiquery/scripts/run-direct |
This endpoint executes SQL you supply inline, with no prior approval or audit of the script text. Prefer Run Stored Script in all production workflows. Use Run Direct Script only during initial tenant setup or emergency recovery operations where storing the script in advance is impractical.
When to Use
Run Direct Script is appropriate in the following scenarios:
- Tenant setup operations — one-time initialisation steps performed during tenant onboarding that are executed once and then discarded.
- Data migrations during deployment — inline scripts needed at deploy time that are authored, reviewed, and executed as part of the deployment runbook.
- Emergency fixes — time-critical data corrections that cannot wait for the full stored-script approval cycle. Must be followed up by a post-incident review.
For all other production write operations, use Run Stored Script. It provides a full audit trail, version control, and pre-approval of the SQL that will be executed.
Request Body
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
sqlScriptText |
string | Yes |
The full SQL script to execute. Must use @ParamName placeholders for
all runtime values. Never construct this string by concatenating user-supplied input.
|
scriptParameters |
object | No |
Key-value map of named parameters referenced in sqlScriptText.
TenantID must not be included — it is injected automatically from
the JWT as @TenantID.
|
Example Request Body
{
"sqlScriptText": "UPDATE dbo.EmployeePaySettings SET BaseSalary = @NewSalary WHERE EmployeeID = @EmployeeID AND TenantID = @TenantID",
"scriptParameters": {
"NewSalary": 60000,
"EmployeeID": 42
}
}
Full Request Example
POST /api/v1/expressions/multiquery/scripts/run-direct
Authorization: Bearer eyJ...
Content-Type: application/json
{
"sqlScriptText": "UPDATE dbo.EmployeePaySettings SET BaseSalary = @NewSalary WHERE EmployeeID = @EmployeeID AND TenantID = @TenantID",
"scriptParameters": {
"NewSalary": 60000,
"EmployeeID": 42
}
}
TenantID is automatically added to scriptParameters from the caller's JWT.
You do not need to supply it in the request body, but you must include
@TenantID in your WHERE clause to ensure operations are
correctly scoped to the caller's tenant.
Response
On success, the endpoint returns HTTP 200 OK:
{
"success": true
}
No script code or SQL text is echoed back in the response. No row data is returned. If you need to verify the effect of the script, issue a separate Execute → JSON read call after the write.
Authorization
The caller's JWT must include the TenantAdmin role. Requests with
insufficient role are rejected with 403 Forbidden before the SQL is
evaluated or executed.
This endpoint is protected by the ApiLimit("MultiQuery.RunDirectScript")
rate limit policy. Limits are configured per tenant by a platform administrator.
Security Considerations
sqlScriptText must never be constructed by concatenating user-supplied
input, URL parameters, form values, or any data from an untrusted source.
This endpoint executes the SQL you provide with full service account
privileges. A script built from untrusted input is a SQL injection
vulnerability.
Use parameterized @ParamName placeholders in sqlScriptText
and supply all runtime values through scriptParameters. The engine passes
these to the database driver as typed parameters — not as interpolated strings.
Additional security guidelines for this endpoint:
- Restrict network access to this endpoint — it should not be reachable from untrusted networks or end-user browsers.
- Log all invocations with the caller identity, the full script text, and all parameter values in your operational audit system.
- Never expose this endpoint through a public-facing API gateway or relay it through a less-privileged service.
- If the script will modify sensitive data (PII, payroll figures, credentials), apply a mandatory second-approval workflow in your runbook before calling this endpoint.
- Include
AND TenantID = @TenantIDin everyWHEREclause. Do not rely on data integrity alone — the explicit filter is a defence-in-depth measure.
Comparison — Stored vs Direct
Use this table to select the right endpoint for your use case:
| Dimension | Run Stored Script | Run Direct Script |
|---|---|---|
| Audit trail | Full — catalogue code, caller identity, parameters, timestamp | Caller identity and parameters only — SQL text not stored in audit log |
| Pre-approval | Required — script must exist in catalogue before call | None — SQL is executed as-supplied |
| Production use | Recommended for all production operations | Not recommended — emergency and setup only |
| Flexibility | Fixed to the stored script text; parameters vary at call time | Full flexibility — any SQL can be executed at call time |
| Version control | Yes — stored in dbo.Shared_Configurations with history |
No — script exists only in the request body; not persisted |
| Rate limit policy | ApiLimit("MultiQuery.RunStoredScript") |
ApiLimit("MultiQuery.RunDirectScript") |
| Required role | TenantAdmin | TenantAdmin |
| SQL injection risk | Low — SQL text is pre-stored; only parameters vary | High if sqlScriptText is built from untrusted input |
Error Handling
| HTTP Status | Error Condition | Resolution |
|---|---|---|
400 Bad Request |
sqlScriptText is null or empty |
Supply a non-empty SQL string in the request body. |
400 Bad Request |
Missing declared parameter | Add the missing parameter to scriptParameters. |
401 Unauthorized |
Missing or invalid JWT | Obtain a fresh token and retry. |
403 Forbidden |
Caller lacks TenantAdmin role | Use a service account with the correct role. |
429 Too Many Requests |
Rate limit exceeded | Wait for the Retry-After interval before retrying. |
500 Internal Server Error |
SQL execution error | Review the error response body. Check constraint violations, syntax errors, or missing objects in the script. |