Restart service
POSThttps://api.instacloud.com/projects/{projectId}/services/{serviceId}/restart
Token scope: account · org · project — read-only tokens refused (not a GET).
Restart a compute service by re-submitting the image reference recorded on it, against a freshly resolved env bundle. This is how a changed secret or binding reaches a running machine, and how a machine that is up but wedged gets cycled (start only wakes a machine that is DOWN — it no-ops on one that is already started). It asks for no new version and no new spec, but it does not pin a digest: a service recorded against a MOVING tag (app:latest) gets whatever that tag resolves to now, exactly as a redeploy of the same tag would. Requires desired_state 'running': a stopped or suspended service is brought back with start, which also re-enables auto-wake. All plans. Gated under deploy, like the deploy route it shares its pipeline with — a policy denying deploys denies this too, and start/stop stay ungated for cycling a wedged machine without one.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
projectId | path | string | yes | |
serviceId | path | string | yes |
Responses
200
Default Response
| Field | Type | Required | Description |
|---|---|---|---|
service | object | no | A project-level service (postgres | storage | compute | redis | mysql | mongodb). |
service.id | string | no | |
service.project_id | string | no | |
service.type | "postgres" | "storage" | "compute" | "redis" | "mysql" | "mongodb" | no | |
service.name | string | no | |
service.spec | object | no | compute: {cpu_kind,cpus,memory_mb}; postgres: sized by its instance ceiling (cpuMilli/memoryMib) |
service.machine_count | integer | no | compute only |
service.desired_state | "running" | "stopped" | "suspended" | no | compute only — developer-set lifecycle intent |
service.always_on | boolean | no | compute and managed databases (redis, mysql, mongodb) — true: machines never scale to zero; false: idle machines suspend and wake on request. A new compute service is born false (scale-to-zero, except a worker); a new managed database is born from INSTA_DB_ALWAYS_ON_DEFAULT (true on InstaCloud). Postgres is not recorded here: its idle mode lives on the database instance (GET /projects/{projectId}/database/instance, scaleToZero). Billing is actual usage either way. |
service.websocket | boolean | null | no | compute only — the app speaks WebSocket, so its machines carry connections-based concurrency and a 512 MB guest floor. Re-asserted by any redeploy given no flag, including restart. null: never recorded. |
service.endpoint | "http" | "tcp" | "udp" | "tcp+udp" | null | no | compute only — how the service is reached. http: Host-routed HTTPS at `domain`. tcp / udp / tcp+udp: raw TCP, UDP, or both at `endpoint_host`:`port` on the service’s own public IPv6 address (IPv6 clients only; no TLS from the platform, no custom domain, no WebSocket flag). Chosen at create, and changed by a deploy that passes `endpoint`. null: never chosen, which is http. |
service.endpoint_host | string | null | no | compute, endpoint tcp/udp/tcp+udp only — the host to reach on `port` (an IPv6-only name), set once a deploy has confirmed it; null otherwise |
service.region | string | null | no | |
service.domain | string | null | no | default access domain (postgres/compute) |
service.public | boolean | no | storage — bucket(s) served with anonymous public-read; managed databases — the database port is exposed on a public address (on insta-compute, false = reachable only over the private network, *_PRIVATE_URL); postgres — the public endpoint accepts connections (true by default; false = not reachable from the internet, private network lane only); compute — the service answers the internet at its URL / endpoint_host (true by default; false = the URL answers 403 and never wakes it, and only services in the same branch reach it, at private_host). Change it with PUT .../services/{serviceId}/access |
service.private_host | string | null | no | compute and managed databases on insta-compute — the name other services in the SAME project branch reach this one at, on `port` over TCP: `<name>.insta.internal` for compute, `<name>-<type>.insta.internal` for a managed database (redis/mysql/mongodb). Other branches and projects cannot reach it. Resolves through the search domain every service is started with; tools that skip the search list (nslookup, dig) need private_fqdn. null: the service has no private address (a worker, a name ending in '-', a service not yet back-filled, or a region without the private network) |
service.private_fqdn | string | null | no | compute and managed databases on insta-compute — the fully-qualified form of private_host, `<private name>.<network>.insta.internal`, for clients that do not use the search domain. null whenever private_host is |
service.image | string | null | no | compute only — container image currently run |
service.port | integer | null | no | compute/managed database — compute image port, or the private database TCP port |
service.start_command | string | null | no | Runtime startup override, run via sh -c; on insta-compute it runs in place of the image's ENTRYPOINT and CMD: a wrapper entrypoint (e.g. docker-entrypoint.sh) does not run while it is set. null restores the image's own ENTRYPOINT and CMD. Stored as readable service settings. |
service.volume_applied_mount_path | string | null | no | Last successfully confirmed Compute mount path; null means unknown, not proof of a changed path. |
service.volume_mount_path | string | null | no | Compute volume mount path; null or omitted means /data for legacy volumes. Changes apply on deployment. |
service.volume_gib | integer | null | no | compute/managed database — size (whole Gi) of the persistent data volume; null = no volume. Compute can attach/grow via PUT .../volume; managed databases are platform-managed in v1 |
service.pg_version | integer | null | no | postgres only — the Postgres MAJOR version the service runs (e.g. 16), known before the instance is ever connected to or woken. Pick client tooling (pg_dump/pg_restore/psql) of the same major. null: never recorded (a legacy row). The exact server_version of a RUNNING instance is on GET .../database/metrics |
service.template_deployment_id | string | null | no | the template deployment that created this service (survives branch clones); null for services created directly |
service.template_modified | boolean | no | true once the service was reconfigured away from its template-deployed spec |
service.template_code | string | null | no | the template this service was deployed from; null for services created directly, and for one whose deployment record has been pruned |
service.template_logo_url | string | null | no | the template's mark; null when the template is not in the registry (or carries no logo). Official templates: a commit-pinned jsDelivr URL (TEMPLATE_LOGO_HOST). Community templates: any https:// link the author set. Joined live rather than stored, because a republish moves it |
service.template_name | string | null | no | the template's name as the registry spells it, for a surface people read; null when the template is not in the registry, or its manifest omits a name. Read from the manifest the registry serves NOW, beside the logo, because a republish can rename it |
service.template_version | string | null | no | the template version this instance was deployed from; null for a service created directly. Read from the deployment record, so it does not move when the registry is republished |
service.template_latest_version | string | null | no | the version the registry serves for this template now; null when the registry does not serve it — absent, unpublished or taken down. The row still reports template_code and template_name in those cases, because attribution of a resource its owner deployed is not catalog visibility. For display beside template_version, never for deciding whether an update exists |
service.template_update_available | boolean | no | true when upgrading this service's template deployment to the version the registry serves now would actually change something about the services it runs: a setting the new manifest would write, an environment variable it would write differently, a service it would add, or a variable it now requires that this instance holds no value for. A republish that only moved presentation is not an update, because applying it would change nothing, and neither is a new version string on identical content, which is what every community republish produces. False whenever the answer cannot be determined: a template absent from the registry, unpublished, taken down, a manifest this version of the platform cannot parse, or a registry read that failed. False too while the deployment's own run has not succeeded, because what an unfinished deploy needs is a retry, not an upgrade |
service.source | object | no | compute only — where the running image comes from: an image somebody deployed (type=image) or a connected repository (type=github). Full resource: GET /projects/{id}/services/{serviceId}/source |
service.source.type | "image" | "github" | yes | |
service.source.owner | string | no | |
service.source.repo | string | no | |
service.source.branch | string | no | the repo branch this service tracks |
service.source.auto_deploy | boolean | no | a push to `branch` rebuilds and redeploys the service |
service.status | "creating" | "active" | "error" | "deleting" | "deleted" | no | |
service.created_at | string | no | |
state | string | no | live runtime state: running|suspended|stopped|none|unknown |
202
Default Response
| Field | Type | Required | Description |
|---|---|---|---|
status | "approval_required" | no | |
approvalId | string | no | |
action | string | no | the gated action, or a comma-joined compound set — prefer `actions` |
actions | string[] | no | every capability this approval covers |
message | string | no | |
url | string | no | the console page where a project admin reviews this request |
nextActions | object[] | no | |
nextActions.op | string | yes | Neutral logical action id, e.g. "service.add" — NOT an operationId or a CLI/MCP tool name; each client maps it to its own surface. |
nextActions.reason | string | yes | Natural-language, human/LLM-facing "why do this now". |
nextActions.args | object | no | Suggested, flat named arguments; "<placeholder>"s where a value is unknown. |
nextActions.gated | boolean | no | True if the action passes a governance gate. |
400
not a compute service, nothing deployed yet, deliberately stopped/suspended, or the app did not answer on its port coming back up — in that last case the machines are rolled back to the config they were serving, best-effort: the message names any the provider could not put back
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes |
403
Default Response
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes |
404
Default Response
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes |
501
the service has a start command its region cannot run yet — remove the start command, or retry once the region enables custom start commands
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes |
502
the compute provider could not roll the restart — safe to retry
| Field | Type | Required | Description |
|---|---|---|---|
error | string | yes |