Simplifyd CloudSimplifyd Cloud
HomeHTTP APIServices

Services

Create a service, and list, attach, and remove its custom domains through the HTTP API.

Send a project token as a bearer token. If the token is scoped to an environment, use that environment's ID in the path.

BASE = https://api.cloud.simplifyd.com/v1/workspaces/{workspace}/projects/{project}/envs/{env}/svcs

Set BASE using your workspace, project, and environment slugs. Set SIMPLIFYD_API_TOKEN to your project token and SERVICE to the service slug returned at creation.

Method and pathWhat it does
POST {BASE}Creates a service
GET {BASE}/{service}/ingressLists the service's hostnames and custom domains
POST {BASE}/{service}/ingressAttaches a custom domain to an HTTP service
DELETE {BASE}/{service}/ingress/{hostname}Removes a custom domain from an HTTP service
POST {BASE}/{service}/site/domainsAttaches a custom domain to a static site

Create a service

POST {BASE}
Content-Type: application/json

Creates a service in the target environment. This example uses the nginx:alpine image. Deploy the container before it can serve traffic.

Body

FieldDescription
typeRequired service type. Use docker for a container.
nameDisplay name. For a container, it defaults to the image name.
docker_image_svc.imageContainer image name. Supply this when creating a container.
docker_image_svc.tagOptional image tag.
static_site_svc.nameSite name when type is static_site. The API also accepts the top-level name for a static site.
curl --fail-with-body -X POST "$BASE" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"name": "web", "type": "docker", "docker_image_svc": {"image": "nginx", "tag": "alpine"}}'
const response = await fetch(`${BASE}`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"name": "web", "type": "docker", "docker_image_svc": {"image": "nginx", "tag": "alpine"}}),
});
const result = await response.json();
if (!response.ok) throw new Error(result.message ?? response.statusText);

Response

201 Created.

{
  "slug": "0192e7a0-55c1-7b3e-8f2d-4a1b6c9d0e15",
  "name": "web",
  "type": "docker",
  "vcpus": 2,
  "memory": 4096,
  "replicas": 1,
  "region": "ng-west-1"
}

The response is trimmed. Use slug as {service} in subsequent requests. For VM-specific fields, see Create a VM.


List a service's custom domains

GET {BASE}/{service}/ingress

Returns the service's ingress ports. Each HTTP port lists its platform hostname and every custom domain attached to it, with DNS and certificate status. A service with no ingress returns [].

curl --fail-with-body "$BASE/$SERVICE/ingress" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN"

To print only the custom domain hostnames:

curl --fail-with-body -s "$BASE/$SERVICE/ingress" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN" \
  | jq -r '.[].custom_fqdns[]?.fqdn'
const response = await fetch(`${BASE}/${SERVICE}/ingress`, {
  headers: { Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}` },
});
const ports = await response.json();
if (!response.ok) throw new Error(ports.message ?? response.statusText);
const hostnames = ports.flatMap((port) => (port.custom_fqdns ?? []).map((d) => d.fqdn));

Response

200 OK.

[
  {
    "slug": "0192e7a1-0c4f-7d2a-9b6e-3f8a1c5d7e20",
    "protocol": "HTTP",
    "port": 80,
    "vanity_fqdn": "api-acme.simplifyd.app",
    "custom_fqdns": [
      {
        "slug": "0192e7a1-2b7d-7e91-a4c3-6d0f2e8b9a31",
        "fqdn": "app.example.com",
        "verified": true,
        "verified_at": "2026-11-03T14:22:09Z",
        "cname": "z-0192e7a0-55c1-7b3e-8f2d-4a1b6c9d0e16.simplifyd.app",
        "cert_status": "ready"
      }
    ]
  }
]
FieldDescription
slugThe ingress port's ID.
protocolHTTP, gRPC, TCP, or UDP. TCP and UDP ports have external_port and no hostnames.
vanity_fqdnThe platform hostname for the port, if it has one.
custom_fqdns[].fqdnThe custom domain. Pass this, or its slug, to remove it.
custom_fqdns[].verifiedWhether the domain's DNS record has been found.
custom_fqdns[].cnameThe target to point the domain's CNAME record at.
custom_fqdns[].cert_statuspending, issuing, ready, or failed. cert_status_message explains a failure.
custom_fqdns[].dns_zoneSet when the domain is in a DNS zone the workspace hosts here, so its records are managed for you.

Optional fields with no value are left out, and custom_fqdns is absent on a port with no custom domains.


Attach a custom domain to an HTTP service

POST {BASE}/{service}/ingress
Content-Type: application/json

Routes a hostname to an HTTP port on the service.

Body

FieldDescription
protocolRequired. Use http for this request.
portApplication port. HTTP gateways and Kubernetes services use port 80 automatically.
custom_fqdnHostname to attach, such as app.example.com.
curl --fail-with-body -X POST "$BASE/$SERVICE/ingress" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"protocol": "http", "port": 80, "custom_fqdn": "app.example.com"}'
const response = await fetch(`${BASE}/${SERVICE}/ingress`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"protocol": "http", "port": 80, "custom_fqdn": "app.example.com"}),
});
const result = await response.json();
if (!response.ok) throw new Error(result.message ?? response.statusText);

Response

201 Created.

{
  "success": true,
  "is_wildcard": false,
  "cname": "z-0192e7a0-55c1-7b3e-8f2d-4a1b6c9d0e16.simplifyd.app",
  "wildcard_cname": "",
  "wildcard_base_domain": "",
  "dns_zone": "",
  "dns_zone_pending": false,
  "dns_records": [],
  "dns_error": ""
}

For external DNS, point your hostname at cname. The response includes dns_zone and dns_records when the platform writes records to a managed zone. Check dns_error for a DNS write failure and dns_zone_pending for a zone awaiting delegation. For wildcard validation records, see Wildcard custom domains.


Remove a custom domain from an HTTP service

DELETE {BASE}/{service}/ingress/{hostname}

Detaches one custom domain from the service. This is the API equivalent of the trash icon next to a domain in the console. {hostname} is the domain, such as app.example.com, or its slug from the list response. There is no changeset to apply.

Other domains on the same port keep working. If the domain was the port's last hostname, the port is removed too.

curl --fail-with-body -X DELETE "$BASE/$SERVICE/ingress/app.example.com" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN"
const response = await fetch(`${BASE}/${SERVICE}/ingress/app.example.com`, {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}` },
});
const result = await response.json();
if (!response.ok) throw new Error(result.message ?? response.statusText);

Response

201 Created.

{
  "success": true
}

A hostname that is not on the service returns 404, so a typo is never reported as a removal. After removing a domain, delete its CNAME record at your DNS provider. Records in a zone hosted here are removed for you.


Attach a custom domain to a static site

POST {BASE}/{service}/site/domains
Content-Type: application/json

Adds a hostname to the site alongside any existing domains.

Body

FieldDescription
domainRequired hostname to attach.
curl --fail-with-body -X POST "$BASE/$SERVICE/site/domains" \
  -H "Authorization: Bearer $SIMPLIFYD_API_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"domain": "www.example.com"}'
const response = await fetch(`${BASE}/${SERVICE}/site/domains`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIMPLIFYD_API_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"domain": "www.example.com"}),
});
const result = await response.json();
if (!response.ok) throw new Error(result.message ?? response.statusText);

Response

200 OK.

{
  "display_name": "Docs",
  "domain_cname_target": "example-site.simplifyd.app",
  "custom_domains": [
    {
      "slug": "0192e7a0-55c1-7b3e-8f2d-4a1b6c9d0e15",
      "domain": "www.example.com",
      "status": "pending",
      "created_at": "2026-01-15T12:00:00Z"
    }
  ]
}

The response is trimmed. For external DNS, point your hostname at domain_cname_target. Check the domain entry for dns_zone or dns_error when Simplifyd Cloud manages the zone.


Errors

StatusWhen
400The request is missing a required field, the domain is invalid, or the protocol does not support custom domains.
401The project token is missing or invalid.
402The workspace is suspended when creating a service.
403The workspace, project, or environment is outside the token scope.
404The service does not exist, or the hostname being removed is not attached to it.