Ship a project that already exists — on disk or in a Git repository — to a Hostinger website. Building a new site from a prompt (design, store, blog) is the hostinger-headless skill; this one takes code as it is.
Calling the operations
- Read the
inputSchemathatsearchreturns before the first call of each operation. If a name below is rejected as unknown,searchfor what the step does (e.g. "deploy static"). - Batch reads with
multi-execute; values pass between steps as$steps.<i>.<path>. Batches chain operations from one server only — the Hostinger Connector runshosting,wordpressandagency-hostingas separate servers. - Every deploy overwrites the website's current contents. Confirm the target domain with the user before the first deploy to a site that already has content.
1. Pick the target website
.hostinger/site.jsonin the project: reuse itsdomainandusername(orwebsite_uid).- Otherwise look the domain up with
hosting_websites_list(Shared and Cloud; substring match — take the exact entry) andagency-hosting_websites_list-plan(Agency; keepdetails.uid). - No website yet:
- Shared and Cloud: take a domain (the user's own, or
hosting_domains_generate-free-subdomain) and anorder_idfromhosting_orders_list, thenhosting_websites_create.datacenter_codeis needed only for the first website on a new plan (first entry ofhosting_datacenters_list). Pollhosting_websites_list-setupswithdomainevery 10–15 s untilstatus: completed— uploads and deploys return 404 or 409 before that. - Agency:
agency-hosting_website-setups_createwithflavor: "php-fpm"(plustype: "node-static"for built frontends),settings.php.versionfromagency-hosting_php_list-versions-for-orderanddatacenter_codefromagency-hosting_datacenters_list. Pollagency-hosting_website-setups_statusuntilcompleted; it returns thewebsite_uid.
- Shared and Cloud: take a domain (the user's own, or
- Node.js apps run on Business and Cloud plans (
hostinger_business_*,cloud_*inhosting_orders_list). On other plans, build locally and deploy the output as a static site.
2. Choose the deploy
Wrong method is the most common failure. Decide from the project on disk:
| Project | Shared / Cloud |
|---|---|
| Plain HTML/CSS/JS, or a framework's static build output | hosting_deploy-static-website |
package.json with a build or a server (Next.js, Nuxt, Express, Vite…) |
hosting_deploy-js-application |
| PHP code, no build step | hosting_deploy-static-website (extracts the archive as-is) |
| WordPress plugin or theme folder | hosting_deploy-wordpress-plugin / hosting_deploy-wordpress-theme (activate optional) |
| A whole WordPress site from elsewhere | the migrate-to-hosting skill |
On Agency the website's type decides (agency-hosting_websites_get): sites created as node-static take agency-hosting_deploy-node-static-website, which runs the build when the project has one; every other site takes agency-hosting_deploy-php-application, which extracts the archive as-is. WordPress plugins and themes on Agency sites are installed from wp-admin.
Archive rules (name archives name_YYYYMMDD_HHMMSS.zip):
- Static: build locally first.
index.htmlmust be at the archive root, not inside a folder:cd dist && zip -r ../site_20260101_120000.zip . - Node.js source: no
node_modules/, no build output (dist/,.next/,build/), no.env*, nothing matched by.gitignore; 50 MB at most.git archive --format=zip -o app_20260101_120000.zip HEADproduces exactly the committed files — mention that uncommitted changes are left out. - Agency deploys are synchronous: the site is live when the call returns.
The operations in the table read the archive from this machine, so only the local hostinger-api-mcp server has them. On the hosted server (mcp.hostinger.com) search does not find them — upload the files yourself as below.
Without the local deploy operations
- Get upload credentials:
hosting_files_generate-upload-url(username,domain); Agency:agency-hosting_files_generate-upload-url(website_uid). Both returnurl,auth_keyandrest_auth_key, which authenticate the upload instead of the API token. - Upload each file with TUS, where
DESTis its path in the website's storage:
SIZE=$(wc -c < "$FILE" | tr -d ' ')
curl -sS -X POST "$URL/$DEST?override=true" -H "X-Auth: $AUTH_KEY" -H "X-Auth-Rest: $REST_AUTH_KEY" -H "Tus-Resumable: 1.0.0" -H "Upload-Length: $SIZE" -H "Upload-Offset: 0"
curl -sS -X PATCH "$URL/$DEST?override=true" -H "X-Auth: $AUTH_KEY" -H "X-Auth-Rest: $REST_AUTH_KEY" -H "Tus-Resumable: 1.0.0" -H "Content-Type: application/offset+octet-stream" -H "Upload-Offset: 0" --data-binary "@$FILE"
The first call returns 201, the second 204 with an Upload-Offset header equal to the file size. override=true makes a retry safe.
3. Deploy from the uploaded files (RANDOM8 is any fresh 8-character string, e.g. $(LC_ALL=C tr -dc 'a-z0-9' < /dev/urandom | head -c 8)):
| Project | DEST |
Then |
|---|---|---|
| Static or PHP | site.zip |
hosting_websites_deploy-static-site-archive with archive_path: "site.zip" |
| Node.js | app.zip |
hosting_nodejs_build-settings-from-archive with archive_path: "app.zip", then hosting_nodejs_start-build with those settings, source_type: "archive" and source_options.archive_path: "app.zip" |
| WordPress plugin | every file, as wp-content/plugins/SLUG-RANDOM8/<path in the plugin> |
wordpress_plugins_deploy with slug and plugin_path: "SLUG-RANDOM8" |
| WordPress theme | every file, as wp-content/themes/SLUG-RANDOM8/<path in the theme> |
wordpress_themes_deploy with slug, theme_path: "SLUG-RANDOM8" and optional is_activated |
| Agency, extracted as-is | .h5g/site.zip |
agency-hosting_files_import-website-from-archive with archive_name: "site.zip" |
Agency node-static |
.h5g/RANDOM8/app.zip |
agency-hosting_websites_build-nodejs-assets with archive_path: ".h5g/RANDOM8" — the directory, not the file |
3. Node.js builds
hosting_deploy-js-application uploads the archive to the document root, detects settings from package.json and starts a build. Track it with hosting_nodejs_list-builds and hosting_nodejs_build (by uuid), polling every 10–20 s — builds take minutes.
- Failed build:
hosting_nodejs_analyse-failed-buildonce per build (5 calls a minute), thenhosting_nodejs_build-logsif the analysis is empty. - Wrong detection (framework,
output_directory, or a missingentry_filefor express, fastify, nest, nuxt and hono): runhosting_nodejs_start-buildwith explicit values,source_type: "archive"andsource_options.archive_pathset to the archive's file name in the document root (check it is there withhosting_files_list-website-and-directories). Store the same values withhosting_nodejs_update-build-settings. - To review detected settings before any build: upload the archive with
hosting_files_generate-upload-url(the TUS steps are in its description), thenhosting_nodejs_build-settings-from-archive.
4. Auto-deploy from Git
hosting_git_list-installations. With noactiveinstallation (checkstatus: "pending"and"suspended"too), the user connects GitHub or GitLab once in hPanel under Websites → Manage → Advanced → Git; there is no API for that step.hosting_git_list-installation-repositorieswith the installationuuidgivesowner,nameanddefault_branch(10 calls a minute).hosting_git_update-auto-deployment-settingswithinstallation_uuid,owner,repository,branchand optionaldirectory.- PHP and static sites deploy the branch immediately and again on every push.
- Node.js sites clone nothing on save: start the first build with
hosting_nodejs_start-build,source_type: "git"and the samesource_options. Later pushes build with the stored settings, so keephosting_nodejs_update-build-settingscorrect.
- Confirm with
hosting_git_auto-deployment-settings.
Agency Plan sites have no Git operations; deploy archives.
5. Environment variables (Node.js)
hosting_nodejs_replace-environment-variables replaces the whole set — anything not sent is deleted.
hosting_nodejs_list-environment-variablesfor the current keys. Values come back as********; never send those back.- Build the full set: every current key plus the new ones, with real values from the project's
.envor the user. When the real value of an existing key is unknown, ask — do not drop it. - Send it once; the app restarts. Values baked in at build time (Next.js
NEXT_PUBLIC_*, ViteVITE_*) need a newhosting_nodejs_start-build.
Keys use uppercase letters, digits and underscores. Never commit .env files or repeat secret values back to the user.
6. Database
- Node.js:
hosting_databases_setup-websitecreates a MySQL database and writesDB_HOST,DB_PORT,DB_NAME,DB_USER,DB_PASSWORDandDATABASE_URLinto the environment, then restarts the app. The password is generated and never returned. It fails with 422 when any of those keys exists — remove them first with the step 5 replace. - PHP:
hosting_databases_createwithname,user, a strong generatedpasswordandwebsite_domain; read the prefixed full name back fromhosting_databases_list. The app reads credentials from a config file on the server that stays out of Git, and connects tolocalhostor127.0.0.1. - Agency:
agency-hosting_databases_create-website; the app connects tolocalhost. - The
srvNNNN.hstgr.iohost fromhosting_databases_listis only for connections from outside Hostinger — never put it in the deployed app.
7. Verify and record
curl -s -o /dev/null -w "%{http_code}\n" https://DOMAIN/
curl -s https://DOMAIN/ | grep -o "TEXT THE PROJECT RENDERS"
A 200 alone can be a placeholder page; match real copy. A new site may serve a default page briefly — clear it with hosting_cache_clear-website and retry before calling the deploy failed.
Write .hostinger/site.json in the project so later runs reuse the target: { "domain", "username" or "website_uid", "type": "static" | "nodejs" | "php" }, keeping any fields already there.