Documentation

REST API v1 for static hosting workspaces. Base URL: https://ipfshost.io/api/v1

Bearer Create keys in Dashboard → API KeysAPI Keys

Static-only hosting

IPFSHost hosts static output only. Apps that need a running server, database, or PHP runtime must be exported to static or use an external backend.

Supported: HTML/CSS/JS, React/Vue/Astro/Vite builds, docs sites, ZIP exports. Not supported: PHP, MySQL, SSR without static export.

Quick start

Deploy a static site in three steps — no infrastructure expertise required.

  1. Sign up at onboarding or create a workspace.
  2. Deploy — public GitHub repo (Deploy) or ZIP with index.html (Upload).
  3. Share — use the preview URL immediately; connect a custom domain when ready.

Reliable static hosting with predictable deploys and rollback — no VPS to manage.

Git deploy (Dashboard)

Public GitHub or GitLab.com repo URL in Dashboard → Deploy — framework detection, isolated build, preview URL. Not available via REST API v1 (ZIP and file upload are). SSR/PHP runtimes are not supported.

Accepted URLs: https://github.com/owner/repo, https://gitlab.com/group/repo (nested groups supported), git@gitlab.com:group/repo.git. Self-hosted GitLab is not supported.

ZIP deploy

Upload a static build archive via dashboard or POST /api/v1/sites/deploy-zip.

Alpha limits

Build timeout, repo size, and output caps are listed under Build limits. Plan quotas apply per workspace.

Static compatibility matrix

See Frameworks — only static output (HTML/CSS/JS assets) is hosted.

Workspace registration

Creates a workspace (tenant), owner account, and an onboarding API key. Used by guided onboarding and by integrations — no API key required for this call.

POST /api/v1/onboarding/register — JSON body:

{
  "name": "my-site",
  "email": "you@example.com",
  "password": "min-8-chars",
  "slug": "optional-workspace-slug",
  "invite_code": "alpha-optional-when-required"
}
  • name — workspace / project label (required, max 64 characters after trim).
  • email — owner login (required, unique per account).
  • password — min. 8 characters (required).
  • slug — optional URL-safe id; derived from name if omitted.
  • invite_code — required when public alpha invite mode is enabled on the server.

Response 201 — example:

{
  "ok": true,
  "tenant": { "id": "…", "slug": "my-site", "name": "my-site" },
  "user": { "id": "…", "email": "you@example.com", "role": "owner" },
  "api_key": {
    "id": "…",
    "prefix": "ipfh_…",
    "key": "ipfh_…full_secret_shown_once"
  },
  "dashboard_login": "/dashboard/login",
  "steps": ["Save your API key — shown once", "…"]
}

The onboarding key is created with scopes upload, deploy, and read. Store api_key.key immediately — it is not shown again.

Guided onboarding then signs in via POST /dashboard/auth/login (browser cookie). API-only clients can use the returned key without a session.

Errors: project_name_required, project_name_too_long (with max_length), Tenant slug already exists, Invite code required / Invalid invite code (when invites enabled), other validation as 400 with error message.

Guided onboarding

The wizard at /onboarding walks through project type, deploy method (GitHub, GitLab, ZIP, API, or docs), workspace registration, and first deploy.

  • Guests must complete workspace registration (email + password) before Git/ZIP/API deploy steps — the UI calls POST /api/v1/onboarding/register then opens the dashboard or deploy screen.
  • ZIP — upload at step 4 or use POST /api/v1/sites/deploy-zip with the onboarding key.
  • GitHub / GitLab — after registration, continue in Dashboard → Deploy (not available on REST API v1).
  • API-only path — choose API in the wizard or skip the UI: register via this endpoint, then call v1 with Authorization: Bearer ….
  • Documentation-only — selecting docs still shows the registration step, then returns here.

Shortcut: /onboarding?mode=zip pre-selects ZIP upload.

Dashboard session (browser)

Cookie-based auth for the web dashboard (separate from API keys). Base path: /dashboard/auth.

MethodPathNotes
POST/dashboard/auth/registerSame fields as onboarding register (+ optional invite_code); sets session cookie.
POST/dashboard/auth/loginJSON { "email", "password" } → session cookie.
POST/dashboard/auth/logoutClears session cookie.
GET/dashboard/auth/meReturns { ok, session } with tenant_id, email, role when logged in.
POST/dashboard/auth/resend-verificationResend verification email (session or email in body). Cooldown 30s.
GET/dashboard/auth/verify-email?token=…Email confirmation link (confirms on server, redirects to login). Legacy /dashboard/verify-email redirects here.
POST/dashboard/auth/forgot-passwordRequest reset link (+ captcha). JSON may include lang: en | ru.
POST/dashboard/auth/reset-passwordSet new password with token from email.
POST/dashboard/auth/sync-localeSave UI language (lang) for transactional emails (session required).
GET/dashboard/auth/oauth/providersLists enabled OAuth providers (GitHub, Google).

Dashboard ZIP deploy: POST /dashboard/api/deploy-zip (multipart archive, session cookie) — see Deploy ZIP.

Register and forgot-password require a captcha (GET /dashboard/auth/captcha?purpose=register|forgot_password). Pass captcha_id, captcha_answer, and optional lang in the POST body.

Account & email

New workspaces must confirm the owner email before deploy, API keys, or custom domains. Password reset and security notices are sent from IPFSHost (noreply@ipfshost.io).

  • Verification — after register or OAuth sign-up, open the link in the email (valid 24h). Until verified, the dashboard shows a resend gate.
  • Language — emails use EN or RU based on the site language switcher, lang in auth requests, cookie ipfshost_lang, or Accept-Language. Changing language in the dashboard updates stored preference.
  • OAuthGET /dashboard/auth/oauth/{provider}?mode=login|register starts GitHub or Google sign-in when configured. Email from the provider must be visible.
  • Workspace slug — the optional slug at registration is an internal workspace address, not your public website domain. Custom hostnames are added later under Custom domains.

Authentication

Send your API key in the Authorization header (or use a session cookie only for dashboard HTML/API under /dashboard/api, not for /api/v1).

Authorization: Bearer ipfh_your_secret_key

Or header X-API-Key: ipfh_…. Raw key is shown once at creation. Verify a key with GET /api/v1/me (scope read).

curl -sS "https://ipfshost.io/api/v1/me" \
  -H "Authorization: Bearer $IPFSHOST_API_KEY"

Upload file

POST /api/v1/files/upload — multipart file, optional name.

curl -X POST "https://ipfshost.io/api/v1/files/upload" \
  -H "Authorization: Bearer $IPFSHOST_API_KEY" \
  -F "file=@./document.pdf" \
  -F "name=document.pdf"
Response 201
{
  "ok": true,
  "site": { "id": "…", "release_id": "…", "status": "live", "preview_url": "https://…" }
}

Deploy ZIP site

POST /api/v1/sites/deploy-zip — multipart field file (.zip), optional name (display name, max 64 chars). Requires index.html at site root or in dist/.

Dashboard ZIP upload uses field archive on POST /dashboard/api/deploy-zip — different from API v1.

curl -X POST "https://ipfshost.io/api/v1/sites/deploy-zip" \
  -H "Authorization: Bearer $IPFSHOST_API_KEY" \
  -F "file=@./dist.zip" \
  -F "name=my-site"

POST /api/v1/sites/:id/redeploy-zip — same multipart shape (file, optional name).

List sites & preview URLs

GET /api/v1/sites — each site includes preview_url, gateway_url, and urls (stable for the active release CID). GET /api/v1/sites/:id for one site. Preview links are not one-time tokens — they stay valid while the release is published.

curl -sS "https://ipfshost.io/api/v1/sites" \
  -H "Authorization: Bearer $IPFSHOST_API_KEY"

Platform status

GET /api/status — public metrics. trust.deploys_today counts ZIP publishes + Git builds today; trust.storage_nodes_total is delivery fleet size; trust.nodes_online is platform workers. See metric_hints in the JSON.

Quotas

GET /api/v1/quota returns storage, objects, bandwidth usage vs soft/hard limits. Exceeding hard limits returns 402 with quota_exceeded.

Error format

CodeHTTPMeaning
auth_required401Missing API key
scope_denied403Key lacks scope
quota_exceeded402Hard quota hit
rate_limited429Too many requests
project_name_required400Empty workspace name (onboarding)
project_name_too_long400Name longer than 64 characters
Tenant slug already exists400Pick another slug or name
Invite code required400Alpha invite mode — send invite_code
Invalid invite code400Unknown or exhausted invite
{ "ok": false, "error": "Human message", "code": "quota_exceeded" }

Scopes

ScopeAccess
readList files, sites, quota
uploadUpload files
deployDeploy ZIP sites
adminAPI keys, settings (workspace admin)

Rate limits

Per-workspace API RPS and per-key windows apply. Response 429 includes Retry-After header (seconds).

Git deploy flow

1. Dashboard → Deploy — paste GitHub or GitLab.com URL
2. Auto-detect framework (Vite, Next static export, Astro, …)
3. Build → preview URL
4. Dashboard → Domains → verify DNS records

Framework matrix (static-only)

PresetBuildOutputNotes
Angularnpm run builddist/browser/Browser build only — no SSR server on IPFS; base href="./"
React / Vue (Vite)npm run builddist/SPA — API on separate origin
Next.js staticnpm run buildout/Requires output: export
Astro / Nuxt / GatsbySSG commanddist/ / .output/publicNo SSR on IPFS
WordPressstatic exportSimply Static / WP2Static ZIP only
ZIP uploadZIP onboarding

IPFS hosts immutable static snapshots — not PHP, Node servers, or SSR runtimes.

Point your domain to immutable content via TXT record:

_dnslink.example.com  TXT  dnslink=/ipfs/<release-id>

After deploy, use Dashboard → Domains to add your hostname, copy TXT instructions, and run verify.

Custom gateway

Serve https://yourdomain.com via gateway.ipfshost.io (or your configured PUBLIC_GATEWAY_URL):

  • DNSLink — _dnslink.example.com TXT dnslink=/ipfs/<release-id>
  • CNAME — point www to your preview hostname
  • nginx — proxy_pass to /ipfs/<release-id>/

Preview URLs: https://preview.ipfshost.io/ipfs/<release-id> (see PUBLIC_PREVIEW_URL).

Build limits

LimitDefault
Build timeoutBUILD_MAX_SECONDS=300
Repo clone sizeBUILD_MAX_REPO_MB=200
Output sizeBUILD_MAX_OUTPUT_MB=500
Log linesBUILD_MAX_LOG_LINES=5000

Preflight checks (git, node, npm, disk) run before each build. Long-running dev servers are blocked.

SPA routing on IPFS

Gateways serve files by path. Browser history routes (/about) need either:

  • Hash router#/about (works everywhere)
  • Gateway fallback — nginx/Cloudflare serves index.html for unknown paths
  • Vite basebase: './' for relative assets

React (Vite)

npm run builddist/. Use HashRouter or configure gateway SPA fallback. Avoid absolute /assets/ URLs.

Vue (Vite)

Same as React — base: './' in vite.config, history mode needs gateway fallback.

Astro

Static output only. Large content collections increase build size — trim assets if output exceeds limits.

Common deployment fixes

Symptom → cause → fix for the most common Dashboard deploy failures.

SymptomLikely causeFix
Multiple index.htmlMonorepo root / Static HTML presetReact+Vite preset + tree URL to app folder, or npm run builddist/
Git clone failedWrong repo URL or private repoPublic repo; monorepos: /tree/branch/path
No build / raw repo publishedStatic HTML preset on app repoMatch preset to detection (Vite → React/Vite)
Routes 404SPA history modeHash router or gateway fallback
Blank pageWrong asset basebase: './' in Vite
npm exit 1Install/build errorRun npm ci && npm run build locally
npm ci EUSAGENo package-lock.jsonRedeploy (auto npm install) or commit lockfile
Daily build limitBuilds today ≥ planWait UTC midnight or Dashboard → Usage
SSR errorNext server codeoutput: 'export'
DNS verify failsTXT not propagatedWait TTL, grey-cloud TXT on Cloudflare

Troubleshooting builds

Build-time issues on the Git worker. Anchor: #troubleshooting.

  • Multiple index.html — monorepo root with Static HTML preset.
  • Git clone / auth — public repos only; use tree URLs from templates.
  • Wrong framework preset — align preset with detection on step 2.
  • Preflight fail — install git/node/npm on the host or pick a simpler preset.
  • Timeout — reduce dependencies or split build; default 300s.
  • Output missing — check preset output dir (dist, out, …).
  • DNSLink verify — wait for TXT propagation; disable CF proxy on TXT.
  • No verification email — check spam; wait 2 minutes before resend; link expires after 24h.

Node.js & Python

const fd = new FormData();
fd.append("file", fileBlob, "file.txt");
const res = await fetch("https://ipfshost.io/api/v1/files/upload", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.IPFSHOST_API_KEY}` },
  body: fd,
});
if (!res.ok) throw new Error((await res.json()).error);
const { site } = await res.json();
import os, requests
r = requests.post(
    "https://ipfshost.io/api/v1/files/upload",
    headers={"Authorization": f"Bearer {os.environ['IPFSHOST_API_KEY']}"},
    files={"file": open("file.txt", "rb")},
)
r.raise_for_status()
print(r.json()["site"]["cid"])