Vai al contenuto
Deploy
Sfoglia la documentazione

API REST: deploy dalla CI e automazione dei server

Riferimento dell'API REST di Vimonto Deploy: token API e ambiti, ogni endpoint con esempi, task, errori, limiti di frequenza e un deploy con GitHub Actions.

Visualizza come Markdown Aggiornato il 7 ottobre 2026

L'API di Vimonto Deploy permette a script e pipeline CI di lavorare con le tue organizzazioni tramite HTTPS e JSON: elencare server e siti, avviare un deploy e seguirlo, creare e rimuovere database, eseguire backup e ricette. Ogni richiesta è autenticata con un token API personale che crei nel tuo account.

Un token agisce come te. Può fare solo ciò che il tuo ruolo consente, solo sui server a cui hai accesso e solo entro gli ambiti che gli hai assegnato.

La pagina dei token API con un elenco di token e i loro ambiti
Token API nel tuo account

Creare un token API

  1. Apri il menu account in alto a destra e scegli Impostazioni account → Token API.
  2. Fai clic su Nuovo token.
  3. Inserisci un Nome che indichi dove viene usato, per esempio "GitHub Actions".
  4. In Ambiti, seleziona cosa può fare il token (vedi sotto).
  5. In Scade, scegli Tra 30 giorni, Tra 90 giorni (il valore predefinito), Tra 365 giorni o Mai.
  6. Fai clic su Crea token.

Il token viene mostrato una sola volta, in Il tuo nuovo token. Fai clic su Copia e conservalo in un posto sicuro, come i secret della tua CI; Vimonto Deploy ne conserva solo un hash e non può mostrarlo di nuovo. Un token è fatto così: 12| seguito da una lunga stringa di lettere e cifre.

L'elenco mostra per ogni token il nome, quando è stato usato l'ultima volta, quando scade e i suoi ambiti. Fai clic su Revoca per eliminare un token: script e pipeline che lo usano smettono subito di funzionare. Eliminando il tuo account revochi tutti i tuoi token.

Ambiti

Ambito Valore Consente
Lettura read Vedere server, siti, deploy, database, backup, ricette e task.
Deploy deploy Avviare deploy e seguirli: trovare un sito per dominio o ID, elencare e vedere i deploy e vedere i task. Pensato per le pipeline CI.
Scrittura write Tutto ciò che consente Lettura, più avviare deploy, creare e rimuovere database ed eseguire backup e ricette.

Un token con solo Deploy può cercare il sito di cui fa il deploy (vedi trovare un sito), ma non può elencare server o siti: dai a una pipeline CI solo questo ambito e usa Lettura o Scrittura per gli script che hanno bisogno di più.

L'ambito è il primo controllo. Il tuo ruolo è il secondo: avviare un deploy, modificare database ed eseguire backup o ricette richiedono il ruolo di proprietario, amministratore, manager o sviluppatore. Il token di un osservatore può leggere, ma ogni modifica viene rifiutata con 403.

URL di base e autenticazione

Tutti gli endpoint si trovano sotto /api/v1 all'indirizzo dove usi Vimonto Deploy. Negli esempi qui sotto è https://deploy.example.com/api/v1; sostituisci deploy.example.com con il tuo indirizzo.

Invia il token come bearer token nell'header Authorization e chiedi JSON:

curl https://deploy.example.com/api/v1/user \
  -H "Authorization: Bearer $VIMONTO_TOKEN" \
  -H "Accept: application/json"

Solo i token aprono l'API: aver effettuato l'accesso all'app nel browser non basta. I corpi delle richieste sono JSON (Content-Type: application/json). Le date sono in ISO 8601 con fuso orario. I messaggi nelle risposte, come gli errori, sono nella lingua impostata nel tuo account; se non ne hai scelta una, nella lingua dell'header Accept-Language della richiesta (inglese, olandese, tedesco, francese o italiano), altrimenti in inglese.

Organizzazioni, server e siti nell'URL

Gli endpoint di un'organizzazione iniziano con /orgs/{organization}, dove {organization} è lo slug dell'organizzazione: la prima parte del suo indirizzo nell'app (https://deploy.example.com/acme/… ha lo slug acme). GET /user elenca gli slug che il tuo token può raggiungere.

Server, siti e tutto ciò che sta sotto sono indicati con il loro ID numerico, lo stesso numero che compare nell'indirizzo dell'app: /acme/servers/12/sites/34 nell'app è /orgs/acme/servers/12/sites/34 nell'API. Un elemento figlio deve appartenere al suo genitore: il sito 34 sul server 12 funziona solo se il sito si trova su quel server, altrimenti l'API risponde 404.

Un'organizzazione di cui non sei membro, e un server a cui i tuoi team non ti danno accesso, rispondono 404, non 403.

Endpoint

Metodo Percorso Ambiti
GET /user qualsiasi
GET /orgs/{organization}/servers read, write
GET /orgs/{organization}/servers/{server} read, write
GET /orgs/{organization}/servers/{server}/sites read, write
GET /orgs/{organization}/servers/{server}/sites/{site} read, write
GET /orgs/{organization}/sites read, deploy, write
GET /orgs/{organization}/servers/{server}/sites/{site}/deployments read, deploy, write
GET /orgs/{organization}/servers/{server}/sites/{site}/deployments/{deployment} read, deploy, write
POST /orgs/{organization}/servers/{server}/sites/{site}/deployments deploy, write
GET /orgs/{organization}/servers/{server}/databases read, write
POST /orgs/{organization}/servers/{server}/databases write
DELETE /orgs/{organization}/servers/{server}/databases/{database} write
GET /orgs/{organization}/servers/{server}/backups read, write
POST /orgs/{organization}/servers/{server}/backups/{backup}/run write
GET /orgs/{organization}/recipes read, write
POST /orgs/{organization}/recipes/{recipe}/run write
GET /orgs/{organization}/tasks/{task} read, deploy, write

Un token ha bisogno di uno degli ambiti indicati. I percorsi qui sotto omettono il prefisso https://deploy.example.com/api/v1.

Ottenere l'utente del token

GET /user restituisce a chi appartiene il token, il nome e gli ambiti del token e le organizzazioni che può raggiungere, con il tuo ruolo in ciascuna. Ogni ambito può chiamarlo, quindi è un buon primo test per un token.

curl https://deploy.example.com/api/v1/user \
  -H "Authorization: Bearer $VIMONTO_TOKEN" -H "Accept: application/json"
{
  "data": {
    "id": 7,
    "name": "Sam de Vries",
    "email": "sam@example.com",
    "token": {
      "name": "GitHub Actions",
      "scopes": ["deploy"]
    },
    "organizations": [
      { "slug": "acme", "name": "Acme", "role": "developer" }
    ]
  }
}

Elencare i server

GET /orgs/{organization}/servers restituisce i server dell'organizzazione a cui hai accesso, in ordine di nome. GET /orgs/{organization}/servers/{server} restituisce un solo server.

curl https://deploy.example.com/api/v1/orgs/acme/servers \
  -H "Authorization: Bearer $VIMONTO_TOKEN" -H "Accept: application/json"
{
  "data": [
    {
      "id": 12,
      "name": "web-1",
      "type": "app",
      "status": "active",
      "provider": "hetzner",
      "region": "fsn1",
      "size": "cx32",
      "ip_address": "203.0.113.10",
      "private_ip_address": "10.0.0.2",
      "ssh_port": 22,
      "user": "vimonto",
      "php_version": "8.4",
      "database": "mysql-8.4",
      "ubuntu_version": "24.04",
      "timezone": "UTC",
      "tags": ["production"],
      "created_at": "2026-09-01T09:30:00+00:00"
    }
  ]
}
Campo Valori
type app, web, worker, database, cache, meilisearch, loadbalancer
status creating, waiting, provisioning, active, failed, disconnected, deleting
provider Il provider cloud, oppure custom per un VPS personalizzato.
database mysql-8.4, mysql-8.0, mariadb-11.4, mariadb-10.11, postgres-18, postgres-17, postgres-16, oppure null

Segreti come password e chiavi non fanno mai parte di una risposta.

Elencare i siti

GET /orgs/{organization}/servers/{server}/sites restituisce i siti del server, in ordine di dominio. GET /orgs/{organization}/servers/{server}/sites/{site} restituisce un solo sito.

{
  "data": {
    "id": 34,
    "server_id": 12,
    "domain": "shop.example.com",
    "aliases": ["www.shop.example.com"],
    "preview_domain": "kalme-rivier-4821.on-deploy.link",
    "framework": "laravel",
    "status": "installed",
    "php_version": "8.4",
    "repository": "acme/shop",
    "branch": "main",
    "quick_deploy": true,
    "zero_downtime": true,
    "isolated": false,
    "current_release": "20261007143012",
    "deployed_at": "2026-10-07T14:31:40+00:00",
    "created_at": "2026-09-01T10:02:11+00:00"
  }
}

framework è uno tra laravel, symfony, statamic, wordpress, phpmyadmin, php, nextjs, nuxt, html, other e loadbalancer. status è installed quando il sito è pronto; mentre cambia è installing, updating o removing, e failed quando qualcosa è andato storto. quick_deploy è il deploy a ogni push; isolated indica se il sito gira con un proprio utente Linux. Il file di ambiente del sito e l'URL di deploy non vengono mai restituiti.

Trovare un sito

GET /orgs/{organization}/sites restituisce i siti su tutti i server a cui hai accesso, in ordine di dominio, ciascuno con il suo server (ID e nome). Gli altri campi sono gli stessi visti sopra. Restringi l'elenco con i parametri della query:

Parametro Cerca per
domain Il dominio del sito, senza distinguere maiuscole e minuscole.
id L'ID del sito.
server L'ID o il nome del server.
curl "https://deploy.example.com/api/v1/orgs/acme/sites?domain=shop.example.com" \
  -H "Authorization: Bearer $VIMONTO_TOKEN" -H "Accept: application/json"
{
  "data": [
    {
      "id": 34,
      "server_id": 12,
      "server": { "id": 12, "name": "web-1" },
      "domain": "shop.example.com",
      "status": "installed",
      "branch": "main"
    }
  ]
}

Anche un token con il solo ambito Deploy può chiamarlo, per trovare il sito di cui fa il deploy, ma deve indicare domain o id; senza, la risposta è 422. Se nulla corrisponde, data è un elenco vuoto.

Elencare i deploy

GET /orgs/{organization}/servers/{server}/sites/{site}/deployments restituisce i deploy del sito, dal più recente, 25 per pagina (vedi paginazione). GET …/deployments/{deployment} ne restituisce uno.

{
  "data": {
    "id": 581,
    "site_id": 34,
    "status": "succeeded",
    "trigger": "api",
    "branch": "main",
    "commit": {
      "hash": "9f2c4e1a7b3d5f60812a9c4e7d1b3a5c7e9f1a2b",
      "author": "Sam de Vries",
      "message": "Add checkout page"
    },
    "release": "20261007143012",
    "task_id": 9120,
    "started_at": "2026-10-07T14:30:12+00:00",
    "finished_at": "2026-10-07T14:31:40+00:00",
    "created_at": "2026-10-07T14:30:11+00:00"
  }
}
Campo Valori
status queued, running, succeeded, failed, cancelled
trigger manual, push, url (l'URL di deploy), rollback, api
commit null finché il codice non è stato scaricato.
release La directory della release, oppure live per un sito senza deploy zero-downtime; null finché il deploy non è iniziato.

Avviare un deploy

POST /orgs/{organization}/servers/{server}/sites/{site}/deployments fa il deploy del branch del sito, esattamente come Fai il deploy nell'app. Non ha corpo. Risponde 202 Accepted con il nuovo deploy; seguilo tramite il suo task_id.

curl -X POST https://deploy.example.com/api/v1/orgs/acme/servers/12/sites/34/deployments \
  -H "Authorization: Bearer $VIMONTO_TOKEN" -H "Accept: application/json"
{
  "data": {
    "id": 582,
    "site_id": 34,
    "status": "queued",
    "trigger": "api",
    "branch": "main",
    "commit": null,
    "release": null,
    "task_id": 9121,
    "started_at": null,
    "finished_at": null,
    "created_at": "2026-10-07T15:02:45+00:00"
  }
}
  • 409 quando è già in corso un deploy del sito; il task_id nella risposta è il task in corso.
  • 422 quando il sito non è ancora pronto per il deploy o non ha un repository.

Vedi deploy per cosa fa un deploy.

Elencare e creare database

GET /orgs/{organization}/servers/{server}/databases restituisce i database del server, in ordine di nome.

{
  "data": [
    { "id": 3, "server_id": 12, "name": "shop", "status": "installed", "created_at": "2026-09-01T10:05:00+00:00" }
  ]
}

POST /orgs/{organization}/servers/{server}/databases crea un database sul server. Il corpo ha un solo campo:

Campo Regole
name Obbligatorio. Da 1 a 63 lettere, cifre e trattini bassi, unico sul server.
curl -X POST https://deploy.example.com/api/v1/orgs/acme/servers/12/databases \
  -H "Authorization: Bearer $VIMONTO_TOKEN" -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name": "shop_staging"}'
{
  "data": { "id": 4, "server_id": 12, "name": "shop_staging", "status": "installing", "created_at": "2026-10-07T15:10:00+00:00", "task_id": 9122 }
}

La risposta è 202: il database viene creato da un task sul server. Il suo status è installing, poi installed, oppure failed se il task non riesce. Il server deve essere attivo e avere un database installato, altrimenti la risposta è 422.

Eliminare un database

DELETE /orgs/{organization}/servers/{server}/databases/{database} elimina il database sul server. Risponde 202 con il database, ora removing, e il task che lo rimuove in task_id, dentro data come ogni endpoint che avvia un task:

{
  "data": { "id": 4, "server_id": 12, "name": "shop_staging", "status": "removing", "created_at": "2026-10-07T15:10:00+00:00", "task_id": 9123 }
}

Vedi database.

Elencare i backup ed eseguirne uno

GET /orgs/{organization}/servers/{server}/backups restituisce le configurazioni di backup del server, in ordine di nome, ciascuna con i suoi 20 backup più recenti. size è in byte.

{
  "data": [
    {
      "id": 2,
      "name": "Nightly",
      "databases": ["shop"],
      "frequency": "nightly",
      "schedule": "0 0 * * *",
      "retention": 7,
      "storage": "Backups bucket",
      "backups": [
        {
          "id": 140,
          "status": "succeeded",
          "size": 48213504,
          "databases": ["shop"],
          "task_id": 9050,
          "created_at": "2026-10-07T00:00:02+00:00",
          "finished_at": "2026-10-07T00:01:15+00:00"
        }
      ]
    }
  ]
}

frequency è minute, hourly, nightly, weekly, monthly, reboot o custom; schedule è l'espressione cron. Lo status di un backup è running, succeeded o failed.

POST /orgs/{organization}/servers/{server}/backups/{backup}/run, con l'ID di una configurazione di backup, avvia subito un backup. Non ha corpo e risponde 202:

{ "data": { "backup_id": 141, "task_id": 9124 } }

409 quando è già in corso un backup di quella configurazione. Vedi backup.

Elencare le ricette ed eseguirne una

GET /orgs/{organization}/recipes restituisce le ricette dell'organizzazione, in ordine di nome. run_as è root o server_user.

{
  "data": [
    { "id": 5, "name": "Install htop", "run_as": "root", "script": "apt-get install -y htop", "updated_at": "2026-09-20T08:12:00+00:00" }
  ]
}

POST /orgs/{organization}/recipes/{recipe}/run esegue una ricetta su uno o più server.

Campo Regole
servers Obbligatorio. Un elenco di ID di server, almeno uno.
notify Facoltativo, true o false (predefinito). Con true ricevi un report via email quando tutti i server hanno finito.
curl -X POST https://deploy.example.com/api/v1/orgs/acme/recipes/5/run \
  -H "Authorization: Bearer $VIMONTO_TOKEN" -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"servers": [12, 13], "notify": false}'
{
  "data": {
    "run_id": 77,
    "servers": [
      { "server_id": 12, "task_id": 9125 },
      { "server_id": 13, "task_id": 9126 }
    ]
  }
}

Ogni server che indichi deve esistere, esserti accessibile ed essere attivo. Altrimenti la ricetta non viene eseguita da nessuna parte e la risposta è 422: errors.servers elenca gli ID dei server che non esistono o a cui non hai accesso, oppure i nomi dei server non attivi. La risposta elenca ogni server con il proprio task. Vedi ricette.

Seguire un task

Il lavoro lungo (un deploy, un database, un backup, una ricetta su un server) gira come task in background, lo stesso che vedi in attività. GET /orgs/{organization}/tasks/{task} ne restituisce lo stato e l'output:

{
  "data": {
    "id": 9121,
    "type": "site.deploy",
    "name": "Deploying to shop.example.com",
    "status": "running",
    "step": "Run deploy script",
    "progress": 30,
    "error": null,
    "server_id": 12,
    "output": "Cloning into 'releases/20261007150246'...\n",
    "started_at": "2026-10-07T15:02:46+00:00",
    "finished_at": null,
    "created_at": "2026-10-07T15:02:45+00:00"
  }
}

status è queued, running, succeeded, failed o cancelled; gli ultimi tre sono definitivi. progress va da 0 a 100. Quando un task non riesce, error spiega perché. Interroga l'endpoint ogni pochi secondi finché lo stato non è definitivo.

Paginazione

Solo l'elenco dei deploy è paginato, con 25 deploy per pagina, dal più recente. Chiedi un'altra pagina con ?page=2. La risposta contiene links e meta accanto a data:

{
  "data": [ … ],
  "links": {
    "first": "https://deploy.example.com/api/v1/orgs/acme/servers/12/sites/34/deployments?page=1",
    "last": "https://deploy.example.com/api/v1/orgs/acme/servers/12/sites/34/deployments?page=4",
    "prev": null,
    "next": "https://deploy.example.com/api/v1/orgs/acme/servers/12/sites/34/deployments?page=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 4,
    "path": "https://deploy.example.com/api/v1/orgs/acme/servers/12/sites/34/deployments",
    "per_page": 25,
    "to": 25,
    "total": 92
  }
}

meta contiene anche un elenco links per i pulsanti delle pagine. Segui links.next finché non è null. Tutti gli altri elenchi restituiscono tutto in una sola risposta.

Errori

Gli errori sono JSON con un message:

{ "message": "shop.example.com is not ready to deploy yet." }
Stato Significato
401 Nessun token, un token sbagliato o revocato, oppure scaduto: {"message": "Unauthenticated."}
403 Al token manca l'ambito ("Invalid ability provided."), oppure il tuo ruolo non consente la modifica ("Your role does not allow this.").
404 L'organizzazione, il server, il sito o un altro elemento non esiste, oppure non hai accesso. Non fare affidamento sul message.
409 Lo stesso lavoro è già in corso. La risposta contiene il task_id del task in corso.
422 La richiesta non si può eseguire: campi non validi, oppure un motivo come un server non ancora pronto.
429 Troppe richieste; vedi limiti di frequenza.

Un 409 è fatto così:

{ "message": "Deploying to shop.example.com is already running.", "task_id": 9121 }

Un 422 per campi non validi li elenca in errors:

{
  "message": "The name field format is invalid.",
  "errors": {
    "name": ["The name field format is invalid."]
  }
}

Limiti di frequenza

Ogni token può fare 120 richieste al minuto. Ogni risposta ha gli header X-RateLimit-Limit e X-RateLimit-Remaining. Oltre il limite, l'API risponde 429 con un header Retry-After: il numero di secondi da attendere.

Quando interroghi un task, una volta ogni pochi secondi è più che sufficiente.

Deploy da GitHub Actions

Questo workflow fa il deploy dopo che i test sono passati e fallisce quando il deploy non riesce. Crea un token con solo l'ambito Deploy e aggiungilo ai secret del repository come VIMONTO_TOKEN (Settings → Secrets and variables → Actions su GitHub). Inserisci il tuo indirizzo, lo slug dell'organizzazione, l'ID del server e l'ID del sito.

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    # needs: tests   # deploy solo dopo che il job dei test è passato
    steps:
      - name: Deploy to production
        env:
          VIMONTO_TOKEN: ${{ secrets.VIMONTO_TOKEN }}
          API: https://deploy.example.com/api/v1/orgs/acme
          SERVER: 12
          SITE: 34
        run: |
          set -euo pipefail
          auth=(-H "Authorization: Bearer $VIMONTO_TOKEN" -H "Accept: application/json")

          # Avvia il deploy; curl fallisce con 4xx/5xx, per esempio 409 se ne è già in corso uno.
          task=$(curl -sS --fail-with-body -X POST "${auth[@]}" \
            "$API/servers/$SERVER/sites/$SITE/deployments" | jq -r '.data.task_id')
          echo "Deploy started, task $task"

          # Segui il task finché non è terminato.
          while true; do
            sleep 5
            response=$(curl -sS --fail-with-body "${auth[@]}" "$API/tasks/$task")
            status=$(echo "$response" | jq -r '.data.status')
            echo "Status: $status ($(echo "$response" | jq -r '.data.step // ""'))"
            case "$status" in
              succeeded) exit 0 ;;
              failed|cancelled)
                echo "$response" | jq -r '.data.error // "", .data.output'
                exit 1 ;;
            esac
          done

Disattiva Deploy a ogni push per il sito quando è la CI a fare il deploy. Altrimenti un push avvia già da solo un deploy, e la richiesta della pipeline riceve 409 perché un deploy è già in corso.

Oppure usa la CLI

La CLI di Vimonto Deploy racchiude queste richieste in un solo comando: deploy deploy shop.example.com --watch avvia il deploy, segue il task ed esce con il suo risultato. Nella CI legge il token da DEPLOY_TOKEN.

Oppure usa l'URL di deploy

Se ti basta avviare un deploy, l'URL di deploy segreto del sito è più semplice: un solo POST senza token e niente da seguire. Però non dice alla tua pipeline se il deploy è riuscito. Vedi deploy.

Domande frequenti

Un token è legato a una sola organizzazione?

No. Un token raggiunge ogni organizzazione di cui sei membro, con il tuo ruolo in ciascuna. GET /user le elenca. Crea un account separato se una pipeline deve raggiungere una sola organizzazione.

Cosa succede ai miei token quando cambia il mio ruolo?

Un token segue sempre il tuo ruolo attuale e il tuo accesso ai server. Quando perdi un permesso o lasci un'organizzazione, anche il token lo perde, subito.

Posso creare server o siti tramite l'API?

Non ancora. L'API copre la lettura di server, siti, deploy, database, backup, ricette e task; il deploy; la creazione e la rimozione di database; e l'esecuzione di backup e ricette.

Dove trovo l'ID del server e del sito?

Nella barra degli indirizzi dell'app: nelle pagine di un sito l'indirizzo è /{organization}/servers/{server}/sites/{site}/…. Anche GET /orgs/{organization}/servers e GET …/servers/{server}/sites li elencano, e GET /orgs/{organization}/sites?domain=shop.example.com trova un sito con l'ID del suo server a partire dal dominio.