PUBLIC REFERENCERun remotely.
Retrieve asynchronously.
Relay runs shell commands on your devices through reverse SSH tunnels. Submit a command over HTTPS, receive a job ID immediately, then poll for status and output.
This documentation is public. Device data, commands, and results require authentication.
Base URL: https://re.eldento.com
Quick start
First, add a device in the web app, upload its SSH login private key, start the displayed reverse SSH command on that device, and accept its host key. Keep the tunnel running.
In these examples, replace USERNAME, PASSWORD, DEVICE_ID, and JOB_ID with your own values. The API credentials are the same as your web login.
1. Get the device ID
curl -u 'USERNAME:PASSWORD' \
https://re.eldento.com/api/devices
The response is a JSON array. Use the id of the device you want to target.
2. Submit a command
curl -u 'USERNAME:PASSWORD' \
https://re.eldento.com/api/devices/DEVICE_ID/jobs/ \
-d 'pwd; ls;'
Returns 202 Accepted. This means the command was queued, not that it completed successfully.
{
"id": "JOB_ID",
"status": "queued",
"status_url": "/api/jobs/JOB_ID"
}3. Retrieve the result
curl -u 'USERNAME:PASSWORD' \
https://re.eldento.com/api/jobs/JOB_ID
Poll every 1–2 seconds while status is queued or running. All other statuses are terminal. Inspect exit_code and error as well as the output.
Authentication
Use HTTP Basic authentication over HTTPS for scripts and services. No separate login request or API token is needed. Curl’s -u 'USERNAME:PASSWORD' option sends the credentials. For interactive use, -u 'USERNAME' prompts for the password instead of putting it in the command.
This is a single-account service. The credentials grant access to all registered devices, job results, and account settings. Changing the account password also changes the password used by API clients.
Unauthenticated protected requests return 401 with:
{"error":"Authentication required"}Use a server-side HTTP client for integrations. Cross-origin browser access is not supported. The public documentation does not expose device IDs, saved keys, or execution history.
Commands & results
POST /api/devices/{device_id}/jobs
Submit a new asynchronous job. A trailing slash is also accepted. The body can be raw shell text or JSON.
curl -u 'USERNAME:PASSWORD' \
-H 'Content-Type: application/json' \
https://re.eldento.com/api/devices/DEVICE_ID/jobs \
-d '{"command":"pwd; ls -la;","timeout":300}'For multiline commands or shell scripts, send the file contents directly:
curl -u 'USERNAME:PASSWORD' \
-H 'Content-Type: text/plain' \
--data-binary @commands.sh \
https://re.eldento.com/api/devices/DEVICE_ID/jobs
Commands execute as the device’s configured SSH user, without a terminal or interactive input. Each job uses a new SSH session. State such as cd or environment variables does not carry over to the next job; put related operations in the same command.
The response includes a relative status_url and a matching Location header. Every submission creates a new job; there is no idempotency key. Do not automatically resubmit after an ambiguous network failure, as that may execute the command twice. Check recent jobs first.
GET /api/jobs/{job_id}
Returns the complete job record, including partial output while running. Example completed response:
{
"id": "JOB_ID",
"device_id": "DEVICE_ID",
"command": "pwd; ls;",
"status": "succeeded",
"stdout": "/home/alice\nnotes.txt\n",
"stderr": "",
"exit_code": 0,
"error": null,
"timeout": 3600,
"created": 1790500000.0,
"started": 1790500000.4,
"finished": 1790500000.8,
"truncated": 0
}created, started, and finished are Unix timestamps in seconds. started and finished remain null until those events occur. exit_code is null until a remote exit status is available. Output is returned as UTF-8 text; invalid bytes are replaced.
stdout and stderr are cumulative snapshots, not incremental chunks. Replace previously displayed output when polling. Each stream retains its first 4 MiB; truncated: 1 means at least one stream exceeded that limit. Output is saved approximately every 500 milliseconds.
A successful HTTP response only means the job record was retrieved. A failed remote command still returns HTTP 200 with status: "failed".
GET /api/jobs
Lists the latest 100 jobs, newest first. Each summary contains id, device_id, device_name, command, status, exit_code, created, started, and finished. Fetch the individual job for output and error details. There are no pagination parameters.
Job states
Queued jobs survive a service restart. Running jobs are marked interrupted and are never automatically retried. Timeouts and disconnects do not guarantee termination of remote child processes; check the device before retrying consequential commands. There is no job-cancellation endpoint.
Device setup
The web UI provides the simplest setup path. These endpoints are also available for programmatic onboarding. All require authentication.
GET /api/devices
Returns a JSON array with id, name, username, port, ssh_port, host_key, and created. Here, port is the reverse tunnel’s server-side loopback port; ssh_port is the SSH port on the device. Private keys are not included.
POST /api/devices
Creates a device; returns 201 with {"id":"DEVICE_ID"}. Send JSON:
{
"name": "My laptop",
"username": "alice",
"ssh_port": 22,
"private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n...\n-----END OPENSSH PRIVATE KEY-----\n",
"passphrase": "",
"host_key": ""
}name, username, and private_key are required. The device name is limited to 80 characters. ssh_port defaults to 22. passphrase is optional. RSA, Ed25519, and ECDSA login private keys in supported OpenSSH/PEM formats are accepted and encrypted at rest.
Leave host_key blank or omit it to accept the detected key on first connection. Alternatively, supply a known host public key in key-type base64-key format. The login private key and SSH server host key have different roles.
GET /api/devices/{device_id}/tunnel-key
Downloads the separate reverse-tunnel private key as an attachment. Save it on the device with file permissions 600.
GET /api/devices/{device_id}/connection
Returns command, containing the SSH tunnel command to run on the device, and server_host_key, containing the Relay server’s fingerprint. Run the command from the folder containing the downloaded tunnel key and keep it running.
The tunnel connects to re@re.eldento.com. Each tunnel key is restricted to its assigned reverse listener on 127.0.0.1; it cannot open a server shell or forward another port.
Accepting host keys
POST /api/devices/{device_id}/check
Tests the SSH connection. No request body is required. If a saved key matches and authentication succeeds, returns {"connected":true}. If the key is not yet saved or differs from the saved key, returns HTTP 200 with a preview instead:
{
"needs_host_key": true,
"fingerprint": "SHA256:EXAMPLE_FINGERPRINT",
"key_type": "ssh-ed25519",
"replacing": false,
"token": "SIGNED_PREVIEW_TOKEN"
}needs_host_key is not a successful connection result. Review the fingerprint before accepting. replacing: true indicates an existing saved key would be replaced. A preview does not save the key or send login credentials.
POST /api/devices/{device_id}/host-key/accept
After acceptance, submit the preview token:
curl -u 'USERNAME:PASSWORD' \
-H 'Content-Type: application/json' \
https://re.eldento.com/api/devices/DEVICE_ID/host-key/accept \
-d '{"token":"SIGNED_PREVIEW_TOKEN"}'The token expires after five minutes and is bound to the device and its previously saved key. Relay reconnects using the exact detected key, verifies SSH authentication, then saves it. Success returns {"connected":true}. An expired token returns 400; a changed device configuration returns 409. Obtain a new preview in either case.
Additional host-key endpoints
POST /api/devices/{device_id}/host-key/preview explicitly fetches a preview, using the same response shape as above. PUT /api/devices/{device_id}/host-key manually saves a supplied key with JSON {"host_key":"ssh-ed25519 AAAA…"} and returns {"ok":true}. Manual saving does not test connectivity. Jobs never automatically accept unknown or changed keys.
Errors & limits
Application errors normally return JSON {"error":"Description"}. Proxy-generated errors, including some rate-limit and body-size errors, may return HTML; check the HTTP status before assuming JSON.
- 4 concurrent jobs, with at most 100 queued or running jobs combined.
- 100 registered devices.
- API rate limit: 5 requests per second per IP, with a burst allowance of 15.
- Maximum application request body: 100,000 bytes.
- Maximum command: 32 KiB. Maximum captured output: 4 MiB per stream.
- Default execution deadline: 1 hour. Maximum: 24 hours.
Relay does not provide webhooks or server-sent events. Poll for results. Job history is persisted; the list endpoint returns the newest 100 records, while older jobs remain retrievable by ID.
Browser sessions & account settings
These endpoints support the web UI. HTTP Basic authentication is simpler for scripts. Session cookies are Secure, HttpOnly, and SameSite=Strict, and expire after 12 hours. For session-authenticated modifying requests, include the returned csrf value in the X-CSRF-Token header.
GET /healthz is a public service health endpoint returning {"ok":true}. It does not test device connectivity.