# Hosting core concepts (https://developer.godaddy.com/en/docs/api-users/hosting/concepts)

---
title: Hosting core concepts
description: >-
  Variants, deployments, async jobs, and secrets — the mental model behind the
  Hosting API.
keywords: >-
  preview variant, publish variant, async job polling, terminal states active
  failed, deployment snapshot, batch secret operations, idempotency key, hosting
  model
related:
  tutorials:
    - title: Deploy your Node.js app
      href: /docs/api-users/hosting/workflows/deploy-nodejs-app
  guides:
    - title: Manage secrets
      href: /docs/api-users/hosting/manage-secrets
    - title: Read logs
      href: /docs/api-users/hosting/read-logs
  apis:
    - title: Hosting API reference
      href: /docs/references/rest/hosting
---

## Overview

This page explains the mental model behind the Hosting API. Three concepts run through all resource groups: variants, async jobs, and deployments. Understanding these makes the rest of the surface readable on first contact.

The Hosting API supports Node.js apps. Other product types will be supported in future releases.

Go to [Deploy your Node.js app](https://developer.godaddy.com/docs/api-users/hosting/workflows/deploy-nodejs-app) for a hands-on walkthrough. Go to the [Hosting API reference](https://developer.godaddy.com/docs/references/rest/hosting) for endpoint details.

## Variants

Every hosted app needs a way to test a change without exposing it to the traffic your users are already hitting. The Hosting API solves this by giving every app two parallel runtime copies, called variants, instead of leaving you to provision and wire up separate staging and production environments yourself. Each variant has its own source, its own secrets, and its own URL; however, they belong to the same app and share the same id.

The following table describes the two variants:

| Variant   | What it is                                                    | Typical use                              |
| --------- | ------------------------------------------------------------- | ---------------------------------------- |
| `preview` | Working copy. Receives new source uploads and secret changes. | Iteration, integration testing, staging. |
| `publish` | Production copy. Serves live traffic.                         | Whatever your users actually hit.        |

Uploads land on `preview`. **Publishing** promotes the current preview to `publish`. Only the next upload overwrites `preview`.

Per-variant reads differ by endpoint. `GET /status` returns both variants in one response with no filter parameter. `GET /secrets` accepts an optional `variant` query parameter. `GET /logs` accepts an optional `variant` query parameter (`PREVIEW` or `PUBLISH`, defaults to `PREVIEW`), plus optional filters for `source` (stream), `level` (severity), and `since` (timestamp). Secret writes take `variant` in the request body.

## Async jobs

Operations that outlive a single request return immediately with a job or deployment record. Poll a status endpoint until they reach a terminal state.

The following diagram shows the create-app polling sequence:

### Terminal states

The following table lists the terminal states for each job type and the endpoint to poll:

| Job type      | Poll endpoint                                                                 | Terminal states                                                                                                    |
| ------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| Create app    | `GET /app-operations/{operationId}`                                           | `COMPLETED` (ready), `FAILED`                                                                                      |
| Source import | `GET /apps/{appId}/imports/{importId}`                                        | `COMPLETED`, `FAILED`                                                                                              |
| Publish       | `GET /apps/{appId}/deployments/{deploymentId}` and `GET /apps/{appId}/status` | Latest deployment reaches `COMPLETED`; then inspect `variants` on the status response for the affected environment |

### Polling guidance

The following list provides guidance for polling async jobs:

* **Interval:** two to five seconds is a good starting point. Back off on longer jobs.
* **Give-up window:** most create and upload jobs complete in under a minute. If you're still in `pending` after several minutes, treat it as stuck and surface an error.
* **Idempotency:** re-polling is free. The status endpoints have no side effects.
* **Idempotency-Key header:** Include `Idempotency-Key: <uuid>` on mutation requests (POST, PATCH) to make retries safe. If the server receives a duplicate request with the same key, it returns the original response without creating a duplicate resource.

## Deployments

A deployment is a snapshot of source + config that ran (or is running). Deployments are numbered and durable. Even after publish overwrites the live one, older deployments remain listable.

The following calls create and list deployments:

```
POST /apps/{appId}/imports          # upload zip → job → new source on preview
POST /apps/{appId}/deployments      # publish preview → new deployment on publish
GET  /apps/{appId}/deployments      # history (paginate with limit, default 20, max 50)
```

Runtime status (`GET /apps/{appId}/status`) is a separate concern from deployments — it tells you whether the variant is actually up and serving, independent of what deployment it points at.

## Secrets

You configure secrets per variant using a standard [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) array. Pass the environment as the `variant` query parameter (`PREVIEW` or `PUBLISH`). Each path is `/{SECRET_NAME}`. A single PATCH request can add, replace, or remove secrets. The combined total must not exceed 50 operations per request. The following request body shows all three operation types in one call:

```json
[
  { "op": "add",     "path": "/STRIPE_KEY", "value": "sk_test_..." },
  { "op": "replace", "path": "/DB_URL",     "value": "postgres://..." },
  { "op": "remove",  "path": "/OLD_FLAG" }
]
```

The response contains metadata only (like names and last-updated timestamps). No endpoint returns secret values, including reads. If you need to know what a secret is set to, look it up in whatever system generated it.

## Putting it together

The following diagram shows the full iteration loop across variants:

Every step above is a single API call plus polling. That's the whole model.

For the end-to-end deploy walkthrough, go to [Deploy your Node.js app](https://developer.godaddy.com/docs/api-users/hosting/workflows/deploy-nodejs-app). For endpoints, go to the [Hosting API reference](https://developer.godaddy.com/docs/references/rest/hosting).

## Scopes reference

Every Hosting API operation requires a specific scope on your Personal Access Token (PAT). Select only the scopes your integration needs. Narrower tokens are easier to reason about when something goes wrong.

Go to [Personal Access Tokens](https://developer.godaddy.com/personal-access-token) to create or update a token.

The following table describes each scope and what it unlocks:

| Scope                        | What it unlocks                      |
| ---------------------------- | ------------------------------------ |
| `hosting.application:read`   | Read application details             |
| `hosting.application:create` | Create new applications              |
| `hosting.application:update` | Update application settings          |
| `hosting.application:delete` | Delete applications                  |
| `hosting.deployment:execute` | Trigger deployments and restarts     |
| `hosting.source:read`        | Read source import status            |
| `hosting.source:write`       | Upload or link source code           |
| `hosting.secret:read`        | List application secrets             |
| `hosting.secret:write`       | Create or update application secrets |
| `hosting.log:read`           | Read application logs                |
| `hosting.domain:read`        | Read attached domains                |
| `hosting.domain:write`       | Attach or remove domains             |
| `hosting.subscription:read`  | Read subscription data               |
| `hosting.subscription:write` | Attach subscriptions to applications |
