Skip to content

Documentation

Save scenario version

POST /api/v1/scripts/{script}/versions

Save source as a draft and return a validation report.

Access

A Bearer API key for this workspace with write permission is required. The server also checks the owner’s permission for this resource and action. An inaccessible object is not disclosed.

Parameters

Path parameters: script. Use IDs from your own installation.

Example request parameters or JSON body:

{
  "source": "<?php\nfunction run(\\Sdk\\Context $ctx): void\n{\n    $ctx->emit([\"sku\" => \"A-001\", \"name\" => \"Product\"]);\n}",
  "comment": "Catalog fields added"
}

source is required and limited to 500,000 characters. Saving identical source may return the existing version with HTTP 200. Saving does not publish code.

Response 201

The example is shortened; actual responses may include more fields. Sample IDs are placeholders.

{
  "id": 3,
  "script_id": 2,
  "number": 1,
  "state": "draft",
  "is_published": false,
  "validation": {
    "valid": true,
    "parse_error": null,
    "issues": []
  }
}

Send the request

Set BASE to your installation URL without a trailing slash and API_KEY to a secret stored on your server. Client setup and browser JavaScript.

curl

curl --fail-with-body -X POST "$BASE/api/v1/scripts/2/versions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "source": "<?php\nfunction run(\\Sdk\\Context $ctx): void\n{\n    $ctx->emit([\"sku\" => \"A-001\", \"name\" => \"Product\"]);\n}",
  "comment": "Catalog fields added"
}
JSON

Node.js · server

// Node.js server example. Save as request.mjs.
const response = await fetch(process.env.BASE + "/api/v1/scripts/2/versions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.API_KEY}`,
    Accept: "application/json",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({"source":"<?php\nfunction run(\\Sdk\\Context $ctx): void\n{\n    $ctx->emit([\"sku\" => \"A-001\", \"name\" => \"Product\"]);\n}","comment":"Catalog fields added"}),
  signal: AbortSignal.timeout(120000)
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
console.log(await response.json());

Python

import json
import os
import urllib.request
import urllib.error

body = '{"source":"<?php\\nfunction run(\\\\Sdk\\\\Context $ctx): void\\n{\\n    $ctx->emit([\\"sku\\" => \\"A-001\\", \\"name\\" => \\"Product\\"]);\\n}","comment":"Catalog fields added"}'.encode("utf-8")
request = urllib.request.Request(
    os.environ["BASE"] + "/api/v1/scripts/2/versions",
    method="POST",
    headers={"Authorization": "Bearer " + os.environ["API_KEY"],
             "Accept": "application/json", "Content-Type": "application/json"},
    data=body,
)
try:
    with urllib.request.urlopen(request, timeout=120) as response:
        print(json.load(response))
except urllib.error.HTTPError as error:
    print(error.code, error.read().decode("utf-8", errors="replace"))
    raise

PHP · external client

<?php
$handle = curl_init(getenv("BASE") . "/api/v1/scripts/2/versions");
curl_setopt_array($handle, [
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 120,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("API_KEY"),
        "Accept: application/json",
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => <<<'JSON'
{"source":"<?php\nfunction run(\\Sdk\\Context $ctx): void\n{\n    $ctx->emit([\"sku\" => \"A-001\", \"name\" => \"Product\"]);\n}","comment":"Catalog fields added"}
JSON,
]);
$content = curl_exec($handle);
$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
if ($content === false) {
    throw new RuntimeException(curl_error($handle));
}
curl_close($handle);
if ($status < 200 || $status >= 300) {
    throw new RuntimeException("HTTP $status: $content");
}
print_r(json_decode($content, true, 512, JSON_THROW_ON_ERROR));

Go

package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
    "time"
    "strings"
)

func main() {
    body := strings.NewReader(`{"source":"<?php\nfunction run(\\Sdk\\Context $ctx): void\n{\n    $ctx->emit([\"sku\" => \"A-001\", \"name\" => \"Product\"]);\n}","comment":"Catalog fields added"}`)
    request, err := http.NewRequest("POST", os.Getenv("BASE") + "/api/v1/scripts/2/versions", body)
    if err != nil { panic(err) }
    request.Header.Set("Authorization", "Bearer " + os.Getenv("API_KEY"))
    request.Header.Set("Accept", "application/json")
    request.Header.Set("Content-Type", "application/json")
    client := &http.Client{Timeout: 120 * time.Second}
    response, err := client.Do(request)
    if err != nil { panic(err) }
    defer response.Body.Close()
    content, err := io.ReadAll(response.Body)
    if err != nil { panic(err) }
    if response.StatusCode < 200 || response.StatusCode >= 300 {
        panic(fmt.Sprintf("HTTP %d: %s", response.StatusCode, content))
    }
    fmt.Println(string(content))
}

If the request fails

401: check the key and its expiry. 403: check permissions, read/write scope, and 2FA. 404: check the ID and workspace. 422: check fields and resource state. 429: respect Retry-After. Errors and retries.