Skip to content

Init Script

Manage one-off startup scripts and cron-like jobs.

All endpoints below are mounted under /api. Authentication: Authorization: Bearer <token> unless noted as public.

Endpoint count: 8

Endpoints

Method Path Handler Guards
GET /api/init-script/presets listInitScriptPresets RequireSuperuser()
POST /api/init-script/presets createInitScriptPreset RequireSuperuser()
DELETE /api/init-script/presets/:id deleteInitScriptPreset RequireSuperuser()
GET /api/init-script/presets/:id/export exportInitScript RequireSuperuser()
GET /api/init-script/presets/:id/recordings listInitScriptRecordings RequireSuperuser()
POST /api/init-script/presets/:id/toggle-recording toggleInitScriptRecording RequireSuperuser()
DELETE /api/init-script/recordings/:id deleteInitScriptRecording RequireSuperuser()
POST /api/init-script/share shareInitScript RequireSuperuser()

Source

Handlers for this section live in api/routes/handlers_*.go in the StarkOne source. Each handler binds its request body with gin.ShouldBindJSON(&req) and responds with the standard envelope:

{ "data": { ... } }

On error:

{ "error": { "code": "string", "message": "string" } }

Note: the init-script handlers emit errors as { "error": { "message": "..." } }. They do not populate a code field, so the tables below omit the Code column where it does not apply.

Reference

GET /api/init-script/presets

Lists all init-script presets ordered by creation date (newest first), each with its recording count.

Guards: RequireSuperuser()

Response - 200 OK

{
  "data": {
    "presets": [
      {
        "id": 1,
        "name": "Fresh server bootstrap",
        "description": "Baseline setup",
        "is_recording": false,
        "created_at": "2026-06-17 09:00:00",
        "updated_at": "2026-06-17 09:00:00",
        "recording_count": 12
      }
    ]
  }
}

If the init_script_presets table does not exist (plugin not installed), the handler returns 200 OK with an empty list: { "data": { "presets": [] } }.

Errors

Status Meaning
500 Database query failed (message in error.message).

Example

curl -X GET https://panel.example.com:2087/api/init-script/presets \
  -H "Authorization: Bearer $TOKEN"

POST /api/init-script/presets

Creates a new init-script preset with a name and optional description.

Guards: RequireSuperuser()

Request body

{ "name": "string (required)", "description": "string (optional)" }
Field Type Required Description
name string yes Preset display name.
description string no Free-text description.

Response - 200 OK

{ "data": { "id": 7, "message": "Preset created" } }

id is the new preset's auto-increment row id.

Errors

Status Meaning
400 Plugin not installed ("Init Script plugin not installed"), or invalid/missing body (binding error, e.g. name required).
500 Insert failed (message in error.message).

Side effects

  • Inserts a row into init_script_presets.

Example

curl -X POST https://panel.example.com:2087/api/init-script/presets \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Fresh server bootstrap", "description": "Baseline setup"}'

DELETE /api/init-script/presets/:id

Deletes a preset and all of its recordings.

Guards: RequireSuperuser()

Path parameters

Name Type Description
id integer Preset id to delete.

Response - 200 OK

{ "data": { "message": "Preset deleted" } }

The handler does not check whether the id existed; it always returns success.

Side effects

  • Deletes all rows from init_script_recordings where preset_id = :id.
  • Deletes the matching row from init_script_presets.

Example

curl -X DELETE https://panel.example.com:2087/api/init-script/presets/7 \
  -H "Authorization: Bearer $TOKEN"

GET /api/init-script/presets/:id/export

Generates a runnable Bash script from a preset's recorded API calls and returns it as a string in the JSON envelope.

Guards: RequireSuperuser()

Path parameters

Name Type Description
id integer Preset id whose recordings are compiled into the script.

Response - 200 OK

{ "data": { "script": "#!/bin/bash\n# StarkOne Panel - Init Script\n..." } }

The script embeds a curl-based api() helper, takes <panel-url> <api-token> as arguments, and replays every recorded non-GET call. GET requests and any path containing /auth/ or /status are skipped. Single quotes in recorded bodies are shell-escaped. This is a JSON response, not a file download.

Errors

Status Meaning
500 Failed to query recordings (message in error.message).

Example

curl -X GET https://panel.example.com:2087/api/init-script/presets/7/export \
  -H "Authorization: Bearer $TOKEN"

GET /api/init-script/presets/:id/recordings

Lists the recorded API calls belonging to a preset, ordered by record time.

Guards: RequireSuperuser()

Path parameters

Name Type Description
id integer Preset id whose recordings are returned.

Response - 200 OK

{
  "data": {
    "recordings": [
      {
        "id": 41,
        "method": "POST",
        "path": "/domains",
        "body": "{\"domain\":\"example.com\"}",
        "response_status": 200,
        "recorded_at": "2026-06-17 09:05:12"
      }
    ]
  }
}

Errors

Status Meaning
500 Failed to query recordings (message in error.message).

Example

curl -X GET https://panel.example.com:2087/api/init-script/presets/7/recordings \
  -H "Authorization: Bearer $TOKEN"

POST /api/init-script/presets/:id/toggle-recording

Toggles recording on the given preset; turning one preset on first turns recording off for every other preset (only one active recorder at a time).

Guards: RequireSuperuser()

Path parameters

Name Type Description
id integer Preset id whose recording state is toggled.

Response - 200 OK

{ "data": { "message": "Recording toggled" } }

No request body is read. The response does not report the resulting on/off state.

Side effects

  • Sets is_recording = 0 on all presets except :id.
  • Flips is_recording (1 - is_recording) and updates updated_at on the preset :id.

Example

curl -X POST https://panel.example.com:2087/api/init-script/presets/7/toggle-recording \
  -H "Authorization: Bearer $TOKEN"

DELETE /api/init-script/recordings/:id

Deletes a single recorded API call by its recording id.

Guards: RequireSuperuser()

Path parameters

Name Type Description
id integer Recording id to delete (from init_script_recordings).

Response - 200 OK

{ "data": { "message": "Recording deleted" } }

The handler does not check whether the id existed; it always returns success.

Side effects

  • Deletes the matching row from init_script_recordings.

Example

curl -X DELETE https://panel.example.com:2087/api/init-script/recordings/41 \
  -H "Authorization: Bearer $TOKEN"

POST /api/init-script/share

Uploads a script body to a transfer.sh-compatible host and returns the resulting download URL.

Guards: RequireSuperuser()

Request body

{ "script": "string", "filename": "string" }
Field Type Required Description
script string no (not binding:"required") Script contents to upload (the PUT request body).
filename string no (not binding:"required") File name appended to the upload URL path.

Response - 200 OK

{ "data": { "url": "https://wget.co.il/abc123/init-script.sh" } }

The upload host defaults to https://wget.co.il, overridable via the transfersh_url setting. The returned url is the trimmed response body from the upload host.

Errors

Status Meaning
400 Invalid JSON body (binding error).
500 Failed to build the upload request, upload failed, or the host returned an empty body ("No URL in response: ...").

Side effects

  • Performs an outbound HTTP PUT to <transfersh_url>/<filename> with Content-Type: text/plain and the script as the body.
  • Reads the transfersh_url value from the settings store.

Example

curl -X POST https://panel.example.com:2087/api/init-script/share \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"script": "#!/bin/bash\necho hi", "filename": "init-script.sh"}'