5050cloud

API

The 5050cloud REST API serves everything the console and the CLI do, with the same roles and audit log.

Basics

  • Base URL: https://<your console domain>/api/v1. Health endpoints /healthz and /readyz sit at the root.
  • Authentication: Authorization: Bearer 5050_... with an API token from Account > Tokens or 5050 login. Browser sessions use the 5050_session cookie and must send the header X-5050-CSRF: 1 on every request that changes state.
  • Scopes: an account token acts as its user. An environment token can deploy, read logs and set variables in one environment.
  • Roles: Public needs no login. Viewer, Member, Admin and Owner are the install roles; a project grant can replace the install role for one project.
  • Errors are JSON {code, message, field?} with the codes unauthorized, forbidden, not_found, conflict, validation, rate_limited, unavailable (also read-only mode) and internal.
  • Request bodies are capped at 1 MiB, except uploads. Unknown JSON fields are rejected.
  • Every request that is not a GET writes an audit log entry. The Audit column names its action.
  • Types named in the tables are the Go types in pkg/api/types.go (MIT licensed), with camelCase JSON names. TypeScript types are generated from them.

System, auth, users

MethodPathBody and responseRoleAudit
GET/healthz200 "ok" when the process runsPublic
GET/readyz{version, ready, readOnly, checks{db,migrations,hub,agents}}Public
GET/api/v1/version{version, commit, date}Public
GET/api/v1/setupSetupStatusPublic
POST/api/v1/setupSetupRequest -> Me (sets cookie)Publicsetup.complete
POST/api/v1/auth/loginLoginRequest -> Me or {needTotp: true, ticket}Publicauth.login
POST/api/v1/auth/login/totp{ticket, code} -> MePublicauth.login_totp
POST/api/v1/auth/logout-> 204Viewerauth.logout
POST/api/v1/auth/forgot{email} -> 204 (always)Publicauth.forgot
POST/api/v1/auth/reset{token, password} -> MePublicauth.reset
POST/api/v1/auth/verify-email{token} -> 204Publicauth.verify_email
GET/api/v1/meMeViewer
PATCH/api/v1/me{name?, password?, currentPassword?} -> UserViewerme.update
POST/api/v1/me/2fa/setup-> {secret, otpauthUrl} / {code} -> {recoveryCodes} / {password, code} -> 204Viewerme.2fa_setup
POST/api/v1/me/2fa/enableTOTPEnableRequest -> TOTPEnableResponseViewerme.2fa_enable
POST/api/v1/me/2fa/disableTOTPDisableRequest -> 204Viewerme.2fa_disable
GET/api/v1/me/notification-prefs[]NotificationPrefViewer
PUT/api/v1/me/notification-prefs[]NotificationPref -> []NotificationPrefViewerme.notification_prefs
GET/api/v1/me/notificationsPage[Notification] (query before=)Viewer
POST/api/v1/me/notifications/read{ids[] or all} -> 204Viewer
POST/api/v1/cli/auth/start-> CLIAuthStartPubliccli_auth.start
POST/api/v1/cli/auth/approve{code} -> 204Viewercli_auth.approve
POST/api/v1/cli/auth/pollCLIAuthPoll -> CLIAuthPollResponsePublic
GET/api/v1/tokens[]APITokenViewer
POST/api/v1/tokensCreateTokenRequest -> CreateTokenResponseViewertoken.create
DELETE/api/v1/tokens/{id}-> 204Viewertoken.delete
GET/api/v1/members[]UserViewer
GET/api/v1/invites[]InviteAdmin
POST/api/v1/invitesCreateInviteRequest -> InviteAdmininvite.create
DELETE/api/v1/invites/{id}-> 204Admininvite.delete
GET/api/v1/invites/{id}InvitePreviewPublic
POST/api/v1/invites/accept{token, email, name, password} -> MePublicinvite.accept
PATCH/api/v1/members/{id}UpdateMemberRequest -> UserAdminmember.update
DELETE/api/v1/members/{id}204Adminmember.delete
POST/api/v1/members/{id}/transfer-ownership{password, code?} -> 204Ownermember.transfer_ownership
GET/api/v1/auditPage[AuditEntry] (query before=&limit=)Admin

Install, settings, hosts, upgrades

MethodPathBody and responseRoleAudit
GET/api/v1/installInstallViewer
PATCH/api/v1/installUpdateInstallRequest -> Install (name, base domain, console domain, ACME email, trusted proxies, registry cap, build timeout default)Admininstall.update
GET/api/v1/settings/backupsBackupSettingsAdmin
PUT/api/v1/settings/backupsBackupSettings -> BackupSettingsAdminsettings.backups_update
POST/api/v1/settings/backups/test-> {ok, error?}Adminsettings.backups_test
GET/api/v1/settings/smtpSMTPSettingsAdmin
PUT/api/v1/settings/smtpSMTPSettings -> SMTPSettingsAdminsettings.smtp_update
POST/api/v1/settings/smtp/test{to} -> {ok, error?}Adminsettings.smtp_test
GET/api/v1/settings/alertsInstallNotificationsAdmin
PUT/api/v1/settings/alertsInstallNotifications -> InstallNotificationsAdminsettings.alerts_update
POST/api/v1/settings/recovery-key{password} -> {recoveryKey} (audited)Ownersettings.recovery_key_reveal
GET/api/v1/hosts[]Host (with conflicts, reachability, usage)Viewer
POST/api/v1/hosts/join-tokensCreateJoinTokenRequest -> JoinTokenAdminhost.join_token
PATCH/api/v1/hosts/{id}UpdateHostRequest -> Host (name, roles, drain, reserve)Adminhost.update
POST/api/v1/hosts/{id}/maintenance{on} -> HostAdminhost.maintenance
POST/api/v1/hosts/{id}/readopt-> HostAdminhost.readopt
DELETE/api/v1/hosts/{id}/conflictsHostAdminhost.clear_conflicts
DELETE/api/v1/hosts/{id}-> 204 (refused while it runs replicas, unless ?force=1) (query force=1)Adminhost.delete
GET/api/v1/hosts/{id}/metricsMetricsResponse (query range=&from=&until=)Viewer
POST/api/v1/upgradeUpgradeRequest -> UpgradeStatusAdmininstall.upgrade
GET/api/v1/upgradeUpgradeStatusViewer
GET/api/v1/registry-credentials[]RegistryCredentialMember
POST/api/v1/registry-credentialsCreateRegistryCredentialRequest -> RegistryCredentialMemberregistry_credential.create
DELETE/api/v1/registry-credentials/{id}-> 204 (refused while a service uses it)Memberregistry_credential.delete
GET/api/v1/restore/unknown-replicas[]UnknownReplicaAdmin
POST/api/v1/restore/unknown-replicas/{id}/adopt-> 204Adminrestore.adopt
POST/api/v1/restore/unknown-replicas/{id}/remove204Adminrestore.remove
POST/api/v1/restore/finish204Adminrestore.finish

Projects, environments, canvas, changes

MethodPathBody and responseRoleAudit
GET/api/v1/projects[]Project (query sort=activity|created|name)Viewer
POST/api/v1/projectsCreateProjectRequest (name optional: a two-word name is generated) -> Project (with production)Memberproject.create
GET/api/v1/projects/{pid}ProjectViewer
PATCH/api/v1/projects/{pid}UpdateProjectRequest -> ProjectMemberproject.update
DELETE/api/v1/projects/{pid}{confirm: "<name>"} -> 204 (stops everything, deletes volumes after 48 h)Adminproject.delete
GET/api/v1/projects/{pid}/members[]ProjectGrantViewer
PUT/api/v1/projects/{pid}/members[]ProjectGrant -> []ProjectGrantAdminproject.grants_update
GET/api/v1/projects/{pid}/usageUsageResponse (query from=&until=)Viewer
POST/api/v1/projects/{pid}/environmentsCreateEnvironmentRequest -> EnvironmentMemberenvironment.create
PATCH/api/v1/environments/{eid}UpdateEnvironmentRequest (name, egress) -> EnvironmentMemberenvironment.update
DELETE/api/v1/environments/{eid}{confirm} -> 204 (not the last one)Adminenvironment.delete
POST/api/v1/environments/{eid}/sync{from: eid} -> ChangesResponse (staged, with tags)Memberenvironment.sync
GET/api/v1/environments/{eid}/canvasCanvasViewer
PUT/api/v1/environments/{eid}/positionsSavePositionsRequest -> 204 (broadcast)Member
PUT/api/v1/environments/{eid}/groups[]Group -> []GroupMembercanvas.groups_update
POST/api/v1/environments/{eid}/presence{cursor?} -> 204Viewer
GET/api/v1/environments/{eid}/changesChangesResponseViewer
DELETE/api/v1/environments/{eid}/changes-> 204Memberchanges.discard_all
DELETE/api/v1/environments/{eid}/changes/{cid}204Memberchanges.discard
POST/api/v1/environments/{eid}/changes/commitCommitRequest -> CommitResponseMemberchanges.commit
GET/api/v1/environments/{eid}/activityPage[Activity] (query service=&kind=&before=)Viewer
GET/api/v1/commits/{id}CommitDetail (message, author, full diff, secrets masked)Viewer
GET/api/v1/eventsEvent (Server-Sent Events, query environment=)Viewer
GET/api/v1/environments/{eid}/shared-variablesVariablesResponseViewer
PUT/api/v1/environments/{eid}/shared-variablesSetVariablesRequest -> VariablesResponseMembershared_variables.stage
POST/api/v1/environments/{eid}/shared-variables/revealRevealRequest -> RevealResponseMembershared_variables.reveal
POST/api/v1/environments/{eid}/shared-variables/share{name, services[]} -> 204 (staged)Membershared_variables.share
GET/api/v1/environments/{eid}/export5050.yaml text (manifest.ProjectFile)Viewer
POST/api/v1/imports/railway{token, projectName?} -> Import (creates a project with staged changes)Memberimport.railway
POST/api/v1/environments/{eid}/imports/composeYAML body -> Import (staged)Memberimport.compose
POST/api/v1/environments/{eid}/services/{sid}/imports/heroku-envtext body -> Import (staged)Memberimport.heroku_env
GET/api/v1/imports/{id}Import with reportMember
GET/api/v1/searchSearchResult (query q=)Viewer

Services

MethodPathBody and responseRoleAudit
POST/api/v1/environments/{eid}/servicesCreateServiceRequest -> CreateServiceResponseMemberservice.create
GET/api/v1/environments/{eid}/services/{sid}Service (config with source map for file-set fields)Viewer
PATCH/api/v1/environments/{eid}/services/{sid}/configUpdateServiceConfigRequest -> Service (staged)Memberservice.config_stage
PATCH/api/v1/environments/{eid}/services/{sid}/info{name?, icon?} -> Service (rename staged, icon immediate)Memberservice.info_update
POST/api/v1/environments/{eid}/services/{sid}/duplicate-> Service (staged)Memberservice.duplicate
DELETE/api/v1/environments/{eid}/services/{sid}{confirm} -> 204 (staged)Adminservice.delete
GET/api/v1/environments/{eid}/services/{sid}/variablesVariablesResponseViewer
PUT/api/v1/environments/{eid}/services/{sid}/variablesSetVariablesRequest -> VariablesResponseMembervariables.stage
POST/api/v1/environments/{eid}/services/{sid}/variables/revealRevealRequest -> RevealResponseMembervariables.reveal
GET/api/v1/environments/{eid}/services/{sid}/deployments[]Deployment (query limit=&q=)Viewer
POST/api/v1/environments/{eid}/services/{sid}/deployDeployRequest -> DeploymentMemberdeployment.deploy
POST/api/v1/environments/{eid}/services/{sid}/uploadsapplication/gzip -> UploadResponse (query message=)Memberdeployment.upload
GET/api/v1/deployments/{did}DeploymentDetailViewer
POST/api/v1/deployments/{did}/redeploy-> DeploymentMemberdeployment.redeploy
POST/api/v1/deployments/{did}/rollbackDeploymentMemberdeployment.rollback
POST/api/v1/deployments/{did}/restartDeploymentMemberdeployment.restart
POST/api/v1/deployments/{did}/abortDeploymentMemberdeployment.abort
POST/api/v1/deployments/{did}/removeDeploymentMemberdeployment.remove
POST/api/v1/replicas/{rid}/move{hostId?} -> 204 (singleton move after confirm, 7.1)Adminreplica.move
GET/api/v1/deployments/{did}/build-logsLogsResponse (query follow=1 (SSE of []LogLine))Viewer
GET/api/v1/logsLogsResponse (query environment=&services=&deployment=&type=deploy,build,http&q=&since=&until=&limit=&around=)Viewer
GET/api/v1/logs/stream[]LogLine (Server-Sent Events, query same as /logs)Viewer
GET/api/v1/environments/{eid}/services/{sid}/metricsMetricsResponse (query range=&from=&until=&view=sum|replica)Viewer
GET/api/v1/environments/{eid}/services/{sid}/db-metricsDBMetricsResponse (query range=)Viewer
GET/api/v1/environments/{eid}/services/{sid}/monitors[]MonitorViewer
POST/api/v1/environments/{eid}/services/{sid}/monitorsCreateMonitorRequest -> MonitorMembermonitor.create
PATCH/api/v1/monitors/{id}UpdateMonitorRequest -> MonitorMembermonitor.update
DELETE/api/v1/monitors/{id}204Membermonitor.delete
GET/api/v1/environments/{eid}/services/{sid}/domains[]DomainViewer
POST/api/v1/environments/{eid}/services/{sid}/domainsCreateDomainRequest -> DomainMemberdomain.create
PATCH/api/v1/domains/{id}UpdateDomainRequest -> DomainMemberdomain.update
DELETE/api/v1/domains/{id}204Memberdomain.delete
POST/api/v1/domains/{id}/check-> DomainMemberdomain.check
POST/api/v1/domains/{id}/retry-certificateDomainMemberdomain.retry_certificate
POST/api/v1/environments/{eid}/services/{sid}/tcp-proxiesCreateTCPProxyRequest -> TCPProxyMembertcp_proxy.create
DELETE/api/v1/environments/{eid}/services/{sid}/tcp-proxies/{id}204Membertcp_proxy.delete
POST/api/v1/environments/{eid}/services/{sid}/volumeCreateVolumeRequest -> VolumeMembervolume.create
GET/api/v1/environments/{eid}/services/{sid}/volumeVolumeDetailViewer
PATCH/api/v1/environments/{eid}/services/{sid}/volumeUpdateVolumeRequest -> VolumeMembervolume.update
DELETE/api/v1/environments/{eid}/services/{sid}/volumeConfirmRequest -> 204Adminvolume.delete
POST/api/v1/environments/{eid}/services/{sid}/volume/wipeConfirmRequest -> 204Adminvolume.wipe
GET/api/v1/environments/{eid}/services/{sid}/backupsBackupsResponseViewer
POST/api/v1/environments/{eid}/services/{sid}/backupsBackupMemberbackup.create
PUT/api/v1/environments/{eid}/services/{sid}/backups/scheduleBackupSchedule -> BackupScheduleMemberbackup.schedule_update
POST/api/v1/backups/{id}/lock{locked}Memberbackup.lock
DELETE/api/v1/backups/{id}204Adminbackup.delete
POST/api/v1/environments/{eid}/services/{sid}/restoreRestoreRequest -> RestoreResponseAdminbackup.restore
POST/api/v1/environments/{eid}/services/{sid}/promotePromoteRequest -> 204Adminbackup.promote
POST/api/v1/environments/{eid}/services/{sid}/major-upgradeMajorUpgradeRequest -> RestoreResponseAdmindatabase.major_upgrade
GET/api/v1/environments/{eid}/services/{sid}/connect-infoConnectInfoMember
POST/api/v1/environments/{eid}/services/{sid}/regenerate-credentialsCommitResponseAdmindatabase.regenerate_credentials
GET/api/v1/environments/{eid}/services/{sid}/dataDataResponseMember
GET/api/v1/environments/{eid}/services/{sid}/extensions[]ExtensionMember
POST/api/v1/environments/{eid}/services/{sid}/extensionsEnableExtensionRequest -> ExtensionAdmindatabase.extension_enable
GET/api/v1/environments/{eid}/services/{sid}/redis/keysRedisKeysPage (query match=&cursor=)Member
POST/api/v1/environments/{eid}/services/{sid}/redis/keys/revealRedisRevealRequest -> RedisRevealResponseMemberdatabase.redis_reveal
GET/api/v1/environments/{eid}/services/{sid}/cron-runs[]CronRunViewer
POST/api/v1/environments/{eid}/services/{sid}/cron-runsCronRunMembercron.run_now
GET/api/v1/environments/{eid}/services/{sid}/shell204 (WebSocket, query replica=&cols=&rows=&session=)Memberservice.shell
GET/api/v1/environments/{eid}/services/{sid}/tunnel204 (WebSocket, query port=)Memberservice.tunnel

Templates, GitHub, webhooks

MethodPathBody and responseRoleAudit
GET/api/v1/templates[]TemplateSummary (query q=)Viewer
GET/api/v1/templates/{id}TemplateDetail (services, inputs with generated defaults)Viewer
POST/api/v1/environments/{eid}/templates/{id}/deploy{inputs} -> TemplateDeployResponseMembertemplate.deploy
GET/api/v1/icons/{name}SVG/PNG icons for templates, sources and the devicon pickerPublic
GET/api/v1/githubGitHubStatusViewer
POST/api/v1/github/app{owner?: "org", returnTo?} -> {formUrl, manifest}Admingithub.app_create
GET/api/v1/github/app/callback204 (302 redirect, query code=)Admingithub.app_callback
GET/api/v1/github/repos[]GitHubRepo (query q=&refresh=1)Member
GET/api/v1/github/branches[]string (query repo=)Member
POST/api/v1/github/scanScanRequest -> ScanResult (builder, start command, config files, packages, variable names, port)Membergithub.scan
POST/api/v1/github/webhookGitHub delivery (signature checked)Publicgithub.webhook
GET/api/v1/projects/{pid}/webhooks[]WebhookAdmin
POST/api/v1/projects/{pid}/webhooksWebhook -> WebhookAdminwebhook.create
PATCH/api/v1/webhooks/{id}Webhook -> WebhookAdminwebhook.update
DELETE/api/v1/webhooks/{id}204Adminwebhook.delete
POST/api/v1/webhooks/{id}/test-> {status, responseCode}Adminwebhook.test
POST/api/v1/join204Publicagent.join
GET/api/v1/connect204 (WebSocket)Publicagent.connect
GET/api/v1/uploads/{id}application/gzipPublic

Agent endpoints

Agents call these. They are also served on agents.<console domain> so you can firewall them separately. See Agent protocol.

MethodPathAuth
POST/api/agent/v1/joinjoin token in body (rate limited 10 per minute per IP)
GET (WebSocket)/api/agent/v1/connecthost token bound to machine-id and WireGuard key
GET/api/agent/v1/uploads/{id}host token; serves a 5050 up tarball to the build host

Next steps

View as Markdown · Edit this page