<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Cloudron API Docu - Set Operators correction?]]></title><description><![CDATA[<p dir="auto">Hi <a class="plugin-mentions-user plugin-mentions-a" href="/user/girish" aria-label="Profile: girish">@<bdi>girish</bdi></a> et al, I may read this wrong but when I troubleshot a n8n call to set an operator for an app, the manual says:</p>
<pre><code class="language-json">{
  "accessRestriction": {
    "users": [
      "uid-321dsa..."
    ],
    "groups": [
      "gid-321dsa..."
    ]
  }
}
</code></pre>
<p dir="auto">But when I ran it I kept getting errors until:</p>
<pre><code class="language-json">{
  "operators": {
    "users": [
      "uid-321dsa..."
    ]
}
}
</code></pre>
<p dir="auto">The manual also says in the main part:<br />
<img src="/assets/uploads/files/1762896562572-117d1ae9-ded5-4398-8af2-e6677a33e2c5-image.png" alt="117d1ae9-ded5-4398-8af2-e6677a33e2c5-image.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">accessRestriction instead of operators.</p>
<p dir="auto">Am I reading it wrong or should it be updated to say operators?</p>
<p dir="auto">Ref. <a href="https://docs.cloudron.io/api.html#tag/Apps/operation/setAppOperators" target="_blank" rel="noopener noreferrer nofollow ugc">https://docs.cloudron.io/api.html#tag/Apps/operation/setAppOperators</a></p>
]]></description><link>https://forum.cloudron.io/topic/14537/cloudron-api-docu-set-operators-correction</link><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Jul 2026 14:04:43 GMT</lastBuildDate><atom:link href="https://forum.cloudron.io/topic/14537.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 11 Nov 2025 21:30:23 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Cloudron API Docu - Set Operators correction? on Tue, 11 Nov 2025 23:24:54 GMT]]></title><description><![CDATA[<p dir="auto">Hello <a class="plugin-mentions-user plugin-mentions-a" href="/user/3246" aria-label="Profile: 3246">@<bdi>3246</bdi></a><br />
With the cloudron cli you can run e.g:</p>
<pre><code class="language-bash">cloudron exec --app $APP -- fallocate -l 4M /app/data/4M
</code></pre>
<p dir="auto">See <code>cloudron exec --help</code>:</p>
<pre><code class="language-bash">Usage: cloudron exec [options] [cmd...]

Exec a command in an application

Options:
  -t,--tty             Allocate tty
  --app &lt;id/location&gt;  App id or location
  -h, --help           display help for command
  Examples:

    $ cloudron exec --app myapp          # run an interactive shell
    $ cloudron exec --app myapp ls       # run command
    $ cloudron exec --app myapp -- ls -l # use -- to indicate end of options
</code></pre>
<p dir="auto">Was not sure if possible via the API but since I can debug the cloudron cli and see what it do I figured something out.</p>
<pre><code>Send the to /api/v1/apps/$APPID/exec
# Command is an array `ls -lah /app/data` would become for each space ["ls", "-lah", "/app/data/"]
curl "https://my.$DOMAIN.$TLD/api/v1/apps/$APPID/exec" \
  -H 'Authorization: Bearer $APITOKEN' \
  -H 'content-type: application/json' \
  --data-raw '["ls", "-lah", "/app/data/"]'
# this returns and id
{
  "id": "a90bcfcec1d29f7a595638ea66c8ac0bb53b594047ac74fc80bf97f75fed0c19"
}
</code></pre>
<p dir="auto">But getting the output of the executed command is. . . tricky.<br />
Just look at the source code for the cli for this part:</p>
<pre><code class="language-js">    const searchParams = new URLSearchParams({
        rows: stdout.rows || 24,
        columns: stdout.columns || 80,
        access_token: token,
        tty
    });

    const req = https.request({
        hostname: adminFqdn,
        path: `/api/v1/apps/${app.id}/exec/${execId}/start?${searchParams.toString()}`,
        method: 'GET',
        headers: {
            'Connection': 'Upgrade',
            'Upgrade': 'tcp'
        },
        rejectUnauthorized
    }, function handler(res) {
        if (res.statusCode === 403) exit('Unauthorized.'); // only admin or only owner (for docker addon)

        exit('Could not upgrade connection to tcp. http status:', res.statusCode);
    });

    req.on('upgrade', function (resThatShouldNotBeUsed, socket /*, upgradeHead*/) {
        // do not use res here! it's all socket from here on
        socket.on('error', exit);

        socket.setNoDelay(true);
        socket.setKeepAlive(true);

        if (tty) {
            stdin.setRawMode(true);
            stdin.pipe(socket, { end: false }); // the remote will close the connection
            socket.pipe(stdout); // in tty mode, stdout/stderr is merged
            socket.on('end', exitWithCode); // server closed the socket
        } else { // create stdin process on demand
            if (typeof stdin === 'function') stdin = stdin();

            stdin.on('data', function (d) {
                var buf = Buffer.alloc(4);
                buf.writeUInt32BE(d.length, 0 /* offset */);
                socket.write(buf);
                socket.write(d);
            });
            stdin.on('end', function () {
                var buf = Buffer.alloc(4);
                buf.writeUInt32BE(0, 0 /* offset */);
                socket.write(buf);
            });

            stdout.on('close', exitWithCode); // this is only emitted when stdout is a file and not the terminal

            demuxStream(socket, stdout, process.stderr); // can get separate streams in non-tty mode
            socket.on('end', function () {  // server closed the socket
                if (typeof stdin.end === 'function') stdin.end(); // required for this process to 'exit' cleanly. do not call exit() because writes may not have finished . the type check is required for when stdin: 'ignore' in execSync, not sure why
                if (stdout !== process.stdout) stdout.end(); // for push stream

                socket.end();

                // process._getActiveHandles(); process._getActiveRequests();
                if (stdout === process.stdout) setImmediate(exitWithCode); // otherwise, we rely on the 'close' event above
            });
        }
    });

    req.on('error', exit); // could not make a request
    req.end(); // this makes the request
</code></pre>
<p dir="auto">From a little debugging I got the API path:</p>
<pre><code class="language-bash">/api/v1/apps/$APPID/exec/$EXECID/start?rows=21&amp;columns=257&amp;tty=false
</code></pre>
<p dir="auto">But when CURL'ing this:</p>
<pre><code class="language-bash">curl "https://my.$DOMAIN.TLD/api/v1/apps/$APPID/exec/$EXECID/start?rows=21&amp;columns=257&amp;tty=false" \
  -H "Authorization: Bearer $APITOKEN" \
  -H 'content-type: application/json'
{
  "status": "Not Found",
  "message": "exec requires TCP upgrade"
}
</code></pre>
<p dir="auto">And I am not sure how to "TCP upgrade" the curl request.<br />
I will ask the team.</p>
]]></description><link>https://forum.cloudron.io/post/115233</link><guid isPermaLink="true">https://forum.cloudron.io/post/115233</guid><dc:creator><![CDATA[james]]></dc:creator><pubDate>Tue, 11 Nov 2025 23:24:54 GMT</pubDate></item><item><title><![CDATA[Reply to Cloudron API Docu - Set Operators correction? on Tue, 11 Nov 2025 21:42:21 GMT]]></title><description><![CDATA[<p dir="auto">Super, thanks James!</p>
<p dir="auto">While I have you, can you let me know how to run a cmd in an app via the API. I tried using "Create exec" but not getting anywhere, although it doesn't error (I wish it did, at least I had more to go on!) lol</p>
]]></description><link>https://forum.cloudron.io/post/115231</link><guid isPermaLink="true">https://forum.cloudron.io/post/115231</guid><dc:creator><![CDATA[3246]]></dc:creator><pubDate>Tue, 11 Nov 2025 21:42:21 GMT</pubDate></item><item><title><![CDATA[Reply to Cloudron API Docu - Set Operators correction? on Tue, 11 Nov 2025 21:39:49 GMT]]></title><description><![CDATA[<p dir="auto">Hello <a class="plugin-mentions-user plugin-mentions-a" href="/user/3246" aria-label="Profile: 3246">@<bdi>3246</bdi></a><br />
The API doc is currently outdated.<br />
Here is a full curl example for making a user / a group an app operator:</p>
<pre><code class="language-bash">curl "https://my.$DOMAIN.$TLD/api/v1/apps/$APPID/configure/operators" \
  -H "Authorization: Bearer $APITOKEN" \
  -H 'content-type: application/json' \
  --data-raw '{"operators":{"users":["uid-3eca9898-baca-473c-a988-d127967218c9"],"groups":[]}}'
</code></pre>
<p dir="auto">You can always grab the API paths from the Cloudron dashboard in the browser network inspect when you do the task in the dashboard.<br />
<img src="/assets/uploads/files/1762897142335-afdf21b7-5edc-4621-abd9-5c5030d66da2-image-resized.png" alt="afdf21b7-5edc-4621-abd9-5c5030d66da2-image.png" class=" img-fluid img-markdown" /></p>
]]></description><link>https://forum.cloudron.io/post/115230</link><guid isPermaLink="true">https://forum.cloudron.io/post/115230</guid><dc:creator><![CDATA[james]]></dc:creator><pubDate>Tue, 11 Nov 2025 21:39:49 GMT</pubDate></item></channel></rss>