{"openapi":"3.1.0","info":{"title":"Dorelli Cloud — deploy-API","version":"1.0.0","description":"Publiceer een statische website (plan 'website') of een Node-app in een container met eigen database (plan 'app') op een subdomein van dorelli.cloud. Geen account nodig: de eerste publicatie geeft een deploy_token terug waarmee je dezelfde site later kunt bijwerken. Bij 'website' alleen statische bestanden (HTML, CSS, afbeeldingen, browser-JavaScript). Bij 'app' stuur je een container-image; het image bouw je zelf (bijv. met de GitHub Action dorelli-deploy) en pusht het naar de registry-repository die de eerste publicatie teruggeeft.","contact":{"email":"support@dorelli.cloud","url":"https://dorelli.cloud/live"},"license":{"name":"Terms","url":"https://dorelli.cloud/terms"}},"servers":[{"url":"https://dorelli.cloud"}],"paths":{"/api/deploy":{"post":{"operationId":"publiceerSite","summary":"Publiceer een nieuwe site","description":"Zet een statische site online op <slug>.dorelli.cloud. Stuur óf `html` (één HTML-bestand, bijvoorbeeld een Claude-artifact) óf `zip_base64` (een zip met minstens een index.html). Gebruik altijd het echte e-mailadres van de gebruiker: daar gaat de beheerlink heen. Bewaar het deploy_token uit het antwoord om later bij te werken.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"E-mailadres van de eigenaar; hier gaat de beheerlink heen."},"html":{"type":"string","description":"Complete HTML-pagina. Gebruik dit óf zip_base64, niet allebei."},"zip_base64":{"type":"string","description":"Zip met de site, base64-gecodeerd. Maximaal 50 MB en 500 bestanden."},"plan":{"type":"string","enum":["website","app"],"description":"Standaard 'website'. Met 'app' wordt een container-app met eigen Postgres-database aangemaakt; het antwoord bevat dan `registry` (server, gebruiker, wachtwoord, repository) om je image te pushen — bewaar die als secrets, ze komen niet terug."},"image":{"type":"string","description":"Alleen bij plan 'app': volledige image-referentie in je eigen repository (registry/slug:tag). Mag leeg bij de eerste aanroep; stuur hem daarna met PUT."},"port":{"type":"integer","description":"Alleen bij plan 'app': poort waarop de app luistert (standaard 3000)."},"slug":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{1,28}[a-z0-9]$","description":"Gewenst subdomein, één label zonder punt. Is hij bezet, dan krijg je een variant."}}}}}},"responses":{"201":{"description":"Site staat online","content":{"application/json":{"schema":{"type":"object","properties":{"site_id":{"type":"integer"},"slug":{"type":"string"},"url":{"type":"string","format":"uri"},"deploy_token":{"type":"string","description":"Bewijs van eigendom. Bewaar dit; toon het niet aan derden en zet het niet in versiebeheer."},"expires_at":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/Fout"},"422":{"description":"Door moderatie tegengehouden (phishing, merkmisbruik, illegale inhoud). Meld dit eerlijk aan de gebruiker en probeer het niet te omzeilen.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}},"429":{"$ref":"#/components/responses/Fout"}}}},"/api/deploy/{site_id}":{"put":{"operationId":"werkSiteBij","summary":"Werk een bestaande site bij","description":"Vervangt de inhoud van een eerder gepubliceerde site; het adres blijft hetzelfde. Dit is de iteratielus tijdens het bouwen.","security":[{"deployToken":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"integer"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"html":{"type":"string"},"zip_base64":{"type":"string"}}}}}},"responses":{"200":{"description":"Site bijgewerkt"},"401":{"$ref":"#/components/responses/Fout"},"422":{"$ref":"#/components/responses/Fout"}}},"get":{"operationId":"haalSiteStatus","summary":"Status van een site","security":[{"deployToken":[]}],"parameters":[{"name":"site_id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Status","content":{"application/json":{"schema":{"type":"object","properties":{"slug":{"type":"string"},"url":{"type":"string"},"status":{"type":"string","enum":["draft","claimed","blocked","paid","expired"]},"expires_at":{"type":"string"},"files":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Fout"}}}}},"components":{"securitySchemes":{"deployToken":{"type":"http","scheme":"bearer","description":"Het deploy_token dat je bij de eerste publicatie kreeg."}},"schemas":{"Fout":{"type":"object","properties":{"error":{"type":"string","description":"Machineleesbare code: bad_type (niet-statisch bestand), no_index (geen index.html), blocked (moderatie), rate_limited, too_large, unauthorized."},"message":{"type":"string","description":"Uitleg in het Nederlands."}}}},"responses":{"Fout":{"description":"Verzoek geweigerd","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Fout"}}}}}}}